title: "Securing EKS with HashiCorp Vault" date: "2026-03-20" excerpt: "A step-by-step guide to integrating HashiCorp Vault with Amazon EKS for secrets management in production Kubernetes clusters." coverImage: "/images/posts/securing-eks-vault.png" tags: ["kubernetes", "vault", "aws", "security"] language: "en"
Why Vault for Kubernetes Secrets?
Kubernetes Secrets are base64-encoded — not encrypted. Anyone with RBAC access to the namespace can decode them. HashiCorp Vault solves this with:
- Dynamic secrets with automatic rotation
- Fine-grained access policies
- Full audit logging of every secret access
- Encryption as a service
Never store production secrets as plain Kubernetes Secrets. Use an external secrets manager like Vault, AWS Secrets Manager, or Azure Key Vault.
Architecture Overview
The integration uses the Vault Agent Injector pattern:
- Vault runs as an external service (or in-cluster via Helm)
- The Vault Agent Injector mutating webhook intercepts pod creation
- Secrets are injected as files in a shared volume
- Applications read secrets from the filesystem — no SDK needed
Installing Vault via Helm
# vault-values.yaml
server:
ha:
enabled: true
replicas: 3
raft:
enabled: true
dataStorage:
enabled: true
size: 10Gi
storageClass: gp3
ingress:
enabled: true
hosts:
- host: vault.internal.example.com
injector:
enabled: true
replicas: 2helm repo add hashicorp https://helm.releases.hashicorp.com
helm repo update
helm install vault hashicorp/vault \
--namespace vault \
--create-namespace \
-f vault-values.yamlConfiguring Kubernetes Auth
resource "vault_auth_backend" "kubernetes" {
type = "kubernetes"
}
resource "vault_kubernetes_auth_backend_config" "eks" {
backend = vault_auth_backend.kubernetes.path
kubernetes_host = data.aws_eks_cluster.main.endpoint
kubernetes_ca_cert = base64decode(data.aws_eks_cluster.main.certificate_authority[0].data)
}
resource "vault_kubernetes_auth_backend_role" "app" {
backend = vault_auth_backend.kubernetes.path
role_name = "app-role"
bound_service_account_names = ["app-sa"]
bound_service_account_namespaces = ["production"]
token_ttl = 3600
token_policies = ["app-secrets"]
}The Kubernetes auth method lets pods authenticate to Vault using their service account token — no hardcoded credentials needed.
Injecting Secrets into Pods
apiVersion: apps/v1
kind: Deployment
metadata:
name: my-app
spec:
template:
metadata:
annotations:
vault.hashicorp.com/agent-inject: "true"
vault.hashicorp.com/role: "app-role"
vault.hashicorp.com/agent-inject-secret-db-creds: "secret/data/production/db"
vault.hashicorp.com/agent-inject-template-db-creds: |
{{- with secret "secret/data/production/db" -}}
export DB_HOST="{{ .Data.data.host }}"
export DB_USER="{{ .Data.data.username }}"
export DB_PASS="{{ .Data.data.password }}"
{{- end -}}
spec:
serviceAccountName: app-sa
containers:
- name: app
image: my-app:latest
command: ["/bin/sh", "-c", "source /vault/secrets/db-creds && ./start.sh"]Key Takeaways
- Vault Agent Injector is the cleanest integration pattern — no application changes needed
- Kubernetes auth eliminates credential bootstrapping problems
- Dynamic secrets with TTLs are far more secure than long-lived static credentials
- Always enable audit logging in Vault for compliance
- Use Terraform to manage Vault configuration as code
Start with the Agent Injector pattern. It works with any language or framework since secrets are just files on disk.
"Security is not a feature — it's the foundation. Build it in from day one, or pay the price later."
