VaultKubernetesSécuritéDevOps

HashiCorp Vault et Kubernetes : injection de secrets dans les pods

3 septembre 2026 · Sphinx-Digital

Stocker des secrets dans des Kubernetes Secrets en base64 est une fausse sécurité — ils sont lisibles par quiconque a accès à etcd. Vault résout ce problème en devenant la source de vérité pour les secrets, avec rotation automatique et audit complet.

Les trois approches d’intégration

1. Vault Agent Injector (sidecar)

Le Vault Agent Injector injecte automatiquement un conteneur sidecar dans les pods annotés. Ce sidecar s’authentifie auprès de Vault, récupère les secrets, et les écrit dans des fichiers montés dans le conteneur principal.

apiVersion: apps/v1
kind: Deployment
metadata:
  name: myapp
spec:
  template:
    metadata:
      annotations:
        # Active l'injection
        vault.hashicorp.com/agent-inject: "true"
        # Rôle Vault pour l'authentification Kubernetes
        vault.hashicorp.com/role: "myapp-role"
        # Secret à récupérer → écrit dans /vault/secrets/db-creds
        vault.hashicorp.com/agent-inject-secret-db-creds: "secret/data/myapp/db"
        # Template pour formater le fichier
        vault.hashicorp.com/agent-inject-template-db-creds: |
          {{- with secret "secret/data/myapp/db" -}}
          export DB_HOST="{{ .Data.data.host }}"
          export DB_PASSWORD="{{ .Data.data.password }}"
          {{- end }}
    spec:
      serviceAccountName: myapp   # SA utilisé pour l'auth Kubernetes
      containers:
        - name: app
          image: myapp:1.0
          command: ["/bin/bash", "-c"]
          args:
            - source /vault/secrets/db-creds && exec python app.py

2. External Secrets Operator

ESO synchronise des secrets Vault vers des Kubernetes Secrets natifs. Plus simple à intégrer dans des apps existantes qui lisent déjà des env vars.

apiVersion: external-secrets.io/v1beta1
kind: ExternalSecret
metadata:
  name: myapp-db-secret
spec:
  refreshInterval: 1h    # re-sync toutes les heures
  secretStoreRef:
    name: vault-backend
    kind: SecretStore
  target:
    name: myapp-db-secret    # nom du K8s Secret créé
    creationPolicy: Owner
  data:
    - secretKey: password        # clé dans le K8s Secret
      remoteRef:
        key: secret/myapp/db     # chemin dans Vault
        property: password       # champ dans le secret Vault
    - secretKey: username
      remoteRef:
        key: secret/myapp/db
        property: username
# SecretStore : la connexion à Vault
apiVersion: external-secrets.io/v1beta1
kind: SecretStore
metadata:
  name: vault-backend
spec:
  provider:
    vault:
      server: "https://vault.example.com"
      path: "secret"
      version: "v2"
      auth:
        kubernetes:
          mountPath: "kubernetes"
          role: "myapp-role"
          serviceAccountRef:
            name: myapp

3. Vault Secrets Operator (HashiCorp officiel)

Plus récent que ESO, natif HashiCorp, avec support de la rotation automatique des secrets dans les Deployments.

apiVersion: secrets.hashicorp.com/v1beta1
kind: VaultStaticSecret
metadata:
  name: myapp-config
spec:
  vaultAuthRef: my-vault-auth
  mount: secret
  type: kv-v2
  path: myapp/db
  destination:
    name: myapp-db-secret
    create: true
  rolloutRestartTargets:
    - kind: Deployment
      name: myapp    # redémarre automatiquement le deployment quand le secret change

Configurer l’auth Kubernetes dans Vault

# Activer le backend d'auth Kubernetes
vault auth enable kubernetes

# Configurer avec le service account du cluster
vault write auth/kubernetes/config \
    kubernetes_host="https://kubernetes.default.svc" \
    kubernetes_ca_cert=@/var/run/secrets/kubernetes.io/serviceaccount/ca.crt \
    token_reviewer_jwt=@/var/run/secrets/kubernetes.io/serviceaccount/token

# Créer un rôle qui associe un SA Kubernetes à des policies Vault
vault write auth/kubernetes/role/myapp-role \
    bound_service_account_names=myapp \
    bound_service_account_namespaces=production \
    policies=myapp-policy \
    ttl=1h

Policy Vault : principe du moindre privilège

# myapp-policy.hcl
# L'application peut uniquement lire ses propres secrets
path "secret/data/myapp/*" {
  capabilities = ["read"]
}

# Accès explicitement refusé aux secrets d'autres apps
path "secret/data/otherapp/*" {
  capabilities = ["deny"]
}
vault policy write myapp-policy myapp-policy.hcl

Rotation de secrets avec Vault Dynamic Secrets

Pour les bases de données, Vault peut générer des credentials temporaires à la demande — les credentials expirent automatiquement, éliminant le problème des credentials permanents volés.

# Configurer le backend database
vault secrets enable database
vault write database/config/mydb \
    plugin_name=postgresql-database-plugin \
    connection_url="postgresql://{{username}}:{{password}}@db:5432/myapp" \
    allowed_roles="myapp-role" \
    username="vault-admin" \
    password="vault-admin-password"

# Créer un rôle qui génère des credentials temporaires
vault write database/roles/myapp-role \
    db_name=mydb \
    creation_statements="CREATE ROLE \"{{name}}\" WITH LOGIN PASSWORD '{{password}}' VALID UNTIL '{{expiration}}'; GRANT SELECT, INSERT, UPDATE ON ALL TABLES IN SCHEMA public TO \"{{name}}\";" \
    default_ttl="1h" \
    max_ttl="24h"

Chaque pod reçoit maintenant des credentials PostgreSQL qui expirent au bout d’une heure. En cas de fuite, la fenêtre d’exploitation est limitée à cette durée.

Notre formation Vault couvre l’intégration Kubernetes avec des ateliers sur des clusters réels.