
Table of Contents
By Khimananda Oli | Last reviewed: August 2026
Managing static credentials in Kubernetes manifests is a security liability that fails audits and complicates rotation. Integrating External Secrets Operator with Vault solves this by dynamically syncing secrets from HashiCorp Vault into native Kubernetes Secret objects without exposing long-lived tokens in your Git repository. This approach decouples secret storage from application deployment, enabling automated rotation and least-privilege access patterns required for SOC 2 and ISO 27001 compliance. If you are already managing sensitive data, understanding Kubernetes secrets management done right provides the necessary foundation before implementing an external backend.
How do you configure External Secrets Operator with Vault authentication?
The most common failure point when deploying External Secrets Operator with Vault is misconfigured authentication. Never use static AppRole credentials or root tokens in production; these violate least-privilege principles and create audit findings. Instead, use Kubernetes ServiceAccount authentication, which binds Vault access directly to pod identity and namespace boundaries.
Enable Kubernetes Auth Method in Vault
First, enable the Kubernetes auth method and configure it to trust your cluster's API server. This allows Vault to validate ServiceAccount tokens presented by ESO.
# Enable K8s auth method
vault auth enable kubernetes
# Configure the connection to your K8s API
vault write auth/kubernetes/config \
kubernetes_host="https://kubernetes.default.svc:443" \
kubernetes_ca_cert=@/var/run/secrets/kubernetes.io/serviceaccount/ca.crt
# Create a policy for reading secrets
vault policy write eso-read-policy -<<EOF
path "secret/data/apps/*" {
capabilities = ["read"]
}
path "pki/issue/web-certs" {
capabilities = ["create", "update"]
}
EOF
# Bind the policy to a specific ServiceAccount and namespace
vault write auth/kubernetes/role/eso-role \
bound_service_account_names=external-secrets \
bound_service_account_namespaces=external-secrets-system \
policies=eso-read-policy \
ttl=1h This configuration restricts Vault access to only the external-secrets ServiceAccount in the external-secrets-system namespace. For multi-cluster setups, you must repeat this binding for each cluster’s unique CA certificate and service account. Teams managing complex RBAC should review Kubernetes RBAC: Secure Your Cluster to ensure namespace isolation aligns with Vault policies.
Create the ClusterSecretStore Resource
The ClusterSecretStore defines how ESO connects to Vault. Unlike a namespaced SecretStore, this resource is available cluster-wide, reducing duplication across environments.
apiVersion: external-secrets.io/v1beta1
kind: ClusterSecretStore
metadata:
name: vault-backend
spec:
provider:
vault:
server: "https://vault.internal.example.com:8200"
path: "secret"
version: "v2"
auth:
kubernetes:
mountPath: "kubernetes"
role: "eso-role"
serviceAccountRef:
name: "external-secrets"
namespace: "external-secrets-system" A common mistake here is omitting the namespace field in serviceAccountRef. Even though ClusterSecretStore is cluster-scoped, ESO needs explicit permission to read the ServiceAccount token from its home namespace. Without this, reconciliation fails silently with authentication errors in the controller logs.
How does secret synchronization and templating work in practice?
Once authenticated, External Secrets Operator with Vault translates external data structures into Kubernetes-native formats. Real-world applications rarely consume raw JSON blobs; they expect specific key names, environment variable formats, or PEM-encoded certificates. ESO’s templating engine handles this transformation declaratively.
Basic Secret Sync vs. Advanced Templating
For simple key-value pairs, a direct mapping suffices. However, most production workloads require restructuring Vault output to match application expectations.
apiVersion: external-secrets.io/v1beta1
kind: ExternalSecret
metadata:
name: app-database-creds
namespace: production-apps
spec:
refreshInterval: 1h
secretStoreRef:
name: vault-backend
kind: ClusterSecretStore
target:
name: db-credentials
creationPolicy: Owner
template:
type: Opaque
data:
DB_HOST: "{{ .db_host }}"
DB_USER: "{{ .username }}"
DB_PASS: "{{ .password }}"
# Transform JSON metadata into a config string
APP_CONFIG: |
{"pool_size": {{ .pool_size }}, "timeout": {{ .timeout }}}
data:
- secretKey: db_host
remoteRef:
key: apps/production/database
property: host
- secretKey: username
remoteRef:
key: apps/production/database
property: username
- secretKey: password
remoteRef:
key: apps/production/database
property: password
- secretKey: pool_size
remoteRef:
key: apps/production/database
property: metadata.pool_size
- secretKey: timeout
remoteRef:
key: apps/production/database
property: metadata.timeout The refreshInterval controls how often ESO polls Vault for changes. Setting this too low increases API load; setting it too high delays credential rotation. In my experience auditing fintech systems, a 1-hour interval balances operational overhead with security requirements for most database credentials. For highly sensitive short-lived tokens, reduce this to 5–15 minutes and ensure your application supports graceful credential reloading.
What are the trade-offs between ESO, CSI Driver, and direct Vault Agent?
Choosing the right integration pattern depends on your operational constraints, compliance requirements, and application architecture. Each approach has distinct trade-offs that affect security posture, complexity, and developer experience.
| Criteria | External Secrets Operator | Vault CSI Driver | Vault Agent Injector |
|---|---|---|---|
| Secret Format | Native K8s Secrets | Ephemeral Volume Files | Annotated Sidecar Files |
| Rotation Handling | Polling + Secret Update | Volume Remount (TTL) | Sidecar Re-render |
| App Compatibility | Any (env vars/volumes) | File-based only | File-based only |
| Audit Trail | K8s Events + Vault Audit | Vault Audit Only | Vault Audit Only |
| Complexity | Moderate (CRDs + Store) | Low (DaemonSet) | High (Annotations + Init) |
| SOC 2 Evidence | Strong (Declarative State) | Moderate (Runtime Only) | Weak (Implicit Config) |
For teams pursuing SOC 2 or ISO 27001 certification, External Secrets Operator with Vault offers superior auditability because every secret sync is represented as a declarative Kubernetes object with status conditions and events. Auditors can inspect ExternalSecret resources to verify that secrets originate from approved Vault paths rather than ad-hoc manual entries. The CSI driver excels for high-security scenarios where secrets must never touch etcd, but it requires applications to read files rather than environment variables. Vault Agent remains useful for legacy migrations but introduces significant annotation complexity and sidecar resource overhead.
How do you handle dynamic secrets and certificate rotation?
Static credentials are a liability. Vault’s dynamic secrets engines generate short-lived credentials on demand, and ESO can consume them natively. This is particularly valuable for databases, cloud providers, and PKI certificates where long-lived credentials increase blast radius during breaches.
Dynamic Database Credentials
Configure Vault’s database secrets engine to generate PostgreSQL credentials with 1-hour TTLs. ESO will automatically request new credentials before expiration and update the Kubernetes Secret.
apiVersion: external-secrets.io/v1beta1
kind: ExternalSecret
metadata:
name: dynamic-db-creds
spec:
refreshInterval: 30m
secretStoreRef:
name: vault-backend
kind: ClusterSecretStore
target:
name: postgres-dynamic-creds
data:
- secretKey: username
remoteRef:
key: database/creds/app-role
property: username
- secretKey: password
remoteRef:
key: database/creds/app-role
property: password Set refreshInterval to less than half the Vault lease TTL to prevent credential expiration during reconciliation delays. Applications must handle connection resets gracefully when credentials rotate. For PostgreSQL specifically, connection poolers like PgBouncer can abstract credential changes from application code, reducing restart requirements during rotation cycles.
PKI Certificate Automation
For TLS certificates, ESO integrates with Vault’s PKI engine to issue and renew certificates automatically. This eliminates manual cert-manager configurations when Vault is already your certificate authority.
apiVersion: external-secrets.io/v1beta1
kind: ExternalSecret
metadata:
name: web-tls-cert
spec:
refreshInterval: 24h
secretStoreRef:
name: vault-backend
kind: ClusterSecretStore
target:
name: web-tls
template:
type: kubernetes.io/tls
data:
tls.crt: "{{ .certificate }}"
tls.key: "{{ .private_key }}"
ca.crt: "{{ .issuing_ca }}"
data:
- secretKey: certificate
remoteRef:
key: pki/issue/web-certs
property: certificate
- secretKey: private_key
remoteRef:
key: pki/issue/web-certs
property: private_key
- secretKey: issuing_ca
remoteRef:
key: pki/issue/web-certs
property: issuing_ca This pattern centralizes certificate lifecycle management within Vault while maintaining compatibility with Ingress controllers and service meshes that expect standard TLS secret types. Teams operating observability stacks should correlate certificate expiration metrics with their monitoring platform; see Prometheus Metrics Monitoring Fundamentals for exporting ESO sync status and certificate TTL gauges.
Securing External Secrets Operator with Vault for Production Compliance
Deploying External Secrets Operator with Vault in production requires hardening beyond default installations. Enable Vault audit logging to capture every secret access request with timestamps, identities, and outcomes—this is non-negotiable for compliance audits. Configure ESO controller replicas with anti-affinity rules to prevent single points of failure during node maintenance. Implement NetworkPolicies restricting ESO pod egress to only Vault endpoints and Kubernetes API servers, blocking lateral movement if the controller is compromised.
Monitor ESO reconciliation failures through Prometheus metrics (externalsecret_status_condition) and alert on sustained sync failures before applications encounter stale credentials. Regularly rotate the Kubernetes ServiceAccount tokens used for Vault authentication and test failover procedures quarterly. For teams building comprehensive observability around secret operations, integrating structured logging practices from Structured Logging Best Practices ensures ESO events correlate with application logs during incident investigation.
If your team needs assistance architecting compliant secret management workflows or validating existing ESO deployments against security frameworks, reach out for a consultation. Proper secrets infrastructure prevents breaches and accelerates audit cycles—invest the engineering time now to avoid remediation costs later.