Aller au contenu
Conteneurs & Orchestration medium
🔐 Alerte sécurité — Incident supply chain Trivy : lire mon analyse de l'attaque

Secrets Kubernetes : stocker les données sensibles

12 min de lecture

logo kubernetes

Un Secret Kubernetes permet de stocker des données sensibles comme des mots de passe, des clés API, des tokens ou des certificats. Il fournit un conteneur dédié pour ce type d’information, mais sa sécurité dépend surtout du RBAC, du chiffrement au repos et de la manière dont vous l’injectez dans vos Pods.

Ce guide montre comment créer un Secret, choisir son type, l’injecter dans un Pod et appliquer les bonnes pratiques de sécurité.

Prérequis : un cluster Kubernetes avec kubectl configuré.

  • Comprendre ce qu’un Secret protège (et ce qu’il ne protège pas)
  • Créer des Secrets de différents types (Opaque, TLS, docker-registry)
  • Injecter les Secrets dans vos Pods (env ou volume)
  • Appliquer les bonnes pratiques de sécurité essentielles
  • Décider quand passer à un gestionnaire de secrets externe

Ce qu’un Secret apporte de plus qu’un ConfigMap

Section intitulée « Ce qu’un Secret apporte de plus qu’un ConfigMap »

Un Secret Kubernetes est pensé pour des données sensibles, mais il ne devient réellement sûr que si vous mettez en place les bonnes protections autour :

  • Contrôle d’accès strict avec RBAC
  • Chiffrement au repos dans etcd
  • Limitation des accès API
  • Montage en volume plutôt qu’en variables d’environnement lorsque c’est pertinent

Par défaut, un Secret reste lisible par toute identité autorisée à le récupérer via l’API Kubernetes.

C’est le piège le plus courant. Beaucoup pensent que l’encodage base64 protège leurs données. C’est faux.

Fenêtre de terminal
# Créer un Secret
kubectl create secret generic demo-secret --from-literal=password='S3cr3t!P@ss'
# Voir le Secret "protégé"
kubectl get secret demo-secret -o jsonpath='{.data.password}'
Sortie
UzNjcjN0IVBAc3M=
Fenêtre de terminal
# Décoder en une commande
echo 'UzNjcjN0IVBAc3M=' | base64 -d
Sortie
S3cr3t!P@ss

Le décodage est instantané. Base64 sert uniquement à transporter des données binaires dans du YAML/JSON, pas à les protéger.

Kubernetes propose plusieurs types de Secrets, chacun avec une structure adaptée :

TypeUsageClés créées
OpaqueUsage générique (mots de passe, tokens)Libres
kubernetes.io/tlsCertificats TLStls.crt, tls.key
kubernetes.io/dockerconfigjsonAuthentification registry.dockerconfigjson
kubernetes.io/basic-authAuthentification HTTP basiqueusername, password
kubernetes.io/ssh-authClé SSHssh-privatekey

La méthode la plus simple pour des identifiants :

Fenêtre de terminal
kubectl create secret generic db-credentials \
--from-literal=username=admin \
--from-literal=password='S3cr3t!P@ss'

Vérifiez la création :

Fenêtre de terminal
kubectl get secret db-credentials
Sortie
NAME TYPE DATA AGE
db-credentials Opaque 2 5s

Pour stocker un certificat et sa clé privée :

Fenêtre de terminal
kubectl create secret tls my-tls-secret \
--cert=server.crt \
--key=server.key
Fenêtre de terminal
kubectl get secret my-tls-secret
Sortie
NAME TYPE DATA AGE
my-tls-secret kubernetes.io/tls 2 5s

Pour s’authentifier auprès d’un registre privé :

Fenêtre de terminal
kubectl create secret docker-registry my-registry \
--docker-server=registry.example.com \
--docker-username=myuser \
--docker-password=mypassword

Utilisez-le dans un Pod avec imagePullSecrets :

spec:
imagePullSecrets:
- name: my-registry
containers:
- name: app
image: registry.example.com/myapp:latest

Pour un contrôle total et la gestion en GitOps :

secret.yaml
apiVersion: v1
kind: Secret
metadata:
name: db-credentials
type: Opaque
data:
username: YWRtaW4= # echo -n 'admin' | base64
password: UzNjcjN0IVBAc3M= # echo -n 'S3cr3t!P@ss' | base64

Vous pouvez aussi utiliser stringData pour éviter l’encodage manuel :

secret-stringdata.yaml
apiVersion: v1
kind: Secret
metadata:
name: db-credentials
type: Opaque
stringData:
username: admin
password: S3cr3t!P@ss

Kubernetes convertit automatiquement stringData en data encodé.

Deux méthodes principales, chacune avec ses cas d’usage :

MéthodeCas d’usageMise à jour auto
Variable d’environnementIdentifiants simplesNon
VolumeCertificats, fichiers de configOui (~60s)
deployment-secret-env.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: myapp
spec:
replicas: 1
selector:
matchLabels:
app: myapp
template:
metadata:
labels:
app: myapp
spec:
containers:
- name: app
image: nginx
env:
- name: DB_USERNAME
valueFrom:
secretKeyRef:
name: db-credentials
key: username
- name: DB_PASSWORD
valueFrom:
secretKeyRef:
name: db-credentials
key: password

Vérifiez l’injection :

Fenêtre de terminal
kubectl exec deploy/myapp -- env | grep DB_
Sortie
DB_USERNAME=admin
DB_PASSWORD=S3cr3t!P@ss

Les valeurs sont décodées automatiquement dans le conteneur.

Recommandé pour les certificats et fichiers de configuration :

deployment-secret-volume.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: myapp
spec:
selector:
matchLabels:
app: myapp
template:
metadata:
labels:
app: myapp
spec:
containers:
- name: app
image: nginx
volumeMounts:
- name: secret-volume
mountPath: /etc/secrets
readOnly: true
volumes:
- name: secret-volume
secret:
secretName: db-credentials
defaultMode: 0400

Vérifiez les fichiers montés :

Fenêtre de terminal
kubectl exec deploy/myapp -- ls -la /etc/secrets
Sortie
lrwxrwxrwx 1 root root 15 password -> ..data/password
lrwxrwxrwx 1 root root 15 username -> ..data/username

Les liens symboliques permettent la mise à jour automatique (~60s de délai).

volumes:
- name: secret-volume
secret:
secretName: db-credentials
items:
- key: password
path: db-password

Le fichier /etc/secrets/db-password contient uniquement le mot de passe.

Par défaut, tout utilisateur avec get sur les Secrets peut les lire. Créez des Roles restrictifs :

role-secrets-readonly.yaml
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
name: secret-reader
namespace: production
rules:
- apiGroups: [""]
resources: ["secrets"]
resourceNames: ["db-credentials"] # Limiter aux Secrets nécessaires
verbs: ["get"]

Par défaut, Kubernetes stocke les Secrets en clair dans etcd. Activez le chiffrement au repos :

encryption-config.yaml (sur le control plane)
apiVersion: apiserver.config.k8s.io/v1
kind: EncryptionConfiguration
resources:
- resources:
- secrets
providers:
- aescbc:
keys:
- name: key1
secret: <base64-encoded-32-byte-key>
- identity: {}

3. Préférer le montage volume aux variables d’environnement

Section intitulée « 3. Préférer le montage volume aux variables d’environnement »
AspectVariable envVolume
Visible dans docker inspectOuiNon
Visible dans /proc/<pid>/environOuiNon
Mise à jour automatiqueNonOui

Le montage en volume est souvent préférable pour limiter certaines expositions accidentelles et bénéficier de mises à jour automatiques, mais il ne remplace ni un bon cloisonnement des accès ni un durcissement du runtime. Si le conteneur est compromis, les fichiers montés restent accessibles au processus.

Fenêtre de terminal
# Mettre à jour le Secret
kubectl create secret generic db-credentials \
--from-literal=username=admin \
--from-literal=password='N0uv3@uP@ss!' \
--dry-run=client -o yaml | kubectl apply -f -
# Redémarrer les Pods pour appliquer
kubectl rollout restart deployment myapp

Les Secrets Kubernetes natifs ont des limites :

LimiteImpact
Pas de rotation automatiqueVous devez mettre à jour manuellement
Pas d’audit détailléQui a accédé à quel Secret ?
Chiffrement etcd à configurerPas activé par défaut
Secrets visibles en YAMLRisque de commit accidentel

Utilisez un gestionnaire externe si vous avez besoin de :

  • Rotation automatique des secrets
  • Audit détaillé des accès
  • Intégration avec des secrets existants (AWS, Azure, GCP)
  • Secrets dynamiques (credentials de BDD à durée limitée)

Solutions recommandées :

  • HashiCorp Vault avec External Secrets ou Vault Sidecar
  • AWS Secrets Manager / Azure Key Vault / GCP Secret Manager
  • Sealed Secrets pour chiffrer les Secrets dans Git
  1. Le Secret existe-t-il ?

    Fenêtre de terminal
    kubectl get secret db-credentials

    Si “NotFound”, créez-le d’abord.

  2. La clé existe-t-elle dans le Secret ?

    Fenêtre de terminal
    kubectl get secret db-credentials -o jsonpath='{.data}'

    Vérifiez l’orthographe exacte de la clé.

  3. Le Pod référence-t-il le bon Secret ?

    Fenêtre de terminal
    kubectl describe pod myapp-xxx | grep -A5 "Environment\|Mounts"
  4. Erreur CreateContainerConfigError ?

    Secret ou clé introuvable. Vérifiez que le Secret existe dans le même namespace que le Pod.

ErreurCauseSolution
CreateContainerConfigErrorSecret ou clé introuvableVérifier nom et namespace
Variable videClé mal orthographiéekubectl get secret -o yaml
unauthorizedRBAC insuffisantVérifier les permissions
  1. Un Secret stocke les données sensibles, mais base64 n’est pas du chiffrement
  2. Les types de Secrets (Opaque, TLS, docker-registry) structurent vos données
  3. Variables d’environnement : simples mais jamais rafraîchies automatiquement
  4. Volumes : préférables pour la sécurité et la mise à jour automatique
  5. RBAC est votre première ligne de défense — restreignez l’accès aux Secrets
  6. Chiffrement etcd : activez-le pour protéger les Secrets au repos
  7. Pour la rotation automatique ou l’audit, passez à un gestionnaire externe

Ce site vous est utile ?

Sachez que moins de 1% des lecteurs soutiennent ce site.

Je maintiens +700 guides gratuits, sans pub ni tracing. Aujourd'hui, ce site ne couvre même pas mes frais d'hébergement, d'électricité, de matériel, de logiciels, mais surtout de cafés.

Un soutien régulier, même symbolique, m'aide à garder ces ressources gratuites et à continuer de produire des guides de qualité. Merci pour votre appui.

Abonnez-vous et suivez mon actualité DevSecOps sur LinkedIn