Skip to main content
In this lesson you’ll convert a plain-text Kubernetes Secret stored in Git into a SealedSecret using Bitnami Sealed Secrets, and then use Flux to apply the encrypted secret to the cluster. This keeps sensitive values encrypted at rest in your repository while allowing the cluster to receive a decrypted Secret at apply-time. Goals
  • Inspect the existing Flux Kustomization and the plain Secret file in Git.
  • Demonstrate Flux reconciliation re-creating a deleted Secret.
  • Suspend reconciliation, delete the in-cluster plain Secret, and show the workload failing.
  • Create a SealedSecret using the kubeseal CLI and the Sealed Secrets controller public certificate.
  • Replace the plain Secret in Git with the SealedSecret and resume reconciliation.
  • Verify the Secret is decrypted in-cluster and the workload recovers.
Overview of resources
Kustomization in the infrastructure repository (applies manifests in the database namespace)
Plain Secret stored in the repository (contains a plain-text password — not recommended)
Note: never keep plain-text secrets in Git. We will replace this file with a SealedSecret.
How Flux reconciliation behaves (short demonstration) Flux constantly reconciles Git to the cluster. If you delete a resource in-cluster, Flux will likely re-create it when it next reconciles. Example session (cleaned for readability):
Because the Kustomization above uses interval: 10s, Flux checks and applies changes frequently.
Suspend reconciliation so we can perform the SealedSecret transition safely Temporarily suspend the Kustomization so Flux does not immediately re-create the plain Secret while you prepare the SealedSecret:
Delete the in-cluster plain Secret and restart the workload to show the pod failing when the Secret is missing:
Describe the failing pod to see the container error: the pod will report CreateContainerConfigError due to the missing Secret.
Create a SealedSecret using the kubeseal CLI We will convert the plain Secret YAML into a SealedSecret using the Sealed Secrets controller public certificate and the kubeseal CLI. The SealedSecret preserves key names (like password) but encrypts values so the file is safe to store in Git.
  1. Ensure the plain Secret manifest (the file that previously lived in Git) is present locally as secret-mysql.yaml.
  2. Run kubeseal with the controller public certificate:
Flags explained:
  • -o yaml — output a SealedSecret resource as YAML.
  • --scope cluster-wide — annotate the SealedSecret for cluster-wide usage (be explicit about scope).
  • --cert ../../sealed-secret.pub — use the Sealed Secrets controller public certificate. Adjust the path to your cert file.
  • < secret-mysql.yaml — read the original Secret from stdin.
  • > sealed-secret-mysql.yaml — write the SealedSecret YAML to a new file.
Example generated SealedSecret (truncated encryptedData value):
Only values are encrypted; the key password remains visible so the manifest stays clear. Before committing the SealedSecret to Git, remove or rename the plain Secret manifest so Flux will no longer reconcile the plain file:
Commit and push the new sealed-secret-mysql.yaml to your repository in the same location where the plain Secret previously lived.
Do not keep plain-text secret files in Git. Use SealedSecrets (or another secret management solution) to store secrets safely in your repository.

Resume Flux reconciliation and let the SealedSecrets controller decrypt and apply After pushing the SealedSecret to Git, resume the Kustomization so Flux fetches the latest revision and applies the SealedSecret:
When Flux applies the SealedSecret manifest, the Sealed Secrets controller in-cluster uses its private key to decrypt the encryptedData and create a standard Kubernetes Secret in the database namespace. Verify the Secret exists and decode the password to confirm the value:
Tools used above: Restart or watch the deployment recover. The pod that previously failed due to the missing Secret should start successfully once the Secret is present:

How it works (high level)
  • kubeseal encrypts secret values using the Sealed Secrets controller public key and produces a SealedSecret manifest safe to store in Git.
  • When Flux applies the SealedSecret, the Sealed Secrets controller (running in-cluster) intercepts it and decrypts the data using its private key, creating a standard Kubernetes Secret in the desired namespace.
  • This workflow lets you keep encrypted secrets in Git while enabling the cluster to receive decrypted Secrets at apply-time, improving security in GitOps workflows.
Common commands quick reference
Links and References That completes the end-to-end workflow for encrypting and decrypting secrets using Bitnami Sealed Secrets with Flux.

Watch Video

Practice Lab