TP18 : Gestion des secrets (Vault, External Secrets Operator, Sealed Secrets, rotation)
Un Secret Kubernetes n’est qu’un objet encodé en base64 : quiconque peut lire les Secrets du namespace ou accéder à etcd voit les valeurs, et on ne peut pas le versionner dans Git. Ce TP présente les trois approches courantes pour faire mieux : un coffre-fort central (HashiCorp Vault) synchronisé vers Kubernetes par External Secrets Operator, des secrets chiffrés versionnables (Sealed Secrets), et la rotation des secrets sans redéploiement manuel.
Fichiers de départ :
manifests.zip,vault.zip
1. Objectifs pédagogiques
À l’issue du TP, vous serez capable de :
- expliquer pourquoi un Secret Kubernetes ne suffit pas et comparer trois approches de gestion ;
- utiliser Vault : moteur KV v2, policies, méthode d’authentification Kubernetes ;
- synchroniser un secret de Vault (puis de Secrets Manager via Floci) vers Kubernetes avec External Secrets Operator ;
- chiffrer un secret pour Git avec Sealed Secrets ;
- réaliser une rotation et comprendre son effet sur les variables d’environnement et sur les fichiers montés.
Les images de cette page sont des schémas explicatifs, pas des captures d’écran.
2. Environnement du TP
- Le cluster K3s du TP14,
kubectlet Helm (TP15). - Le CLI
vaultsur la VM de lab (installation : même dépôt APT HashiCorp que Terraform au TP6). - Floci et AWS CLI (TP13) pour la partie 4.
3. Partie 1 : Installer Vault
-
Installer Vault en mode dev (stockage en mémoire, déverrouillé, jeton root
root) : uniquement pour un lab.helm repo add hashicorp https://helm.releases.hashicorp.com && helm repo update helm install vault hashicorp/vault -n vault --create-namespace \ --set server.dev.enabled=true --set server.dev.devRootToken=root --set injector.enabled=false kubectl -n vault get pods kubectl -n vault port-forward svc/vault 8200:8200 & export VAULT_ADDR=http://127.0.0.1:8200 VAULT_TOKEN=root vault statusEn production, Vault démarre scellé (sealed) : il faut le déverrouiller avec plusieurs clés (Shamir) ou un auto-unseal KMS, et le stockage est persistant (Raft). Le mode dev supprime tout cela.
-
Écrire et relire un secret dans le moteur KV v2 monté sur
secret/:vault kv put secret/tp18/api api-key=v1-initial-value vault kv get secret/tp18/api vault kv metadata get secret/tp18/api # KV v2 conserve les versions
4. Partie 2 : Policies et authentification Kubernetes
-
Compléter
vault/app-policy.hcl(lecture seule sursecret/data/tp18/*) et la charger :vault policy write tp18-app vault/app-policy.hcl -
Activer la méthode d’authentification Kubernetes : Vault vérifie le jeton du ServiceAccount d’un Pod auprès de l’API Kubernetes.
vault auth enable kubernetes vault write auth/kubernetes/config kubernetes_host="https://kubernetes.default.svc:443" vault write auth/kubernetes/role/tp18-app \ bound_service_account_names=app-sa bound_service_account_namespaces=tp18 \ policies=tp18-app ttl=1h -
Expliquer : quel Pod peut obtenir un jeton Vault avec ce rôle ? Que se passe-t-il pour un Pod d’un autre namespace ?
5. Partie 3 : External Secrets Operator
-
Installer ESO :
helm repo add external-secrets https://charts.external-secrets.io && helm repo update helm install external-secrets external-secrets/external-secrets -n external-secrets --create-namespace -
Appliquer le namespace et le ServiceAccount (
manifests/00-app.yaml: le Pod restera en attente tant que le Secret n’existe pas), puis compléter et appliquer10-secretstore.yamlet20-externalsecret.yaml.Si la ressource n’est pas reconnue, vérifiez la version de l’API proposée par votre version d’ESO (
kubectl api-resources | grep external-secrets) :v1dans les versions récentes,v1beta1dans les plus anciennes. -
Vérifier la synchronisation :
kubectl -n tp18 get secretstore,externalsecret # STATUS SecretSynced, READY True kubectl -n tp18 get secret api-credentials -o jsonpath='{.data.api-key}' | base64 -d kubectl -n tp18 logs deploy/secret-reader -f
6. Partie 4 : Rotation
-
Changer la valeur dans Vault, puis observer les logs de
secret-readerpendant une minute :vault kv put secret/tp18/api api-key=v2-rotated-value kubectl -n tp18 logs deploy/secret-reader -f -
Constater : le fichier monté finit par afficher la nouvelle valeur (le kubelet met à jour les volumes Secret), mais la variable d’environnement garde l’ancienne valeur jusqu’au redémarrage du Pod.
-
Rendre le redémarrage automatique, au choix :
kubectl rollout restartdéclenché par la CI, ou l’opérateur Reloader avec l’annotationreloader.stakater.com/auto: "true". -
Revenir à la version précédente (
vault kv rollback -version=1 secret/tp18/api) : que montrevault kv metadata get?
7. Partie 5 : Secrets Manager (Floci) comme seconde source
-
Créer un secret dans Floci (
aws secretsmanager create-secret --name tp18/db-password --secret-string 's3cr3t-lab'), Floci étant joignable depuis le cluster àhttp://<IP-VM-lab>:4566. -
Créer un Secret Kubernetes
floci-credscontenant les identifiants fictifs (access-key=test,secret-access-key=test) et unSecretStorede typeaws(service: SecretsManager,region: us-east-1,auth.secretRef). -
Pointer ESO vers Floci en ajoutant au déploiement du contrôleur la variable d’environnement de endpoint personnalisé décrite dans la documentation ESO (AWS, custom endpoints), par exemple :
helm upgrade external-secrets external-secrets/external-secrets -n external-secrets \ --reuse-values --set "extraEnv[0].name=AWS_SECRETSMANAGER_ENDPOINT" \ --set "extraEnv[0].value=http://<IP-VM-lab>:4566" -
Synchroniser
tp18/db-passworddans un Secretdb-credentialset vérifier sa valeur.
8. Partie 6 : Sealed Secrets (GitOps)
-
Installer le contrôleur et le CLI
kubeseal:helm repo add sealed-secrets https://bitnami-labs.github.io/sealed-secrets && helm repo update helm install sealed-secrets sealed-secrets/sealed-secrets -n kube-system # CLI : binaire kubeseal depuis https://github.com/bitnami-labs/sealed-secrets/releases -
Chiffrer un secret sans jamais l’appliquer en clair :
kubectl -n tp18 create secret generic smtp --from-literal=password='lab-smtp' \ --dry-run=client -o yaml \ | kubeseal --controller-name sealed-secrets --controller-namespace kube-system -o yaml > smtp-sealed.yaml cat smtp-sealed.yaml # valeur chiffrée : peut être commitée kubectl apply -f smtp-sealed.yaml && kubectl -n tp18 get secret smtp -
Copier
smtp-sealed.yamlen changeant le namespace endefaultpuis l’appliquer : pourquoi le déchiffrement échoue-t-il (portée strict) ? -
Que se passe-t-il si la clé privée du contrôleur est perdue ? Comment la sauvegarder ?
9. Partie 7 : Synthèse
- Compléter le tableau comparatif :
| Critère | Secret Kubernetes | Sealed Secrets | Vault + ESO |
|---|---|---|---|
| Versionnable dans Git | |||
| Source de vérité | |||
| Rotation | |||
| Audit des accès | |||
| Complexité d’exploitation | |||
| Adapté à GitOps |
Défi
- Activer le moteur database de Vault pour générer des identifiants PostgreSQL dynamiques à durée de vie limitée (
ttl=1h) pour le PostgreSQL du TP14.- Activer le chiffrement des Secrets au repos dans K3s (
--secrets-encryption) et vérifier aveck3s secrets-encrypt status.
10. Livrables
Captures à déposer dans captures/ :
| Fichier | Contenu attendu |
|---|---|
vault-kv.png |
vault kv get et vault kv metadata get (versions) |
vault-k8s-auth.png |
Rôle Kubernetes et policy tp18-app |
eso-synced.png |
ExternalSecret en état SecretSynced |
rotation.png |
Logs : le fichier change, la variable d’environnement non |
eso-floci.png |
Secret synchronisé depuis Secrets Manager (Floci) |
sealed-secret.png |
SealedSecret chiffré et Secret déchiffré dans le cluster |
Ainsi que : la policy Vault, les manifests ESO, smtp-sealed.yaml et le tableau comparatif. Aucun secret en clair dans Git.