> ## Documentation Index
> Fetch the complete documentation index at: https://notes.kodekloud.com/llms.txt
> Use this file to discover all available pages before exploring further.

# How does Sealed Secrets Work

> Explains how Sealed Secrets encrypt Kubernetes Secret data with kubeseal and a cluster controller so sealed manifests can be safely stored in Git and decrypted in-cluster

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

| Component | Role | Example / Notes |
| - | -: | - |
| Sealed Secrets controller | Runs in-cluster, manages `SealedSecret` CRD and private key | Install via `kubectl apply -f` or Helm |
| `SealedSecret` CRD | Stores encrypted secret data safe for Git | `apiVersion: bitnami.com/v1alpha1` |
| `kubeseal` CLI | Encrypts local `Secret` YAML with the controller's public key | `kubeseal --format yaml < secret.yaml > sealedsecret.yaml` |
| Kubernetes `Secret` | Created by the controller after decryption, used by pods | `kubectl get secret <name> -n <ns>` |

## 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:

```bash theme={null}
# Create a Secret manifest (client-side dry-run)
kubectl create secret generic database \
  --from-literal=DB_PASSWORD='s3cr3t' \
  --dry-run=client -o yaml > secret.yaml

# Seal the Secret into a SealedSecret (writes YAML to stdout)
kubeseal --format yaml < secret.yaml > sealedsecret.yaml
```

A generated `SealedSecret` manifest looks like this:

```yaml theme={null}
apiVersion: bitnami.com/v1alpha1
kind: SealedSecret
metadata:
  name: database
  namespace: mynamespace
spec:
  encryptedData:
    DB_PASSWORD: AgBy3i4OJSWK+PiTySYZZA9r043cGDEq....
```

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:

```bash theme={null}
kubectl apply -f sealedsecret.yaml
```

## 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:

```bash theme={null}
kubectl get secret database -n mynamespace
kubectl describe secret database -n mynamespace
```

## 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.](https://mintcdn.com/kodekloud-c4ac6d9a/7fEHGJt8C5fqT3FG/images/Introduction-to-Sealed-Secrets-in-Kubernetes/Sealed-Secrets-Fundamentals/How-does-Sealed-Secrets-Work/sealed-secrets-kubeseal-encrypt-decrypt.jpg?fit=max\&auto=format\&n=7fEHGJt8C5fqT3FG\&q=85\&s=57ee1a007bbaaeef51a432e3ed8efbdd)

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.

## Links and references

* [Sealed Secrets GitHub (kubeseal)](https://github.com/bitnami-labs/sealed-secrets)
* [kubectl reference](https://kubernetes.io/docs/reference/kubectl/)
* [Helm](https://helm.sh)
* [Kubernetes documentation](https://kubernetes.io/docs/)

> **[Watch Video](https://learn.kodekloud.com/user/courses/introduction-to-sealed-secrets-in-kubernetes/module/0f3ed562-f151-48f9-bb8c-8d3a4dbb4fc3/lesson/c360c15b-8531-4e7d-8740-47e04d1bda44)**


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.