Secrets et configuration sensible
Comprendre les limites structurelles de l'objet Secret Kubernetes, mettre en place le chiffrement au repos, et évaluer les solutions externes de gestion de secrets pour ne pas confondre encodage et protection.
Table des matières
Pourquoi les Secrets Kubernetes déçoivent en production
Le nom de l'objet Secret est trompeur. Beaucoup d'équipes découvrent tardivement qu'un Secret Kubernetes, dans sa configuration par défaut, n'apporte aucune protection cryptographique : les valeurs sont encodées en base64, pas chiffrées, et stockées telles quelles dans etcd. Quiconque a un accès en lecture à etcd — via une sauvegarde, un accès disque au node, ou une fuite de la base elle-même — récupère l'intégralité des secrets du cluster en une commande de décodage triviale.
Ce chapitre pose précisément ce que les Secrets protègent (peu de choses, en configuration par défaut), ce qu'un chiffrementchiffrementCybersécuritéTransformation d'une donnée lisible en une forme inintelligible à l'aide d'une clé. Le destinataire disposant de la clé peut retrouver le message original. C'est le socle de la confidentialité sur Internet.Voir dans le glossaire au repos correctement configuré ajoute, et à quel moment il devient nécessaire de déléguer la gestion des secrets à un système externe conçu pour ça.
Base64 n'est pas du chiffrement. C'est un encodage réversible sans clé :
echo 'cGFzc3dvcmQ=' | base64 -dsuffit à retrouver la valeur en clair. Traiter un Secret Kubernetes comme « déjà protégé » parce qu'il apparaît encodé dans un manifeste est l'erreur la plus fréquente chez les équipes qui découvrent Kubernetes.
Anatomie d'un Secret : ce qu'il protège vraiment
Un Secret est un objet API comme un autre, structurellement proche d'une ConfigMap. La différence tient à trois points :
- Les valeurs sont encodées en base64 dans la représentation YAML/JSON, ce qui évite les problèmes d'échappement de caractères spéciaux — pas une protection de confidentialité.
- Kubelet peut monter un Secret en
tmpfs(mémoire) plutôt que sur le disque du node, réduisant le risque qu'une valeur persiste après la fin du pod. - L'API server applique par défaut certaines restrictions d'affichage (
kubectl get secretne montre pas la valeur en clair sans-o jsonsuivi d'un décodage), ce qui limite l'exposition accidentelle mais ne bloque en rien un accès délibéré.
Ce que le Secret ne fait pas, sauf configuration additionnelle explicite :
- Il ne chiffre pas la donnée stockée dans etcd.
- Il ne chiffre pas la donnée en transit entre l'API server et etcd, sauf TLSTLSRéseauxProtocole cryptographique assurant confidentialité et intégrité des communications applicatives (notamment HTTPS).Voir dans le glossaire correctement configuré sur ce canal — généralement le cas sur les distributions managées, à vérifier sur un cluster self-managed.
- Il n'impose aucune rotation : une clé créée il y a trois ans reste valide indéfiniment tant que personne ne l'a explicitement changée.
- Il ne limite pas qui peut le lire au-delà de ce que RBAC définit — et RBAC, par défaut, n'exclut aucune identité en particulier.
apiVersion: v1
kind: Secret
metadata:
name: db-creds
namespace: billing
type: Opaque
data:
password: cGFzc3dvcmQxMjMh
Ce manifeste, une fois appliqué, place password en clair (une fois décodé) dans etcd, sans chiffrement additionnel tant que EncryptionConfiguration n'est pas activé sur l'API server. Un outil de sauvegarde d'etcd qui ne chiffre pas ses propres snapshots expose ainsi, sans le savoir, l'ensemble des secrets du cluster à quiconque accède au stockage de sauvegarde.
Le chiffrement au repos (encryption at rest)
Kubernetes permet de chiffrer les objets Secret (et d'autres types de ressources, si besoin) avant leur écriture dans etcd, via un fichier EncryptionConfiguration référencé par le flag --encryption-provider-config de l'API server.
apiVersion: apiserver.config.k8s.io/v1
kind: EncryptionConfiguration
resources:
- resources: [secrets]
providers:
- kms:
apiVersion: v2
name: my-kms-provider
endpoint: unix:///var/run/kmsplugin/socket.sock
- identity: {}
Plusieurs fournisseurs sont disponibles, avec des garanties très différentes :
| Provider | Où vit la clé | Garantie |
|---|---|---|
identity |
Aucune clé | Pas de chiffrement — comportement par défaut |
aescbc / aesgcm |
Clé locale, fichier sur le control plane | Chiffre les donnéesdonnéesIAEnsemble d'informations structurées ou non utilisées pour entraîner, évaluer ou alimenter un modèle. La qualité, la quantité et la représentativité des données sont les facteurs décisifs pour les performances en apprentissage automatique.Voir dans le glossaire, mais la clé reste sur disque |
kms (v1, déprécié) |
Service KMS externe | Clé jamais persistée en clair sur le control plane |
kms (v2, recommandé) |
Service KMS externe, DEK mise en cache | Meilleures performances que v1, même séparation clé/données |
Le provider kms v2 est aujourd'hui recommandé : il génère une clé de chiffrement de données (DEK) locale, elle-même chiffrée par une clé maître (KEK) hébergée dans un KMS externe (AWS KMS, GCP Cloud KMS, Azure Key Vault, ou un plugin Vault). La DEK est mise en cache en mémoire pour limiter les appels réseau au KMS à chaque écriture, corrigeant le principal défaut de performance du provider v1.
Activer
EncryptionConfigurationsur un cluster existant ne chiffre pas rétroactivement les Secrets déjà présents dans etcd. Il faut réécrire chaque objet concerné après activationfonction d'activationIAOpération non linéaire appliquée en sortie d'un neurone. Sans elle, empiler des couches serait inutile : une succession d'opérations linéaires reste équivalente à une seule.Voir dans le glossaire — typiquement viakubectl get secrets --all-namespaces -o json | kubectl replace -f -ou un outil équivalent — pour que le chiffrement s'applique effectivement. Un audit post-activation doit vérifier qu'aucun Secret n'est resté en clair.
Ce chiffrement protège contre un scénario précis : un accès non autorisé au stockage physique ou aux sauvegardes d'etcd. Il ne protège pas contre un accès autorisé via l'API — un utilisateur ou un ServiceAccount avec le verbe get sur secrets continue de recevoir la valeur en clair. C'est un point souvent mal compris : le chiffrement au repos et RBAC couvrent deux surfaces différentes, et l'un ne compense jamais les failles de l'autre.
Solutions externes : Vault, External Secrets Operator, Sealed Secrets
Quand les limites du Secret natif deviennent incompatibles avec les exigences de conformité ou d'audit, trois familles d'outilstool callingIACapacité d'un agent ou d'un LLM à invoquer des outils externes (API, calcul, recherche) pendant le raisonnement.Voir dans le glossaire s'imposent en pratique.
HashiCorp Vault est un magasin de secrets à part entière, externe au cluster. Il gère l'authentification, l'autorisation fine, l'audit complet des accès, et surtout les secrets dynamiques : au lieu de stocker un identifiant fixe, Vault génère à la demande des identifiants temporaires avec une durée de vie limitée (bail), révoqués automatiquement à expiration. C'est un changement de modèle plus qu'un simple stockage chiffré — un identifiant volé devient inutile après sa fenêtre de validité. L'intégration se fait via l'agentagentIASystème qui enchaîne des appels d'outils de façon autonome pour atteindre un objectif : il planifie, agit, observe, recommence. Sa fiabilité décroît exponentiellement avec le nombre d'étapes.Voir dans le glossaire injector (init-container écrivant les secrets dans un volume partagé) ou via le CSI provider Secrets Store.
External Secrets Operator (ESO) ne remplace pas un magasin externe : il synchronise des secrets détenus dans un système tiers (Vault, AWS Secrets Manager, GCP Secret Manager, Azure Key Vault) vers des objets Secret Kubernetes standards, via une ressource personnalisée ExternalSecret. Avantage double : les applications consomment un Secret classique (aucun changement de code) tout en centralisant la source de vérité et la rotation dans le système externe.
apiVersion: external-secrets.io/v1beta1
kind: ExternalSecret
metadata:
name: db-creds
namespace: billing
spec:
refreshInterval: 1h
secretStoreRef:
name: vault-backend
kind: SecretStore
target:
name: db-creds
data:
- secretKey: password
remoteRef:
key: billing/db
property: password
Sealed Secrets (Bitnami) répond à un problème différent : comment versionner un secret dans Git sans l'exposer en clair. Un SealedSecret est chiffré côté client avec une clé publique asymétrique propre au cluster ; seul le contrôleur, détenteur de la clé privée correspondante, peut le déchiffrer et produire un Secret standard une fois appliqué. Solution adaptée à un workflow GitOps où les manifestes doivent rester commitables sans fuite — mais elle ne résout ni la rotation ni les secrets dynamiques : elle sécurise uniquement le transport et le stockage en dépôt.
Le choix entre ces outils dépend surtout de la question suivante : où doit vivre la source de vérité du secret ? Si elle doit rester dans un système externe audité indépendamment (conformité, séparation des responsabilités), ESO ou l'agent Vault s'imposent. Si le besoin est uniquement de committer des manifestes sans exposer de valeur en clair dans Git, Sealed Secrets suffit et évite d'introduire une dépendance d'exécution supplémentaire.
Une équipe migre une application legacy qui lit ses identifiants depuis des variables d'environnement statiques. Plutôt que de réécrire l'application pour interroger directement Vault, elle déploie ESO avec un
ExternalSecretpointant vers le secret Vault existant et unrefreshIntervald'une heure. Le Secret généré est monté en variable d'environnement comme avant — l'application ne voit aucune différence — mais la rotation dans Vault se propage désormais automatiquement, sans redéploiement manuel.
RBAC, exposition et rotation
Le chiffrement au repos et un outil externe de gestion de secrets ne dispensent pas d'un contrôle d'accès strict sur les objets Secret eux-mêmes.
Le verbe list est plus dangereux que get. get exige de connaître le nom exact d'un secret. list renvoie l'ensemble des objets d'un namespace, contenu inclus — un rôle qui autorise list sur secrets équivaut, en pratique, à un accès en lecture à tous les secrets présents et futurs de ce namespace.
Les logs applicatifs sont une fuite fréquente. Un secret correctement chiffré dans etcd peut malgré tout se retrouver en clair dans un log, si le code affiche par erreur une variable d'environnement au démarrage, ou si un framework journalise des headers HTTP contenant un tokentokenIAFragment de texte manipulé par un modèle de langage, généralement plus court qu'un mot — trois à quatre caractères en français. La tarification et la limite de contexte se comptent en tokens.Voir dans le glossaire. Aucun mécanisme Kubernetes ne protège contre ce scénario : c'est une discipline de code, pas une configuration de plateforme.
La rotation doit être un processus, pas un événement. Un secret statique jamais renouvelé reste une dette de sécurité croissante : plus il vit longtemps, plus le nombre de systèmes ayant pu y accéder augmente. Les secrets dynamiques de Vault résolvent ce problème par construction ; pour un Secret classique, la rotation doit être planifiée explicitement (changement de la valeur source, propagation via ESO, redémarrage contrôlé des pods).
Un changement de valeur dans un Secret monté en volume est répercuté automatiquement dans le pod par kubelet, généralement en moins d'une minute, sans redémarrage du conteneur. Ce n'est pas le cas d'un Secret monté en variable d'environnement : l'environnement d'un processus est figé au démarrage du conteneur, donc une rotation via variable d'environnement exige un redémarrage explicite du pod pour être prise en compte.
Checklist de durcissement
EncryptionConfigurationest activé sur l'API server, avec un providerkmsv2 adossé à un KMS externe plutôt qu'une clé locale.- Les Secrets préexistants à l'activation du chiffrement ont été réécrits pour être effectivement chiffrés, pas seulement les nouveaux.
- Aucun rôle applicatif n'accorde le verbe
listsursecretssans restriction parresourceNames. - Les secrets consommés en montage volume sont préférés aux variables d'environnement quand une rotation sans redémarrage est souhaitable.
- Les identifiants à privilège élevé (bases de données, comptes cloud) passent par des secrets dynamiques à durée de vie limitée plutôt que par des valeurs statiques.
- Les manifestes commités dans Git ne contiennent jamais de valeur en clair — Sealed Secrets ou équivalent est utilisé pour tout workflow GitOps.
- Les sauvegardes d'etcd sont elles-mêmes chiffrées et soumises au même contrôle d'accès que les secrets qu'elles contiennent.
- Un audit logging est actif sur les verbes d'écriture et de lecture touchant
secrets, avec alerte sur les accèslistinhabituels.
Pièges fréquents
| Piège | Pourquoi c'est dangereux | Remède |
|---|---|---|
| Considérer base64 comme du chiffrement | N'importe qui peut décoder la valeur sans clé ni outil particulier | Documenter explicitement que l'encodage n'est pas une protection, activer le chiffrement au repos |
| Activer EncryptionConfiguration sans réécrire les objets existants | Les secrets créés avant l'activation restent en clair dans etcd | Réécrire systématiquement tous les Secrets après tout changement de configuration de chiffrement |
| Secret injecté en variable d'environnement pour un identifiant à forte sensibilité | Visible dans /proc/<pid>/environ, souvent capturé par des outils d'observabilité ou de crash dump |
Préférer un montage en volume, ou un secret dynamique à durée de vie courte |
| Clé KMS et cluster Kubernetes dans le même compte cloud sans séparation de rôle | Un attaquant qui compromet le compte cloud accède à la fois aux données et à la clé qui les protège | Séparer les permissions IAM du KMS de celles du cluster, appliquer le principe de moindre privilège sur la clé elle-même |
| Secret committé « temporairement » dans Git en clair pour tester | L'historique Git conserve la valeur même après suppression du fichier | Interdire tout secret en clair dans un dépôt via un hook pre-commit ou un scanner dédié, utiliser Sealed Secrets dès le premier commit |
La protection d'un secret ne se résume jamais à un seul mécanisme. Chiffrement au repos, RBAC, rotation et discipline applicative se complètent : retirer l'un des quatre suffit à recréer une brèche, même si les trois autres sont en place.
L'essentiel à retenir
L'objet Secret de Kubernetes encode les valeurs sensibles en base64 mais ne les chiffre pas par défaut, ce qui en fait une protection insuffisante face à un accès à etcd, à une sauvegarde non chiffrée ou à un accès API mal restreint. Ce chapitre détaille le fonctionnement réel des Secrets, la configuration du chiffrement au repos via EncryptionConfiguration et un fournisseur KMS, et les limites que ce chiffrement ne couvre pas. Il présente ensuite les solutions externes les plus utilisées en production — Vault, External Secrets Operator, Sealed Secrets — leurs modèles de menace respectifs, et les pièges d'implémentation les plus fréquents en environnement réel.
Questions fréquentes
Un Secret Kubernetes chiffré au repos est-il suffisant pour être conforme à des exigences réglementaires strictes ?
Faut-il chiffrer aussi les ConfigMaps, ou seulement les Secrets ?
External Secrets Operator introduit-il un point de défaillance supplémentaire ?
Peut-on utiliser Sealed Secrets et External Secrets Operator ensemble ?
Le chiffrement au repos ralentit-il les performances de l'API server ?
Comment détecter qu'un secret a fui dans les logs applicatifs ?
Quelle solution choisir pour une petite équipe qui débute, sans infrastructure Vault existante ?
Progression sauvegardée dans votre navigateur.
Quiz de validation
Quiz Player
Quiz de validation
Plusieurs réponses possibles — validez ensuite.
Vrai ou faux.
Quiz indisponible (données invalides).