Sealed Secrets¶
GitOps means your cluster's desired state lives in Git, but you cannot
commit plain Kubernetes Secret objects there; they are only
base64-encoded, not encrypted. We recommend
Sealed Secrets for this. It
encrypts a secret so it can be safely committed to a Git repository, and
only your cluster can decrypt it.
How it works¶
A controller in your cluster holds a private key. You encrypt secrets
against the matching public key using the kubeseal CLI, producing a
SealedSecret resource. ArgoCD applies the SealedSecret like any other
manifest, and the controller decrypts it in-cluster into a regular
Secret that your pods consume. The plaintext never leaves your machine
in a form anyone but your cluster can read.
Workflow¶
The Sealed Secrets controller publishes its current public certificate through the Kubernetes API. Fetch it with the portal-issued kubeconfig configured in Connecting to your cluster:
kubeseal \
--controller-name sealed-secrets-controller \
--controller-namespace sealed-secrets \
--fetch-cert > sealed-secrets-cert.pem
The certificate is public and contains no secret key material. Your kubeconfig has narrowly scoped access to fetch it; it does not grant access to the controller's private sealing keys.
Use the certificate from the destination cluster
Each cluster has its own sealing keys. A Sealed Secret encrypted for one cluster cannot be decrypted by another cluster.
Write a normal Secret manifest (do not commit this file), then seal it with
the downloaded certificate:
# Create a Secret manifest locally (not committed)
kubectl create secret generic db-credentials \
--namespace my-app \
--from-literal=password='s3cr3t' \
--dry-run=client -o yaml > secret.yaml
# Seal it against the cluster's public key
kubeseal --cert sealed-secrets-cert.pem --format yaml \
< secret.yaml > sealed-secret.yaml
Commit sealed-secret.yaml to your repository and let ArgoCD deploy it.
The resulting Secret appears in the my-app namespace for your pods to
mount or reference as environment variables.
Using --cert makes sealing an offline operation: after fetching the public
certificate, kubeseal does not need further cluster access. Re-fetch the
certificate before creating new Sealed Secrets if SUNET announces a
sealing-key rotation.
A SealedSecret is encrypted for a specific namespace and name by
default, so move or rename it only by re-sealing.