Kubernetes Secrets Management Best Practices
Kubernetes secrets management is the set of controls and practices used to store, access, rotate, and audit sensitive data (API keys, passwords, tokens, certificates) used by workloads running in a Kubernetes cluster. The goal is to reduce the blast radius of credential exposure and prevent accidental disclosure through configuration, logs, CI/CD, or cluster compromise. (If you’re formalizing this concept for incident response, see: what is the blast radius of a credential.)
Kubernetes secrets are not secure by default—a Kubernetes Secret is base64-encoded, and without controls like etcd encryption, tight RBAC, and rotation/auditing, credentials can leak through the API, backups, logs, or overly-permissive service accounts. This guide covers practical secrets management you can apply in real clusters.
How Kubernetes Secrets work (and where they go wrong)
Kubernetes provides a built-in primitive called a Secret (namespaced API object). Applications typically consume secrets via:
- Mounted files (Secret volumes)
- Environment variables (
env:from Secret refs)
Access is governed by Kubernetes RBAC and the Pod’s service account.
Key nuance: by default, Kubernetes stores Secrets in etcd as base64-encoded values. Base64 is not encryption. Without additional controls, anyone with sufficient Kubernetes API permissions (or etcd access/backups) may retrieve the plaintext.
Best practice checklist (practitioner-focused)
1) Encrypt Secrets at rest (etcd encryption)
Turn on encryption at rest so Secrets are encrypted in etcd using a KMS provider or local key provider.
Why it matters: if etcd is compromised (or backups are leaked), raw secret material is harder to extract.
Technical notes: verify and enable encryption at rest
Check if encryption is configured (implementation differs by distro, but you can detect common outcomes):
# If you have access to control plane manifests, look for an encryption-provider-config argument
sudo grep -R "encryption-provider-config" /etc/kubernetes/manifests/ 2>/dev/null
After enabling encryption, you typically need to rewrite Secrets to encrypt existing entries:
# Rewrites Secrets so they get stored using the new encryption provider
kubectl get secrets --all-namespaces -o json | kubectl replace -f -
Operational notes: - Prefer KMS integration when available (stronger key management, rotation, separation of duties). - Protect etcd backups as if they were production credentials.
2) Lock down RBAC to Secrets (least privilege)
Avoid broad permissions like get/list/watch on secrets across namespaces. Many “read-only” roles unintentionally include Secrets access. Tighten roles for:
- CI/CD service accounts
- operators/controllers
- support/ops groups
- developers in shared clusters
Technical notes: find who can read Secrets
# Who can read Secrets in a namespace?
kubectl auth can-i get secrets -n <ns> --as=system:serviceaccount:<ns>:<sa>
# Enumerate roles/clusterroles that include "secrets" rules
kubectl get clusterroles -o json | jq -r '
.items[] | select(.rules[]? | (.resources[]?=="secrets")) | .metadata.name'
Practitioner guidance:
- Prefer namespace-scoped Roles over ClusterRoles for application identities.
- Deny listing Secrets broadly; list can be as damaging as get.
- Separate “deploy” permissions from “read secrets” permissions when possible.
3) Prefer mounted files over environment variables (and avoid logging)
Environment variables are convenient but leaky:
- appear in crash dumps and debug output
- may be surfaced by process introspection tools
- often get printed in misconfigured app logs
Mounted volumes are generally safer and support updates (with caveats).
Best practices:
- Mount secrets as files and set readOnly: true.
- Keep apps from echoing config at startup.
- Never print secret content in readiness/liveness probes or debug endpoints.
Technical notes: safer Secret consumption example
apiVersion: v1
kind: Pod
metadata:
name: app
spec:
serviceAccountName: app-sa
containers:
- name: app
image: your/app:tag
volumeMounts:
- name: app-secret
mountPath: /var/run/secrets/app
readOnly: true
volumes:
- name: app-secret
secret:
secretName: app-credentials
defaultMode: 0400
4) Use external secret managers for high-value secrets
For production, consider storing secrets in a dedicated secrets manager (cloud KMS/secret manager offerings, or self-hosted systems) and syncing or injecting them into Pods. This enables:
- centralized rotation policies
- access control outside Kubernetes
- better auditing
- short-lived credentials (where supported)
Kubernetes-native patterns include:
- CSI Secret Store drivers (mount secrets at runtime)
- External Secrets operators (sync to Kubernetes Secret objects)
- Workload identity / federated identity to avoid static keys entirely
Practical rule: - If compromise of a secret would be “company-ending” (payment, prod DB root, signing keys), avoid long-lived static Kubernetes Secrets.
5) Rotate secrets and minimize lifetime
Secrets should be treated like credentials with expiry:
- define rotation intervals (e.g., 30–90 days for API keys, shorter for tokens)
- revoke old credentials after rollout
- ensure apps can reload secrets without full outages (graceful restart or reload)
Tips: - Use separate credentials per app/environment (prod vs staging). - Avoid sharing one credential across multiple services. - For human-accessed credentials and admin consoles, enforce strong password policy (see: how do i create a strong password/) and prefer password managers for unique, high-entropy values.
Natural tooling note (affiliate): For teams managing shared administrative secrets (break-glass accounts, SaaS admin logins, emergency vaults), a password manager can reduce reuse and improve rotation hygiene. 1Password is a common option: Try 1Password →.
6) Add guardrails: admission control and policy
Prevent bad patterns before they ship:
- block Pods that mount the default service account token if not needed
- restrict which namespaces can create Secrets
- deny use of
hostPathor privileged pods that could scrape node files - enforce labels/annotations for rotation ownership and data classification
Tools/patterns:
- Validating Admission Policies / webhooks
- Policy engines (e.g., OPA Gatekeeper, Kyverno)
- CI checks for manifests (disallow env: secret injection in certain namespaces)
7) Audit and monitor for secret access and exfiltration
Turn on and centralize:
- Kubernetes audit logs
- API server logs (where applicable)
- etcd access logs (if exposed)
- network egress monitoring (exfil often leaves the cluster)
What to watch:
- unusual
get/listcalls onsecrets - service accounts reading secrets outside their normal namespace
- spikes in secret reads after deployment changes
Technical notes: audit log signals to look for
In audit logs (structure varies), search for:
objectRef.resource: "secrets"verb: "get" | "list" | "watch"- suspicious
user.username(service accounts, CI identities) - cross-namespace reads
Example query patterns you can adapt in your log platform:
objectRef.resource=secrets AND verb=listverb=get AND objectRef.resource=secrets AND user.username=system:serviceaccount:*
When you’ll encounter Kubernetes secrets management
You’ll run into Kubernetes secrets management decisions whenever you:
- Deploy applications that need database credentials, API keys, OAuth client secrets, TLS private keys, or signing material.
- Onboard CI/CD systems (GitOps controllers, pipeline runners) that require access to registries and clusters.
- Migrate from VMs to Kubernetes and discover legacy apps expect plaintext config files.
- Implement compliance controls requiring encryption, rotation, and audit trails.
- Investigate an incident where a compromised Pod or over-permissive RBAC role led to credential theft.
Common failure modes seen in real environments:
- cluster-wide roles that allow developers to
listSecrets - storing production credentials in shared namespaces
- logging entire environment variables on startup
- long-lived cloud access keys embedded in Secrets instead of using workload identity
- unencrypted etcd backups stored in accessible object storage
Related terms
Namespaced object for storing sensitive data (base64-encoded; may be encrypted with etcd encryption at rest).
API server feature that encrypts specific resources (like Secrets) before storing them in etcd.
Authorization model controlling which users/service accounts can access Secrets and other resources.
Credential mounted into Pods for Kubernetes API access; should be minimized and scoped.
Mechanism for Pods to access cloud services without static keys (preferred over long-lived secrets).
Integrates external secret stores with Kubernetes by mounting secrets as volumes at runtime.
Syncs secrets from an external manager into Kubernetes Secret objects (useful, but still creates in-cluster Secrets).
Policies enforced at request time to prevent insecure secret usage patterns.
Process of changing credentials regularly and safely, including revocation of old values.
Records API access (including Secret reads) for detection and forensics.