Skip to main content
Sealed Secrets lets you safely store Kubernetes Secret data in Git by encrypting it into a cluster-specific custom resource. Below is a concise, step-by-step explanation of how it works and how to use it in a GitOps workflow.

High-level flow

  1. Install the Sealed Secrets controller in your Kubernetes cluster.
  2. The controller creates a SealedSecret CustomResourceDefinition (CRD) and generates an asymmetric keypair.
  3. Use the controller’s public key to encrypt Secret data locally with the kubeseal CLI, producing a SealedSecret manifest that is safe to commit to Git.
  4. Apply the SealedSecret to the cluster. The controller decrypts it with its private key and creates a regular Kubernetes Secret in the same namespace.
  5. Pods consume the standard Secret as usual.

Components summary

Install the controller

Deploy the Sealed Secrets controller/Helm chart into your cluster. You can use plain kubectl or Helm depending on your workflow:
  • kubectl: apply the controller manifest directly.
  • Helm: install the chart into your cluster.
When installed, the controller registers the SealedSecret CRD and generates an asymmetric keypair:
  • Public key: used to encrypt secrets outside the cluster.
  • Private key: stored inside the cluster and used by the controller to decrypt SealedSecret objects.

Encrypting a Secret (client-side)

  1. Create a regular Kubernetes Secret manifest locally (or generate one via kubectl).
  2. Use the kubeseal CLI to encrypt that Secret into a SealedSecret object. kubeseal uses the controller’s public key to produce encrypted output safe for version control.
Example — generate a Secret manifest and seal it:
A generated SealedSecret manifest looks like this:
Tip: If you need to encrypt without contacting the controller (e.g., CI environment), fetch the public certificate once with kubeseal --fetch-cert and use --cert to seal offline.

Deploying the SealedSecret

Apply the sealed manifest to your cluster as you would any other Kubernetes object:

What the controller does when it sees a SealedSecret

  • The Sealed Secrets controller watches for SealedSecret objects.
  • When it detects one, it uses its private key to decrypt spec.encryptedData.
  • The controller then creates a standard Kubernetes Secret in the same namespace.
  • That resulting Secret behaves like any other: mountable into pods, usable as environment variables, etc.
Verify the decrypted Secret:

Why this is secure for GitOps

  • The SealedSecret you store in Git contains only encrypted blobs generated with the controller’s public key.
  • The private key required for decryption never leaves the cluster—it is kept by the controller.
  • Without the controller’s private key, an attacker cannot decrypt the stored sealed data even if they obtain the Git repository.
The controller’s private key is the only key that can decrypt SealedSecrets. Keep the controller and its backups secure — losing the private key means you will no longer be able to decrypt your sealed secrets.
A diagram titled "How does Sealed Secrets work" showing a user using the kubeseal CLI/HelM to create a SealedSecret CRD in a Kubernetes cluster. The Sealed Secrets controller uses a public/private keypair to encrypt the SealedSecret and then decrypt it into a regular Kubernetes Secret.
Next step: demo And now we’ll move on to a short demo showing how to seal a secret locally and let the controller create a Kubernetes Secret for pods to consume.

Watch Video