Secret management in Kubernetes is often discussed as if there is one correct tool. In production, the right answer depends on what you are protecting, who needs access, how often the value rotates, and whether the workload can authenticate without a stored credential.
The practical comparison is not just Kubernetes Secrets vs Vault. It is stored secrets vs brokered secrets vs workload identity.
Kubernetes Secrets: Native, Simple, and Easy to Misuse
Kubernetes Secrets are built-in API objects for storing sensitive values such as tokens, passwords, certificates, and keys. They integrate naturally with Pods as environment variables or mounted files.
They are useful for simple cluster-native configuration, but they are not a complete secret management strategy by themselves. You still need RBAC, encryption at rest, audit logs, rotation, namespace boundaries, and careful control over who can read Secrets.
apiVersion: v1
kind: Secret
metadata:
name: api-config
type: Opaque
stringData:
DATABASE_URL: postgres://app:password@db:5432/app
The problem is not that Kubernetes Secrets are always bad. The problem is that they often become long-lived credentials copied into many namespaces, CI jobs, Helm values, and developer machines.
Vault: Central Secret Broker and Policy Engine
Vault adds a central control plane for secrets, auth methods, policies, audit logs, leases, dynamic credentials, PKI, and rotation. In Kubernetes, workloads commonly authenticate to Vault using Kubernetes auth, JWT/OIDC, cloud IAM, or an agent/injector pattern.
Vault is strongest when you need dynamic database credentials, PKI issuance, central audit, strict policy, and cross-platform secret access beyond one Kubernetes cluster.
The trade-off is operational complexity. Vault must be deployed, unsealed, backed up, monitored, upgraded, and protected. A poorly operated Vault cluster can become the highest-value outage dependency in your platform.
Workload Identity: Stop Handing Out Shared Secrets
Workload identity means the platform can prove which workload is calling, then issue access based on that identity. In Kubernetes this can involve projected service account tokens, cloud workload identity integrations, SPIFFE/SPIRE SVIDs, service mesh identity, or OIDC federation.
The goal is to replace static credentials with short-lived, scoped, auditable credentials. A Pod should not need an AWS access key stored in a Secret if it can use a federated identity to obtain temporary permissions.
Decision Table
| Need | Good fit | Reason |
|---|---|---|
| Small cluster config value | Kubernetes Secret | Native, simple, works with standard Pod mounting. |
| Dynamic database credentials | Vault | Can issue leased credentials and revoke them centrally. |
| Cloud API access from Pods | Workload identity | Removes long-lived cloud keys from the cluster. |
| Service-to-service trust | SPIFFE/SPIRE or mesh identity | Gives every workload a cryptographic identity. |
Runtime Credential Flow
The biggest difference between these approaches is when the credential exists. A Kubernetes Secret usually exists before the Pod starts. Vault can broker a credential at runtime, but the workload still needs a safe way to authenticate to Vault. Workload identity tries to make the platform identity itself the starting point.
- Secret object exists in cluster.
- Pod mounts it or receives env vars.
- Application uses the static value.
- Workload authenticates to Vault.
- Vault checks policy.
- Vault returns leased credentials.
- Platform proves workload identity.
- Provider issues short-lived access.
- No shared static secret is stored.
Threat Model: What Are You Reducing?
Secret tooling should be chosen by the failure mode it reduces. Kubernetes Secrets mostly reduce configuration sprawl by giving the cluster a native object. Vault reduces unmanaged static credentials by centralizing policy, leases, and audit. Workload identity reduces the need to distribute shared credentials at all. These controls overlap, but they do not solve the same problem.
| Threat | Kubernetes Secret | Vault | Workload identity |
|---|---|---|---|
| Secret copied into Git | Still possible if values are managed in manifests. | Reduced when apps fetch at runtime. | Strongly reduced for supported providers. |
| Credential never rotates | Requires external process. | Leases and dynamic secrets help. | Short-lived tokens are the default model. |
| Pod compromise | Mounted secret can be stolen. | Lease can be stolen until revoked or expired. | Access is scoped, short-lived, and auditable. |
| Over-broad access | Controlled with RBAC and namespace policy. | Controlled with Vault policy. | Controlled with identity claims and provider policy. |
Migration Pattern: Static Keys to Identity
A safe migration starts with the highest-risk static keys: cloud access keys, database admin passwords, long-lived API tokens, and credentials copied into CI. Do not rewrite every application at once. Pick one credential class, replace it with a runtime path, and prove rotation and rollback.
migration_steps:
1_inventory: "find Secrets, CI variables, Helm values, and copied config"
2_classify: "cloud key, database password, API token, certificate"
3_choose_runtime_path: "Vault lease, cloud workload identity, SPIFFE SVID"
4_limit_scope: "one namespace, one service account, one environment"
5_rotate: "replace old value, monitor access, revoke old credential"
6_enforce: "policy prevents new long-lived credentials"
The enforcement step matters. If developers can still create new long-lived secrets with no review, the migration becomes a one-time cleanup instead of a platform improvement. Use admission policy, repository scanning, CI checks, and cloud IAM review to prevent the old pattern from returning.
Operational Ownership
Secret management crosses team boundaries. Platform teams often own Kubernetes RBAC, service account token configuration, Vault deployment, and cloud workload identity integrations. Application teams own which permissions their service needs. Security teams own policy review, audit expectations, and incident response. If those boundaries are not explicit, every credential request becomes a ticket with unclear approval rules.
Common Mistakes
- Base64 is treated as encryption. Kubernetes Secret values are encoded, not magically protected.
- CI writes production secrets into manifests. Secrets should not become Git history.
- Vault tokens are stored as static Kubernetes Secrets. That can recreate the same long-lived credential problem.
- All service accounts can read all secrets. RBAC must be least privilege.
- No rotation path exists. A secret that cannot rotate safely will eventually become an incident.
Production Checklist
- Enable encryption at rest for Kubernetes Secrets.
- Restrict Secret access with RBAC and namespace boundaries.
- Prefer projected service account tokens over legacy token Secrets.
- Use Vault for dynamic secrets and central policy when the operational maturity exists.
- Use cloud workload identity or SPIFFE/SPIRE for runtime identity where possible.
- Audit secret reads and rotate credentials on a schedule and after incidents.
Designing Least-Privilege Secret Access
Least privilege for secrets starts with a simple inventory: which workload needs which value, why it needs it, how long it needs it, and what happens if the value leaks. Many clusters fail this inventory because secrets are copied by environment or team instead of by workload need. A single shared database password might be mounted into ten services because it was convenient during setup.
A better design gives each workload its own service account, its own policy boundary, and the smallest useful credential. If the workload only needs read access to one database schema, the credential should not have write access to every schema. If the workload only needs cloud object read access under one prefix, the role should not include broad bucket administration. The secret mechanism and the target-system permission must both be scoped.
access_review:
workload: "payments-api"
identity: "system:serviceaccount:payments:api"
needs:
- "read payment processor API token"
- "write payment events to database"
should_not_have:
- "read all namespace secrets"
- "admin database user"
- "cloud account-wide storage access"
rotation_owner: "payments platform team"
Handling Break-Glass and Human Access
Production systems still need emergency access paths, but they should be explicit. Break-glass access should be time-bound, logged, approved, and reviewed after use. It should not be the same credential the application uses every day. If a human needs a database password during an incident, that access should come from a controlled flow with audit, not from copying the application's Kubernetes Secret.
Vault can help here because it can issue short-lived credentials and record audit events. Cloud IAM can help when it supports just-in-time access and short-lived role assumption. Kubernetes alone can support temporary RBAC changes, but you need strong process and logging. The goal is not to make emergency access impossible. The goal is to make it visible and revocable.
Incident Response for Secret Exposure
When a secret leaks, the first question is scope. Which workload had the secret? Which system accepted it? What permissions did it carry? Where was it stored? Which logs might contain it? How quickly can it rotate? This is where workload identity and dynamic secrets pay off. Short-lived credentials reduce the useful lifetime of the leak, and identity-based logs help identify the affected workload.
| Exposure type | Immediate response | Long-term fix |
|---|---|---|
| Secret committed to Git | Revoke and rotate; do not rely only on deleting history. | Secret scanning, pre-commit checks, runtime identity for cloud access. |
| Secret printed in CI logs | Revoke credential, restrict log access, inspect recent runs. | Masking, scoped CI permissions, OIDC instead of static keys. |
| Pod reads another service's Secret | Rotate exposed value and review namespace activity. | Fix RBAC, namespace boundaries, and admission policy. |
| Vault token stolen | Revoke token and child leases; inspect audit logs. | Shorter TTLs, narrower policy, stronger workload authentication. |
Secret exposure response should be rehearsed. If rotation requires a manual deploy across many services, the system is fragile. If one leaked credential can access multiple environments, the boundary is too broad. If nobody can answer which services used the credential, observability is incomplete.
Related CodersSecret Guides
- Master SPIFFE and SPIRE for Workload Identity
- Cloud Native Security Engineering
- Kubernetes Security Cheatsheet
- Practice Zero Trust Network Design