External Secrets Operator Reference: Vault, AWS SM, GCP, Azure & Secret Sync Patterns
External Secrets Operator (ESO) syncs secrets from external stores (Vault, AWS Secrets Manager, GCP Secret Manager, Azure Key Vault) into Kubernetes Secrets automatically — the recommended way to avoid storing sensitive values in K8s or Git.
1. Why ESO vs Sealed Secrets vs Vault Agent
Choosing your K8s secret management strategy
| Approach | How it works | Best for |
|---|---|---|
| External Secrets Operator | K8s CRD syncs from external store → K8s Secret | Centralised secret store already exists (Vault, AWS SM) |
| Sealed Secrets | Encrypt secrets in Git, decrypt in cluster | GitOps where secrets live in Git (with Flux/ArgoCD) |
| Vault Agent Injector | Sidecar injects secrets as files in pods | Per-pod secret delivery, short-lived credentials |
| CSI Secrets Store | Mount secrets as volumes via CSI driver | Compliance requirements for file-mounted secrets |
# Install ESO: helm repo add external-secrets https://charts.external-secrets.io helm install external-secrets external-secrets/external-secrets --namespace external-secrets --create-namespace kubectl get pods -n external-secrets kubectl get crds | grep external-secrets.io # SecretStore, ExternalSecret, ClusterSecretStore
2. HashiCorp Vault Backend
Sync secrets from Vault KV into Kubernetes Secrets
# 1. Create a SecretStore (namespaced — for per-namespace Vault access):
apiVersion: external-secrets.io/v1beta1
kind: SecretStore
metadata:
name: vault-backend
namespace: production
spec:
provider:
vault:
server: https://vault.vault.svc.cluster.local:8200
path: secret # KV v2 mount path
version: v2 # KV version (v1 or v2)
auth:
kubernetes:
mountPath: kubernetes # Vault auth method path
role: production-apps # Vault Kubernetes role
serviceAccountRef:
name: external-secrets-sa # K8s SA with Vault auth permission
# 2. Create ExternalSecret — defines what to sync:
apiVersion: external-secrets.io/v1beta1
kind: ExternalSecret
metadata:
name: my-app-secrets
namespace: production
spec:
refreshInterval: 1h # re-sync every hour
secretStoreRef:
name: vault-backend
kind: SecretStore
target:
name: my-app-secrets # name of K8s Secret to create
creationPolicy: Owner # ESO manages lifecycle (deletes when ExternalSecret deleted)
template:
type: Opaque
data:
- secretKey: db-password # key in K8s Secret
remoteRef:
key: myapp/production # Vault path (under secret/data/)
property: db_password # field in Vault secret
- secretKey: api-key
remoteRef:
key: myapp/production
property: api_key
# Check sync status:
kubectl get externalsecret -n production
kubectl describe externalsecret my-app-secrets -n production
# Ready=True = secret successfully synced
# Ready=False → look at Conditions for auth/path errors
3. AWS Secrets Manager & Parameter Store
Sync from AWS SM and SSM Parameter Store
# ClusterSecretStore (cluster-wide — reusable across namespaces):
apiVersion: external-secrets.io/v1beta1
kind: ClusterSecretStore
metadata:
name: aws-secrets
spec:
provider:
aws:
service: SecretsManager # or ParameterStore
region: us-east-1
auth:
jwt:
serviceAccountRef:
name: external-secrets # IRSA: SA annotated with IAM role ARN
namespace: external-secrets
# SA annotation:
# eks.amazonaws.com/role-arn: arn:aws:iam::123456789:role/external-secrets-role
# ExternalSecret pulling from AWS SM:
apiVersion: external-secrets.io/v1beta1
kind: ExternalSecret
metadata:
name: rds-credentials
namespace: production
spec:
refreshInterval: 30m
secretStoreRef:
name: aws-secrets
kind: ClusterSecretStore
target:
name: rds-credentials
data:
- secretKey: DB_PASSWORD
remoteRef:
key: production/rds/credentials # AWS SM secret name
property: password # JSON field in the secret
- secretKey: DB_USERNAME
remoteRef:
key: production/rds/credentials
property: username
# Extract entire secret as multiple K8s keys (dataFrom):
spec:
dataFrom:
- extract:
key: production/myapp # all key/value pairs become K8s Secret keys
# Parameter Store:
spec:
provider:
aws:
service: ParameterStore
region: us-east-1
# ExternalSecret remoteRef.key = /production/myapp/db_password (SSM path)
4. GCP & Azure Backends
GCP Secret Manager and Azure Key Vault integration
# GCP Secret Manager:
apiVersion: external-secrets.io/v1beta1
kind: SecretStore
metadata:
name: gcp-secrets
namespace: production
spec:
provider:
gcpsm:
projectID: my-gcp-project
auth:
workloadIdentity:
clusterLocation: us-central1
clusterName: my-cluster
serviceAccountRef:
name: external-secrets-sa # K8s SA with Workload Identity binding
# ExternalSecret:
data:
- secretKey: api-key
remoteRef:
key: my-app-api-key # GCP Secret Manager secret name
version: latest # or specific version number
# Azure Key Vault:
spec:
provider:
azurekv:
tenantId: "xxxx-xxxx-xxxx"
vaultUrl: https://my-vault.vault.azure.net
authType: WorkloadIdentity # or ServicePrincipal
serviceAccountRef:
name: external-secrets-sa
# ExternalSecret (Key Vault secret):
data:
- secretKey: db-password
remoteRef:
key: production-db-password # Key Vault secret name (no slashes)
5. Push Secrets & Advanced Patterns
Push secrets to external store, secret templates, and rotation
# PushSecret: write a K8s Secret TO an external store (opposite direction):
apiVersion: external-secrets.io/v1alpha1
kind: PushSecret
metadata:
name: push-to-vault
spec:
secretStoreRefs:
- name: vault-backend
kind: SecretStore
selector:
secret:
name: my-k8s-secret # push this K8s Secret to Vault
data:
- match:
secretKey: api-key # key in K8s Secret
remoteRef:
remoteKey: myapp/api # destination path in Vault
property: api_key
# Secret template (transform before creating K8s Secret):
target:
template:
data:
DATABASE_URL: "postgresql://{{ .db_user }}:{{ .db_pass }}@db:5432/mydb"
# Constructs a connection URL from individual Vault fields
# Rotation trigger (force re-sync when upstream secret changes):
# ESO polls at refreshInterval — for immediate rotation, delete ExternalSecret and re-apply
# Or annotate: kubectl annotate externalsecret my-app-secrets # force-sync=$(date +%s) -n production
# Multi-source (merge from multiple stores):
spec:
dataFrom:
- extract: {key: shared/common} # shared secrets
- extract: {key: production/myapp} # app-specific secrets (overwrites shared if collision)
Track External Secrets Operator and security tool releases.
ReleaseRun monitors Kubernetes, Docker, and 13+ DevOps technologies.
Related: HashiCorp Vault Reference | Kubernetes RBAC Reference | OPA & Gatekeeper Reference | Kubernetes EOL Tracker
🔍 Free tool: K8s YAML Security Linter — check your ExternalSecret and workload manifests for K8s security misconfigurations.
Founded
2023 in London, UK
Contact
hello@releaserun.com