Aller au contenu

RBAC — Contrôle d'accès basé sur les rôles

AKKO implémente un modèle de sécurité à 4 couches qui applique le contrôle d'accès de l'authentification jusqu'à l'exécution des requêtes :

Keycloak (authentification) → OPA (autorisation) → Trino (application des requêtes) → Superset (filtrage des tableaux de bord)

Chaque utilisateur s'authentifie via le SSO Keycloak, reçoit des claims de rôle dans son jeton JWT, et ces rôles sont appliqués par les politiques OPA dans Trino, les mappings de rôles dans Superset/Airflow/Dashboards, et le filtrage réseau via OAuth2-Proxy pour les services sans OIDC natif.

Kubernetes-first

Toute la configuration RBAC est déployée via Helm. Le realm Keycloak est importé depuis realm-akko-k3d.json, les politiques OPA depuis un ConfigMap, et les règles Trino depuis des fichiers montés. Aucune étape manuelle requise après helm install.


Rôles

AKKO définit cinq rôles de realm à l'échelle de la plateforme dans Keycloak :

Rôle Description Persona Niveau d'accès
akko-admin Administrateur de la plateforme Alice Chen -- SRE / propriétaire Accès complet à tous les services, consoles admin, DDL/DML, aucun masquage
akko-engineer Ingénieur de données Bob Martin -- construit les pipelines CREATE/INSERT/SELECT sur Iceberg, gestion des pipelines, pas de masquage PII
akko-analyst Analyste senior Carol Santos -- explore les données SELECT uniquement, visibilité complète PII, tableaux de bord, notebooks
akko-user Utilisateur standard / conformité Eve Dupont -- audite les données SELECT uniquement, colonnes PII masquées (email, téléphone, SSN, date de naissance)
akko-viewer Exécutif / visualiseur de tableaux de bord Dave Kim -- consulte les tableaux de bord SELECT sur schémas limités, filtré par lignes, PII masqué

Rôle par défaut

Les nouveaux utilisateurs se voient automatiquement attribuer akko-analyst via le rôle composite default-roles-akko. Cela inclut offline_access et uma_authorization.


Matrice d'accès

Accès par service

Service akko-admin akko-engineer akko-analyst akko-user akko-viewer
Keycloak (console admin) Complet -- -- -- --
Trino (SQL) DDL/DML complet DDL/DML sur schémas désignés SELECT uniquement SELECT, PII masqué SELECT, filtré + masqué
Superset Rôle Admin Rôle Alpha Rôle Gamma Rôle Gamma Rôle Public
Airflow Admin User Viewer Viewer Viewer
Dashboards Admin Editor Viewer Viewer Viewer
JupyterHub Panneau admin + spawn Spawn Spawn Spawn Spawn
MLflow Complet Complet Complet Complet Complet
LiteLLM Complet (clé maître) Complet Complet Complet Complet
object storage Root Root Root Root Root
OpenMetadata Admin Navigation + édition Navigation + édition Navigation Navigation

Services sans RBAC granulaire

MLflow, LiteLLM, object storage et Spark utilisent actuellement des identifiants partagés. L'accès est contrôlé au niveau réseau (OAuth2-Proxy pour MLflow, clé maître pour LiteLLM, identifiants root pour object storage). Le RBAC par utilisateur pour ces services est prévu dans la feuille de route.

Accès aux catalogues Trino

Rôle Iceberg PostgreSQL System
akko-admin tout (propriétaire) tout (propriétaire) tout
akko-engineer tout (DDL sur raw, staging, analytics, sandbox) tout (DDL) lecture seule
akko-analyst lecture seule (tous les schémas) lecture seule lecture seule
akko-user lecture seule (tous les schémas, PII masqué) lecture seule lecture seule
akko-viewer lecture seule (analytics, reporting, public uniquement) -- lecture seule
(défaut) -- -- lecture seule

Privilèges sur les tables Trino (Iceberg)

Rôle Schémas Privilèges
akko-admin tous SELECT, INSERT, DELETE, UPDATE, OWNERSHIP, GRANT_SELECT
akko-engineer raw, staging, analytics, sandbox SELECT, INSERT, DELETE, UPDATE
akko-analyst tous SELECT
akko-user tous SELECT (PII masqué)
akko-viewer analytics, reporting, public SELECT (filtré par lignes, PII masqué)

Configuration Keycloak

Structure du realm

Toute la configuration d'identité AKKO se trouve dans un realm Keycloak unique nommé akko, importé depuis realm-akko-k3d.json au premier démarrage.

Paramètres principaux :

Paramètre Valeur
Nom du realm akko
Thème de connexion akko (personnalisé)
Durée de vie du jeton d'accès 300s (5 min)
Session SSO maximale 36000s (10 heures)
Inscription Désactivée
Protection brute force Activée (5 échecs, verrouillage 5 min)

Définition des rôles

Les rôles sont définis comme des rôles de realm (et non des rôles de client). Chaque rôle est mappé à un claim de groupe via le mapper de protocole groups, qui émet les noms de rôles dans le tableau groups du JWT.

Le mapper groups est configuré dans les scopes client microprofile-jwt et spécifiques aux services :

{
  "name": "groups",
  "protocol": "openid-connect",
  "protocolMapper": "oidc-usermodel-realm-role-mapper",
  "config": {
    "multivalued": "true",
    "claim.name": "groups",
    "id.token.claim": "true",
    "access.token.claim": "true"
  }
}

Cela garantit que lorsqu'un utilisateur se connecte, ses rôles apparaissent dans le jeton JWT sous forme de groups, que OPA, Trino et les autres services utilisent pour les décisions d'autorisation.

Clients OAuth2

13 clients OAuth2 sont préconfigurés dans le realm :

Client Type Mappe les rôles
jupyterhub Confidentiel Oui (flag admin)
superset Confidentiel Oui (Admin/Alpha/Gamma/Public)
airflow Confidentiel Oui (Admin/User/Viewer)
grafana Confidentiel Oui (Admin/Editor/Viewer)
trino Confidentiel Oui (via groupes OPA)
openmetadata Confidentiel Partiel
polaris Confidentiel Non
oauth2-proxy Confidentiel Non (contrôle réseau)
minio Confidentiel Non
account Public Non (interne Keycloak)
account-console Public (PKCE) Non (interne Keycloak)
admin-cli Public Non (interne Keycloak)
broker Confidentiel Non (interne Keycloak)
realm-management Confidentiel Non (interne Keycloak)
security-admin-console Public Non (interne Keycloak)

Pas de client cockpit

Le cockpit AKKO utilise l'adaptateur JavaScript Keycloak avec les clients publics account ou account-console pour la détection de session. Il ne dispose pas de son propre client OAuth2 dédié dans le realm.

Attribuer un rôle à un utilisateur

  1. Ouvrir la console d'administration Keycloak : https://identity.akko.local/admin/
  2. Sélectionner le realm akko
  3. Naviguer vers Users et sélectionner l'utilisateur (ou en créer un nouveau)
  4. Aller dans l'onglet Role mapping
  5. Cliquer sur Assign role et filtrer par rôles de realm
  6. Sélectionner le rôle souhaité (akko-admin, akko-engineer, akko-analyst, akko-user ou akko-viewer)

emailVerified doit être true

Tous les utilisateurs doivent avoir emailVerified=true. Le service oauth2-proxy rejette les utilisateurs sans email vérifié, causant des échecs de connexion pour JupyterHub et les autres services protégés par proxy.


Politiques OPA

OPA (Open Policy Agent) fournit une autorisation policy-as-code pour Trino. Les politiques sont écrites en Rego et déployées sous forme de ConfigMap.

Architecture

Requête utilisateur → Trino → OPA (évaluation Rego) → Autoriser / Refuser / Filtrer / Masquer

Trino délègue trois types de décisions à OPA :

  1. Autorisation -- cet utilisateur peut-il exécuter cette opération ?
  2. Filtrage par lignes -- quelles lignes cet utilisateur peut-il voir ?
  3. Masquage de colonnes -- les colonnes sensibles doivent-elles être masquées ?

Intégration Trino-OPA

Trino est configuré pour appeler OPA à chaque requête :

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

Politique de contrôle d'accès

La politique principale (trino_access.rego) mappe les opérations aux rôles. Voici la politique réelle déployée via ConfigMap dans helm/akko/charts/akko-opa/templates/configmap.yaml :

package trino
import rego.v1

default allow := false

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

# Ingénieurs : SELECT, INSERT, CREATE TABLE, DROP TABLE, ALTER
allow if {
    "akko-engineer" in input.context.identity.groups
    input.action.operation in [
        "ExecuteQuery", "AccessCatalog", "FilterCatalogs",
        "FilterSchemas", "FilterTables", "FilterColumns",
        "SelectFromColumns", "ShowSchemas", "ShowTables",
        "ShowColumns", "ShowCreateTable", "ShowFunctions",
        "ShowStats", "CreateTable", "InsertIntoTable",
        "AddColumn", "DropTable", "RenameTable"
    ]
}

# Analystes (senior) : SELECT uniquement, visibilité complète (pas de masquage)
allow if {
    "akko-analyst" in input.context.identity.groups
    input.action.operation in [
        "ExecuteQuery", "AccessCatalog", "FilterCatalogs",
        "FilterSchemas", "FilterTables", "FilterColumns",
        "SelectFromColumns", "ShowSchemas", "ShowTables",
        "ShowColumns", "ShowCreateTable", "ShowFunctions",
        "ShowStats"
    ]
}

# 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"
    ]
}

# Viewers (exécutifs) : SELECT + métadonnées, filtré par lignes + PII masqué
allow if {
    "akko-viewer" in input.context.identity.groups
    input.action.operation in [
        "ExecuteQuery", "AccessCatalog", "FilterCatalogs",
        "FilterSchemas", "FilterTables", "FilterColumns",
        "SelectFromColumns", "ShowSchemas", "ShowTables",
        "ShowColumns", "ShowCreateTable", "ShowFunctions",
        "ShowStats"
    ]
}

# Identité de filtre par lignes : Trino revérifie les permissions avec l'identité du filtre
allow if {
    input.context.identity.user == "viewer_active_only"
}

Politique de masquage des colonnes

Les colonnes PII sont masquées pour les rôles akko-user et akko-viewer. Les administrateurs, ingénieurs et analystes voient les données en clair :

# Colonnes PII texte : email, phone, ssn, medical_record_number
columnMask := {"expression": expression, "identity": identity} if {
    input.action.resource.column.columnName in [
        "email", "phone", "ssn", "medical_record_number"
    ]
    not "akko-admin" in input.context.identity.groups
    not "akko-engineer" in input.context.identity.groups
    not "akko-analyst" in input.context.identity.groups
    expression := "'***MASKED***'"
    identity := "mask_pii"
}

# Colonnes PII date : date_of_birth (NULL type-safe)
columnMask := {"expression": expression, "identity": identity} if {
    input.action.resource.column.columnName in ["date_of_birth"]
    not "akko-admin" in input.context.identity.groups
    not "akko-engineer" in input.context.identity.groups
    not "akko-analyst" in input.context.identity.groups
    expression := "CAST(NULL AS DATE)"
    identity := "mask_pii"
}

Résumé du masquage :

Colonne admin engineer analyst user viewer
email clair clair clair ***MASKED*** ***MASKED***
phone clair clair clair ***MASKED*** ***MASKED***
ssn clair clair clair ***MASKED*** ***MASKED***
medical_record_number clair clair clair ***MASKED*** ***MASKED***
date_of_birth clair clair clair NULL NULL

Politique de filtrage par lignes

Les filtres par lignes restreignent les lignes visibles par rôle :

# Les viewers ne peuvent voir que les comptes actifs
rowFilters contains {"expression": expression, "identity": identity} if {
    "akko-viewer" in input.context.identity.groups
    input.action.resource.table.tableName == "accounts"
    expression := "status = 'active'"
    identity := "viewer_active_only"
}

Actuellement, seule la table accounts a un filtre par lignes pour akko-viewer. Des filtres supplémentaires peuvent être ajoutés par table selon les besoins.

Ajouter une nouvelle politique OPA

Les politiques OPA sont définies en ligne dans le template ConfigMap à helm/akko/charts/akko-opa/templates/configmap.yaml. Le ConfigMap contient trois fichiers Rego :

Fichier Objectif
trino_access.rego Règles autoriser/refuser par opération et par rôle
column_masking.rego Règles de masquage des colonnes PII
row_filter.rego Filtres de sécurité au niveau des lignes

Étape par étape : Ajouter une nouvelle règle d'accès

  1. Ouvrir helm/akko/charts/akko-opa/templates/configmap.yaml
  2. Ajouter votre règle Rego dans la section .rego appropriée. Par exemple, pour ajouter un filtrage par lignes sur la table transactions pour les viewers :

    # Dans la section row_filter.rego :
    rowFilters contains {"expression": expression, "identity": identity} if {
        "akko-viewer" in input.context.identity.groups
        input.action.resource.table.tableName == "transactions"
        expression := "amount < 10000"
        identity := "viewer_small_txn_only"
    }
    
  3. Si le filtre utilise une identité personnalisée (comme viewer_small_txn_only), ajouter une règle allow correspondante dans trino_access.rego :

    allow if {
        input.context.identity.user == "viewer_small_txn_only"
    }
    
  4. Déployer la politique mise à jour :

    helm upgrade akko helm/akko/ -n akko \
      -f helm/examples/values-dev.yaml \
      --set-file akko-keycloak.realm.data=helm/examples/realm-akko-k3d.json
    
  5. OPA recharge les politiques à chaud depuis le ConfigMap -- aucun redémarrage de pod nécessaire. Vérifier que la politique est chargée :

    # Vérifier qu'OPA a la politique mise à jour
    kubectl exec -n akko deploy/akko-akko-opa -- \
      curl -s http://localhost:8181/v1/policies | python3 -m json.tool
    
    # Tester la politique avec un exemple d'entrée
    kubectl exec -n akko deploy/akko-akko-opa -- \
      curl -s -X POST http://localhost:8181/v1/data/trino/allow \
      -d '{"input":{"context":{"identity":{"user":"dave","groups":["akko-viewer"]}},"action":{"operation":"SelectFromColumns","resource":{"table":{"catalogName":"iceberg","schemaName":"banking","tableName":"transactions"}}}}}' \
      | python3 -m json.tool
    

Tester les politiques localement

Avant de déployer, testez la syntaxe Rego localement :

# Sauvegarder la politique dans un fichier et tester avec opa eval
opa eval -i input.json -d policy.rego "data.trino.allow"
# Ou vérifier la syntaxe uniquement
opa check policy.rego


Application dans Trino

En plus d'OPA, Trino utilise un contrôle d'accès basé sur des fichiers pour les permissions de catalogue/schéma/table. Les deux systèmes fonctionnent ensemble :

  • OPA gère l'autorisation au niveau des opérations (autoriser/refuser), le masquage des colonnes et le filtrage par lignes
  • Les règles basées sur fichiers (rules.json) appliquent l'accès catalogue/schéma/table avec des privilèges granulaires

Mappings de groupes

Trino mappe les utilisateurs aux groupes via group.txt :

akko-admin:admin,alice,trino,airflow
akko-engineer:bob
akko-analyst:carol
akko-user:eve
akko-viewer:dave

Utilisateurs de service

Les utilisateurs trino et airflow doivent être dans le groupe akko-admin. Trino utilise trino pour les opérations internes, et Airflow se connecte en tant que airflow pour exécuter les requêtes de pipeline.

Groupe utilisateur standard

Le groupe akko-user correspond à Eve (analyste conformité). Quand OPA évalue les règles de masquage de colonnes, il vérifie le claim groups dans le JWT -- le fichier Trino group.txt est utilisé pour les règles de contrôle d'accès basées sur fichiers, pas pour les décisions OPA.

Évaluation des règles

Les règles dans rules.json sont évaluées de haut en bas, première correspondance gagne. Le fichier comporte trois sections : catalogs, schemas et tables. Une règle de refus générique à la fin bloque les accès non correspondants :

{ "catalog": ".*", "allow": "none" }

Période de rafraîchissement

Les fichiers rules.json et group.txt sont rafraîchis toutes les 5 minutes. Les modifications prennent effet sans redémarrage de Trino.


Sécurité au niveau des lignes dans Superset

Superset mappe les rôles Keycloak à ses rôles internes :

Rôle Keycloak Rôle Superset Capacités
akko-admin Admin Tous les tableaux de bord, SQL Lab, datasets, paramètres admin
akko-engineer Alpha Créer des tableaux de bord, SQL Lab, datasets
akko-analyst Gamma Voir les tableaux de bord, SQL Lab, voir les datasets
akko-user Gamma Voir les tableaux de bord, SQL Lab, voir les datasets
akko-viewer Public Voir les tableaux de bord publics uniquement, pas de SQL Lab

Superset se connecte à Trino en utilisant l'utilisateur de service trino (qui a les privilèges akko-admin). Cela signifie que le masquage des colonnes et le filtrage par lignes d'OPA ne sont pas appliqués au niveau Superset-vers-Trino. Superset applique l'accès via son propre système de rôles :

  • Visibilité des tableaux de bord -- le rôle Public ne peut voir que les tableaux de bord explicitement publiés
  • SQL Lab -- seuls les rôles Admin, Alpha et Gamma ont accès à SQL Lab
  • Accès aux datasets -- les datasets sont contrôlés par les permissions de rôle Superset

Application de bout en bout

Pour un filtrage complet des données par utilisateur à travers Superset, l'approche recommandée est de configurer Superset pour transmettre l'identité réelle de l'utilisateur à Trino (au lieu de l'utilisateur partagé trino), afin que les politiques OPA s'appliquent aux requêtes des tableaux de bord. Ceci est prévu pour une version future.


Gestion des utilisateurs

Ajouter un nouvel utilisateur (interface web)

  1. Ouvrir la console d'administration Keycloak à https://identity.akko.local/admin/
  2. Se connecter avec les identifiants admin (voir values-dev.yaml pour le mot de passe dev, ou global.auth.keycloakAdminPassword pour la production)
  3. Sélectionner le realm akko (menu déroulant en haut à gauche)
  4. Naviguer vers Users > Add user
  5. Remplir les champs requis :
    • Username (requis, minuscules, sans espaces)
    • Email (requis -- OAuth2-Proxy rejette les utilisateurs sans email)
    • First name, Last name
    • Basculer Email verified sur ON
  6. Cliquer sur Create
  7. Aller dans l'onglet Credentials :
    • Cliquer sur Set password
    • Saisir le mot de passe et confirmer
    • Basculer Temporary sur OFF pour les comptes de service ou de test
    • Cliquer sur Save
  8. Aller dans l'onglet Role mapping :
    • Cliquer sur Assign role
    • Dans le menu déroulant de filtre, sélectionner Filter by realm roles
    • Sélectionner le rôle souhaité (akko-admin, akko-engineer, akko-analyst, akko-user ou akko-viewer)
    • Cliquer sur Assign

Ajouter un nouvel utilisateur (API Admin Keycloak)

Pour l'automatisation ou les pipelines CI/CD, utiliser l'API REST Admin Keycloak :

# 1. Obtenir un jeton admin
ADMIN_TOKEN=$(kubectl exec -n akko deploy/akko-keycloak -- \
  curl -s -X POST http://localhost:8080/realms/master/protocol/openid-connect/token \
  -d "client_id=admin-cli&grant_type=password&username=admin&password=<mot-de-passe-admin>" \
  | python3 -c "import sys,json; print(json.load(sys.stdin)['access_token'])")

# 2. Créer l'utilisateur
kubectl exec -n akko deploy/akko-keycloak -- \
  curl -s -X POST http://localhost:8080/admin/realms/akko/users \
  -H "Authorization: Bearer $ADMIN_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "username": "newuser",
    "email": "newuser@company.com",
    "firstName": "Nouveau",
    "lastName": "Utilisateur",
    "enabled": true,
    "emailVerified": true,
    "credentials": [{"type": "password", "value": "mot-de-passe-fort", "temporary": false}]
  }'

# 3. Obtenir l'ID de l'utilisateur
USER_ID=$(kubectl exec -n akko deploy/akko-keycloak -- \
  curl -s http://localhost:8080/admin/realms/akko/users?username=newuser \
  -H "Authorization: Bearer $ADMIN_TOKEN" \
  | python3 -c "import sys,json; print(json.load(sys.stdin)[0]['id'])")

# 4. Obtenir l'ID du rôle (ex : akko-analyst)
ROLE_ID=$(kubectl exec -n akko deploy/akko-keycloak -- \
  curl -s http://localhost:8080/admin/realms/akko/roles/akko-analyst \
  -H "Authorization: Bearer $ADMIN_TOKEN" \
  | python3 -c "import sys,json; r=json.load(sys.stdin); print(r['id'])")

# 5. Attribuer le rôle
kubectl exec -n akko deploy/akko-keycloak -- \
  curl -s -X POST \
  "http://localhost:8080/admin/realms/akko/users/$USER_ID/role-mappings/realm" \
  -H "Authorization: Bearer $ADMIN_TOKEN" \
  -H "Content-Type: application/json" \
  -d "[{\"id\": \"$ROLE_ID\", \"name\": \"akko-analyst\"}]"

Alternative port-forward

Si vous préférez exécuter les commandes depuis votre machine locale plutôt que via kubectl exec, faites d'abord un port-forward du pod Keycloak :

kubectl port-forward -n akko svc/akko-keycloak 8080:8080 &
# Puis remplacez "kubectl exec ... curl" par simplement "curl http://localhost:8080/..."

Vérification de l'accès

Après avoir attribué un rôle, vérifier que le jeton de l'utilisateur contient les bons claims :

# Obtenir un jeton pour l'utilisateur (via le client JupyterHub, qui a le mapper groups)
TOKEN=$(kubectl exec -n akko deploy/akko-keycloak -- \
  curl -s -X POST http://localhost:8080/realms/akko/protocol/openid-connect/token \
  -d "grant_type=password&client_id=jupyterhub&client_secret=akko-dev-jupyterhub-oidc&username=alice&password=alice123&scope=openid" \
  | python3 -c "import sys,json; print(json.load(sys.stdin)['access_token'])")

# Décoder le JWT et vérifier le claim groups
echo "$TOKEN" | cut -d. -f2 | base64 -d 2>/dev/null | python3 -m json.tool
# Résultat attendu inclut : "groups": ["akko-admin", "default-roles-akko", ...]

Que vérifier dans le JWT

  • Le tableau groups doit contenir le nom du rôle attribué (ex : akko-admin)
  • Le champ email_verified doit être true
  • Le preferred_username doit correspondre au nom d'utilisateur
  • Le iss (émetteur) doit être https://identity.akko.local/realms/akko

Révoquer l'accès

Retirer un rôle à un utilisateur (interface web)

  1. Ouvrir https://identity.akko.local/admin/ et sélectionner le realm akko
  2. Naviguer vers Users et sélectionner l'utilisateur
  3. Aller dans l'onglet Role mapping
  4. Trouver le rôle à retirer et cliquer sur le bouton X (désattribuer) à côté
  5. L'utilisateur doit se déconnecter puis se reconnecter pour que le changement prenne effet (les jetons JWT sont valides jusqu'à expiration -- 5 minutes par défaut)

Retirer un rôle à un utilisateur (API Admin)

# Retirer le rôle akko-engineer d'un utilisateur
kubectl exec -n akko deploy/akko-keycloak -- \
  curl -s -X DELETE \
  "http://localhost:8080/admin/realms/akko/users/$USER_ID/role-mappings/realm" \
  -H "Authorization: Bearer $ADMIN_TOKEN" \
  -H "Content-Type: application/json" \
  -d "[{\"id\": \"$ROLE_ID\", \"name\": \"akko-engineer\"}]"

Désactiver un utilisateur entièrement

  1. Interface web : Naviguer vers l'utilisateur, basculer Enabled sur OFF, cliquer sur Save
  2. API Admin :
    kubectl exec -n akko deploy/akko-keycloak -- \
      curl -s -X PUT \
      "http://localhost:8080/admin/realms/akko/users/$USER_ID" \
      -H "Authorization: Bearer $ADMIN_TOKEN" \
      -H "Content-Type: application/json" \
      -d '{"enabled": false}'
    

Forcer la déconnexion (invalider les sessions actives)

# Déconnecter toutes les sessions d'un utilisateur spécifique
kubectl exec -n akko deploy/akko-keycloak -- \
  curl -s -X POST \
  "http://localhost:8080/admin/realms/akko/users/$USER_ID/logout" \
  -H "Authorization: Bearer $ADMIN_TOKEN"

Délai d'expiration des jetons

Révoquer un rôle ou désactiver un utilisateur ne bloque pas immédiatement l'accès. Les jetons JWT existants restent valides jusqu'à leur expiration (par défaut : 5 minutes). Les services qui cachent les jetons (Superset, Dashboards) peuvent nécessiter que l'utilisateur se déconnecte puis se reconnecte.

Ajouter un utilisateur aux groupes Trino basés sur fichiers

Si Trino utilise le contrôle d'accès basé sur fichiers en plus d'OPA, les nouveaux utilisateurs doivent être ajoutés à group.txt :

  1. Éditer le fichier de groupes Trino dans le chart Helm (l'emplacement exact dépend de la structure de votre chart)
  2. Ajouter le nom d'utilisateur à la ligne de groupe appropriée :
    akko-analyst:carol,newuser
    
  3. Mettre à jour la release Helm :
    helm upgrade akko helm/akko/ -n akko \
      -f helm/examples/values-dev.yaml \
      --set-file akko-keycloak.realm.data=helm/examples/realm-akko-k3d.json
    
  4. Attendre jusqu'à 5 minutes que Trino recharge le fichier (ou redémarrer le pod coordinateur Trino)

Utilisateurs de test par défaut

Nom d'utilisateur Rôle Mot de passe Email Nom complet
alice akko-admin alice123 alice@akko.local Alice Chen
bob akko-engineer bob123 bob@akko.local Bob Martin
carol akko-analyst carol123 carol@akko.local Carol Santos
eve akko-user eve123 eve@akko.local Eve Dupont
dave akko-viewer dave123 dave@akko.local Dave Kim

Tous les utilisateurs de test ont emailVerified=true et enabled=true. Alice a également le rôle client realm-admin, lui donnant accès à la console d'administration Keycloak.

Mots de passe de test

Dans le realm de développement (realm-akko-k3d.json), les mots de passe suivent le modèle <nom_utilisateur>123. Ne jamais utiliser ces identifiants en production. Utilisez des mots de passe forts, des fournisseurs d'identité externes (LDAP, SAML) ou les politiques de mots de passe de Keycloak.


Dépannage

L'utilisateur ne peut pas accéder à un service

  1. Vérifier le jeton JWT -- vérifier que le claim groups contient le rôle attendu
  2. Vérifier emailVerified -- doit être true pour les services protégés par OAuth2-Proxy
  3. Vérifier la session Keycloak -- l'utilisateur peut avoir une ancienne session avec des claims de rôle obsolètes. Se déconnecter puis se reconnecter.

Mauvaises permissions dans Trino

  1. Vérifier group.txt -- vérifier que l'utilisateur est dans le bon groupe Trino
  2. Vérifier les logs OPA -- kubectl logs -n akko deploy/akko-akko-opa pour voir les évaluations de politique
  3. Vérifier rules.json -- les règles fonctionnent en première correspondance ; une règle plus haute dans la liste peut correspondre en premier
  4. Attendre le rafraîchissement -- Trino rafraîchit les fichiers de groupes et de règles toutes les 5 minutes

Le masquage des colonnes ne fonctionne pas

  1. Vérifier le nom de la colonne -- doit correspondre à un nom dans la politique OPA (email, phone, ssn, medical_record_number, date_of_birth)
  2. Vérifier le rôle de l'utilisateur -- seuls akko-user et akko-viewer voient les valeurs masquées
  3. Tester via CLI -- utiliser curl pour interroger Trino directement avec le jeton de l'utilisateur pour exclure le cache de Superset

Le rôle ne se propage pas à Superset/Airflow/Dashboards

Ces services mappent les rôles Keycloak aux rôles internes au moment de la connexion. Si un rôle change :

  1. L'utilisateur doit se déconnecter du service
  2. Effacer la session du service (ou utiliser une fenêtre de navigation privée)
  3. Se reconnecter -- le nouveau rôle sera mappé

Exécuter les tests RBAC

# Tous les tests d'intégration RBAC
pytest tests/integration/ -m rbac -v

# Tests de sécurité (inclut l'application des politiques OPA)
pytest tests/integration/ -m security -v

# Service spécifique
pytest tests/integration/test_rbac_grafana.py -v

# Suite de tests complète
bash tests/run-all.sh --fast

Décisions d'architecture

ADR Décision
Keycloak comme IdP Source unique de vérité pour l'identité. Tous les services s'authentifient via OIDC.
OPA pour Trino ABAC Policy-as-code permet la sécurité au niveau des lignes et des colonnes sans modifier Trino.
Règles Trino basées sur fichiers Complément à OPA pour les permissions catalogue/schéma/table. Rafraîchissement de 5 minutes.
Rôles de realm (pas de rôles client) Gestion simplifiée. Un rôle par utilisateur, visible sur tous les clients via le claim groups.
5 rôles Couvre les personas admin, ingénierie, analyse, conformité et exécutif. Extensible selon les besoins.