Packaging & Config

External Secrets Operator

Opérateur Kubernetes CNCF pour synchroniser les secrets depuis Vault, AWS Secrets Manager, Azure Key Vault, GCP Secret Manager vers des Secrets K8s natifs. Apache 2.0.

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

ComposantValeur
CRDsExternalSecret, SecretStore, ClusterSecretStore, PushSecret
API versionexternal-secrets.io/v1beta1
Namespace installexternal-secrets
ProvidersVault, AWS SM, Azure KV, GCP SM, 1Password, Bitwarden, SSM Parameter Store, Conjur...
SyncPolling (interval configurable) ou webhook push

Prérequis

RessourceValeur
Kubernetes1.19+
Gestionnaire de secretsAu 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

Newsletter · 2 000+ abonnés

Reste au courant de ce qui bouge en prod

RudeOps veille devops hebdo, droit au but.

Gratuit · Sans spam · Désinscription en un clic