Aller au contenu

OPA — Contrôle d'accès fin

Open Policy Agent (OPA) fournit une autorisation policy-as-code pour AKKO. Il s'intègre à Trino pour appliquer la sécurité par ligne, le masquage de colonnes et le contrôle d'accès basé sur les attributs (ABAC) — le tout défini en politiques Rego.

Fonctionnement

Utilisateur (alice) → Requête Trino → Vérification OPA → Autoriser / Refuser / Filtrer / Masquer

OPA évalue chaque requête Trino par rapport aux politiques Rego avant l'exécution :

  1. Autorisation — Cet utilisateur peut-il accéder à ce catalogue/schéma/table ?
  2. Filtrage par ligne — Quelles lignes cet utilisateur peut-il voir ?
  3. Masquage de colonnes — Les colonnes sensibles doivent-elles être masquées ?

Structure des politiques

Les politiques sont définies en Rego et déployées via ConfigMap (voir helm/akko/charts/akko-opa/templates/configmap.yaml). Trois fichiers de politique gèrent différents aspects :

Fichier Objectif
trino_access.rego Autoriser/refuser par opération et par rôle
column_masking.rego Masquage PII des colonnes pour user/viewer
row_filter.rego Sécurité au niveau des lignes (ex : viewers ne voient que les comptes actifs)
package trino
import rego.v1

# Refus par défaut — chaque accès doit être explicitement autorisé
default allow := false

# Les administrateurs peuvent tout faire
allow if {
    "akko-admin" in input.context.identity.groups
}

# Utilisateurs standard (conformité) : SELECT uniquement, PII masqué (voir column_masking.rego)
allow if {
    "akko-user" in input.context.identity.groups
    input.action.operation in [
        "ExecuteQuery", "AccessCatalog", "FilterCatalogs",
        "FilterSchemas", "FilterTables", "FilterColumns",
        "SelectFromColumns", "ShowSchemas", "ShowTables",
        "ShowColumns", "ShowCreateTable", "ShowFunctions", "ShowStats"
    ]
}

Rôles RBAC

Les politiques OPA correspondent aux cinq rôles Keycloak :

Rôle Niveau d'accès
akko-admin Accès complet, aucun masquage
akko-engineer DDL + DML (CREATE, INSERT, SELECT), aucun masquage
akko-analyst SELECT uniquement, visibilité PII complète (aucun masquage)
akko-user SELECT uniquement, colonnes PII masquées
akko-viewer SELECT uniquement, filtré par lignes, PII masqué

Pour la matrice d'accès complète et les détails des politiques, voir le Guide d'administration RBAC.

Intégration Trino

Trino est configuré pour déléguer le contrôle d'accès à OPA :

access-control.name=opa
opa.policy.uri=http://akko-akko-opa:8181/v1/data/trino/allow
opa.policy.row-filters-uri=http://akko-akko-opa:8181/v1/data/trino/rowFilters
opa.policy.column-masking-uri=http://akko-akko-opa:8181/v1/data/trino/columnMask

Configuration

Kubernetes (Helm)

akko-opa:
  enabled: true
  resources:
    requests:
      cpu: 50m
      memory: 64Mi
    limits:
      cpu: 200m
      memory: 256Mi

OPA est léger — il nécessite des ressources minimales et ajoute une latence négligeable aux requêtes.

Ajouter des politiques

  1. Créez ou modifiez les fichiers Rego dans le répertoire des politiques OPA
  2. Les politiques sont montées via ConfigMap avec subPath par fichier (pas un montage de répertoire, pour éviter les boucles de liens symboliques)
  3. OPA recharge les politiques à chaud — aucun redémarrage nécessaire

Tester les politiques

Utilisez opa eval localement pour tester avant de déployer :

opa eval -i input.json -d policy.rego "data.trino.allow"

Dépannage

Évaluation de politique refusée de manière inattendue

Symptômes : Les requêtes Trino échouent avec Access Denied pour des utilisateurs qui devraient avoir accès. Le journal de décisions OPA affiche "result": false pour des requêtes qui devraient être autorisées.

Cause : La logique de la politique Rego est incorrecte, les appartenances aux groupes de l'utilisateur depuis Keycloak ne sont pas transmises correctement dans l'entrée OPA, ou le rôle de l'utilisateur n'est pas couvert par une règle allow (rappel : default allow := false).

Solution :

# Consulter les journaux de décisions OPA
kubectl logs -n akko deploy/akko-akko-opa --tail=100

# Interroger OPA directement pour déboguer la décision
kubectl exec -n akko deploy/akko-akko-opa -- curl -s -X POST \
  http://localhost:8181/v1/data/trino/allow \
  -d '{"input":{"context":{"identity":{"user":"alice","groups":["akko-admin"]}},"action":{"operation":"SelectFromColumns"},"resource":{"table":{"catalogName":"iceberg","schemaName":"banking","tableName":"customers"}}}}' | python3 -m json.tool

# Vérifier que les groupes de l'utilisateur sont correctement mappés depuis Keycloak
kubectl exec -n akko deploy/akko-trino-coordinator-0 -- \
  curl -s http://localhost:8080/v1/info | python3 -m json.tool

Échec d'intégration Trino (bundle non chargé)

Symptômes : Trino démarre mais toutes les requêtes retournent Access Denied. Les logs OPA affichent Bundle download failed ou policy not found. L'endpoint /health d'OPA retourne un état non sain.

Cause : Le ConfigMap de politiques n'est pas monté correctement, les fichiers Rego sont vides (0 octet à cause d'un .Files.Get mal configuré), ou OPA ne peut pas analyser les fichiers de politique à cause d'erreurs de syntaxe.

Solution :

# Vérifier la santé du pod OPA
kubectl get pods -n akko -l app.kubernetes.io/name=akko-opa

# Vérifier que les fichiers de politique sont montés et non vides
kubectl exec -n akko deploy/akko-akko-opa -- ls -la /policies/
kubectl exec -n akko deploy/akko-akko-opa -- cat /policies/trino.rego

# Consulter les logs OPA pour les erreurs de compilation de politique
kubectl logs -n akko deploy/akko-akko-opa --tail=50 | grep -i "error\|compile\|parse\|bundle"

# Vérifier que le ConfigMap contient les politiques
kubectl get cm -n akko -l app.kubernetes.io/name=akko-opa -o yaml | head -50

# Si les fichiers font 0 octet, vérifier que le chart Helm utilise .Files.Get (pas .Values)

Mappage des rôles depuis le JWT Keycloak

Symptômes : Les politiques OPA qui vérifient input.context.identity.groups ne correspondent jamais. Les utilisateurs authentifiés via Keycloak sont traités comme n'ayant aucun groupe, même s'ils ont des rôles assignés.

Cause : Trino n'extrait pas correctement les groupes du token JWT Keycloak. Le claim groups est peut-être imbriqué sous realm_access.roles ou resource_access au lieu d'être un champ groups de premier niveau.

Solution :

# Décoder un token JWT pour inspecter sa structure
# D'abord, obtenir un token depuis Keycloak
kubectl exec -n akko deploy/akko-keycloak -- \
  curl -s -X POST http://localhost:8080/realms/akko/protocol/openid-connect/token \
  -d "client_id=trino&client_secret=<secret>&grant_type=client_credentials" \
  | python3 -c "import sys,json,base64; t=json.load(sys.stdin)['access_token'].split('.')[1]; print(json.dumps(json.loads(base64.urlsafe_b64decode(t+'==')),indent=2))"

# Vérifier la configuration d'extraction de groupes de Trino
kubectl exec -n akko deploy/akko-trino-coordinator-0 -- cat /etc/trino/config.properties | grep -i group

# Vérifier l'entrée OPA en activant le journal de décisions
kubectl exec -n akko deploy/akko-akko-opa -- curl -s http://localhost:8181/v1/data/trino/allow \
  -X POST -d '{"input":{"context":{"identity":{"user":"alice","groups":[]}}}}'

Erreurs de syntaxe Rego dans les politiques

Symptômes : Le pod OPA démarre mais les politiques ne sont pas chargées. Les logs affichent rego_parse_error ou rego_type_error. Toutes les requêtes Trino échouent avec accès refusé.

Cause : Le fichier de politique Rego contient des erreurs de syntaxe (imports manquants, opérateurs incorrects, variables non définies ou utilisation incompatible de future.keywords).

Solution :

# Consulter les logs OPA pour les erreurs d'analyse/compilation
kubectl logs -n akko deploy/akko-akko-opa --tail=50 | grep -i "error\|parse\|compile"

# Valider la politique localement avant de déployer
kubectl exec -n akko deploy/akko-akko-opa -- opa check /policies/trino.rego

# Tester la politique avec un exemple d'entrée
kubectl exec -n akko deploy/akko-akko-opa -- opa eval \
  -d /policies/trino.rego \
  -i /dev/stdin "data.trino.allow" <<< '{"context":{"identity":{"user":"alice","groups":["akko-admin"]}}}'

# Si la politique est cassée, corriger le fichier Rego dans le chart Helm et redéployer
# Le ConfigMap sera mis à jour et OPA rechargera automatiquement à chaud