9) Sécurité, conformité, gouvernance — RAG
PII & masquage, GDPR/registre & DSR, RBAC/RLS & filtres, purge ciblée, chiffrement & rotation, gouvernance/audit & supply-chain.
PII & classification GDPR, DPA & DSR RBAC/RLS & filtres Chiffrement & rotation Gouvernance & audit
Mise en Œuvre des Outils
Sanitizers PII & DLP, RLS Postgres/pgvector & filtres Search, OPA/Rego, purge DSR, KMS/Vault, supply-chain & alerting sécurité.
9) Sécurité, conformité, gouvernance (en parallèle)
Catalogue & politiques
- Classification : Public Interne Confidentiel Très sensible (PII/Secrets).
- PII ciblées : noms, emails, tél., adresses, IBAN, NIR, num. client, identifiants internes.
- Masquage à l’ingestion (regex/NER) + pseudonymisation déterministe.
- Filtrage à la restitution : suppression sélective des champs pii + caviardage dans les citations RAG.
- Logs/traces : interdiction PII → user_hash + métadonnées non identifiantes.
Revue mensuelle des faux positifs/negatifs du DLP + mise à jour des règles & dictionnaires.
Table de mapping (ex.)
| Attribut | Détection | Action ingestion | Action restitution |
|---|---|---|---|
| regex | hash SHA-256 | mask “u***@d***” | |
| Téléphone | regex | normalisation + mask | supprimer |
| IBAN | regex + check | tokenisation Vault | token → dernier 4 |
| Noms | NER fr/en | pseudonyme stable | sur demande DSR : remplacement |
Registre & bases légales
- Registre des traitements (finalité, base légale, durée, sous-traitants, transfert hors UE).
- DPA fournisseurs (LLM API, SaaS index/search), clauses SCC.
- DPIA si données sensibles/volumes élevés.
Rétention & localisation
- Logs 90j, traces 30j, index 12–24 mois. TTL/partitions DB.
- Stockage UE only, sauvegardes chiffrées (KMS/HSM).
DSR (Data Subject Rights)
- Accès : export JSON des traces/feedback par user_hash (sous 30 j).
- Suppression : purge document + chunks + embeddings + snapshots d’index.
- Rectification : correctif + ré-indexation priorisée.
Journal DSR : demande, identity check, artefacts purgés, date de clôture, agent responsable.
Contrôle d’accès
- Claims IdP : role business_unit region scopes.
- RBAC + ABAC : vérification back-end + RLS côté SQL.
- Filtrage au retrieval : métadonnées index = claims utilisateur.
- Decision logs : tracer allow/deny + raison.
Matrice d’accès (ex.)
| Rôle | BU | Doc types | Région | Lang |
|---|---|---|---|---|
| Support L1 | IT | runbook, faq | EU | fr,en |
| RH | HR | policy, guide | EU | fr |
| Partner | EXT | public | Global | en |
Chiffrement
- At-rest : DB, blobs, index (clé KMS/Vault, enveloppe AES-256-GCM).
- In-transit : TLS 1.2+ mutual TLS entre services sensibles.
- Bring-Your-Own-Key / HSM pour documents très sensibles.
Rotation & secrets
- Rotation clés 90j (KMS/Vault), re-chiffrement lazy.
- Secrets via Vault (short-lived) + sidecar/agent.
- CI/CD : scan secrets (gitleaks), image signing (cosign), SBOM (Syft).
Réseau & durcissement
- Private endpoints / VPC-peering ; egress restreint.
- WAF/Rate limit, mTLS pour l’API RAG.
- Pods rootless, PSS/PSA, read-only FS, seccomp.
Gouvernance
- Policies écrites : classification, IA acceptable, secrets, accès.
- Comité risque : revue mensuelle incidents/red teaming.
- SoD / break-glass : accès admin temporaires tracés.
Audit & KPIs sécurité
- Événements : policy_deny purge key_rotate dsr_done.
- KPIs : taux deny, âge clés, délai DSR, secrets détectés, conformité scans.
- Alertes : deny_rate↑, purge_fail↑, key_age_hours > seuil.
Livrables
- Matrice d’accès (roles × BU × types × régions).
- Procédures : purge DSR, rotation clés, onboarding/offboarding.
- Registre GDPR + DPA + DPIA.
- Rapport d’audit trimestriel + plan d’actions.
Contrat sécurité (JSON exportable)
{
"classification":["public","interne","confidentiel","tres_sensible"],
"pii":{"ingest_mask":true,"output_filters":true,"log_user_hash":true},
"retention":{"logs_days":90,"traces_days":30,"index_days":365},
"rbac":{"claims":["role","business_unit","region"],"rls_sql":true,"search_filters":true},
"crypto":{"at_rest":"KMS_AES256","in_transit":"TLS1.2+","rotation_days":90},
"dsr":{"access":true,"delete":true,"rectify":true,"sla_days":30},
"audit":{"events":["policy_deny","purge","key_rotate","dsr_done"],"retention_days":365}
}Mise en Œuvre des Outils — Sécurité/Conformité
# pii_sanitize.py (regex + NER)
import re, hashlib
RE_EMAIL = re.compile(r"[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\.[A-Za-z]{2,}")
def h(x): return hashlib.sha256(x.encode()).hexdigest()[:16]
def sanitize(txt):
txt = RE_EMAIL.sub(lambda m: f"email:{h(m.group(0))}", txt)
# TODO: NER noms → pseudonymes stables
return txt# policy sortie (post-process)
def redact_out(answer, meta):
if meta.get("pii_level") == "high": return "[Contenu caviardé]"
return answer-- Postgres RLS (pgvector)
ALTER TABLE chunks ENABLE ROW LEVEL SECURITY;
CREATE POLICY chunks_policy ON chunks
USING (business_unit = current_setting('app.claims.bu', true)
AND region = current_setting('app.claims.region', true));# OpenSearch / Weaviate query (filtre métadonnées)
q = {
"knn": {"field":"vec","query_vector": qvec, "k":50, "num_candidates":1000},
"filter": {"bool":{"must":[
{"term":{"business_unit": claims["bu"]}},
{"term":{"region": claims["region"]}}
]}}
}# purge.py (DSR delete / purge ciblée)
def purge_source(source_id):
for t in ["documents","chunks","embeddings","index_snapshots"]:
delete(t, where={"source_id": source_id})
log_sec("purge", source_id=source_id)# TTL / partition (ex. Postgres)
CREATE TABLE logs_2025_09 PARTITION OF logs FOR VALUES FROM ('2025-09-01') TO ('2025-10-01');
-- job mensuel : DROP PARTITION (rétention 90j)# rotation clé (AWS KMS – auto)
aws kms enable-key-rotation --key-id <KEY_ID># chiffrement applicatif
from cryptography.hazmat.primitives.ciphers.aead import AESGCM
KEY = os.environ["RAG_ENC_KEY"] # fourni par KMS/Vault
def enc(b):
aes = AESGCM(KEY)
return aes.encrypt(os.urandom(12), b, None)# policy.rego (deny avec raisons)
package rag.access
default allow = false
deny[reason] {
input.doc.doc_type == "restricted"
input.claims.role != "admin"
reason := "doc_type_restricted"
}
allow {
input.claims.bu == input.doc.business_unit
not deny[_]
}# décision
opa eval -i input.json -d policy.rego "data.rag.access.allow"# GitHub Actions (SAST + SBOM + image signing)
- run: pip install bandit && bandit -q -r src/
- run: syft packages dir:./ -o json > sbom.json
- run: cosign sign --key cosign.key $IMAGE# Network Policy (K8s)
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
spec:
podSelector: {matchLabels: {app: rag-api}}
policyTypes: ["Ingress","Egress"]
egress:
- to: [{namespaceSelector:{matchLabels:{ns:"vectordb"}}}]# PromQL (sécurité)
sum(rate(policy_deny_total[5m])) by (reason)
avg_over_time(dsr_completion_days[30d])
(max(time() - key_last_rotated_seconds) / 3600) > 24*90 # > 90 jours
sum(rate(secrets_detected_total[1h]))