Aller au contenu
Sécurité medium

Vault comme courtier d'identité (identity broker)

15 min de lecture

Vault n’est pas qu’un coffre-fort à secrets. Son vrai pouvoir est de servir de courtier d’identité : un workload prouve qui il est, Vault vérifie cette identité, puis délivre un accès temporaire vers une ressource cible.

Ce pattern est au cœur de l’approche zero trust : pas de credentials permanents, des accès basés sur l’identité vérifiée.

Le problème : credentials permanents dans les workloads

Section intitulée « Le problème : credentials permanents dans les workloads »
Modèle classique : secret permanent dans Kubernetes

Ce qui arrive tôt ou tard :

  • Le secret fuite (commit Git, log, debug)
  • Une compromission d’un pod = accès permanent à la DB
  • L’audit montre “app_user a fait X” mais pas quel pod

La vision première de Vault est souvent “un endroit sécurisé pour stocker des secrets”. C’est vrai, mais c’est la partie la moins intéressante.

La vraie valeur de Vault :

FonctionDescription
AuthentificationVérifie l’identité du demandeur
AutorisationVérifie ce qu’il a le droit de demander
ÉmissionGénère un credential temporaire, unique
AuditTrace qui a demandé quoi, quand
RévocationInvalide le credential à tout moment

Vault transforme une identité prouvée en accès temporaire.

Identity Broker Pattern : workload vers Vault vers ressource cible

Le workload ne possède jamais de credential permanent vers la cible. Il possède une identité source (service account K8s, rôle IAM, token OIDC) qui lui permet de prouver qui il est à Vault.

Ce que Vault courtier d’identité change vraiment

Section intitulée « Ce que Vault courtier d’identité change vraiment »

Le pattern identity broker diffère fondamentalement de la distribution classique de secrets :

  • Le workload ne reçoit pas un secret “par défaut” : il obtient un accès parce qu’il a prouvé qui il est
  • Vault devient le point de traduction entre identité source (K8s service account, cloud IAM, token OIDC) et accès cible (credentials base de données, clés cloud, certificats)
  • Pas de secret pré-distribué : l’identité source suffit à initier le flux, Vault fait le reste

Flux complet : authentification → identité → accès dynamique

Section intitulée « Flux complet : authentification → identité → accès dynamique »
  1. Le workload s’authentifie

    Le pod Kubernetes présente son service account token à Vault :

    Fenêtre de terminal
    vault write auth/kubernetes/login \
    role="my-app" \
    jwt="$(cat /var/run/secrets/kubernetes.io/serviceaccount/token)"
  2. Vault vérifie l’identité

    Vault contacte l’API Kubernetes pour valider :

    • Le token est-il valide ?
    • Le service account correspond-il au rôle Vault configuré ?
    • Le namespace est-il autorisé ?
  3. Vault associe l’authentification à sa couche Identity

    Si valide, Vault associe l’authentification à sa couche Identity via des aliases, et peut exploiter des métadonnées pour appliquer des policies ou tracer l’accès :

    • Service account name
    • Namespace
    • Annotations Kubernetes (si configurées)
  4. Vault délivre un token Vault

    Le workload reçoit un token Vault avec les policies attachées au rôle.

  5. Le workload demande un credential dynamique

    Fenêtre de terminal
    vault read database/creds/app-readonly
  6. Vault génère et renvoie

    • Crée un user PostgreSQL unique
    • Retourne username/password avec lease
  7. Le workload utilise le credential

    Se connecte à PostgreSQL avec ces credentials temporaires.

  8. À expiration

    Vault révoque le credential (supprime l’user PostgreSQL).

Méthodes d’authentification adaptées au brokering

Section intitulée « Méthodes d’authentification adaptées au brokering »

Idéal pour : pods dans un cluster K8s.

Le pod prouve son identité via son service account token. Vault contacte l’API Kubernetes pour valider.

Fenêtre de terminal
# Configurer l'auth Kubernetes dans Vault
vault auth enable kubernetes
vault write auth/kubernetes/config \
kubernetes_host="https://kubernetes.default.svc" \
kubernetes_ca_cert=@/var/run/secrets/kubernetes.io/serviceaccount/ca.crt
vault write auth/kubernetes/role/my-app \
bound_service_account_names="my-app-sa" \
bound_service_account_namespaces="production" \
policies="app-policy" \
ttl="1h"

Idéal pour : VMs, fonctions serverless, workloads cloud.

Le workload prouve son identité via son IAM role (AWS), service account (GCP), ou managed identity (Azure).

Fenêtre de terminal
# AWS IAM auth
vault auth enable aws
vault write auth/aws/role/ec2-role \
auth_type="iam" \
bound_iam_principal_arn="arn:aws:iam::123456789012:role/my-ec2-role" \
policies="app-policy" \
ttl="1h"

Avantage : pas de secret à distribuer au workload, il utilise son identité cloud native.

Idéal pour : CI/CD (GitHub Actions, GitLab CI), authentification humaine.

Le workload présente un token JWT signé par un provider OIDC. Vault vérifie la signature et les claims.

Fenêtre de terminal
vault auth enable jwt
vault write auth/jwt/config \
oidc_discovery_url="https://token.actions.githubusercontent.com" \
bound_issuer="https://token.actions.githubusercontent.com"
vault write auth/jwt/role/github-deploy \
role_type="jwt" \
bound_audiences="https://github.com/my-org" \
bound_claims='{"repository": "my-org/my-repo"}' \
user_claim="actor" \
policies="deploy-policy" \
ttl="15m"

Exemple : pod Kubernetes → credentials PostgreSQL

Section intitulée « Exemple : pod Kubernetes → credentials PostgreSQL »

Un pod order-service dans le namespace production a besoin d’accéder à PostgreSQL en lecture.

Fenêtre de terminal
# 1. Auth Kubernetes configurée (voir ci-dessus)
# 2. Database secrets configurés
vault write database/roles/order-readonly \
db_name="production-postgres" \
creation_statements="..." \
default_ttl="1h" \
max_ttl="4h"
# 3. Policy
vault policy write order-service - <<EOF
path "database/creds/order-readonly" {
capabilities = ["read"]
}
EOF
# 4. Rôle Kubernetes lié à la policy
vault write auth/kubernetes/role/order-service \
bound_service_account_names="order-service" \
bound_service_account_namespaces="production" \
policies="order-service" \
ttl="1h"

Avec Vault Agent Injector ou le CSI driver :

apiVersion: v1
kind: Pod
metadata:
name: order-service
annotations:
vault.hashicorp.com/agent-inject: "true"
vault.hashicorp.com/role: "order-service"
vault.hashicorp.com/agent-inject-secret-db: "database/creds/order-readonly"
vault.hashicorp.com/agent-inject-template-db: |
{{- with secret "database/creds/order-readonly" -}}
PGUSER={{ .Data.username }}
PGPASSWORD={{ .Data.password }}
{{- end }}
spec:
serviceAccountName: order-service
containers:
- name: app
image: order-service:latest
command: ["source", "/vault/secrets/db", "&&", "./start.sh"]

Résultat :

  1. Le pod démarre avec son service account
  2. Vault Agent s’authentifie via Kubernetes auth
  3. Vault génère des credentials PostgreSQL uniques
  4. Le fichier /vault/secrets/db contient user/pass
  5. L’app utilise ces credentials
  6. Vault Agent renouvelle automatiquement avant expiration

Un workflow GitHub Actions doit déployer sur S3.

Fenêtre de terminal
# 1. JWT auth pour GitHub Actions (voir ci-dessus)
# 2. AWS secrets configurés
vault write aws/roles/github-deploy \
credential_type="assumed_role" \
role_arns="arn:aws:iam::123456789012:role/S3DeployRole" \
default_sts_ttl="15m" \
max_sts_ttl="1h"
# 3. Policy
vault policy write github-deploy - <<EOF
path "aws/creds/github-deploy" {
capabilities = ["read"]
}
EOF
# 4. Rôle JWT lié
vault write auth/jwt/role/github-deploy \
bound_claims='{"repository": "my-org/my-repo", "ref": "refs/heads/main"}' \
policies="github-deploy" \
ttl="15m"
jobs:
deploy:
runs-on: ubuntu-latest
permissions:
id-token: write # Nécessaire pour OIDC
contents: read
steps:
- uses: hashicorp/vault-action@v2
with:
url: https://vault.example.com
method: jwt
role: github-deploy
jwtGithubAudience: https://github.com/my-org
secrets: |
aws/creds/github-deploy access_key | AWS_ACCESS_KEY_ID ;
aws/creds/github-deploy secret_key | AWS_SECRET_ACCESS_KEY ;
aws/creds/github-deploy security_token | AWS_SESSION_TOKEN
- run: aws s3 sync ./dist s3://my-bucket

Résultat :

  • Le workflow prouve son identité via le token OIDC de GitHub
  • Vault vérifie que c’est bien my-org/my-repo sur main
  • Vault assume un rôle IAM et retourne des credentials STS
  • Le workflow déploie sur S3 avec des credentials valides 15 min
AspectDistribution classiqueIdentity brokering
Secret permanent vers la cibleOui (dans K8s Secret, env vars)Non
Rotation des credentialsManuelle, coordinationAutomatique par TTL
Credential unique par workloadRarementToujours
Audit”app_user a fait X""pod order-abc123 a fait X”
CompromissionAccès permanentAccès limité au TTL
Complexité initialeFaibleMoyenne à élevée
Complexité de rotation/gestionHaute (coordination manuelle)Faible (automatisé)
Complexité de plateformeFaibleHaute (Vault à opérer)

Le workload ne peut pas démarrer si Vault est inaccessible. Mitigations :

  • Vault en HA
  • Cache local (Vault Agent)
  • TTL assez longs pour survivre à une panne courte

Chaque demande de credential ajoute un appel réseau. Mitigations :

  • Vault Agent avec cache
  • TTL suffisants pour éviter trop de renouvellements
  • Pooling de connexions côté app

Plus complexe qu’un Secret K8s statique. À justifier par :

  • Nombre de services
  • Exigences de sécurité/audit
  • Fréquence de rotation souhaitée

Vault ne se contente pas de vérifier l’identité : il peut aussi s’en servir pour construire les permissions à la volée.

Avec les templated policies, vous pouvez exploiter les métadonnées d’alias pour créer des ACL dynamiques :

policy-namespace-scoped.hcl
path "database/creds/{{identity.entity.aliases.auth_kubernetes_*.metadata.service_account_namespace}}-*" {
capabilities = ["read"]
}

Avantages :

  • Une seule policy pour plusieurs namespaces
  • Isolation automatique : chaque namespace n’accède qu’à ses propres credentials
  • Moins de policies à maintenir

Vault excelle comme courtier d’identité pour secrets dynamiques : le workload reçoit les credentials et gère la connexion lui-même.

Si vous voulez aller plus loin vers un accès interactif sans exposition directe des credentials (SSH, RDP, bases de données), HashiCorp Boundary couvre un autre niveau :

  • Brokering : le client reçoit les credentials (ce que fait Vault)
  • Credential injection : un worker intermédiaire cache les credentials au client final (ce que fait Boundary)

Boundary complète Vault pour les accès interactifs privilégiés.

  1. Vault = courtier d’identité : transforme une identité prouvée en accès temporaire vers une ressource cible
  2. Pas de credential permanent vers la cible : le workload conserve une preuve d’identité source (token K8s, OIDC, IAM) mais pas de secret vers la ressource finale
  3. Couche Identity : Vault associe les authentifications à des entities et aliases, permettant consolidation et policies dynamiques
  4. Auth native : K8s service account, cloud IAM, OIDC — pas de secret à distribuer au workload
  5. Credential unique : chaque workload obtient ses propres credentials
  6. Audit complet : qui (identité source) a demandé quoi (secret) et quand
  7. TTL courts réduisent le besoin de révocation : mais ne remplacent pas totalement la capacité à révoquer avant expiration
  8. Compromis plateforme : on gagne en sécurité et gestion, mais Vault devient une dépendance critique à opérer

Ce site vous est utile ?

Sachez que moins de 1% des lecteurs soutiennent ce site.

Je maintiens +700 guides gratuits, sans pub ni tracing. Aujourd'hui, ce site ne couvre même pas mes frais d'hébergement, d'électricité, de matériel, de logiciels, mais surtout de cafés.

Un soutien régulier, même symbolique, m'aide à garder ces ressources gratuites et à continuer de produire des guides de qualité. Merci pour votre appui.

Abonnez-vous et suivez mon actualité DevSecOps sur LinkedIn