Manage Secrets in GitOps with Sealed Secrets

Khimananda Oli 9 min read Virtualization
Manage Secrets in GitOps with Sealed Secrets

By Khimananda Oli | Last reviewed: August 2026

The fundamental promise of GitOps is that your Git repository serves as the single source of truth for your entire infrastructure state. This model breaks immediately when you need to store database passwords, API keys, or TLS certificates because committing plaintext credentials to version control is a critical security failure. To manage secrets in GitOps with Sealed Secrets, you encrypt sensitive data locally using a public key so it can be safely committed to Git, while only the in-cluster controller holds the private key needed to decrypt it into usable Kubernetes Secrets.

This approach preserves the declarative workflow without resorting to manual post-deployment steps or external vault dependencies for every environment. For teams adopting GitOps with ArgoCD, this pattern eliminates the drift between what is declared in Git and what actually runs in the cluster. If you are new to the broader ecosystem of credential handling, start with my guide on Kubernetes secrets management done right before implementing encryption layers.

Developer Laptopkubeseal CLI+ Public CertGit RepositorySealedSecret YAML(Safe to Commit)ArgoCD / FluxSyncs Manifestto ClusterK8sControllerDecryptsPrivate Key NEVER leaves the cluster boundary
End-to-end flow to manage secrets in GitOps with Sealed Secrets: encryption happens locally, only encrypted blobs traverse Git and CI/CD.

How do you install and configure Sealed Secrets for GitOps?

Before you can encrypt anything, the Sealed Secrets controller must be running in your target cluster. This component generates the key pair on first boot and exposes the public certificate via an HTTP endpoint. In production environments, especially those requiring SOC 2 or ISO 27001 compliance, you should never rely on the auto-generated keys. Instead, supply your own pre-generated RSA key pair stored securely in a backup system or hardware security module.

Installing the Controller via Helm

Helm is the standard deployment method in 2026. Add the Bitnami chart repository and install the controller into a dedicated namespace:

helm repo add sealed-secrets https://bitnami-labs.github.io/sealed-secrets
helm repo update

helm install sealed-secrets-controller sealed-secrets/sealed-secrets \
  --namespace kube-system \
  --set resources.requests.cpu=100m \
  --set resources.requests.memory=128Mi \
  --set resources.limits.memory=256Mi

Verify the pod is running and fetch the public certificate that developers will use for encryption:

kubectl get pods -n kube-system -l app.kubernetes.io/name=sealed-secrets
kubeseal --fetch-cert > sealed-secrets-cert.pem

Store this sealed-secrets-cert.pem file in your team’s shared configuration repository or distribute it via your internal developer platform. It is not sensitive — it is a public key — but losing it means developers cannot seal new secrets until they fetch a fresh copy.

Key Rotation and Backup Strategy

A common mistake in audits is finding no evidence of key rotation or backup procedures. The controller stores its private key as a Kubernetes Secret named sealed-secrets-key in the same namespace. You must back up this secret externally. If the cluster is destroyed and recreated without restoring this key, all existing SealedSecrets in Git become permanently undecryptable.

  • Backup: Export the private key quarterly and store it in an offline, access-controlled vault.
  • Rotation: The controller supports multiple active keys. Trigger rotation by sending SIGUSR1 to the pod or setting --key-renew-period. Old keys remain valid for decryption during the transition window.
  • Disaster Recovery: Document the restore procedure in your runbooks. Test restoration annually as part of compliance evidence collection.

How do you encrypt and commit secrets safely with kubeseal?

The kubeseal binary performs client-side encryption. It contacts the controller (or uses a cached certificate) to obtain the public key, then encrypts each value in your Secret manifest individually. The output is a SealedSecret custom resource that is safe to store anywhere.

Basic Encryption Workflow

Create a standard Kubernetes Secret manifest locally. Do not commit this file:

# secret.yaml — DO NOT COMMIT
apiVersion: v1
kind: Secret
metadata:
  name: app-db-credentials
  namespace: production
type: Opaque
stringData:
  DB_HOST: postgres.prod.internal
  DB_USER: app_service
  DB_PASS: SuperS3cret!2026

Seal it using the fetched certificate:

kubeseal --cert sealed-secrets-cert.pem \
  --format yaml \
  < secret.yaml \
  > sealed-secret.yaml

The resulting sealed-secret.yaml contains encrypted blobs under spec.encryptedData. This file is now safe to commit to Git. Delete the original plaintext secret.yaml immediately after sealing.

Namespace and Name Binding

By default, Sealed Secrets are bound to the exact namespace and name specified in the metadata. Renaming the resource or moving it to a different namespace after sealing will cause decryption to fail silently. This is a deliberate security feature preventing lateral movement if an attacker gains write access to Git. If you require reusability across namespaces, use the --scope namespace-wide or --scope cluster-wide flags during sealing, but understand this weakens the security boundary significantly.

SealedSecret CRencryptedData:DB_PASS: AgBx...9kQ==namespace: productionController PodWatches CR EventsDecrypts w/ Private KeyValidates NS + Name BindNative K8s Secretdata:DB_PASS: U3VwZXJT...Mounted by PodsStatus FeedbackSuccess → Creates SecretFail → Logs Decryption Err
Controller internals: validates namespace/name binding before decrypting SealedSecret into a native Kubernetes Secret for pod consumption.

How does Sealed Secrets compare to External Secrets Operator and SOPS?

Choosing the right tool depends on your team’s operational maturity, compliance requirements, and existing cloud investments. There is no universal best option — only trade-offs. Understanding these differences prevents costly migrations later when you realize your chosen solution doesn’t fit your audit scope or multi-cloud strategy.

CriteriaSealed SecretsExternal Secrets Operator (ESO)Mozilla SOPS
Primary Use CasePure GitOps without external depsSyncing from AWS SM / Vault / GCPEncrypted files in Git, multi-format
External DependencyNone (self-contained in-cluster)Requires cloud provider or VaultRequires age/GPG/AWS KMS keys
Encryption LocationClient-side (kubeseal CLI)N/A (fetches at runtime)Client-side (sops CLI)
Key ManagementIn-cluster RSA keypairCloud KMS / HSM / VaultAge, GPG, Cloud KMS
Compliance Audit TrailGit history onlyCloud provider audit logsGit history + KMS logs
Multi-Cluster SupportSeparate key per clusterCentralized secret storeShared key across clusters
Learning CurveLowMedium-HighMedium
Best For Nepal TeamsStartups, limited cloud budgetEnterprises with AWS/Azure spendMulti-cloud, strong crypto teams

For Nepali startups and SMEs operating on tight budgets without enterprise cloud agreements, Sealed Secrets removes the recurring cost of managed secret stores while maintaining acceptable security posture. Enterprises pursuing SOC 2 Type II or ISO 27001 certification often prefer ESO because cloud provider audit logs satisfy evidence requirements more easily than self-managed key rotation records. Teams already standardized on HashiCorp Vault for secrets management should use ESO as the bridge rather than adopting Sealed Secrets as a parallel system.

What are the common pitfalls when managing secrets in GitOps with Sealed Secrets?

After reviewing dozens of GitOps implementations across Nepal and global clients, I see the same failures repeatedly. These aren’t theoretical risks — they cause production outages and audit findings.

Silent Decryption Failures

The controller does not crash when it cannot decrypt a SealedSecret. It logs an error and updates the resource status, but ArgoCD may still report the sync as successful because the SealedSecret CR itself was applied correctly. Always check the status.conditions field on SealedSecret resources in your monitoring dashboards. Set up alerts for Synced=False conditions using Prometheus metrics exported by the controller.

Certificate Drift Between Environments

Each cluster has its own key pair. Using a staging cluster’s certificate to seal secrets intended for production will result in decryption failures. Label your certificates clearly (prod-cert.pem, staging-cert.pem) and enforce validation in CI pipelines before merging. A simple pre-commit hook verifying the certificate fingerprint against the target environment prevents this class of errors entirely.

Overlooking RBAC Restrictions

The controller needs permissions to read SealedSecrets and create/update native Secrets in every namespace where you deploy applications. Missing ClusterRole bindings cause silent failures. Verify RBAC during installation and restrict the controller’s ServiceAccount to only the namespaces it actually manages — never grant cluster-admin privileges for convenience.

Storing Plaintext Temporarily

Developers often create plaintext Secret files, seal them, then forget to delete the originals. Add *.secret.yaml and similar patterns to .gitignore globally. Better yet, pipe directly from stdin to avoid intermediate files:

kubectl create secret generic app-db-credentials \
  --from-literal=DB_HOST=postgres.prod.internal \
  --from-literal=DB_USER=app_service \
  --from-literal=DB_PASS=SuperS3cret!2026 \
  --dry-run=client -o yaml | \
  kubeseal --cert prod-cert.pem --format yaml > sealed-secret.yaml

This one-liner never writes plaintext to disk. Integrate it into your team’s documentation and onboarding materials for handling secrets in CI/CD pipelines safely.

Need GitOps Secrets?External Vault / Cloud SM?YESNOUse ESOAudit-ready, centralizedSelf-Contained OK?YESNOSealed SecretsSimple, zero external depsUse SOPSMulti-format, shared keys
Decision framework: choose Sealed Secrets for self-contained GitOps, ESO for cloud-backed stores, or SOPS for multi-cluster key sharing.

Implementing Secure Secret Management in Your GitOps Pipeline

To successfully manage secrets in GitOps with Sealed Secrets, treat the encryption workflow as a first-class part of your delivery pipeline, not an afterthought. Automate certificate distribution through your internal developer platform or config repo. Enforce pre-commit hooks that reject plaintext Secret manifests. Monitor decryption status alongside application health metrics. Rotate keys on a documented schedule and test restoration procedures before auditors ask.

This pattern gives you true GitOps — declarative, versioned, auditable — without sacrificing security or compliance readiness. For teams in Nepal building cloud-native products on limited budgets, it removes the barrier of expensive managed secret stores while maintaining professional-grade security practices. Global teams use it as a lightweight complement to enterprise vaults for non-critical environments or edge deployments.

If your team needs help designing a secrets management strategy that passes audits and survives production incidents, reach out to discuss your specific architecture. I’ve implemented this pattern across regulated fintech systems, government platforms, and high-growth startups — the right solution depends on your compliance scope, team size, and cloud footprint.

Frequently Asked Questions

Sealed Secrets encrypt Kubernetes secrets using a public key so they can be safely committed to Git repositories. Only the cluster-side controller with the private key can decrypt them into standard secrets for pod consumption.

Install via Helm chart sealed-secrets/sealed-secrets or apply the official release manifest. The controller runs in kube-system by default and automatically generates an asymmetric key pair on first startup for encryption operations.

Use kubeseal v0.28 or later for full compatibility with Kubernetes 1.32 clusters. Always match your CLI version to your controller version to prevent encryption format mismatches during secret sealing operations.

Yes, ArgoCD syncs sealed secret manifests like any other resource. The in-cluster controller decrypts them post-sync. Ensure the controller is installed before ArgoCD attempts to reconcile sealed secret objects.

The controller supports multiple active keys simultaneously. Rotate by triggering key renewal, resealing affected secrets at your pace, then removing old keys. Existing sealed secrets remain valid until explicitly resealed with newer keys.

Yes, kubeseal only requires the public certificate, never the private key. Fetch the cert from the controller once and store it as a pipeline artifact or config map for offline sealing without cluster access.

All existing sealed secrets become permanently undecryptable. Back up the master private key secret regularly using Velero or manual export. Store backups encrypted offline separate from your Git repository and cluster etcd.

Yes, use strict scope mode to bind sealed secrets to exact namespace and name pairs. This prevents accidental decryption if a sealed secret manifest is copied to another namespace or renamed maliciously.

Retrieve the current plain secret, modify it locally, reseal with kubeseal using the same scope parameters, and commit the updated manifest. GitOps controllers will reconcile the change and the controller decrypts the new payload.

No, it manages keys internally within the cluster. For AWS KMS, GCP KMS, or HashiCorp Vault integration, consider External Secrets Operator or SOPS instead, as Sealed Secrets lacks native external provider support.

Common causes include namespace/name mismatch in strict mode, expired controller certificates, or version skew between kubeseal and controller. Check controller logs for decryption errors and verify scope annotations match the target resource exactly.

Yes, but use namespace-scoped sealing to isolate team secrets. Each team should only possess the public cert and seal resources within their designated namespaces to prevent cross-team secret exposure or accidental overwrites.

Limited by Kubernetes etcd object size limits, typically 1MB. Large binary files should be stored externally in object storage with credentials managed via Sealed Secrets instead of embedding entire payloads directly.

Yes, Bitnami continues releasing updates and security patches. However, evaluate alternatives like SOPS or External Secrets Operator for newer features. Sealed Secrets remains stable and widely adopted for basic GitOps secret management needs.

No, sealing is an offline client operation requiring only the public certificate. However, applying sealed secrets to the cluster requires standard create/update permissions on sealedsecrets.bitnami.com resources in target namespaces.