Tutoriel External Secrets Operator : Synchroniser vos secrets Kubernetes
15/12/2025
Chargement…
GitOps : Sécurisez vos secrets Kubernetes avec External Secrets Operator (ESO)
INTRODUCTION
La gestion des secrets est souvent le talon d'Achille d'une approche GitOps. Stocker des fichiers chiffrés dans Git (via des outils comme Sealed Secrets) complexifie la rotation des clés et manque de souplesse.
External Secrets Operator (ESO) résout ce problème en inversant le paradigme : il ne stocke rien, il synchronise. Il récupère les secrets natifs depuis un gestionnaire externe (AWS Secrets Manager, HashiCorp Vault, Azure Key Vault, Google Secret Manager) et les injecte directement en tant que secrets Kubernetes standards.
Dans ce tutoriel, nous allons voir comment implémenter une architecture robuste de gestion des secrets sur Kubernetes couplée à AWS.
Prérequis
Pour suivre ce guide, vous aurez besoin de :
- Un cluster Kubernetes (v1.24+).
- Helm (v3+) installé sur votre poste.
- kubectl configuré avec les droits d'administration (
cluster-admin). - Un compte AWS avec accès à Secrets Manager et IAM.
Tutoriel pas à pas
1. Installation de l'opérateur (ESO)
Nous utilisons Helm pour déployer l'opérateur dans un namespace dédié, garantissant une isolation propre des composants système.
# 1. Ajouter le dépôt Helm officiel
helm repo add external-secrets https://charts.external-secrets.io
# 2. Mettre à jour les index
helm repo update
# 3. Installer l'opérateur
helm install external-secrets external-secrets/external-secrets \
-n external-secrets \
--create-namespace \
--set installCRDs=true
Vérification : Assurez-vous que les pods sont en statut
Running:kubectl get pods -n external-secrets
2. Configuration de l'accès IAM (AWS)
Pour que le cluster puisse lire dans AWS Secrets Manager, une identité IAM est requise.
A. La politique IAM (Policy)
Voici une politique respectant le principe de moindre privilège. Elle limite l'accès à des secrets spécifiques.
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": [
"secretsmanager:GetSecretValue",
"secretsmanager:DescribeSecret"
],
"Resource": "arn:aws:secretsmanager:<AWS_REGION>:<AWS_ACCOUNT_ID>:secret:prod/my-app/*"
}
]
}
B. Authentification (Méthode simple vs Production)
Pour ce tutoriel, nous utiliserons une paire de clés (Access Key/Secret Key).
⚠️ Mise en garde Production (IRSA) : En production, n'utilisez jamais de clés statiques (long-term credentials). Privilégiez IAM Roles for Service Accounts (IRSA) via OIDC pour une authentification temporaire et sécurisée.
Créez un secret Kubernetes contenant vos identifiants IAM :
kubectl create secret generic aws-creds \
--from-literal=access-key=<VOTRE_ACCESS_KEY> \
--from-literal=secret-access-key=<VOTRE_SECRET_KEY> \
-n default
3. Création du SecretStore
Le SecretStore est la ressource qui fait le pont entre Kubernetes et votre fournisseur (ici AWS). Il est scopé au namespace (contrairement au ClusterSecretStore).
apiVersion: external-secrets.io/v1beta1
kind: SecretStore
metadata:
name: aws-secrets-store
namespace: default
spec:
provider:
aws:
service: SecretsManager
region: eu-west-3 # Remplacez par votre région
auth:
secretRef:
accessKeyIDSecretRef:
name: aws-creds
key: access-key
secretAccessKeySecretRef:
name: aws-creds
key: secret-access-key
4. Création de l'ExternalSecret
C'est ici que la magie opère. L'ExternalSecret déclare quel secret distant récupérer et comment le transformer en secret Kubernetes.
Imaginez un secret dans AWS nommé prod/db-credentials contenant le JSON : {"username":"admin", "password":"supersecurepassword"}.
apiVersion: external-secrets.io/v1beta1
kind: ExternalSecret
metadata:
name: my-db-secret
namespace: default
spec:
refreshInterval: 1h # Vérifie les changements côté AWS toutes les heures
secretStoreRef:
name: aws-secrets-store
kind: SecretStore
target:
name: db-credentials-k8s # Nom du secret final généré dans K8s
creationPolicy: Owner # Supprime le secret K8s si l'ExternalSecret est supprimé
data:
- secretKey: db_user # Clé dans le secret K8s
remoteRef:
key: prod/db-credentials
property: username # Clé du JSON AWS
- secretKey: db_pass
remoteRef:
key: prod/db-credentials
property: password
Appliquez le fichier : kubectl apply -f external-secret.yaml
Sécurité 🔐
- Least Privilege : Bannissez les wildcards (
*) dans vos policies IAM. Ciblez toujours des ARNs précis. - ClusterSecretStore vs SecretStore :
- Utilisez
SecretStorepour isoler les tenants (chaque équipe gère son auth). - Réservez
ClusterSecretStore(global) uniquement si tous les secrets proviennent du même compte AWS de manière centralisée.
- Utilisez
- Validation OPA/Kyverno : Implémentez des règles pour empêcher un namespace de développement de référencer des secrets de production (en filtrant sur le nom ou les tags).
Observabilité et Monitoring 📈
L'opérateur expose des métriques Prometheus sur le port 8080. Il est crucial d'alerter sur :
externalsecret_sync_calls_error: Indique un problème IAM, réseau, ou une clé manquante.- Status des CRDs : Un
ExternalSecretdoit toujours avoir la conditionReadyàTrue.
Commande de diagnostic rapide :
kubectl get externalsecrets
# Le STATUS doit être 'SecretSynced'
# Le READY doit être 'True'
Tests / Validation ✅
- Vérification de la présence :
kubectl get secret db-credentials-k8s -o jsonpath='{.data.db_pass}' | base64 -d - Linting CI/CD : Intégrez
kubeconformdans votre pipeline GitOps pour valider la syntaxe YAML avant le déploiement. - Test de rotation : Modifiez une valeur dans AWS Secrets Manager. Attendez le délai du
refreshInterval(ou forcez-le via une annotation) et vérifiez que Kubernetes a bien la nouvelle valeur.
Erreurs fréquentes & diagnostics 🛠️
Erreur :
SecretSyncedError/AccessDeniedException- Cause : Le rôle IAM n'a pas les droits sur l'ARN exact.
- Solution : Vérifiez la policy AWS et assurez-vous que la région dans le
SecretStoreest correcte.
Erreur :
Key not found- Cause : La propriété JSON demandée n'existe pas dans le secret AWS.
- Solution : Attention à la casse !
Passwordest différent depassword.
Bonus : Rotation automatique des Pods 🔄
ESO met à jour le secret Kubernetes, mais vos applications (Pods) ne rechargent pas forcément cette configuration à chaud.
Pour une solution complète, couplez ESO avec Reloader (de Stakater). Cet outil surveille les changements sur les Secrets et ConfigMaps et redémarre automatiquement (Rolling Update) les déploiements associés.
Ajoutez simplement cette annotation sur votre Deployment :
metadata:
annotations:
reloader.stakater.com/auto: "true"
Conclusion
L'utilisation d'External Secrets Operator renforce considérablement la sécurité de votre chaîne GitOps en découplant le cycle de vie des secrets de celui du code applicatif. Vous obtenez le meilleur des deux mondes : la puissance de gestion d'un Vault/AWS et la simplicité native de Kubernetes.
Prêt à passer en prod ? Assurez-vous d'abord de migrer vers l'authentification IRSA !