Aller au contenu

RBAC LLM — Contrôle d'accès aux modèles IA par rôle

AKKO associe les 5 rôles de la plateforme (akko-admin, akko-engineer, akko-analyst, akko-user, akko-viewer) aux access_groups LiteLLM et à des quotas, centralisant la matrice d'accès IA dans un unique ConfigMap exposé via l'UI Cockpit sous Governance → LLM Access Matrix.


Matrice par défaut

Rôle Chat (qwen2.5:3b) Embed (nomic) Code (qwen-coder) GPU (vLLM) Quota/jour Rate limit
akko-admin illimité illimité
akko-engineer 50 k tokens 120 req/min
akko-analyst 20 k tokens 60 req/min
akko-user 5 k tokens 30 req/min
akko-viewer aucun

Source : helm/akko/charts/akko-cockpit/templates/configmap-llm-rbac.yaml (ConfigMap rendu akko-llm-rbac dans le namespace akko).


Architecture

Cockpit UI (Governance → onglet LLM Access)
GET /api/cockpit/llm-rbac.json     ← servi par nginx cockpit depuis le ConfigMap monté
  ├── lecture navigateur → rend la matrice (lecture seule)
  └── écriture : GitOps uniquement — éditer le ConfigMap Helm, commit, push,
       laisser la CI redéployer. Pas d'endpoint de mutation runtime. Ça évite
       d'avoir besoin d'un ServiceAccount K8s avec droit patch-ConfigMap
       dans le cockpit, et garde chaque changement auditable dans Git.

Fichiers

Fichier Rôle
helm/akko/charts/akko-cockpit/templates/configmap-llm-rbac.yaml Source de vérité (Helm template)
helm/akko/charts/akko-cockpit/templates/deployment.yaml Monte le ConfigMap sur /usr/share/nginx/html/api/cockpit/llm-rbac.json
branding/cockpit/index.html Page Governance avec UI matrice (Sprint 15.5)
branding/cockpit/app.js loadLlmRbac() fetch le JSON + rend

Utilisation depuis du code

Depuis un notebook (jupyter-alice)

import os
import requests
resp = requests.post(
    f"http://akko-akko-litellm:4000/chat/completions",
    headers={"Authorization": f"Bearer {os.environ['LITELLM_USER_KEY']}"},
    json={"model": "akko-chat", "messages": [{"role": "user", "content": "hi"}]}
)

Si le rôle user ne matche pas les access_groups du modèle, LiteLLM renvoie 403 Forbidden.

Depuis Trino (via fonctions ai_*())

-- Le middleware ai_service passe le rôle Keycloak du user Trino à LiteLLM
SELECT akko_ai_sentiment(comment) FROM reviews LIMIT 10;

Depuis Claude Desktop (via MCP)

Le serveur MCP Trino propage le rôle user via header HTTP. LiteLLM l'applique de la même manière.


Modifier la matrice

Via GitOps (recommandé — prod)

Éditer helm/akko/charts/akko-cockpit/templates/configmap-llm-rbac.yaml → commit → push → CI auto-deploy → ConfigMap mis à jour.

Via UI Cockpit (Sprint 15.5, admin uniquement — vue lecture seule)

  1. Se connecter en tant qu'alice (akko-admin)
  2. Naviguer vers Governance → onglet LLM Access
  3. La matrice complète s'affiche : 4 modèles × 5 rôles, avec quotas et rate limits par rôle
  4. Pour modifier la matrice, éditer le ConfigMap Helm et push (GitOps uniquement — pas d'édition runtime)

Le design lecture seule est délibéré : chaque changement passe par revue de code et atterrit comme commit Git, donc l'historique des access-controls est auditable pour toujours. Le fichier configmap-llm-rbac.yaml est l'unique source de vérité.


Ajouter un nouveau modèle

  1. Éditer helm/examples/values-dev.yaml — ajouter le modèle dans akko-litellm.config.model_list
  2. Éditer configmap-llm-rbac.yaml — ajouter dans la section models
  3. Commit + push → CI deploy
  4. LiteLLM pick up le nouveau modèle auto; matrice affiche la nouvelle colonne

Auditer l'usage LLM

Chaque appel LLM est loggé dans logs layer par le middleware AI Service :

{service="ai-service"} |= "llm_call" | json | line_format
"{{.user}} {{.model}} {{.status}} tokens={{.tokens}}"

Dashboard Dashboards LLM Usage by Role (Sprint 15.7) affichera : - Tokens/heure par rôle - Top 10 users par volume - Taux d'erreur par modèle - Estimation coût (quand modèles commerciaux ajoutés)


Verrouillage d'urgence

Mettre le rôle à access_groups: [] pour bloquer immédiatement tout accès LLM à ce rôle, sans toucher Keycloak ni redéployer :

kubectl edit configmap akko-llm-rbac -n akko
# Trouver "akko-analyst" → set "access_groups": []
# Save → LiteLLM reload → effectif immédiatement

Voir aussi