External Secrets Operator for Kubernetes Secrets Management
External Secrets Operator Kubernetes integration solves one of the most persistent challenges in container orchestration: managing sensitive configuration data securely. Native Kubernetes Secrets are base64-encoded (not encrypted), stored in etcd, and difficult to rotate. External Secrets Operator (ESO) bridges Kubernetes with enterprise secret management platforms, automatically syncing secrets from AWS Secrets Manager, HashiCorp Vault, Azure Key Vault, and GCP Secret Manager into your clusters.
This guide covers installing and configuring ESO for production environments, including multi-cluster synchronization, automatic rotation, and disaster recovery patterns. Moreover, you will learn how to implement zero-trust secret access policies that satisfy SOC 2 and PCI-DSS compliance requirements.
Why Native Kubernetes Secrets Fall Short
Kubernetes Secrets have fundamental limitations that make them unsuitable for production secret management. They are only base64-encoded — anyone with RBAC access to read secrets can decode them trivially. Furthermore, secrets stored in etcd may not be encrypted at rest depending on your cluster configuration.
Secret rotation requires redeploying pods. There is no native audit trail for who accessed which secret and when. Additionally, sharing secrets across multiple clusters requires manual synchronization or custom tooling that often becomes a maintenance burden.
Installing External Secrets Operator
# Install ESO via Helm
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 \
--set installCRDs=true \
--set webhook.port=9443 \
--set certController.requeueInterval=5mExternal Secrets Operator Kubernetes: AWS Provider Setup
# cluster-secret-store.yaml — Cluster-wide secret store
apiVersion: external-secrets.io/v1beta1
kind: ClusterSecretStore
metadata:
name: aws-secrets-manager
spec:
provider:
aws:
service: SecretsManager
region: us-east-1
auth:
jwt:
serviceAccountRef:
name: external-secrets-sa
namespace: external-secrets
---
# IRSA (IAM Role for Service Account) configuration
apiVersion: v1
kind: ServiceAccount
metadata:
name: external-secrets-sa
namespace: external-secrets
annotations:
eks.amazonaws.com/role-arn: arn:aws:iam::123456789:role/external-secrets-role# IAM policy for the ESO role (Terraform)
resource "aws_iam_policy" "external_secrets" {
name = "external-secrets-policy"
policy = jsonencode({
Version = "2012-10-17"
Statement = [
{
Effect = "Allow"
Action = [
"secretsmanager:GetSecretValue",
"secretsmanager:DescribeSecret",
"secretsmanager:ListSecretVersionIds"
]
Resource = "arn:aws:secretsmanager:us-east-1:123456789:secret:myapp/*"
},
{
Effect = "Allow"
Action = [
"kms:Decrypt",
"kms:DescribeKey"
]
Resource = "arn:aws:kms:us-east-1:123456789:key/mrk-*"
}
]
})
}Syncing Secrets from External Providers
Therefore, ExternalSecret resources define which secrets to sync and how to map them into Kubernetes Secrets. ESO watches these resources and automatically creates or updates the corresponding Kubernetes Secret whenever the source changes.
# external-secret.yaml — Sync database credentials
apiVersion: external-secrets.io/v1beta1
kind: ExternalSecret
metadata:
name: database-credentials
namespace: production
spec:
refreshInterval: 5m
secretStoreRef:
name: aws-secrets-manager
kind: ClusterSecretStore
target:
name: db-credentials
creationPolicy: Owner
deletionPolicy: Retain
template:
type: Opaque
data:
DB_HOST: "{{ .host }}"
DB_PORT: "{{ .port }}"
DB_USERNAME: "{{ .username }}"
DB_PASSWORD: "{{ .password }}"
DB_CONNECTION_STRING: "postgresql://{{ .username }}:{{ .password }}@{{ .host }}:{{ .port }}/{{ .database }}"
data:
- secretKey: host
remoteRef:
key: myapp/production/database
property: host
- secretKey: port
remoteRef:
key: myapp/production/database
property: port
- secretKey: username
remoteRef:
key: myapp/production/database
property: username
- secretKey: password
remoteRef:
key: myapp/production/database
property: password
- secretKey: database
remoteRef:
key: myapp/production/database
property: databaseAutomatic Secret Rotation
Consequently, ESO can trigger pod restarts when secrets are rotated in the source provider. Combined with AWS Secrets Manager’s automatic rotation for RDS credentials, this creates a fully automated rotation pipeline.
# Deployment with secret rotation awareness
apiVersion: apps/v1
kind: Deployment
metadata:
name: api-server
namespace: production
annotations:
reloader.stakater.com/auto: "true"
spec:
template:
spec:
containers:
- name: api
image: myapp/api:latest
envFrom:
- secretRef:
name: db-credentials
volumeMounts:
- name: tls-certs
mountPath: /etc/tls
readOnly: true
volumes:
- name: tls-certs
secret:
secretName: api-tls-certMulti-Cluster Secret Synchronization
Additionally, for organizations running multiple Kubernetes clusters, ESO enables consistent secret distribution from a single source of truth. Each cluster runs its own ESO instance pointing to the same secret store, ensuring all environments have synchronized credentials.
# ClusterExternalSecret — sync across all namespaces
apiVersion: external-secrets.io/v1beta1
kind: ClusterExternalSecret
metadata:
name: shared-tls-certificates
spec:
namespaceSelector:
matchLabels:
requires-tls: "true"
externalSecretSpec:
refreshInterval: 15m
secretStoreRef:
name: aws-secrets-manager
kind: ClusterSecretStore
target:
name: shared-tls
creationPolicy: Owner
data:
- secretKey: tls.crt
remoteRef:
key: shared/tls/wildcard-cert
property: certificate
- secretKey: tls.key
remoteRef:
key: shared/tls/wildcard-cert
property: private_keyWhen NOT to Use External Secrets Operator
For simple applications with a handful of non-sensitive configuration values, ESO adds operational overhead that may not be justified. If your secrets rarely change and your cluster already encrypts etcd at rest, native Kubernetes Secrets with RBAC restrictions may suffice. As a result, evaluate the actual threat model before committing to ESO.
ESO introduces a dependency on external secret providers — if AWS Secrets Manager experiences an outage, new pods cannot start because they cannot fetch their secrets. Plan for this with appropriate caching and fallback strategies.
Key Takeaways
External Secrets Operator Kubernetes integration transforms secret management from a manual, error-prone process into an automated, auditable pipeline. By syncing secrets from enterprise-grade providers, you get encryption at rest, access auditing, and automatic rotation without changing your application code. Furthermore, the ClusterExternalSecret pattern enables consistent secret distribution across multi-cluster environments.
Start with a single non-critical application to validate the ESO workflow before rolling it out organization-wide. For more information, see the External Secrets Operator documentation and AWS Secrets Manager best practices. Our guides on Kubernetes network policies and mTLS in Kubernetes complement this security-focused approach.