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
- The
sealed-secrets-controllerruns in the cluster and holds the private key. - You use the
kubesealCLI to encrypt a plain Secret with the cluster's public key. - The encrypted
SealedSecretis committed to Git and applied to the cluster. - 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:
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:
The controller automatically creates the decrypted Secret in the same namespace.
Verify
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 |