Sealed Secrets permet de stocker des secrets Kubernetes chiffrés directement dans Git, pour des workflows GitOps 100% déclaratifs. Le contrôleur déployé dans le cluster détient la clé privée RSA. L'outil CLI kubeseal chiffre les secrets avec la clé publique exposée par le contrôleur - le résultat (SealedSecret) est safe à committer dans Git. Seul le contrôleur du cluster concerné peut déchiffrer. La CRD SealedSecret est réconciliée automatiquement en Secret Kubernetes natif.
Informations essentielles
Origine : Bitnami (VMware/Broadcom) · Licence : Apache 2.0 · Architectures : x86_64, ARM64
Liens : Documentation · GitHub · Releases
Support : Maintenu activement par Bitnami/Broadcom. Projet mature et stable.
Stack par défaut
| Composant | Valeur |
|---|---|
| Contrôleur | Déployé dans kube-system |
| CLI | kubeseal |
| CRD | SealedSecret (apiVersion bitnami.com/v1alpha1) |
| Chiffrement | RSA-4096 (clé publique/privée) + AES-256-GCM (données) |
| Clé privée | Stockée en Secret dans kube-system, jamais exposée |
| Rotation | Automatique des clés (30 jours par défaut, configurable) |
Prérequis
| Ressource | Valeur |
|---|---|
| Kubernetes | 1.16+ |
| kubectl | Configuré avec accès cluster |
Installation
Contrôleur via Helm
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
# Vérifier
kubectl get pods -n kube-system -l app.kubernetes.io/name=sealed-secrets
Contrôleur via kubectl
kubectl apply -f \
https://github.com/bitnami-labs/sealed-secrets/releases/latest/download/controller.yaml
CLI kubeseal
# Homebrew (macOS/Linux)
brew install kubeseal
# Binaire Linux (version dynamique)
KUBESEAL_VERSION=$(curl -s "https://api.github.com/repos/bitnami-labs/sealed-secrets/releases/latest" \
| grep '"tag_name"' | sed 's/.*"v\([^"]*\)".*/\1/')
curl -Lo kubeseal.tar.gz \
"https://github.com/bitnami-labs/sealed-secrets/releases/download/v${KUBESEAL_VERSION}/kubeseal-${KUBESEAL_VERSION}-linux-amd64.tar.gz"
tar -xzf kubeseal.tar.gz kubeseal
sudo install -m 755 kubeseal /usr/local/bin/
kubeseal --version
Sceller un secret
# 1. Créer le Secret K8s standard (sans l'appliquer)
kubectl create secret generic my-db-secret \
--from-literal=username=admin \
--from-literal=password=SuperSecret123 \
--namespace production \
--dry-run=client -o yaml > secret.yaml
# 2. Chiffrer avec kubeseal
kubeseal \
--controller-name=sealed-secrets \
--controller-namespace=kube-system \
-f secret.yaml \
-w sealed-secret.yaml
# 3. Supprimer le fichier non chiffré
rm secret.yaml
# 4. Committer sealed-secret.yaml dans Git et l'appliquer
kubectl apply -f sealed-secret.yaml
Le SealedSecret résultant
apiVersion: bitnami.com/v1alpha1
kind: SealedSecret
metadata:
name: my-db-secret
namespace: production
spec:
encryptedData:
password: AgBy3i4OJSWK+PiTySYZZA9rO43cGDEQAx... # Chiffré, safe dans Git
username: AgBy3i4OJSWK+PiTySYZZA9rO43cGDEQAx...
template:
metadata:
name: my-db-secret
namespace: production
Scopes de chiffrement
Par défaut, un SealedSecret est lié à un namespace ET un nom spécifique (strict). Ce comportement est configurable :
# strict (défaut) : lié au namespace + nom exact
kubeseal --scope strict -f secret.yaml -w sealed.yaml
# namespace-wide : utilisable pour tout secret dans ce namespace
kubeseal --scope namespace-wide -f secret.yaml -w sealed.yaml
# cluster-wide : utilisable dans tout le cluster pour tout nom
kubeseal --scope cluster-wide -f secret.yaml -w sealed.yaml
Utilisation sans connexion cluster (CI/CD)
Dans un pipeline CI, le cluster n'est pas toujours accessible. On peut chiffrer hors-ligne avec la clé publique :
# Récupérer la clé publique une fois et la stocker dans le repo
kubeseal --fetch-cert \
--controller-name=sealed-secrets \
--controller-namespace=kube-system > public-cert.pem
# Chiffrer hors-ligne (pas besoin d'accès cluster)
kubeseal --cert public-cert.pem -f secret.yaml -w sealed.yaml
# Chiffrer une valeur brute (pour injection dans un YAML existant)
echo -n "SuperSecret123" | kubeseal --raw \
--name my-db-secret \
--namespace production \
--cert public-cert.pem \
--scope strict
Rotation des clés
Le contrôleur génère automatiquement une nouvelle clé de chiffrement tous les 30 jours (configurable). Les anciennes clés sont conservées pour déchiffrer les anciens SealedSecrets.
# Lister les clés disponibles
kubectl get secrets -n kube-system \
-l sealedsecrets.bitnami.com/sealed-secrets-key
# Forcer la génération d'une nouvelle clé maintenant
kubectl annotate secret sealed-secrets-key \
-n kube-system \
sealedsecrets.bitnami.com/sealed-secrets-key=active
# Exporter les clés (backup critique - à stocker de façon sécurisée)
kubectl get secrets -n kube-system \
-l sealedsecrets.bitnami.com/sealed-secrets-key \
-o yaml > sealed-secrets-keys-backup.yaml
Mise à jour
helm repo update
helm upgrade sealed-secrets sealed-secrets/sealed-secrets \
--namespace kube-system \
--reuse-values
Troubleshooting
# Logs du contrôleur
kubectl logs -n kube-system \
-l app.kubernetes.io/name=sealed-secrets --tail=50
# SealedSecret en erreur : vérifier les events
kubectl describe sealedsecret my-db-secret -n production
# Erreur "no key could decrypt secret" : le SealedSecret a été chiffré
# avec une clé d'un autre cluster. Recréer avec la clé du bon cluster.
# Vérifier que le Secret K8s a bien été créé
kubectl get secret my-db-secret -n production
# Vérifier l'état de tous les SealedSecrets
kubectl get sealedsecrets -A
Ressources
- Documentation officielle : https://sealed-secrets.netlify.app/
- GitHub : https://github.com/bitnami-labs/sealed-secrets
- Getting started : https://sealed-secrets.netlify.app/getting-started/
- Releases : https://github.com/bitnami-labs/sealed-secrets/releases