La gestion efficace des configurations et des données sensibles est un pilier fondamental de toute architecture cloud-native. Ce module explore les mécanismes de Kubernetes pour séparer les données de configuration de la logique applicative, garantissant ainsi la portabilité, la sécurité et la maintenabilité de vos applications.
Séparer la configuration du code :
Configuration Kubernetes
├── ConfigMap
│ ├── Données non sensibles
│ ├── Fichiers de configuration
│ └── Variables d'environnement
└── Secret
├── Données sensibles (mots de passe, tokens, clés)
├── Certificats TLS
└── Clés de registre Docker
Une ConfigMap est un objet API Kubernetes conçu pour découpler la configuration de l'application de son image container. Elle stocke des données non sensibles sous forme de paires clé-valeur.
apiVersion: v1
kind: ConfigMap
metadata:
name: app-config
namespace: default
labels:
app: mon-application
version: "1.0"
data:
# Clé-valeur simple
DATABASE_URL: "postgresql://db.example.com:5432"
LOG_LEVEL: "info"
MAX_CONNECTIONS: "100"
FEATURE_FLAG_X: "enabled"
# Contenu de fichier complet
nginx.conf: |
events {
worker_connections 1024;
}
http {
server {
listen 80;
server_name localhost;
location / {
return 200 'Hello from ConfigMap!';
add_header Content-Type text/plain;
}
}
}
config.json: |
{
"database": {
"host": "db.example.com",
"port": 5432,
"retries": 5
},
"logging": {
"level": "info",
"format": "json"
},
"features": {
"enableMetrics": true,
"enableTracing": false
}
}
# Depuis des valeurs littérales
kubectl create configmap app-config \
--from-literal=DATABASE_URL=postgresql://db.example.com:5432 \
--from-literal=LOG_LEVEL=info
# Depuis des fichiers
kubectl create configmap app-config \
--from-file=config.json \
--from-file=nginx.conf
# Depuis un répertoire
kubectl create configmap app-config \
--from-file=./config/
# Depuis des variables d'environnement
kubectl create configmap app-config \
--from-env-file=.env
apiVersion: v1
kind: Pod
metadata:
name: app-avec-env-vars
spec:
containers:
- name: application
image: nginx:1.29.5
env:
# Variable depuis une clé spécifique
- name: DATABASE_HOST
valueFrom:
configMapKeyRef:
name: app-config
key: DATABASE_URL
# Variable avec nom différent
- name: APP_LOG_LEVEL
valueFrom:
configMapKeyRef:
name: app-config
key: LOG_LEVEL
apiVersion: v1
kind: Pod
metadata:
name: app-avec-toutes-env-vars
spec:
containers:
- name: application
image: nginx:1.29.5
envFrom:
# Importer toutes les clés de la ConfigMap
- configMapRef:
name: app-config
# Optionnel : préfixer les noms des variables
- configMapRef:
name: app-config
prefix: "APP_"
apiVersion: v1
kind: Pod
metadata:
name: app-avec-volumes
spec:
containers:
- name: nginx
image: nginx:1.29.5
volumeMounts:
# Monter toute la ConfigMap
- name: config-volume
mountPath: /etc/nginx # Attention le montage écrase tous les fichiers/dossiers distant
readOnly: true
# Monter des clés spécifiques avec des noms personnalisés
- name: app-config-volume
mountPath: /app/config
readOnly: true
volumes:
- name: config-volume
configMap:
name: app-config
# Spécifier les permissions des fichiers
defaultMode: 0644
- name: app-config-volume
configMap:
name: app-config
items:
- key: config.json
path: application.json
- key: nginx.conf
path: nginx/default.conf
mode: 0755
apiVersion: apps/v1
kind: Deployment
metadata:
name: app-deployment
spec:
replicas: 3
selector:
matchLabels:
app: mon-application
template:
metadata:
labels:
app: mon-application
spec:
containers:
- name: application
image: mon-app:v1.0
env:
- name: DATABASE_URL
valueFrom:
configMapKeyRef:
name: app-config
key: DATABASE_URL
volumeMounts:
- name: config-files
mountPath: /etc/app/
volumes:
- name: config-files
configMap:
name: app-config
Les Secrets sont similaires aux ConfigMaps mais sont destinés à stocker des données sensibles, telles que des mots de passe, des jetons OAuth ou des clés SSH. Les données d'un Secret sont stockées en base64, mais il est important de noter que ce n'est pas un chiffrement, c'est un encodage. Des mécanismes supplémentaires comme RBAC ou des solutions comme Sealed Secrets sont nécessaires pour une sécurité renforcée.
Kubernetes propose plusieurs types de Secrets prédéfinis :
| Type | Usage | Exemple |
|---|---|---|
Opaque |
Données arbitraires (par défaut) | Mots de passe, tokens API |
kubernetes.io/service-account-token |
Token de compte de service | Généré automatiquement |
kubernetes.io/dockercfg |
Config Docker sérialisée | Accès aux registres privés |
kubernetes.io/dockerconfigjson |
Config Docker JSON | Accès aux registres privés |
kubernetes.io/basic-auth |
Authentification basique | Username/password |
kubernetes.io/ssh-auth |
Authentification SSH | Clés SSH privées |
kubernetes.io/tls |
Données TLS | Certificats et clés privées |
# Secret Opaque depuis des valeurs littérales
kubectl create secret generic db-credentials \
--from-literal=username=admin \
--from-literal=password=motdepasse123
# Secret depuis des fichiers
echo -n 'admin' > username.txt
echo -n 'motdepasse123' > password.txt
kubectl create secret generic db-file-credentials \
--from-file=username.txt \
--from-file=password.txt
# Secret TLS depuis des certificats
kubectl create secret tls tls-secret \
--cert=server.crt \
--key=server.key
# Secret pour registre Docker
kubectl create secret docker-registry regcred \
--docker-server=registry.exemple.com \
--docker-username=utilisateur \
--docker-password=motdepasse \
[email protected]
apiVersion: v1
kind: Secret
metadata:
name: db-credentials
namespace: default
labels:
app: database
type: Opaque
data:
# Les valeurs DOIVENT être encodées en base64
username: YWRtaW4= # "admin" en base64
password: bW90ZGVwYXNzZTEyMw== # "motdepasse123" en base64
database-url: cG9zdGdyZXNxbDovL2FkbWluOm1vdGRlcGFzc2UxMjNAZGI6NTQzMi9hcHBkYg==
---
apiVersion: v1
kind: Secret
metadata:
name: api-keys
type: Opaque
stringData:
# stringData permet d'utiliser du texte brut (encodé automatiquement)
api-key: "sk-1234567890abcdef"
webhook-secret: "mon-secret-webhook"
jwt-secret: "cle-tres-secrete-pour-jwt"
apiVersion: v1
kind: Secret
metadata:
name: tls-secret
type: kubernetes.io/tls
data:
# Certificat encodé en base64
tls.crt: LS0tLS1CRUdJTi...
# Clé privée encodée en base64
tls.key: LS0tLS1CRUdJTi...
apiVersion: v1
kind: Pod
metadata:
name: app-avec-secrets
spec:
containers:
- name: application
image: postgres:13
env:
# Variable depuis un Secret
- name: POSTGRES_USER
valueFrom:
secretKeyRef:
name: db-credentials
key: username
- name: POSTGRES_PASSWORD
valueFrom:
secretKeyRef:
name: db-credentials
key: password
# Importer tout le Secret
envFrom:
- secretRef:
name: api-keys
apiVersion: v1
kind: Pod
metadata:
name: app-avec-secret-volumes
spec:
containers:
- name: nginx
image: nginx:1.29.5
volumeMounts:
# Monter le Secret TLS
- name: tls-volume
mountPath: /etc/nginx/ssl
readOnly: true
# Monter les credentials
- name: db-creds
mountPath: /etc/db-credentials
readOnly: true
volumes:
- name: tls-volume
secret:
secretName: tls-secret
defaultMode: 0400 # Permissions restrictives
- name: db-creds
secret:
secretName: db-credentials
items:
- key: username
path: db-user
mode: 0400
- key: password
path: db-pass
mode: 0400
apiVersion: v1
kind: Pod
metadata:
name: app-registre-prive
spec:
containers:
- name: app
image: registry.exemple.com/mon-app:latest
# Secret pour accéder au registre privé
imagePullSecrets:
- name: regcred
# Création des environnements
kubectl create namespace dev
kubectl create namespace staging
kubectl create namespace prod
# ConfigMaps spécifiques par environnement
kubectl create configmap app-config --from-literal=LOG_LEVEL=debug -n dev
kubectl create configmap app-config --from-literal=LOG_LEVEL=info -n staging
kubectl create configmap app-config --from-literal=LOG_LEVEL=warn -n prod
Principe : Même nom de ConfigMap, valeurs différentes par namespace.
| Critère | Variables d'environnement | Fichiers en volume |
|---|---|---|
| Simplicité | ✅ Très simple | ⚠️ Plus complexe |
| Rechargement à chaud | ❌ Nécessite redémarrage | ✅ Automatique (1-2 min) |
| Taille des données | ⚠️ Limitée | ✅ Fichiers volumineux |
| Sécurité | ⚠️ Visible dans ps |
✅ Permissions fichiers |
| Formatage | ❌ Texte simple uniquement | ✅ JSON, YAML, XML, etc. |
| Usage recommandé | Configurations simples | Fichiers de config complets |
⚠️ ATTENTION : L'encodage base64 n'est PAS du chiffrement !
Les Secrets Kubernetes sont stockés en base64 dans etcd et peuvent être décodés par toute personne ayant accès au cluster.
# Limitation d'accès avec RBAC
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
namespace: production
name: secret-reader
rules:
- apiGroups: [""]
resources: ["secrets"]
verbs: ["get", "list"]
resourceNames: ["app-secrets"] # Limité à des Secrets spécifiques
Sealed Secrets
Sealed Secrets permettent de chiffrer les Secrets de manière sécurisée pour le stockage dans Git :
# Installation du contrôleur
kubectl apply -f https://github.com/bitnami-labs/sealed-secrets/releases/download/v0.32.2/controller.yaml
# Installation de kubeseal
wget https://github.com/bitnami-labs/sealed-secrets/releases/download/v0.32.2/kubeseal-0.32.2-linux-amd64.tar.gz && tar -xvf kubeseal-0.32.2-linux-amd64.tar.gz && mv kubeseal /bin
# Création d'un SealedSecret
kubectl create secret generic monsecret \
--from-literal=username=admin \
--from-literal=password=SuperSecret123 \
-o yaml --dry-run=client > mysecret.yaml
cat mysecret.yaml | kubeseal -o yaml > mysealedsecret.yaml
# Déploiement sécurisé
kubectl apply -f mysealedsecret.yaml
Autres solutions open source :
# Mettre à jour une ConfigMap (ouvre un éditeur)
kubectl edit configmap app-config
# Modifier les valeurs dans l'éditeur, puis sauvegarder
# L'application recevra la nouvelle valeur automatiquement (1-2 min)
# Si utilisation en volume, sinon redémarrage requis :
kubectl rollout restart deployment mon-app
# Mettre à jour un Secret (ouvre un éditeur)
kubectl edit secret db-credentials
# Modifier les valeurs en base64 dans l'éditeur, puis sauvegarder
# Ou recréer le Secret (plus simple)
kubectl delete secret db-credentials
kubectl create secret generic db-credentials \
--from-literal=username=admin \
--from-literal=password=nouveau-mot-de-passe
# Redémarrer pour utiliser le nouveau secret
kubectl rollout restart deployment mon-app
Astuce : kubectl edit ouvre votre éditeur par défaut (vim, nano...) et applique automatiquement les changements à la sauvegarde.
# Lister toutes les ConfigMaps et Secrets
kubectl get configmaps,secrets
# Détailler une ConfigMap
kubectl describe configmap mon-config
# Voir le contenu décodé d'un Secret
kubectl get secret mon-secret -o jsonpath='{.data.password}' | base64 -d
# Vérifier quelles ressources utilisent une ConfigMap/Secret
kubectl get pods -o json | jq '.items[] | select(.spec.volumes[]?.configMap.name=="mon-config" or .spec.containers[].env[]?.valueFrom.configMapKeyRef.name=="mon-config") | .metadata.name'
# Surveiller les changements de configuration
kubectl get events --field-selector involvedObject.kind=ConfigMap
| Problème | Symptomes | Solution |
|---|---|---|
| Secret non monté | Pod en erreur, volumes vides | Vérifier l'existence du Secret, permissions RBAC |
| Encodage base64 incorrect | Caractères corrompus | Utiliser stringData ou vérifier l'encodage |
| Configuration non mise à jour | Anciens paramètres actifs | Attendre 1-2 min ou redémarrer le Pod |
| Taille limite dépassée | Erreur "too large" | Diviser en plusieurs ConfigMaps ou utiliser des volumes |
| Accès refusé | Erreur "forbidden" | Vérifier les permissions RBAC et ServiceAccount |
kubectl create pour les Secrets (pas de traces en ligne de commande)kubectl get -o yaml sans précautionsPoints clés à retenir :
TP associé : TP 6 : ConfigMaps et Secrets