Skip to content

Managing Kubernetes Secrets Securely with Sealed Secrets

Are you storing your Kubernetes secrets in Git? If so, you're probably exposing sensitive data without realizing it. Sealed Secrets offer a secure, GitOps-friendly way to encrypt your secrets so they’re safe even in public repositories.

In this guide, you'll learn:

  • What Kubernetes secrets are and why they're insecure by default
  • What Sealed Secrets are and how they work
  • When to use them — and what to watch out for
  • How to install and use them with real examples
  • Alternatives like SOPS and Vault

Let’s dive in and make your GitOps workflow both secure and maintainable.


What is a Kubernetes Secret?

A Kubernetes Secret is an object used to store sensitive data like passwords, OAuth tokens, and SSH keys. These secrets are base64-encoded and stored within the cluster. While convenient, they lack strong encryption, making them unsuitable for storing in Git repositories directly.

Base64 encoding is not encryption. Storing Kubernetes secrets in Git without protection exposes them to risk.


What is a Sealed Secret?

Sealed Secrets, developed by Bitnami, provide a way to store encrypted Kubernetes secrets safely in Git repositories. A SealedSecret is an encrypted version of a regular Secret, which can only be decrypted by the controller running in the target cluster.

How it works

  1. You create a Kubernetes Secret manifest as you normally would.

  2. You use the kubeseal CLI to encrypt this secret. The encryption is done using the public key of the Sealed Secrets controller running in your cluster.

  3. The public key is automatically generated by the controller upon installation.

  4. You can retrieve it with: kubeseal --fetch-cert or by accessing the controller's secret via kubectl.
  5. You do not need to generate keys manually; the controller handles key pair generation internally.

  6. The encrypted secret (called a SealedSecret) is safe to store in Git, even in a public repository, because it cannot be decrypted without the matching private key.

  7. When you apply this SealedSecret to the cluster, the Sealed Secrets controller uses its private key (stored only inside the cluster) to decrypt it and generate a standard Kubernetes Secret.

Because the private key never leaves the controller inside the cluster, only that specific cluster can decrypt and use the sealed secret, ensuring your sensitive data remains protected.


Why Use Sealed Secrets?

  • GitOps-Friendly: Safe to commit to Git and track changes over time.
  • Cluster-Specific Decryption: Only the intended cluster can decrypt secrets.
  • Simple Workflow: Easy integration with CI/CD tools.
  • Open Source and Maintained: Backed by the community and Bitnami.

Things to Watch Out For

  • If you lose the private key (e.g., during cluster recreation), you won’t be able to decrypt existing sealed secrets.
  • Sealed secrets are one-way encrypted—you cannot retrieve the original secret from the sealed one.
  • Rotation or migration requires planning (e.g., backing up keys).

Installing Sealed Secrets

1. Install the Sealed Secrets Controller

Use Helm (recommended):

helm repo add sealed-secrets https://bitnami-labs.github.io/sealed-secrets
helm repo update

helm install sealed-secrets sealed-secrets/sealed-secrets \
  --namespace kube-system

Or using a manifest:

kubectl apply -f https://github.com/bitnami-labs/sealed-secrets/releases/download/v0.25.0/controller.yaml

Replace the version URL with the latest release if needed.

2. Install the CLI

brew install kubeseal  # macOS
# or download from https://github.com/bitnami-labs/sealed-secrets/releases

Using Sealed Secrets in Practice

Step-by-step

1. Create a Kubernetes Secret manifest

apiVersion: v1
kind: Secret
metadata:
  name: mysecret
  namespace: default
type: Opaque
data:
  password: bXlzZWNyZXRwYXNzd29yZA==  # base64 encoded

2. Seal the secret

kubeseal --controller-name=sealed-secrets \
  --format=yaml < mysecret.yaml > mysealedsecret.yaml

Tip: You can seal directly from kubectl output too:

kubectl create secret generic mysecret \
  --from-literal=password=mypassword \
  --dry-run=client -o json | \
  kubeseal --format=yaml > mysealedsecret.yaml

3. Commit to Git

The mysealedsecret.yaml is now safe to commit and store in your Git repository.

4. Apply it to your cluster

kubectl apply -f mysealedsecret.yaml

This will automatically generate a Kubernetes Secret in the target namespace.


Notes and Alternatives

Rotating Keys

To back up and rotate your sealing key:

kubectl get secret -n kube-system sealed-secrets-key -o yaml > backup-key.yaml

Keep this in a secure location like a password manager or encrypted storage.

Alternatives

SOPS is a good choice if you prefer file-level encryption and flexibility over integration with Kubernetes controllers.


Summary

Sealed Secrets provide a GitOps-compatible and secure way to manage sensitive data in Kubernetes. They are ideal for teams that:

  • Want to store secrets in Git
  • Need a straightforward and cluster-scoped solution
  • Prefer not to manage a separate secrets backend like Vault

By understanding its limitations and setup requirements, you can confidently integrate Sealed Secrets into your CI/CD pipeline.


Resources