Sync Django Secrets Into Kubernetes With External Secrets Operator
Use External Secrets Operator to load Django secrets from AWS Secrets Manager, Google Secret Manager, Azure Key Vault, Vault, or Infisical into Kubernetes Secrets: configure a SecretStore with workload identity, map keys, set refresh intervals, and roll pods on change.
Problem statement
Your Django app on Kubernetes reads settings from a Kubernetes Secret, but creating that Secret by hand or committing it (even base64-encoded) to git is unsafe and drifts from the source of truth in your cloud's secrets manager. External Secrets Operator (ESO) solves this: you declare which external secrets a Kubernetes Secret should contain, and the operator fetches and refreshes them using the cluster's cloud identity.
- Install ESO with Helm:
helm install external-secrets external-secrets/external-secrets -n external-secrets --create-namespace. - Create a
SecretStore(namespaced) orClusterSecretStorefor your provider, authenticated with workload identity (IRSA, GKE Workload Identity, Azure workload identity). - Create an
ExternalSecretthat maps provider keys to Kubernetes Secret keys such asSECRET_KEYandDATABASE_URL. - Reference the resulting Secret in the Django Deployment with
envFromorsecretKeyRef. - Set
refreshInterval, and restart pods on change with a reloader or a checksum annotation.
Step-by-step solution
1. Install the operator
helm repo add external-secrets https://charts.external-secrets.io
helm install external-secrets external-secrets/external-secrets \
-n external-secrets --create-namespace
2. Create a SecretStore
AWS Secrets Manager with IRSA (EKS):
apiVersion: external-secrets.io/v1
kind: SecretStore
metadata:
name: aws
namespace: prod
spec:
provider:
aws:
service: SecretsManager
region: eu-central-1
auth:
jwt:
serviceAccountRef:
name: shop-secrets-reader
The service account is annotated with an IAM role allowed to read shop/prod/* secrets. Other providers (gcpsm, azurekv, vault, infisical, doppler) use the same structure with their own auth blocks. Check the API version (v1 or v1beta1) your ESO release serves.
3. Declare the ExternalSecret
apiVersion: external-secrets.io/v1
kind: ExternalSecret
metadata:
name: django-env
namespace: prod
spec:
refreshInterval: 1h
secretStoreRef: { name: aws, kind: SecretStore }
target:
name: django-env
creationPolicy: Owner
data:
- secretKey: SECRET_KEY
remoteRef: { key: shop/prod/django, property: SECRET_KEY }
- secretKey: DATABASE_URL
remoteRef: { key: shop/prod/django, property: DATABASE_URL }
Or pull every property of a JSON secret with dataFrom: [{ extract: { key: shop/prod/django } }]. ESO creates and owns the django-env Secret.
4. Use it in the Deployment
envFrom:
- secretRef:
name: django-env
If the ExternalSecret has not synced yet, pods fail with CreateContainerConfigError. Check kubectl get externalsecret -n prod; the status should be SecretSynced.
5. Roll pods when secrets change
Environment variables are read at container start, so a refreshed Secret does not affect running pods. Use a controller such as Stakater Reloader (annotate the Deployment with reloader.stakater.com/auto: "true"), or include a checksum of the secret's version in a pod template annotation during deploys.
Explanation
ESO runs controllers that watch ExternalSecret resources, authenticate to the configured provider through a SecretStore, read the referenced values, and write them into a normal Kubernetes Secret. Applications, including Django, consume the Secret as usual. The external manager stays the source of truth, access is controlled by cloud IAM, and git contains only the mapping, never the values.
Edge cases / notes
- Kubernetes Secret storage. Synced values still live in etcd; enable encryption at rest for Secrets in the cluster.
- Many environments. Use one SecretStore per namespace with an identity scoped to that environment's secrets.
- Templates. ESO's
target.templatecan build values such asDATABASE_URLfrom several remote fields.
Next steps
- Organize configuration with Kubernetes Secrets and ConfigMaps for Django.
- Fix startup failures with Fix Kubernetes CreateContainerConfigError.
- Use AWS as the source with Manage Django Secrets With AWS Secrets Manager.
FAQ
Why not commit Kubernetes Secrets to git?
Base64 is encoding, not encryption. Anyone with repository access can read them. ESO keeps values out of git.
Do pods update automatically when a secret changes?
The Secret updates, but environment variables in running pods do not. Roll the Deployment with a reloader.
Which secrets managers does ESO support?
AWS, Google Cloud, Azure, HashiCorp Vault, and many others, including Doppler and Infisical.
What if ESO cannot reach the provider?
The existing Kubernetes Secret stays as it was, so running pods continue; new syncs fail until access returns.