akko-policy-sync — auto-propagation PII¶
akko-policy-sync ferme la boucle entre la classification des
données et l'application des accès. Un steward classifie une colonne
en PII.Sensitive dans Catalogue. Le daemon récupère le tag à la
prochaine boucle de synchronisation, calcule les masques de colonnes
correspondants pour chaque sujet non administrateur dont le périmètre
couvre la table, puis fait un PATCH sur le ConfigMap du bundle Moteur de politiques.
Moteur de requête recharge le bundle et commence à masquer la colonne pour les
analystes — typiquement en moins de 30 secondes, ou en moins de
5 secondes si le steward déclenche une synchro manuelle depuis le
cockpit.
Le daemon est désactivé par défaut. Activez enabled: true
seulement après avoir provisionné un JWT bot Catalogue.
Sprint 67 PR-D / ADR-055 — V1 timer + déclenchement manuel
La V1 livre l'ordonnanceur périodique (30 min), le déclenchement manuel, le panneau cockpit et l'audit OCSF 3007. La V2 ajoutera un EventListener OM par webhook quand le retour client montrera que la fenêtre 30 min est trop longue. Voir ADR-055.
Quand l'activer¶
Activez-le quand les quatre conditions sont vraies :
- Catalogue est la source de vérité du tagging PII colonne par colonne.
- Le bundle Moteur de politiques détient vos policies de masquage ligne + colonne (topologie AKKO par défaut — Sprint 67 PR-C).
- Vous voulez que le travail de classification déclenche l'enforcement automatiquement, sans édition manuelle.
- Vous pouvez créer un user bot OM avec accès en lecture à
/api/v1/tables+/api/v1/classifications.
Si l'une de ces conditions est fausse, gardez enabled: false. Les
stewards continuent d'éditer les masques manuellement via
l'assistant de la page Data Access du cockpit (Sprint 67 PR-C) —
cette boucle fonctionne déjà seule.
Architecture¶
flowchart LR
subgraph Déclencheurs
T1[CronJob 30 min]
T2[POST /api/v1/sync<br/>panneau cockpit]
end
T1 --> SVC
T2 --> SVC
SVC[akko-policy-sync<br/>FastAPI + asyncio]
SVC -->|GET tags<br/>Bearer JWT| OM[OpenMetadata<br/>:8585]
SVC -->|PATCH ConfigMap<br/>If-Match resourceVersion| OPA[bundle OPA<br/>ConfigMap]
SVC -->|HTTP /insert/jsonline<br/>OCSF 3007| VL[VictoriaLogs<br/>:9428]
OPA --> Trino[Enforcement Trino<br/>masquage SHA-256]
Configuration¶
Le values.yaml umbrella expose akko-policy-sync. Le minimum
viable est :
akko-policy-sync:
enabled: true
openmetadata:
baseUrl: http://akko-openmetadata-server:8585
jwtSecret:
name: akko-openmetadata-bot-jwt
key: token
piiTagToMask:
PII.Sensitive: sha256
PII.NonSensitive: identity
adminSubjects:
- akko-admin
- AD_admin
syncIntervalSeconds: 1800
akko-cockpit-backend:
policySync:
url: http://akko-akko-policy-sync:8080
Remplacez akko par votre release name s'il diffère.
JWT bot — création d'un token Catalogue¶
# 1. Ouvrir l'UI admin OM avec un user qui a `Settings` / `Bots`.
# 2. Créer un nouveau bot, p.ex. `akko-policy-sync`.
# 3. Générer un JWT avec rôle `DataStewardRole` (lecture tables/tags)
# et expiration 1 an.
# 4. Persister dans le namespace AKKO :
kubectl -n akko create secret generic akko-openmetadata-bot-jwt \
--from-literal=token="<coller-le-jwt-ici>"
À la rotation du token, mettez le Secret à jour. Le daemon relit le fichier à chaque cycle ; pas de redémarrage nécessaire.
Mapping tag → masque¶
piiTagToMask est le seul levier produit. Tout tag OM à gauche
mappe vers le nom de masque à droite. Le nom doit exister dans le
mask_library Moteur de politiques (sha256, md5, null, redact, identity,
partial_last4 par défaut).
piiTagToMask:
PII.Sensitive: sha256
PII.NonSensitive: identity
PCI.PAN: partial_last4
Compliance.HealthRecord: null
Un tag absent du map ne déclenche aucune auto-propagation — la colonne passe sans modification.
Exempter des sujets¶
Les sujets dans adminSubjects sont sautés : le propagateur ne
hashe jamais leurs requêtes. Par défaut = [akko-admin, AD_admin].
Ajoutez tout sujet qui doit toujours voir le clair (auditeurs, DBA
d'astreinte, comptes break-glass).
Exploitation¶
Lancer une synchro depuis le cockpit¶
Ouvrez https://demo.<votre-domaine>/#data-access, descendez
jusqu'à Auto-propagation PII, cliquez Lancer la synchro
maintenant. La grille sous la barre d'outils s'actualise avec le
résumé du run :
- timestamp + durée du dernier run
- tables traitées
- sujets impactés
- échecs de publication (doit rester à 0)
- prochaine exécution planifiée
Le déclencheur est protégé par akko-admin et émet un événement
OCSF 3007 vers Couche Logs (VictoriaLogs) (activity_id = OTHER, cible =
service:policy-sync). L'onglet Audit liste chaque run manuel à
côté des éditions humaines de la Data Access.
Inspection en kubectl¶
kubectl -n akko port-forward svc/akko-akko-policy-sync 8080:8080 &
curl -s localhost:8080/api/v1/status | jq .
curl -s localhost:8080/api/v1/config | jq .
curl -X POST localhost:8080/api/v1/sync | jq .
Couche Métriques (Prometheus)¶
akko_policy_sync_runs_total{outcome="success"}
akko_policy_sync_runs_total{outcome="failure"}
akko_policy_sync_tables_processed_total
akko_policy_sync_subjects_affected_total
akko_policy_sync_publish_failures_total
akko_policy_sync_last_run_timestamp_seconds
Un publish_failures_total non nul sur deux runs consécutifs doit
appeler l'astreinte. Causes courantes :
| Cause | Symptôme | Correction |
|---|---|---|
| JWT bot OM expiré | Tous les runs échouent en HTTP 401 OM | Régénérer le token + mettre à jour le Secret |
| OM injoignable | connect-refused dans les logs du pod |
Vérifier le Service OM + l'egress NetworkPolicy en 8585 |
| Drift du configmap Moteur de politiques | HTTP 409 sur le PATCH | Un second writer édite le bundle ; vérifier les logs de l'éditeur Data Access |
pii_tag_to_mask réfère un masque inexistant |
Le rechargement Moteur de politiques garde silencieusement l'ancien bundle | Ajouter le masque à l'overlay mask_library Moteur de politiques |
Masques manuels vs masques auto¶
Le daemon marque chaque entrée qu'il écrit avec
source: "auto-pii". À chaque cycle de synchro, seules les
entrées avec ce source sont remplacées. Les masques manuels ajoutés
via l'assistant de la Data Access (Sprint 67 PR-C) ne portent pas
de champ source et passent sans modification. Les stewards peuvent
mélanger les deux librement : un masque manuel partial_last4 sur
customers.phone cohabite avec un masque auto-propagé sha256 sur
customers.email sans conflit.
Piste d'audit¶
Chaque run de synchro produit un événement OCSF 3007 :
class_uid= 3007 (Data Access Management)activity_id= 99 (OTHER)actor.user.name=system:policy-syncpour les runs périodiques, lepreferred_usernamede l'admin pour les runs manuelsmetadata.product.name=akko-policy-syncunmapped.tables_processed,unmapped.subjects_affected,unmapped.publish_failuresresources= liste complète des sujets dont la policy a été touchée
Requête Couche Logs :
Ou ouvrez l'onglet Audit du cockpit — les entrées arrivent dans le même flux que les éditions humaines.
Sécurité¶
| Vecteur | Mitigation |
|---|---|
| Élévation de privilèges | RoleBinding scopé à un seul ConfigMap par resourceNames, verbes limités à get / patch / update (pas de list / create / delete / *) |
| Tag-injection depuis un OM compromis | Le propagateur ne peut poser que des masques existant dans mask_library ; un tag malveillant mappé sur rien est un no-op |
| Exfiltration réseau | Allow-list NetworkPolicy egress : OM 8585, VL 9428, kube API 443 + 6443 (kube-router post-DNAT) ; tout le reste refusé |
| Contournement audit | Chaque run émet OCSF 3007 ; les déclencheurs manuels portent le sub de l'admin appelant |
| Vol du JWT bot | Token dans un Secret namespace-scopé ; rotation annuelle |