
September 12, 2026
14 min read
By Kokil Thapa | Last reviewed: September 2026
Choosing between Sealed Secrets vs External Secrets Operator is one of the first architectural calls a Kubernetes team makes when secrets leave `.env` files and enter Git. Both tools keep plain-text credentials out of your repository. They solve the problem differently. Sealed Secrets encrypts values into a custom resource you commit safely. External Secrets Operator pulls live secrets from Vault, AWS Secrets Manager, Azure Key Vault, or GCP Secret Manager into native Kubernetes Secrets. If you run GitOps with sealed commits on a small cluster, the trade-offs look nothing like a multi-cloud platform syncing from three vault backends.
What is the difference between Sealed Secrets and External Secrets Operator?
Both projects sit in the Kubernetes secrets-management layer above native Secret objects. Native secrets are base64-encoded, not encrypted at rest unless you enable etcd encryption. Neither approach replaces that etcd layer. They control how secret material enters the cluster in the first place.
Bitnami Sealed Secrets adds a cluster-scoped controller and a CLI (kubeseal). You encrypt plaintext with the controller's public key. The output is a SealedSecret custom resource. You commit that YAML to Git. The controller decrypts it into a standard Secret at reconcile time. The private key never leaves the cluster.
External Secrets Operator (ESO) is a Kubernetes operator that watches ExternalSecret and SecretStore resources. It calls external APIs — HashiCorp Vault, AWS Secrets Manager, Azure Key Vault, GCP Secret Manager, and dozens of providers — and writes the result into a native Secret. Git holds the mapping, not the value.
The mental model is simple. Sealed Secrets is a Git-first encryption envelope. ESO is a vault-first sync bridge. I've seen teams run both on the same cluster without conflict. Sealed Secrets covers app config that developers rotate via PR. ESO covers platform credentials that security owns in Vault. For background on native objects, see the official Kubernetes Secret documentation.
| Criteria | Sealed Secrets | External Secrets Operator |
|---|---|---|
| Source of truth | Git (encrypted SealedSecret) | External vault or cloud secret store |
| Git-safe commits | Yes — ciphertext in repo | Yes — only references in repo |
| Secret rotation | Re-seal and commit new CR | Update vault; ESO refreshes on interval |
| Multi-cluster sharing | Per-cluster key; re-seal for each | Same vault path serves many clusters |
| Offline / air-gapped GitOps | Strong — no outbound API calls | Needs vault connectivity from cluster |
| Operational overhead | Low — one controller + CLI | Higher — operator + vault IAM + stores |
| Blast radius if Git leaks | Ciphertext only (without private key) | Metadata only (paths, not values) |
| Best fit | Small teams, single cloud, Flux/Argo CD | Enterprise vault, multi-cloud, compliance |
How does Bitnami Sealed Secrets work in a GitOps pipeline?
Sealed Secrets fits teams that treat Git as the single source of truth. The workflow mirrors how I commit Laravel .env.example files while keeping real credentials out of the repo. Here the encryption step happens before the commit lands.
Install the controller
Apply the upstream manifest or Helm chart into kube-system (or a dedicated namespace). The controller generates an RSA key pair on first boot. Back up that private key immediately. Losing it means re-sealing every secret in every environment.
helm repo add sealed-secrets https://bitnami-labs.github.io/sealed-secrets
helm install sealed-secrets sealed-secrets/sealed-secrets \
--namespace kube-system \
--set fullnameOverride=sealed-secrets-controller Seal a secret with kubeseal
Create a local secret manifest, pipe it through kubeseal, and commit the output. Scope matters: cluster-wide sealing ignores namespace; strict mode binds name and namespace.
kubectl create secret generic db-credentials \
--from-literal=username=app_user \
--from-literal=password='s3cr3t' \
--dry-run=client -o yaml | \
kubeseal \
--controller-name=sealed-secrets-controller \
--controller-namespace=kube-system \
--format yaml > sealed-db-credentials.yaml Flux or Argo CD applies sealed-db-credentials.yaml. The controller decrypts it. A native Secret named db-credentials appears in the target namespace. Your pods mount it unchanged. This pattern pairs well with guides on Kubernetes Secrets and ConfigMaps done right and secrets scanning in Git with Gitleaks as a defence-in-depth layer.
Key rotation and multi-environment sealing
Each cluster has its own sealing certificate. You cannot copy a SealedSecret from staging to production unless both clusters share a key (possible but rarely desirable). In practice, CI runs kubeseal per environment using the cluster's fetched public cert. I've encountered this during production deployments where the same GitOps repo targets three EKS clusters. Each cluster needs its own sealed artefact for shared secret names.
How does External Secrets Operator sync secrets from external vaults?
ESO treats Kubernetes as a consumer, not the vault. Platform teams centralise credentials in HashiCorp Vault, AWS Secrets Manager, or Azure Key Vault. Application teams declare what they need in YAML. The operator handles fetch, refresh, and ownership.
This mirrors how I wire Laravel apps to read secrets from environment variables populated at deploy time. The difference is the sync loop runs inside the cluster on a configurable interval. For a deep walkthrough, see External Secrets Operator with Vault and secrets management with HashiCorp Vault.
Define a SecretStore and ExternalSecret
A SecretStore (namespace-scoped) or ClusterSecretStore holds provider credentials and connection details. An ExternalSecret maps remote keys to a target Kubernetes Secret.
apiVersion: external-secrets.io/v1beta1
kind: ClusterSecretStore
metadata:
name: aws-secretsmanager
spec:
provider:
aws:
service: SecretsManager
region: ap-south-1
auth:
jwt:
serviceAccountRef:
name: external-secrets-sa
namespace: external-secrets
---
apiVersion: external-secrets.io/v1beta1
kind: ExternalSecret
metadata:
name: app-db-credentials
namespace: production
spec:
refreshInterval: 1h
secretStoreRef:
name: aws-secretsmanager
kind: ClusterSecretStore
target:
name: db-credentials
creationPolicy: Owner
data:
- secretKey: password
remoteRef:
key: prod/app/database
property: password ESO creates or updates db-credentials every hour. Change the value in AWS Secrets Manager and the cluster picks it up without a Git commit. That is the main operational win for teams with strict rotation policies.
Provider coverage and ClusterSecretStore patterns
ESO supports 40+ providers through a plugin-style architecture documented at external-secrets.io. Multi-cloud setups use one operator install and multiple stores. A Nepal-based SaaS might keep payment gateway keys in AWS Secrets Manager while IRD-related signing certs sit in Azure Key Vault. ESO normalises both into the same Kubernetes consumption pattern.
Authentication typically uses workload identity: IRSA on EKS, Workload Identity on GKE, or Azure Workload Identity. Avoid long-lived cloud access keys in the cluster. Bind IAM roles to the ESO service account instead. This aligns with multi-cloud secrets management guidance and CI/CD secrets management best practices.
Which should you choose: Sealed Secrets or External Secrets Operator?
There is no universal winner in the Sealed Secrets vs External Secrets Operator debate. The right choice follows your source-of-truth policy, team size, and compliance requirements. Use this decision framework before you install either controller.
- No central vault yet? Start with Sealed Secrets. It adds one controller and a CLI. You avoid standing up Vault HA, cloud IAM policies, and cross-team access workflows on day one.
- Vault or cloud secret store already exists? ESO is the natural fit. Duplicating values into sealed blobs creates two sources of truth and doubles rotation work.
- Strict audit and dynamic rotation? ESO wins. Vault audit logs and automatic refresh beat manual re-seal PRs for database credentials that rotate weekly.
- Air-gapped or offline GitOps? Sealed Secrets needs no outbound network from the controller. ESO requires live vault API access on every refresh interval.
- Developer self-service? Sealed Secrets lets devs seal locally and open a PR. ESO usually needs platform approval for vault paths plus a Git PR for the
ExternalSecretmanifest. - Multi-cluster, same secret value? ESO reads one vault path everywhere. Sealed Secrets needs per-cluster sealing unless you share keys (discouraged).
On production Laravel platforms with GitLab CI and Deployer, I treat Kubernetes secrets the same way I treat .env on EC2: isolate production values, never commit plaintext, and document the rotation owner. When those apps move into K8s, Sealed Secrets covers developer-owned config. ESO covers platform-owned infra credentials. That split keeps PR velocity high without sacrificing auditability.
Teams migrating from bare-metal Deployer releases to Kubernetes often underestimate ESO's IAM surface area. Budget time for IRSA roles, SecretStore RBAC, and vault namespace design. Sealed Secrets installs in an afternoon. ESO is a platform project, not a afternoon task.
How do you install and harden both tools in production?
Whichever side of Sealed Secrets vs External Secrets Operator you pick, production hardening follows the same baseline. Enable etcd encryption at rest. Restrict RBAC on Secret read access. Turn on audit logging. Neither tool replaces those fundamentals. Read encrypt etcd secrets at rest and Kubernetes secrets management done right before go-live.
Sealed Secrets hardening checklist
- Back up the controller's TLS private key to a secure offline store. Test restore quarterly.
- Enable strict scope (
--scope strict) so sealed blobs cannot be replayed across namespaces. - Run the controller with minimal RBAC. It only needs to manage its CRs and create Secrets.
- Integrate
kubesealinto CI so developers never commit unsealed manifests. Pair with pipeline secrets hygiene. - Consider multi-tenant clusters carefully. One controller key per cluster is the default isolation boundary.
External Secrets Operator hardening checklist
- Pin the operator Helm chart version. Upgrades can change CRD schemas.
- Use
ClusterSecretStoreonly when multiple namespaces need the same vault backend. Otherwise prefer namespace-scopedSecretStorefor blast-radius control. - Set
refreshIntervaldeliberately. Too aggressive hammers vault APIs. Too lazy delays rotation uptake. - Enable ESO's webhook validation if your chart supports it. Reject
ExternalSecretresources pointing at unapproved stores. - Monitor sync errors in Prometheus. A failed sync leaves pods on stale credentials silently.
For alternative Git-encryption approaches without a cluster controller, SOPS with age and Ansible Vault remain valid. They differ because decryption happens at apply time in CI, not inside the cluster. Compare all three patterns when designing your enterprise application platform.
Can you run Sealed Secrets and ESO together?
Yes. A common pattern: Sealed Secrets for third-party API keys developers rotate via PR. ESO for RDS master passwords Vault rotates automatically. Label namespaces or use naming conventions so on-call engineers know which tool owns each Secret. Document ownership in your internal runbook. Confusion during incidents costs more than running two controllers.
Understanding how Kubernetes operators extend the API helps when debugging CRD status fields on both projects. Check SealedSecret status conditions and ESO's ExternalSecret Ready condition before you assume the pod misconfigured its mount path.
What are common mistakes when adopting these Kubernetes secret tools?
These failures show up repeatedly across client migrations and forum threads. Avoid them early.
Committing the sealing private key. Only the public cert belongs in CI. The controller private key is as sensitive as root CA material. Store it in offline backup, not in the GitOps repo.
Assuming Sealed Secrets encrypts etcd. It encrypts Git commits. Once decrypted, the native Secret is still base64 in etcd unless you enable encryption at rest separately.
Granting ESO cluster-admin. The operator needs vault read and Secret write in target namespaces. It does not need cluster-admin. Over-permissioning turns a compromised operator pod into a cluster-wide breach.
Ignoring secret drift between environments. A sealed blob sealed for staging applied to production either fails or creates wrong credentials. Automate per-environment sealing in CI with explicit cluster context.
Skipping rotation drills. Re-seal a test secret quarterly with Sealed Secrets. Force a vault rotation with ESO and confirm pods reload. Stale mounts are a common post-rotation outage cause. Generate test credentials with a password generator and run the full loop in staging first.
Treating either tool as encryption for logs. Applications that log environment variables still leak secrets. Inject via mounted files. Mark secrets as sensitive in your logging pipeline. See protecting secrets in application logs for related patterns.
Key Takeaways
- Sealed Secrets encrypts secret values into Git-safe
SealedSecretCRs; ESO syncs live values from external vaults into native Secrets. - Pick Sealed Secrets when Git is your source of truth and you want minimal infrastructure; pick ESO when a vault already exists and rotation is automated.
- Both require etcd encryption at rest and tight RBAC — neither replaces Kubernetes baseline secret hygiene.
- Multi-cluster deployments favour ESO's single vault path; Sealed Secrets needs per-cluster re-sealing unless keys are shared.
- Running both on one cluster is valid: developer-owned config via Sealed Secrets, platform-owned credentials via ESO.
- Back up the Sealed Secrets private key and monitor ESO sync status — silent failures leave workloads on stale credentials.
People Also Ask
Is Sealed Secrets the same as Kubernetes external secrets?
No. Sealed Secrets is a standalone Bitnami project that encrypts values for Git storage. External Secrets Operator is a CNCF-oriented project that fetches secrets from external systems. They solve different parts of the supply chain and can coexist on the same cluster.
Can Sealed Secrets work without internet access?
Yes. After the controller is installed, decryption happens entirely inside the cluster. Developers need cluster API access to fetch the public cert for kubeseal, but the running controller needs no outbound connectivity. This makes Sealed Secrets popular in air-gapped and on-prem GitOps setups.
Does External Secrets Operator replace HashiCorp Vault?
No. ESO is a sync client, not a vault. Vault remains the source of truth and audit trail. ESO reads from Vault (or other providers) and materialises Kubernetes Secrets for pod consumption. You still operate, backup, and secure the vault itself.
Which is easier for small teams in 2026?
Sealed Secrets is faster to adopt: one Helm install, one CLI, and developers seal locally before PR. ESO pays off once you have a vault, multiple clusters, or compliance-driven rotation. Small teams without a vault should start with Sealed Secrets and migrate to ESO when central secret storage becomes a requirement.
Pick the right secrets tool and ship with confidence
The Sealed Secrets vs External Secrets Operator choice is really a source-of-truth decision. Git-encrypted CRs versus live vault sync. Neither is wrong. Wrong is committing plaintext, skipping etcd encryption, or picking ESO before you have a vault to sync from. Map your rotation owners, cluster count, and compliance rules first. Then install the controller that matches how your team already works.
If you are designing a Kubernetes platform, migrating from bare-metal Deployer workflows, or hardening secrets across Linux production infrastructure, a focused architecture review saves weeks of rework. Review the secure client portal work in my portfolio for how credential isolation translates to real business systems. Explore more on the blog or about me page. When you want hands-on help evaluating GitOps secret patterns for your stack, contact us to discuss your deployment.
Frequently Asked Questions
0 Comments
Leave a comment
Your email is not published. Comments appear once they have been read. Sign in to have your details filled in.

