ADR 009 â External Secrets Operator + IRSA (2026-05-29)
Contexte
Gap C5 de l'audit du 2026-05-20 : External Secrets Operator (ESO) est annoncé dans
le design du projet mais n'a jamais été installé. Les secrets applicatifs
(DB_PASSWORD, SECRET_KEY) sont aujourd'hui injectés de façon impérative par le job
deploy du pipeline :
kubectl create secret generic fastapi-secrets \
--from-literal=SECRET_KEY="$SECRET_KEY" \
--from-literal=DB_PASSWORD="$TF_VAR_db_password" \
-n fastapi --dry-run=client -o yaml | kubectl apply -f -
ProblĂšmes :
- Les valeurs vivent dans des variables CI GitLab, dupliquées et gérées à la main.
- Le Secret Kubernetes n'a pas de source de vérité unique ni de rotation.
- IncohĂ©rence design : le ConfigMap et le Deployment documentent dĂ©jĂ
« variables sensibles gérées par ESO », mais ESO est absent.
Objectif (issue #33) : AWS Secrets Manager devient la source de vérité, ESO
synchronise automatiquement le Secret Kubernetes fastapi-secrets, et le job deploy
ne crée plus de secret impérativement.
DĂ©cision 1 â External Secrets Operator comme mĂ©canisme de synchronisation
ESO est retenu pour matérialiser un Secret Kubernetes à partir d'AWS Secrets Manager.
Alternatives écartées :
- Secret impératif en CI (existant) : pas de source unique, pas de rotation, valeur dupliquée.
- Sealed Secrets : chiffre un Secret dans Git, mais la source de vérité reste Git,
pas un coffre managé. Pas d'intégration native AWS.
- Secrets Store CSI Driver : monte les secrets en volume, mais ne crée pas un objet
Secret Kubernetes natif. Le Deployment consomme déjà envFrom.secretRef, ESO colle
mieux sans refonte du PodSpec.
DĂ©cision 2 â IRSA (OIDC) comme mĂ©thode d'authentification vers AWS
Le contrÎleur ESO s'authentifie auprÚs de Secrets Manager via IRSA (IAM Roles for Service Accounts) : le ServiceAccount du contrÎleur est annoté avec l'ARN d'un rÎle IAM dont la trust policy est liée au provider OIDC du cluster.
Alternative écartée : credentials IAM statiques (access key/secret key stockés dans un Secret Kubernetes). Plus simple, mais introduit un secret long-lived dans le cluster pour gérer les secrets, ce qui est contradictoire et affaiblit la posture.
Le rÎle IRSA d'ESO est scopé en moindre privilÚge : secretsmanager:GetSecretValue +
DescribeSecret sur le seul ARN du secret applicatif.
DĂ©cision 3 â Le secret Secrets Manager vit dans le stack persistent
Le secret fastapi-eks/app (payload JSON DB_PASSWORD + SECRET_KEY) est créé dans
le stack Terraform persistent, pas ephemeral.
Raisons :
- Le secret survit au terraform destroy quotidien du stack ephemeral.
- On Ă©vite la fenĂȘtre de rĂ©cupĂ©ration AWS (7 Ă 30 jours) qui complique un
delete/recreate journalier. recovery_window_in_days = 0 permet malgré tout un
recreate propre si le stack persistent est un jour détruit.
- SECRET_KEY est généré par random_password (Terraform en est propriétaire,
aucune valeur humaine à gérer) et reste stable entre les cycles ephemeral.
Le mettre dans ephemeral le régénérerait chaque matin, invalidant tous les JWT.
DB_PASSWORD partage la valeur de var.db_password (mĂȘme TF_VAR_db_password que le
module RDS). Conséquence : une rotation du mot de passe RDS exige de ré-appliquer les
deux stacks (persistent pour le secret, ephemeral pour RDS). Rotation rare, coût accepté.
DĂ©cision 4 â Le provider OIDC et le rĂŽle IRSA vivent dans le stack ephemeral
Le cluster EKS est ephemeral : son issuer OIDC change à chaque recréation. Le
aws_iam_openid_connect_provider et le rÎle IRSA d'ESO (dont la trust policy référence
cet issuer) sont donc créés dans le stack ephemeral, recréés à chaque aws-start.
Le nom du rÎle est fixe, donc son ARN est stable entre les cycles : l'annotation IRSA du ServiceAccount ESO (posée par le bootstrap Ansible) n'a pas à changer.
Conséquences et découpage
Le terraform_ci policy (stack persistent, module IAM) est élargi pour que l'apply
ephemeral puisse gérer le provider OIDC, la policy inline du rÎle ESO, et lire la
metadata du secret. Le stack persistent doit ĂȘtre appliquĂ© (par un admin) avant le
premier apply ephemeral qui crée l'IRSA.
Implémentation étalée sur plusieurs MR (discipline « petit et ciblé ») :
| MR | PérimÚtre |
|---|---|
| MR-A | Stack persistent : secret Secrets Manager + élargissement terraform_ci |
| MR-B | Stack ephemeral : output issuer OIDC + provider OIDC + rĂŽle IRSA ESO |
| MR-C | Ansible : install ESO via Helm + annotation IRSA + uninstall teardown |
| MR-D | Manifests SecretStore + ExternalSecret, retrait du Secret impératif du deploy, validation end-to-end |
Date : 2026-05-29 Sprint : 3 Issue : #33