Skip to content

Sealed Secrets

Sealed Secrets by Bitnami provides a way to encrypt Kubernetes Secrets so they can be safely stored in version control. A SealedSecret can only be decrypted by the controller running in the target cluster.

How it works

  1. The sealed-secrets-controller runs in the cluster and holds the private key.
  2. You use the kubeseal CLI to encrypt a plain Secret with the cluster's public key.
  3. The encrypted SealedSecret is committed to Git and applied to the cluster.
  4. The controller decrypts it and creates the corresponding Kubernetes Secret.

Install the controller

helm repo add sealed-secrets https://bitnami-labs.github.io/sealed-secrets
helm repo update
helm install sealed-secrets sealed-secrets/sealed-secrets \
  -n kube-system --version 2.16.1

Install kubeseal CLI

# macOS
brew install kubeseal

# Linux
curl -sSL https://github.com/bitnami-labs/sealed-secrets/releases/download/v0.27.1/kubeseal-0.27.1-linux-amd64.tar.gz \
  | tar -xz kubeseal
sudo mv kubeseal /usr/local/bin/

Seal a secret

Create a plain Kubernetes Secret manifest (do not apply it to the cluster):

# mysecret.yaml
apiVersion: v1
kind: Secret
metadata:
  name: mysecret
  namespace: default
type: Opaque
stringData:
  username: admin
  password: supersecret

Encrypt it with kubeseal:

kubeseal --format yaml < mysecret.yaml > mysealedsecret.yaml

The resulting SealedSecret is safe to commit to Git:

apiVersion: bitnami.com/v1alpha1
kind: SealedSecret
metadata:
  name: mysecret
  namespace: default
spec:
  encryptedData:
    username: AgBy8hg...
    password: AgCx9pQ...

Apply the sealed secret to the cluster:

kubectl apply -f mysealedsecret.yaml

The controller automatically creates the decrypted Secret in the same namespace.

Verify

kubectl get secret mysecret -n default
kubectl get sealedsecret mysecret -n default

Key renewal and backup

The controller rotates its key pair every 30 days by default. Old keys are retained so existing secrets remain decryptable. To back up the sealing key:

kubectl get secret -n kube-system -l sealedsecrets.bitnami.com/sealed-secrets-key \
  -o yaml > sealed-secrets-keys-backup.yaml

Store the key backup securely — anyone with the private key can decrypt all sealed secrets.

Scope options

By default a SealedSecret is namespace-scoped (only decryptable in the target namespace). Use --scope to change this:

Scope Flag Description
strict (default) --scope strict Bound to name and namespace
namespace-wide --scope namespace-wide Any name in the same namespace
cluster-wide --scope cluster-wide Any name in any namespace
kubeseal --scope cluster-wide --format yaml < mysecret.yaml > mysealedsecret.yaml