Syncing Secrets Into Kubernetes With the External Secrets Operator
Storing secrets in Git is a breach waiting to happen. Here's how External Secrets Operator pulls them from a real secret store into your cluster safely.
- #kubernetes
- #secrets
- #security
- #external-secrets
- #vault
- #gitops
The fastest way to leak credentials is to put a Kubernetes Secret in Git. They’re base64, not encrypted, and base64 is not a security boundary — it’s an encoding. I’ve watched teams discover this the hard way during a routine audit. The External Secrets Operator (ESO) is the clean answer: keep the real secrets in a real secret store, and let the operator project them into the cluster as native Secrets.
Here’s how I set it up and the operational details that actually matter.
The model
ESO is a controller plus two main custom resources:
- A SecretStore (or ClusterSecretStore) describes how to reach a backend — AWS Secrets Manager, GCP Secret Manager, Azure Key Vault, HashiCorp Vault, and many more.
- An ExternalSecret describes what to fetch and where to put it. The operator reads from the store on an interval and writes a normal Kubernetes Secret.
Your pods consume a perfectly ordinary Secret. They have no idea ESO exists. That decoupling is the whole point: your manifests in Git reference secret names, never secret values.
Installing the operator
helm repo add external-secrets https://charts.external-secrets.io
helm install external-secrets external-secrets/external-secrets \
--namespace external-secrets --create-namespace
Confirm it’s up before defining stores:
kubectl get pods -n external-secrets
Defining a SecretStore
Backends differ, but the shape is consistent. For AWS Secrets Manager using IRSA (the cleanest auth path — no static keys anywhere):
apiVersion: external-secrets.io/v1beta1
kind: SecretStore
metadata:
name: aws-secrets
namespace: payments
spec:
provider:
aws:
service: SecretsManager
region: us-east-1
auth:
jwt:
serviceAccountRef:
name: payments-eso
Pair that ServiceAccount with an IAM role that grants secretsmanager:GetSecretValue on a tightly scoped resource ARN. Scope it to a path prefix, not *. The most common mistake I see is a SecretStore whose IAM policy can read every secret in the account — that turns one compromised namespace into a full credential breach.
Fetching a secret
apiVersion: external-secrets.io/v1beta1
kind: ExternalSecret
metadata:
name: db-credentials
namespace: payments
spec:
refreshInterval: 1h
secretStoreRef:
name: aws-secrets
kind: SecretStore
target:
name: db-credentials
creationPolicy: Owner
data:
- secretKey: password
remoteRef:
key: prod/payments/db
property: password
- secretKey: username
remoteRef:
key: prod/payments/db
property: username
This produces a Secret named db-credentials with username and password keys, refreshed hourly. Verify:
kubectl get externalsecret db-credentials -n payments
kubectl describe externalsecret db-credentials -n payments
The STATUS column should read SecretSynced. If it doesn’t, the describe output names the exact failure — usually a permissions error or a key path typo.
Pulling everything from one store entry
If you keep a whole JSON blob in one secret, dataFrom extracts all keys at once instead of listing each:
dataFrom:
- extract:
key: prod/payments/db
I lean on this for app configs that bundle a dozen values. One source of truth in the store, one Secret out, no per-key boilerplate.
The refresh-interval tradeoff
refreshInterval controls how often ESO polls the backend. Tighter intervals mean faster propagation when you rotate a credential, but more API calls (and AWS Secrets Manager charges per 10,000 calls). I use one hour for most things and tighten to a few minutes only for credentials that rotate frequently.
Important caveat: updating the Secret does not restart your pods. Most apps read env vars or mounted files once at startup. If you rotate a secret, you still need to roll the deployment — or pair ESO with a tool like Reloader that watches Secrets and triggers a rollout. Don’t assume rotation is end-to-end automatic; it gets the value into the cluster, not into the running process.
Generators for dynamic credentials
ESO can also generate values — for example, short-lived database credentials via Vault’s database engine, or an ECR auth token that’s only valid for 12 hours. This is where it goes from “secret syncer” to genuine secret-rotation infrastructure, because the credential a pod uses never lives long enough to be worth stealing.
What this buys you operationally
- Git stays clean. Your repo references
db-credentials; the value lives in the store. A leaked repo leaks nothing. - One source of truth. Rotate in the backend, every consuming cluster picks it up.
- Audit trail. Access logging lives in your secret store, where security can actually see it.
Failure modes to watch
- ClusterSecretStore sprawl. A cluster-wide store with broad read access is convenient and dangerous. Prefer namespaced
SecretStores scoped to least privilege. - Silent sync failures. Alert on ExternalSecrets where status isn’t
SecretSynced. A stale secret fails quietly until something tries to use it. - Deleting the ExternalSecret deletes the Secret when
creationPolicy: Owner. Know that before youkubectl deleteduring a cleanup.
Before you ship the IAM policy and SecretStore, get them reviewed — an over-scoped policy is easy to write and hard to spot. Our AI code review flags wildcard resource ARNs and missing least-privilege scoping.
ESO is one of those tools that quietly removes an entire class of incident. For more on running clusters safely, browse the Kubernetes & Helm category.
Secret-management configuration is high-stakes. Verify IAM scoping and store access against your own security requirements before applying to production.
Download the Free 500-Prompt DevOps AI Toolkit
500 battle-tested, copy-paste AI prompts engineered by a senior systems engineer — every one with fill-in placeholders and safety/back-out notes. Drop your email and it's yours.
- 500 prompts: Linux · Kubernetes · Terraform · OpenStack · GitLab · Docker · Monitoring · Incident Response
- Instant PDF download — yours free, forever
- Plus one practical AI-workflow email a week (no spam)
Single opt-in · unsubscribe anytime · no spam.