PRACTITIONER GUIDE
Practitioner Guide13 min read

Kubernetes Secrets Management: External Secrets Operator, Sealed Secrets, and Vault Agent Injector

base64
encoding used for Kubernetes Secret data by default; this is not encryption and any pod with RBAC read access to the Secret can decode it instantly
60 seconds
default kubelet sync period for volume-mounted secrets; rotated secret values propagate to running pods within this window without a pod restart
1 hour
recommended ESO refreshInterval for long-lived credentials; set to a fraction of the Vault lease TTL for dynamic database credentials to prevent expiry
0 Secrets
Kubernetes Secret objects created by the Vault agent injector pattern; secrets exist only in the pod's tmpfs volume for its lifetime and are never persisted to etcd

SponsoredRetool

Retool's new app builder is where AI-generated code ships safely

Building apps with AI is easy. Getting them to production safely is another story.

Start building for free today

The default Kubernetes Secret is base64-encoded, not encrypted. Any pod in the namespace with the right RBAC permissions can read it. Committing a base64-encoded Secret manifest to a Git repository exposes the credential to everyone with repository access. These are the two problems that drive every Kubernetes secrets management architecture conversation.

Three patterns address them at different layers: External Secrets Operator syncs live values from a real secrets manager, Sealed Secrets makes GitOps viable by encrypting manifests with a cluster-specific key, and the Vault agent injector eliminates the Kubernetes Secret object entirely by injecting directly into pods. Choosing among them depends on whether you have an existing secrets manager and whether GitOps compatibility is a requirement.

Choosing the right secrets management pattern

Selecting among External Secrets Operator, Sealed Secrets, and Vault agent injection requires evaluating three factors: whether an external secrets manager already exists in your infrastructure, whether GitOps workflows require committing secret manifests to a Git repository, and whether your threat model justifies eliminating Kubernetes Secret objects from etcd entirely. ESO is the lowest-friction choice when AWS Secrets Manager, GCP Secret Manager, or HashiCorp Vault is already in use because it adds a sync layer without requiring changes to how secrets are stored or managed. Sealed Secrets addresses the GitOps commit problem without any external dependency, at the cost of a cluster-specific sealing key that must be backed up. Vault agent injection provides the strongest isolation guarantee by keeping secrets out of Kubernetes entirely, but adds operational complexity through sidecar management and Vault auth configuration.

Use External Secrets Operator when you already have AWS Secrets Manager or Vault

If your organization manages secrets in AWS Secrets Manager, GCP Secret Manager, Azure Key Vault, or HashiCorp Vault, ESO is the lowest-friction path to Kubernetes integration. ESO creates a sync loop that keeps Kubernetes Secrets current with the external store, handles rotation automatically within the configured refresh interval, and requires no changes to application code (the application reads from the standard Kubernetes Secret mount path). Install ESO with Helm, create a ClusterSecretStore for the external backend, and create ExternalSecret manifests that reference which external secret to sync to which Kubernetes Secret.

Use Sealed Secrets when GitOps is required and no external secrets manager exists

Sealed Secrets is the correct choice when you need to commit secret manifests to a Git repository as part of a GitOps workflow (Flux or ArgoCD) and do not have an existing external secrets manager. The kubeseal workflow encrypts a Kubernetes Secret manifest using the cluster's public key, producing a SealedSecret that is safe to commit. The sealed-secrets-controller in the cluster decrypts it and creates the Kubernetes Secret on apply. The tradeoff: secret rotation requires re-sealing and re-committing the manifest, and the sealing key must be backed up (if the cluster is destroyed and the backup key is lost, you cannot decrypt existing SealedSecrets).

Delivery and rotation: volume mounts and refresh intervals

How secrets are delivered to pod containers and how rotation propagates without restarts are the operational concerns that most Kubernetes secrets implementations get wrong. Environment variables are the default delivery mechanism in most Kubernetes tutorials, but they cannot be updated without restarting the pod, are visible in /proc/PID/environ on the node, and are frequently captured in application startup logs by frameworks that dump environment on boot. Volume-mounted secrets write to an in-memory tmpfs path and update within the kubelet's sync period when the underlying Kubernetes Secret changes, enabling live rotation when ESO refreshes from an external store. The ESO refreshInterval is the tuning knob that controls how quickly a rotation in the external store reaches running pods, and it must be calibrated against the credential TTL for dynamic secrets like Vault database credentials.

Mount secrets as volumes, not environment variables, for live rotation

Kubernetes Secret volume mounts write values to a tmpfs path inside the pod and update within the kubelet sync period (default 60 seconds) when the underlying Kubernetes Secret changes. This means that when ESO refreshes the Kubernetes Secret from the external store after a rotation, the new value propagates to running pods without a restart. Environment variable-based secrets do not propagate without a pod restart. Applications must read secrets from the mounted path on each use (or periodically re-read the file) rather than caching the value at startup to benefit from live rotation.

Set ESO refreshInterval based on secret rotation requirements, not performance assumptions

The refreshInterval in an ExternalSecret controls how often ESO polls the external store for changes. For long-lived credentials that rotate infrequently, 1h or 24h is appropriate. For dynamic database credentials from Vault that have a TTL of hours, the refreshInterval should be set to a fraction of the lease TTL to ensure the Kubernetes Secret is updated before the credential expires. For secrets that should propagate quickly after an emergency rotation (such as after a suspected credential compromise), a 1-minute or 5-minute interval ensures rapid propagation at the cost of additional API calls to the external store.

Free daily briefing

Briefings like this, every morning before 9am.

Threat intel, active CVEs, and campaign alerts, distilled for practitioners. 50,000+ subscribers. No noise.

The bottom line

Kubernetes secrets management has three viable patterns depending on your existing infrastructure. If you have AWS Secrets Manager or HashiCorp Vault, External Secrets Operator is the straightforward integration layer that keeps Kubernetes Secrets synchronized with the external store. If you need GitOps compatibility without an external dependency, Sealed Secrets provides cluster-key encryption that makes manifest storage in Git safe. If you want to eliminate Kubernetes Secret objects entirely, the Vault agent injector delivers secrets directly to pods. In all three cases, mount secrets as volumes rather than environment variables to enable live rotation and prevent credential exposure in process listings.

Frequently asked questions

What is the External Secrets Operator and how does it work?

External Secrets Operator (ESO) is a Kubernetes operator that syncs secrets from external secret stores into Kubernetes Secrets. After installing ESO, you configure a SecretStore or ClusterSecretStore custom resource that specifies the external backend (AWS Secrets Manager, HashiCorp Vault, GCP Secret Manager, or others) and the credentials ESO uses to authenticate to it. Then you create ExternalSecret custom resources that specify which secret keys to sync, which Kubernetes Secret to create or update, and how frequently to refresh. ESO watches for changes in the external store and updates the Kubernetes Secret within the configured refresh interval without manual intervention.

What is the difference between External Secrets Operator and Sealed Secrets?

External Secrets Operator pulls live secret values from an external secret store at runtime and keeps them synchronized with a Kubernetes Secret. It requires an external secrets manager like AWS Secrets Manager or HashiCorp Vault to exist and hold the source values. Sealed Secrets encrypts a Kubernetes Secret manifest using the cluster's public key so the encrypted manifest can be stored safely in Git. The sealed-secrets-controller running in the cluster decrypts the SealedSecret on creation. Sealed Secrets does not require an external secret store but requires managing the cluster's sealing certificate. Use ESO when you already have a secrets manager and want live sync; use Sealed Secrets for GitOps workflows without an external dependency.

How do I configure External Secrets Operator with AWS Secrets Manager?

To configure ESO with AWS Secrets Manager, install ESO using Helm, then create a SecretStore (or ClusterSecretStore for cluster-wide access) specifying aws as the provider with the region and an authentication method. For EKS, use IRSA by annotating the ESO service account with the IAM role ARN and configuring the role with secretsmanager:GetSecretValue permissions. For non-EKS clusters, store AWS credentials in a Kubernetes Secret and reference them in the SecretStore. Then create an ExternalSecret specifying the SecretStore name, the AWS Secrets Manager secret path, and the mapping to the target Kubernetes Secret key, with a refreshInterval such as 1h for how frequently ESO polls for changes.

How does the Vault agent injector work in Kubernetes?

The Vault agent injector uses a Kubernetes mutating admission webhook to intercept pod creation and inject a Vault agent init container and sidecar container into pods that have specific annotations. The init container authenticates to Vault using the pod's Kubernetes ServiceAccount token via Vault's Kubernetes auth method, retrieves the specified secrets, and writes them to a shared emptyDir volume at a path like /vault/secrets/config. The sidecar container continues running after initialization to renew leases and update secrets for dynamic credentials. The application container reads secrets from the shared volume filesystem path rather than environment variables or Kubernetes Secrets.

Should I use environment variables or volume mounts for Kubernetes secrets?

Volume mounts are the correct choice for delivering secrets to Kubernetes pods. Secrets mounted as volumes write values to an in-memory tmpfs filesystem, update automatically when the Kubernetes Secret is rotated (within the kubelet sync period, default 60 seconds) without requiring a pod restart, are not visible in process environment dumps, and are not included in application environment variable logging that many frameworks perform on startup. Environment variables are set at container creation and cannot be updated without a pod restart, are visible in /proc/PID/environ and in logs from frameworks that dump environment, and are a common source of accidental secret disclosure in diagnostic output.

How do I use Sealed Secrets for GitOps with Kubernetes?

Install the sealed-secrets-controller using Helm in your cluster, then install kubeseal CLI on your local machine. To seal a secret, create a standard Kubernetes Secret manifest, then pipe it through kubeseal with the cluster's public key: kubeseal --controller-name sealed-secrets-controller --controller-namespace kube-system --format yaml < secret.yaml > sealed-secret.yaml. The output SealedSecret manifest is safe to commit to your Git repository because it can only be decrypted by the sealed-secrets-controller in the cluster that has the matching private key. On apply to the cluster, the controller decrypts the SealedSecret and creates the corresponding Kubernetes Secret automatically.

How do I authenticate External Secrets Operator to HashiCorp Vault?

ESO supports multiple Vault authentication methods. For Kubernetes-native authentication, configure a Vault Kubernetes auth role that allows the ESO service account to authenticate and access specified secret paths. In the ESO SecretStore, set the provider to vault with the Vault address and configure auth to use the Kubernetes method with the ESO service account name and namespace. ESO presents the service account token to Vault, which validates it against the Kubernetes API and returns a Vault token. For token-based authentication, store a Vault token in a Kubernetes Secret and reference it in the SecretStore auth configuration, but note that tokens expire and require rotation unlike the Kubernetes auth method which rotates automatically.

Sources & references

  1. External Secrets Operator Documentation
  2. Sealed Secrets by Bitnami
  3. HashiCorp Vault Agent Injector
  4. Kubernetes Secrets Documentation

Free resources

25
Free download

Critical CVE Reference Card 2025–2026

25 actively exploited vulnerabilities with CVSS scores, exploit status, and patch availability. Print it, pin it, share it with your SOC team.

No spam. Unsubscribe anytime.

Free download

Ransomware Incident Response Playbook

Step-by-step 24-hour IR checklist covering detection, containment, eradication, and recovery. Built for SOC teams, IR leads, and CISOs.

No spam. Unsubscribe anytime.

Free newsletter

Get threat intel before your inbox does.

50,000+ security professionals read Decryption Digest for early warnings on zero-days, ransomware, and nation-state campaigns. Free, daily, no spam.

Unsubscribe anytime. We never sell your data.

Eric Bang
Author

Founder & Cybersecurity Evangelist, Decryption Digest

Cybersecurity professional with expertise in threat intelligence, vulnerability research, and enterprise security. Covers zero-days, ransomware, and nation-state operations for 50,000+ security professionals every morning.

Black Hat Giveaway

Win a $2,495 Black Hat pass.

Full-access to Black Hat USA 2026 in Las Vegas. Subscribe free to enter.

Joins Decryption Digest daily briefing. Unsubscribe anytime.

Giveaway: Black Hat USA 2026 Full-Access Pass ($2,495 value)

Details →
Daily Briefing

Subscribe to enter the giveaway

Every subscriber is automatically entered. You also get daily threat intel every morning: zero-days, ransomware, and nation-state campaigns. Free. No spam.

Already subscribed? You're already entered.

Giveaway

Win a $2,495 Black Hat USA 2026 pass.