Master HashiCorp Vault and External Secrets Operator to automate your Kubernetes secrets management. Learn how to sync sensitive data securely in your cluster.
Managing secrets in Kubernetes is a constant pain point. If you’re manually creating Kubernetes Secrets or—heaven forbid—committing base64-encoded strings to Git, you’re doing it wrong. I’ve spent years cleaning up these messes. The industry standard isn't just "encrypting at rest"; it's about centralizing your secrets in a dedicated vault and syncing them into your clusters on demand.
In this post, we’re going to set up HashiCorp Vault as our source of truth and use the External Secrets Operator (ESO) to inject those secrets directly into Kubernetes.
Kubernetes native secrets are just base64-encoded strings stored in etcd. They aren't truly secure. By using HashiCorp Vault, you get audit logs, rotation policies, and fine-grained access control. ESO acts as the bridge; it polls Vault and creates native Kubernetes Secret objects, meaning your applications don't need to change their code to talk to Vault.
We’ll install ESO using Helm. It’s the most straightforward path.
Bashhelm repo add external-secrets https://charts.external-secrets.io helm repo update helm install external-secrets external-secrets/external-secrets \ -n external-secrets \ --create-namespace
Once installed, verify the pods are running with kubectl get pods -n external-secrets. You should see the controller and the webhook pods up and ready.
ESO needs a way to talk to Vault. The cleanest way is using Kubernetes ServiceAccount tokens.
First, enable the Kubernetes auth method in Vault:
Bashvault auth enable kubernetes
Configure the auth path to point to your Kubernetes cluster:
Bashvault write auth/kubernetes/config \ kubernetes_host="https://<YOUR_K8S_API_URL>"
Now, create a role in Vault that maps a Kubernetes ServiceAccount to a Vault policy.
The SecretStore is a namespaced resource that tells ESO how to connect to Vault.
YAMLapiVersion: external-secrets.io/v1beta1 kind: SecretStore metadata: name: vault-backend spec: provider: vault: server: "https://vault.example.com:8200" path: "secret" version: "v2" auth: kubernetes: mountPath: "kubernetes" role: "eso-role"
Apply this with kubectl apply -f secretstore.yaml. Ensure the status is Ready by running kubectl get secretstore.
Now for the magic. We define an ExternalSecret resource that tells ESO which keys to fetch from Vault and how to map them to a local Kubernetes Secret.
YAMLapiVersion: external-secrets.io/v1beta1 kind: ExternalSecret metadata: name: app-db-secret spec: refreshInterval: "1h" secretStoreRef: name: vault-backend kind: SecretStore target: name: db-credentials # The name of the resulting K8s Secret creationPolicy: Owner data: - secretKey: db-password remoteRef: key: secret/data/myapp/db property: password
ESO will now reach out to Vault, pull the value for password from the secret/data/myapp/db path, and create a Kubernetes Secret named db-credentials.
I’ve seen teams get this wrong, so keep these three things in mind:
refreshInterval too low (e.g., every 10 seconds). You’ll hammer your Vault instance unnecessarily. 1h or 5m is usually plenty.Integrating HashiCorp Vault with External Secrets Operator transforms your secret management from a manual, error-prone task into a robust, automated DevSecOps pipeline. Your developers get the native Kubernetes Secret experience they expect, while your security team gets the centralized control they demand.
It’s a win-win. Stop hardcoding your credentials and start automating today.
Learn how to automate Kubernetes secrets using HashiCorp Vault and the External Secrets Operator. Secure your infrastructure with this DevSecOps best practice.
Read moreMaster Kubernetes Secret Management by syncing HashiCorp Vault with External Secrets Operator. Learn how to automate secure, GitOps-friendly secret injection.