External Secrets Operator (ESO) est un opérateur Kubernetes, CNCF Sandbox, qui synchronise automatiquement les secrets depuis des gestionnaires externes (HashiCorp Vault, AWS Secrets Manager, Azure Key Vault, GCP Secret Manager, 1Password, Bitwarden, etc.) vers des Secrets Kubernetes natifs. Il repose sur trois CRDs : SecretStore/ClusterSecretStore (configuration du provider), ExternalSecret (quoi synchroniser et vers quel Secret), et PushSecret (synchronisation inverse K8s → provider). Les secrets ne transitent jamais par Git.
Informations essentielles
Origine : Communauté → CNCF Sandbox · Licence : Apache 2.0 · Architectures : x86_64, ARM64
Liens : Site officiel · Documentation · GitHub · Releases
Support : CNCF Sandbox. Communauté active, 30+ providers supportés.
Stack par défaut
| Composant | Valeur |
|---|---|
| CRDs | ExternalSecret, SecretStore, ClusterSecretStore, PushSecret |
| API version | external-secrets.io/v1beta1 |
| Namespace install | external-secrets |
| Providers | Vault, AWS SM, Azure KV, GCP SM, 1Password, Bitwarden, SSM Parameter Store, Conjur... |
| Sync | Polling (interval configurable) ou webhook push |
Prérequis
| Ressource | Valeur |
|---|---|
| Kubernetes | 1.19+ |
| Gestionnaire de secrets | Au moins un provider configuré |
Installation
helm repo add external-secrets https://charts.external-secrets.io
helm repo update
helm install external-secrets external-secrets/external-secrets \
--namespace external-secrets \
--create-namespace
# Vérifier
kubectl get pods -n external-secrets
# external-secrets, external-secrets-cert-controller, external-secrets-webhook Running
Exemple complet avec HashiCorp Vault
SecretStore - configuration du provider
apiVersion: external-secrets.io/v1beta1
kind: SecretStore
metadata:
name: vault-backend
namespace: production
spec:
provider:
vault:
server: https://vault.example.com
path: secret # Mount point du secret engine
version: v2 # KV v2
auth:
kubernetes:
mountPath: kubernetes
role: external-secrets # Role Vault autorisé
serviceAccountRef:
name: external-secrets-sa
ExternalSecret - que synchroniser
apiVersion: external-secrets.io/v1beta1
kind: ExternalSecret
metadata:
name: app-secrets
namespace: production
spec:
refreshInterval: 1h # Resynchroniser toutes les heures
secretStoreRef:
name: vault-backend
kind: SecretStore
target:
name: app-secrets # Nom du Secret K8s créé
creationPolicy: Owner
data:
- secretKey: db-password # Clé dans le Secret K8s
remoteRef:
key: myapp/database # Chemin dans Vault
property: password # Propriété dans le secret Vault
- secretKey: db-username
remoteRef:
key: myapp/database
property: username
ExternalSecret avec dataFrom (tout le secret d'un coup)
spec:
refreshInterval: 30m
secretStoreRef:
name: vault-backend
kind: SecretStore
target:
name: app-config
dataFrom:
- extract:
key: myapp/config # Toutes les clés du secret Vault → clés du Secret K8s
Exemple avec AWS Secrets Manager
ClusterSecretStore (cluster-wide, pour tous les namespaces)
apiVersion: external-secrets.io/v1beta1
kind: ClusterSecretStore
metadata:
name: aws-secrets-manager
spec:
provider:
aws:
service: SecretsManager
region: eu-west-1
auth:
jwt:
serviceAccountRef:
name: external-secrets
namespace: external-secrets
ExternalSecret avec ClusterSecretStore
apiVersion: external-secrets.io/v1beta1
kind: ExternalSecret
metadata:
name: rds-credentials
namespace: production
spec:
refreshInterval: 1h
secretStoreRef:
name: aws-secrets-manager
kind: ClusterSecretStore
target:
name: rds-credentials
dataFrom:
- extract:
key: prod/rds/credentials # ARN ou nom du secret AWS
Templates de secrets
ESO peut transformer les valeurs avant de les écrire dans le Secret Kubernetes :
spec:
target:
name: app-connection-string
template:
type: Opaque
data:
connection.string: |
postgresql://{{ .username }}:{{ .password }}@{{ .host }}:{{ .port }}/{{ .dbname }}
dataFrom:
- extract:
key: myapp/database
Vérifier l'état de synchronisation
# État des ExternalSecrets
kubectl get externalsecrets -A
# Détails d'une synchronisation
kubectl describe externalsecret app-secrets -n production
# Chercher la section "Status" - synced: true
# Forcer une resynchronisation
kubectl annotate externalsecret app-secrets \
force-sync=$(date +%s) -n production
Mise à jour
helm repo update
helm upgrade external-secrets external-secrets/external-secrets \
--namespace external-secrets \
--reuse-values
Troubleshooting
# Logs de l'opérateur
kubectl logs -n external-secrets \
-l app.kubernetes.io/name=external-secrets --tail=50
# ExternalSecret en erreur
kubectl describe externalsecret <nom> -n <ns>
# Vérifier : credentials du provider, chemin du secret, réseau
# SecretStore en erreur
kubectl get secretstore -A
kubectl describe secretstore vault-backend -n production
# Tester manuellement la connexion Vault (depuis un pod)
kubectl run test-vault --rm -it --image=vault -- \
vault login -address=https://vault.example.com
Ressources
- Documentation officielle : https://external-secrets.io/latest/
- GitHub : https://github.com/external-secrets/external-secrets
- Providers : https://external-secrets.io/latest/provider/
- Getting started : https://external-secrets.io/latest/introduction/getting-started/
- Releases : https://github.com/external-secrets/external-secrets/releases