kubectl get secret app-db -o yaml renvoie un bloc data rempli de chaînes illisibles. Ça ressemble à du chiffré. Ça n’en est pas. Les valeurs d’un Secret Kubernetes sont encodées en base64, et le base64 est un encodage de transport que n’importe qui inverse en une commande :
kubectl get secret app-db -o jsonpath='{.data.password}' | base64 -d
Ce seul fait commande toutes les décisions qui suivent. Un Secret natif ne protège rien en lui-même. Ce qui le garde vraiment, c’est le RBAC (qui a le droit de faire get sur l’objet) et, au repos, le fait qu’etcd soit chiffré ou non.
Ce qu’un Secret natif protège, et ce qu’il ne protège pas
Par défaut, etcd stocke les objets Secret sans chiffrement. Le chiffrement au repos s’active explicitement, via une EncryptionConfiguration sur l’API server :
apiVersion: apiserver.config.k8s.io/v1
kind: EncryptionConfiguration
resources:
- resources: ["secrets"]
providers:
- aescbc:
keys:
- name: key1
secret: <clé base64 de 32 octets>
- identity: {}
Sans cette configuration, une sauvegarde d’etcd est une sauvegarde de tous vos credentials en clair (en base64). Avec elle, la valeur est chiffrée dans le datastore mais reste du base64 pour quiconque dispose d’un accès en lecture à l’API. Deux modèles de menace distincts, et les Secrets natifs ne couvrent le premier qu’une fois que vous l’avez délibérément activé.
Le problème que les Secrets natifs ne résolvent jamais, c’est Git. On ne commit pas un manifeste Secret en clair dans un dépôt. C’est dans cette faille que vivent les deux autres approches.
Sealed Secrets : rendre le manifeste committable
Sealed Secrets (le contrôleur de Bitnami) ajoute une CRD et un contrôleur dans le cluster qui détient une paire de clés asymétriques. On chiffre avec le certificat public grâce à kubeseal, et seule la clé privée du contrôleur peut déchiffrer :
kubectl create secret generic app-db \
--from-literal=password='s3cr3t' --dry-run=client -o yaml \
| kubeseal --format yaml > sealed-app-db.yaml
Le SealedSecret obtenu vit sans risque dans Git. Le contrôleur le détecte, le déchiffre et matérialise un Secret ordinaire dans le namespace. Votre pipeline GitOps décrit désormais les secrets comme il décrit tout le reste.
Deux propriétés dessinent les limites. Le scellage est lié au cluster : un SealedSecret est chiffré pour la clé d’un contrôleur donné, donc restaurer les manifestes dans un cluster neuf échoue tant que vous n’avez pas sauvegardé puis restauré la clé de scellage (elle-même un Secret dans kube-system). Perdre cette clé rend irrécupérable chaque SealedSecret présent dans Git. Le scope par défaut est également strict : le chiffré est lié au couple exact name plus namespace, et on ne peut ni renommer ni déplacer un SealedSecret sans le resceller.
Sealed Secrets stocke des valeurs chiffrées. Il ne les fait pas tourner, ne les expire pas, ne trace pas qui les lit. Faire tourner un mot de passe reste un commit.
Vault : secrets dynamiques, leasing, audit
Vault en externe change le modèle. Plutôt que de stocker un credential statique, Vault peut en générer un à la demande et le remettre avec un lease :
vault write database/roles/app-db \
db_name=app-postgres \
creation_statements="CREATE ROLE \"{{name}}\" WITH LOGIN PASSWORD '{{password}}' VALID UNTIL '{{expiration}}';" \
default_ttl="1h" max_ttl="24h"
Une application s’authentifie (l’auth Kubernetes échange le token de ServiceAccount d’un pod contre un token Vault), lit database/creds/app-db et récupère un utilisateur Postgres neuf, valide une heure. À l’expiration du lease, Vault révoque le credential à la source. Un credential fuité a alors un rayon d’action qui se compte en minutes, et chaque lecture atterrit dans un journal d’audit.
Tirer ces valeurs jusque dans les pods se fait en général avec l’External Secrets Operator ou le Vault Secrets Operator, qui synchronisent un chemin Vault vers un Secret natif consommé normalement par les workloads.
Le coût est opérationnel et bien réel : un Vault en haute dispo, c’est un stockage Raft sur trois nœuds ou plus, une stratégie d’unseal (auto-unseal via un KMS cloud, ou des porteurs humains de parts de clé Shamir), des sauvegardes testées et une cadence de montée de version à tenir. Depuis le passage de Vault sous licence BSL, OpenBao est le fork open source à mettre dans la balance.
Les pièges classiques
- Prendre le base64 pour une frontière de sécurité. L’erreur la plus fréquente, et de loin. Restreignez le RBAC, activez le chiffrement au repos, et ne lisez jamais
data:comme une protection. - Ne pas sauvegarder la clé de Sealed Secrets. On commit les SealedSecrets, on se sent en sécurité, puis on découvre après une reconstruction de cluster que Git seul ne les restaure pas.
- Déployer Vault pour des secrets statiques. Si rien de ce que vous stockez n’est dynamique et que vous ne touchez jamais au leasing ni à l’audit, vous avez pris en charge la contrainte d’exploitation d’un système distribué pour faire ce qu’un seul contrôleur Sealed Secrets fait déjà.
- Oublier qu’un Secret est référencé par son nom. Faire un rollback d’un Deployment ne fait pas de rollback du Secret qu’il pointe.
Comment trancher
La taille de l’équipe et l’exigence de conformité tracent la ligne :
- Petite équipe, pas de store externe, GitOps déjà en place : Secrets natifs avec chiffrement au repos, plus Sealed Secrets pour que le dépôt soit la source de vérité. Coût d’exploitation minimal, et ça couvre la plupart des PME.
- Secrets statiques, un fournisseur cloud disponible : un secret manager managé derrière External Secrets Operator déplace la séparation des environnements dans l’IAM, exactement là où on la veut. C’est la même logique que celle du service discovery : ne pas coder en dur ce qui doit rester découvrable et révocable.
- Credentials dynamiques, vraies exigences d’audit ou de rotation, parc hétérogène (VMs plus Kubernetes plus CI) : Vault gagne sa place, mais seulement si vous pouvez nommer aujourd’hui la personne qui le mettra à jour dans dix-huit mois.
À retenir
Les Secrets natifs sont du base64, pas du chiffrement ; ce sont le RBAC et le chiffrement d’etcd au repos qui les protègent réellement. Sealed Secrets rend un manifeste committable et s’insère dans un dépôt GitOps, au prix d’une clé liée au cluster qu’il ne faut jamais perdre. Vault achète des secrets dynamiques, du leasing et de l’audit, au prix d’un système distribué à état à opérer. Calez l’outil sur un fait que vous pouvez désigner (une clause de conformité, une obligation de rotation, un parc hybride), pas sur une intention. Ces arbitrages font partie du travail que je mène dans mon offre industrialisation du CI/CD.