Kokil Thapa - Professional Web Developer in Nepal
Freelancer Web Developer in Nepal with 15+ Years of Experience

Kokil Thapa is an experienced full-stack web developer focused on building fast, secure, and scalable web applications. He helps businesses and individuals create SEO-friendly, user-focused digital platforms designed for long-term growth.

Sealed Secrets vs External Secrets Operator

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.

Two Paths Into KubernetesSealed SecretsEncrypted value lives in GitExternal SecretsValue lives in external vaultDeveloper + kubesealEncrypt before commitPlatform teamVault owns the valueSealedSecret CRStored in Git repoExternalSecret CRPoints to vault keyNative Kubernetes Secret
Sealed Secrets vs External Secrets Operator — Git-encrypted CRs versus vault-backed sync both produce native Kubernetes Secrets

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.

CriteriaSealed SecretsExternal Secrets Operator
Source of truthGit (encrypted SealedSecret)External vault or cloud secret store
Git-safe commitsYes — ciphertext in repoYes — only references in repo
Secret rotationRe-seal and commit new CRUpdate vault; ESO refreshes on interval
Multi-cluster sharingPer-cluster key; re-seal for eachSame vault path serves many clusters
Offline / air-gapped GitOpsStrong — no outbound API callsNeeds vault connectivity from cluster
Operational overheadLow — one controller + CLIHigher — operator + vault IAM + stores
Blast radius if Git leaksCiphertext only (without private key)Metadata only (paths, not values)
Best fitSmall teams, single cloud, Flux/Argo CDEnterprise 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.

Sealed Secrets GitOps FlowDeveloperPlaintext locallykubeseal CLIUses public certGit commitSealedSecret YAMLArgo CDSyncs manifestSealed SecretsController decryptsK8s SecretBase64 in etcdPod volumeMountenvFrom or projected volume
Sealed Secrets GitOps pipeline — encrypt locally, commit ciphertext, controller materialises the native Secret for workloads

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.

External Secrets Sync LoopExternal VaultAWS / Vault / AzureESO ControllerReconcile loopK8s SecretTarget for podsExternalSecret CR in GitremoteRef.key = prod/app/databaserefreshInterval: 1hNo secret value in repository
External Secrets Operator pulls live values from vault APIs on a refresh interval and writes native Kubernetes Secrets

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.

  1. 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.
  2. 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.
  3. Strict audit and dynamic rotation? ESO wins. Vault audit logs and automatic refresh beat manual re-seal PRs for database credentials that rotate weekly.
  4. Air-gapped or offline GitOps? Sealed Secrets needs no outbound network from the controller. ESO requires live vault API access on every refresh interval.
  5. 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 ExternalSecret manifest.
  6. 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.

Which Tool Fits Your Team?Need K8s secrets from Git?Central vault exists?Vault / AWS / AzureNo vault yet?Small team / GitOpsExternal SecretsSync + auto rotationSealed SecretsEncrypt and commitBoth OK: split dev config vs platform creds
Decision tree for Sealed Secrets vs External Secrets Operator — vault ownership and rotation policy drive the choice

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 kubeseal into 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 ClusterSecretStore only when multiple namespaces need the same vault backend. Otherwise prefer namespace-scoped SecretStore for blast-radius control.
  • Set refreshInterval deliberately. Too aggressive hammers vault APIs. Too lazy delays rotation uptake.
  • Enable ESO's webhook validation if your chart supports it. Reject ExternalSecret resources 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 SealedSecret CRs; 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

Sealed Secrets encrypts plaintext into a SealedSecret custom resource you commit to Git; the in-cluster controller decrypts it into a native Secret. External Secrets Operator watches ExternalSecret and SecretStore resources, fetches live values from external vaults or cloud secret stores, and writes native Kubernetes Secrets. Git holds ciphertext with Sealed Secrets; Git holds only references with ESO.

Pick Sealed Secrets when Git is your single source of truth and you want a simple GitOps loop with Flux or Argo CD — encrypt locally with kubeseal, commit ciphertext, and let the controller materialise Secrets at reconcile time. Pick External Secrets Operator when credentials already live in HashiCorp Vault, AWS Secrets Manager, Azure Key Vault, or GCP Secret Manager and you want rotation without re-sealing and committing new YAML on every change.

Install the controller into kube-system or a dedicated namespace; it generates an RSA key pair on first boot. Create a local Secret manifest, pipe it through kubeseal using the controller public key, and commit the resulting SealedSecret YAML. Flux or Argo CD applies that file; the controller decrypts it and a standard Secret appears in the target namespace for pods to mount unchanged. Back up the controller private key immediately after install.

Define a SecretStore or ClusterSecretStore with provider credentials and connection details, then an ExternalSecret that maps remote keys to a target Kubernetes Secret name. ESO calls the external API on a configurable refreshInterval — for example every hour — and creates or updates the native Secret. Change the value in the vault and the cluster picks it up without a Git commit, which is the main win for teams with strict rotation policies.

Yes, and many teams do. A common split is Sealed Secrets for third-party API keys developers rotate via pull request, and ESO for platform credentials such as RDS master passwords that Vault rotates automatically. Label namespaces or use naming conventions so on-call engineers know which tool owns each Secret, and document ownership in your runbook to avoid confusion during incidents.

Choose Sealed Secrets when you have no central vault yet, run air-gapped or offline GitOps that cannot make outbound vault API calls, or want low operational overhead with one controller and a CLI. It suits small teams on a single cloud using Flux or Argo CD, and lets developers seal secrets locally and open a PR without waiting on platform approval for vault path access.

Choose ESO when HashiCorp Vault or a cloud secret store already exists, strict audit and dynamic rotation matter, or the same secret value must serve multiple clusters from one vault path. Duplicating vault values into sealed blobs creates two sources of truth and doubles rotation work. ESO also fits enterprise multi-cloud setups where payment keys sit in AWS Secrets Manager and compliance certs sit in Azure Key Vault.

No. Sealed Secrets encrypts Git commits, not etcd storage. Once the controller decrypts a SealedSecret, the resulting native Secret is still base64-encoded in etcd unless you enable etcd encryption at rest separately. Neither Sealed Secrets nor ESO replaces that etcd layer — both control how secret material enters the cluster in the first place.

With Sealed Secrets you re-seal the updated plaintext and commit a new SealedSecret custom resource through your GitOps pipeline. With ESO you update the value in the external vault and the operator refreshes the native Secret on its interval. For credentials that rotate weekly, vault-driven refresh beats manual re-seal pull requests. Run rotation drills in staging quarterly for both approaches to confirm pods reload and mounts are not stale.

You must re-seal every secret in every environment because decryption becomes impossible without that key. The private key never leaves the cluster and is as sensitive as root CA material — back it up to a secure offline store immediately after install and test restore quarterly. Only the public certificate belongs in CI for kubeseal; never commit the sealing private key to your GitOps repository.

Each Sealed Secrets cluster has its own sealing certificate, so you cannot copy a SealedSecret from staging to production unless clusters share a key, which is rarely desirable. CI should run kubeseal per environment using each cluster fetched public cert. ESO reads the same vault path everywhere, so one remote key serves many clusters without re-sealing per cluster.

Committing the sealing private key, assuming Sealed Secrets protects etcd without enabling encryption at rest, granting ESO cluster-admin instead of scoped vault read and Secret write, ignoring per-environment sealing drift, skipping rotation drills, and treating either tool as protection against secrets logged by applications. Inject via mounted files and mark sensitive values in your logging pipeline rather than relying on the secrets tool alone.

No. ESO requires live vault API access from the cluster on every refresh interval. Sealed Secrets needs no outbound network from the controller once installed, making it the stronger fit for air-gapped GitOps where Git carries encrypted artefacts and the cluster decrypts locally.

ESO supports HashiCorp Vault, AWS Secrets Manager, Azure Key Vault, GCP Secret Manager, and dozens of other providers through a plugin-style architecture documented at external-secrets.io — over 40 providers in total. Multi-cloud setups use one operator install with multiple SecretStore or ClusterSecretStore resources, normalising different backends into the same Kubernetes Secret consumption pattern for application pods.

Enable etcd encryption at rest, restrict RBAC on Secret read access, and turn on audit logging for both paths. For Sealed Secrets: back up the TLS private key, enable strict scope so blobs cannot replay across namespaces, run the controller with minimal RBAC, and integrate kubeseal into CI. For ESO: pin the Helm chart version, prefer namespace-scoped SecretStore over ClusterSecretStore when possible, set refreshInterval deliberately, enable webhook validation if available, and monitor sync errors in Prometheus because failed syncs leave pods on stale credentials silently.

Share this article

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.

Quick Contact Options
Choose how you want to connect me: