Kubernetes Intermediate By Samson Tanimawo, PhD Published Aug 31, 2026 9 min read

Kubernetes Secret Management 2026

Built-in Secrets, Sealed Secrets, External Secrets Operator, Vault Agent Injector. Four patterns, four trade-offs, and the one most teams should actually run.

Why built-in Secrets aren’t enough

The native Kubernetes Secret resource is base64-encoded, not encrypted. It sits in etcd; if you can read etcd, you can read every secret. Modern clusters enable etcd-encryption-at-rest, which helps, but the encryption key is local to the cluster, the secrets are decrypted when read by the API server, and any pod with get secrets RBAC can fetch the cleartext.

The bigger problem is the workflow. The natural way to get a Secret into the cluster is kubectl create secret, which means a human types the secret into a terminal, leaving it in shell history, in the kubectl audit log, and possibly in the local config.yaml. The secret is supposed to be a secret; the workflow makes it not.

The third problem: rotation. When a secret rotates (database password, API token), every pod that mounted it needs to re-read it. Kubernetes doesn’t notify pods when a Secret changes; you either restart everything or run a sidecar that polls. Built-in Secrets don’t solve rotation.

So three needs: encryption at rest with a key not in the cluster; a workflow that doesn’t put cleartext in human hands; rotation that doesn’t require deploys. The four patterns below address some or all.

Sealed Secrets

Bitnami’s Sealed Secrets is the simplest of the three add-ons. You encrypt your secret locally with the cluster’s public key; the result is a SealedSecret resource that’s safe to commit to git. The in-cluster controller decrypts and produces a regular Secret.

The strengths. Git-native, the SealedSecret YAML lives in the repo with everything else. No external system to run; one controller, one CRD. Strong encryption (the cluster’s private key never leaves it).

The weak spot. Static secrets only. The secret rotates only when you re-encrypt and commit a new SealedSecret. No external source-of-truth; no automatic rotation. If the cluster’s sealing key is lost, all sealed secrets are unrecoverable, the key backup is a single point of failure.

Where it works. Small teams with low rotation needs; environments where you genuinely want secrets in git for auditability; teams already running GitOps and wanting one fewer external dependency.

External Secrets Operator

The External Secrets Operator (ESO) reads from an external secret store (AWS Secrets Manager, GCP Secret Manager, Azure Key Vault, HashiCorp Vault, 1Password, etc.) and projects them into Kubernetes Secrets. The CRDs ExternalSecret and SecretStore describe what to fetch and from where.

The strengths. The source of truth is the external store; rotation happens there; ESO syncs into the cluster automatically. Multiple backends supported, you can move from one provider to another by changing the SecretStore. Each cluster authenticates to the store with its own IAM identity.

The weak spot. The Kubernetes Secret is still the destination; once it lands in etcd, it has the same protection issues as native Secrets. The encryption-at-rest story is whatever your cluster’s etcd encryption is.

The rotation story. ESO polls the external store on a configurable interval (15 minutes by default). When the secret changes, the in-cluster Secret is updated. Pods that consume the Secret via env-var don’t see the change until they restart; pods that mount it as a file see the new value when the kubelet syncs (typically within 60 seconds). Use file-mount + reload-on-change for true rotation.

Where it works. The default answer for most teams. Easy to set up, integrates with existing secret stores, handles the workflow problem cleanly.

Vault Agent Injector

HashiCorp’s Vault Agent Injector goes further. Instead of projecting a Vault secret into a Kubernetes Secret, it injects a sidecar (Vault Agent) into the pod that fetches secrets directly from Vault and writes them to a shared volume. The application pod reads from the file.

The strengths. The secret never lands in etcd. The Kubernetes Secret resource is bypassed entirely; the secret lives in memory in the agent and on a shared tmpfs volume. Vault’s rich features, dynamic secrets, leasing, automatic revocation, are accessible. PKI on demand: get a fresh TLS cert per pod.

The weak spot. Operational complexity. Vault is its own beast to run; the agent injector adds latency to pod startup; the sidecar consumes resources on every pod. The pattern only makes sense if you’re already running Vault for other reasons.

The dynamic secrets value. The killer feature is dynamic credentials, Vault generates a unique database password per pod, leases it for the pod’s lifetime, revokes it on pod death. No long-lived passwords; no rotation problem; minimal blast radius if a pod is compromised.

Where it works. Regulated industries that need full audit trails on every secret access; orgs with a strong Vault investment; security-sensitive workloads where dynamic secrets justify the operational cost.

Picking the right one

The decision tree.

Do you already run Vault? Use Vault Agent Injector. The marginal cost is low; the dynamic-secrets win is real.

Do you run on a major cloud and use that cloud’s secret store? Use External Secrets Operator. AWS Secrets Manager, GCP Secret Manager, or Azure Key Vault as the source-of-truth; ESO does the sync. The default answer for 70% of teams.

Are you small, all-in on GitOps, with low rotation needs? Sealed Secrets. The simplest option; no external dependency; secrets-in-git is a feature, not a bug, for some teams.

Are you mid-size and don’t want to pick yet? ESO with the cloud-native store. Easiest to migrate away from later if you grow into Vault.

The pattern not to pick. “Just use built-in Secrets and be careful.” The workflow problem (kubectl create with cleartext) and the rotation problem (no notification) compound over time. Pick one of the three add-ons; don’t roll your own.

Antipatterns

Secret as ConfigMap. “It’s easier”, and ConfigMaps don’t even pretend to be encrypted. If it’s a secret, it’s a Secret resource (or skip Kubernetes entirely with Vault Agent).

Secret in container env-var. Env-vars leak: into process listings, into crash dumps, into observability tooling that captures envs. Mount as a file with restrictive permissions.

Same secret across all environments. Production and dev sharing a database password is a vendor-tier breach waiting to happen. Per-environment secrets, per-environment rotation.

Long-lived service-account tokens. Static tokens stored in Secrets are 90% of breach material. Use bound tokens with short TTLs and per-workload service accounts.

What to do this week

Three moves. (1) Audit how secrets currently get into your cluster, if the answer is “kubectl create with cleartext from a terminal”, you have the workflow problem. Pick ESO or Sealed Secrets. (2) Identify your top-5 most-rotated secrets (database passwords, third-party API tokens). Move them to dynamic generation if you can; to ESO-with-cloud-store if you can’t. (3) Verify etcd encryption-at-rest is enabled. It’s a one-line cluster setting that many older clusters skipped.