CKAD - Configuration, Secrets et Sécurité
🎯 Objectifs
Dans ce module, tu vas :
- ✅ Comprendre et utiliser ConfigMaps et Secrets
- ✅ Injecter de la configuration dans tes Pods
- ✅ Gérer les données sensibles (mots de passe, tokens)
- ✅ Configurer les Security Contexts
- ✅ Comprendre les bases du RBAC (Service Accounts, Roles)
- ✅ Mettre en place des Pod Security Standards
📋 Prérequis
- Module Kubernetes - Intermédiaire complété
- Module CKAD - Préparation lu
- Module CKAD - Applications complété
📖 Pourquoi ce module ?
C'est le domaine le plus important de la CKAD : 25% de la note. Comment tu configures tes applications, comment tu gères tes secrets et comment tu les sécurises.
En tant que développeur, tu dois savoir :
- Injecter de la configuration sans la hardcoder
- Gérer les secrets sans risque
- Limiter les permissions (principe du moindre privilège)
- Empêcher les mauvaises configurations de sécurité
🔧 ConfigMaps : Externaliser la Configuration
Problème
Tu as une app qui a besoin de configuration (URL de BD, log level, etc.). Où la mettre ?
- En dur dans le code ? ❌ Non - tu dois reconstruire l'image pour chaque env
- En variable d'env dans le Pod ? ❌ Non - c'est pas versionné, c'est perdu au redémarrage
- Dans un ConfigMap ? ✅ Oui - externalise la config du code
Créer une ConfigMap
Mode impératif :
# À partir de valeurs
k create configmap app-config --from-literal=LOG_LEVEL=info --from-literal=DB_HOST=db.local
# À partir d'un fichier
echo "LOG_LEVEL=debug" > config.env
k create configmap app-config --from-env-file=config.env
# À partir d'un fichier entier
k create configmap app-config --from-file=config.yamlMode déclaratif :
apiVersion: v1
kind: ConfigMap
metadata:
name: app-config
data:
# Simple key-value
LOG_LEVEL: info
DB_HOST: db.local
DB_PORT: "5432"
# Fichier entier
application.yaml: |
server:
port: 8080
timeout: 30s
database:
host: db.local
pool_size: 10Injecter un ConfigMap dans un Pod
Variable d'environnement :
apiVersion: v1
kind: Pod
metadata:
name: myapp
spec:
containers:
- name: myapp
image: myapp:1.0
env:
- name: LOG_LEVEL
valueFrom:
configMapKeyRef:
name: app-config
key: LOG_LEVEL
- name: DB_HOST
valueFrom:
configMapKeyRef:
name: app-config
key: DB_HOST
# Ou charger TOUS les clés en une fois
envFrom:
- configMapRef:
name: app-configVolume (pour un fichier de config) :
apiVersion: v1
kind: Pod
metadata:
name: myapp
spec:
containers:
- name: myapp
image: myapp:1.0
volumeMounts:
- name: config
mountPath: /etc/config
volumes:
- name: config
configMap:
name: app-config
# Ou des fichiers spécifiques
items:
- key: application.yaml
path: app.yaml🔐 Secrets : Gérer les Données Sensibles
Problème
Tu as besoin de stocker des mots de passe, tokens, clés API, etc. Les ConfigMaps ne conviennent pas (elles ne sont pas chiffrées par défaut).
Utilise des Secrets.
Créer un Secret
Mode impératif :
# Générique
k create secret generic db-secret --from-literal=password=mysecretpassword
# Docker Registry (pour les images privées)
k create secret docker-registry ghcr-secret \
--docker-server=ghcr.io \
--docker-username=myuser \
--docker-password=mytoken
# TLS/HTTPS
k create secret tls tls-secret \
--cert=path/to/cert.pem \
--key=path/to/key.pemMode déclaratif :
apiVersion: v1
kind: Secret
metadata:
name: db-secret
type: Opaque
stringData:
# stringData = lisible (encodé en base64 à la création)
username: admin
password: secretpassword
---
apiVersion: v1
kind: Secret
metadata:
name: tls-secret
type: kubernetes.io/tls
data:
# data = base64 (manuel)
tls.crt: LS0tLS1CRUdJTi... # base64 encodé
tls.key: LS0tLS1CRUdJTi...Types de Secrets
| Type | Utilisation |
|---|---|
Opaque | Données génériques (défaut) |
kubernetes.io/dockercfg | Authentification Docker (deprecated) |
kubernetes.io/dockercfg-json | Authentification Docker Registry |
kubernetes.io/basic-auth | Authentification HTTP Basic |
kubernetes.io/ssh-auth | Authentification SSH |
kubernetes.io/tls | Certificats TLS |
bootstrap.kubernetes.io/token | Token de bootstrap |
Injecter un Secret dans un Pod
Variable d'environnement :
apiVersion: v1
kind: Pod
metadata:
name: myapp
spec:
containers:
- name: myapp
image: myapp:1.0
env:
- name: DB_PASSWORD
valueFrom:
secretKeyRef:
name: db-secret
key: password
envFrom:
- secretRef:
name: db-secretVolume (fichiers) :
apiVersion: v1
kind: Pod
metadata:
name: myapp
spec:
containers:
- name: myapp
image: myapp:1.0
volumeMounts:
- name: secrets
mountPath: /etc/secrets
readOnly: true
volumes:
- name: secrets
secret:
secretName: db-secretImaginer les secrets dans le filesystem :
/etc/secrets/
├── username (contient "admin")
└── password (contient "secretpassword")Utiliser un Secret pour les images Docker privées
apiVersion: v1
kind: Pod
metadata:
name: myapp
spec:
imagePullSecrets:
- name: ghcr-secret # Créé avec k create secret docker-registry
containers:
- name: myapp
image: ghcr.io/myorg/myapp:1.0👤 RBAC : Role-Based Access Control
Problème
Tu veux qu'une app n'ait accès qu'à ce dont elle a besoin (principe du moindre privilège). Par défaut, une app dans un Pod peut faire n'importe quoi dans le cluster.
Les 3 concepts
- ServiceAccount : Une identité pour ton app
- Role/ClusterRole : Une liste de permissions
- RoleBinding/ClusterRoleBinding : Lie l'identité aux permissions
Créer un ServiceAccount
# Mode impératif
k create serviceaccount myapp-sa
# Mode déclaratif
apiVersion: v1
kind: ServiceAccount
metadata:
name: myapp-saCréer une Role (pour un namespace)
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
name: pod-reader
spec:
rules:
- apiGroups: [""]
resources: ["pods"]
verbs: ["get", "list", "watch"]
- apiGroups: [""]
resources: ["pods/logs"]
verbs: ["get"]Lier le Role au ServiceAccount (RoleBinding)
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
name: read-pods
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: Role
name: pod-reader
subjects:
- kind: ServiceAccount
name: myapp-sa
namespace: defaultUtiliser le ServiceAccount dans un Pod
apiVersion: v1
kind: Pod
metadata:
name: myapp
spec:
serviceAccountName: myapp-sa
containers:
- name: myapp
image: myapp:1.0Verbes RBAC courants
| Verbe | Signification |
|---|---|
get | Récupérer une ressource |
list | Lister les ressources |
watch | Observer les changements |
create | Créer une ressource |
update | Modifier une ressource |
patch | Modifier partiellement |
delete | Supprimer une ressource |
* | Tous les verbes |
🔒 Security Contexts
Problème
Par défaut, un conteneur peut tourner en root, accéder au système de fichiers, etc. Ce n'est pas sûr.
Les Security Contexts te permettent de restreindre ce que le conteneur peut faire.
Exemple simple
apiVersion: v1
kind: Pod
metadata:
name: secure-app
spec:
securityContext:
runAsNonRoot: true # Ne pas tourner en root
runAsUser: 1000 # Tourner en tant qu'user 1000
fsGroup: 2000 # Groupe pour les fichiers
containers:
- name: myapp
image: myapp:1.0
securityContext:
allowPrivilegeEscalation: false # Pas d'escalade de privilèges
readOnlyRootFilesystem: true # /
est read-only
capabilities:
drop:
- ALL # Supprimer TOUTES les Linux capabilities
add:
- NET_BIND_SERVICE # Ajouter que ce qu'il faut (rare)Options courantes
| Option | Effet |
|---|---|
runAsUser | UID pour tourner le conteneur |
runAsNonRoot | Interdire root (true = safe) |
fsGroup | Propriétaire des volumes |
allowPrivilegeEscalation | Interdire sudo (false = safe) |
readOnlyRootFilesystem | / est read-only (true = safe) |
privileged | Mode privilégié (false = safe) |
capabilities | Linux capabilities |
🛡️ Pod Security Standards
Les Pod Security Standards remplacent les Pod Security Policies (deprecated). Ce sont des ensembles de recommandations de sécurité.
Trois niveaux
| Niveau | Sévérité | Utilisation |
|---|---|---|
restricted | Maximum | Production, données sensibles |
baseline | Défaut | Plupart des apps |
privileged | Minimal | Apps spéciales (Kubernetes system) |
Appliquer une Pod Security Policy
apiVersion: v1
kind: Namespace
metadata:
name: production
labels:
pod-security.kubernetes.io/enforce: restricted
pod-security.kubernetes.io/audit: restricted
pod-security.kubernetes.io/warn: restrictedCela force tous les Pods du namespace à respecter les règles restricted.
🔧 Exemple complet : App sécurisée et configurée
---
apiVersion: v1
kind: Namespace
metadata:
name: myapp-ns
labels:
pod-security.kubernetes.io/enforce: baseline
---
apiVersion: v1
kind: ConfigMap
metadata:
name: app-config
namespace: myapp-ns
data:
LOG_LEVEL: info
API_TIMEOUT: "30"
---
apiVersion: v1
kind: Secret
metadata:
name: app-secrets
namespace: myapp-ns
stringData:
DB_PASSWORD: secretpassword123
API_KEY: sk-1234567890
---
apiVersion: v1
kind: ServiceAccount
metadata:
name: myapp-sa
namespace: myapp-ns
---
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
name: myapp-reader
namespace: myapp-ns
rules:
- apiGroups: [""]
resources: ["configmaps"]
verbs: ["get"]
- apiGroups: [""]
resources: ["secrets"]
verbs: ["get"]
---
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
name: myapp-reader-binding
namespace: myapp-ns
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: Role
name: myapp-reader
subjects:
- kind: ServiceAccount
name: myapp-sa
namespace: myapp-ns
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: myapp
namespace: myapp-ns
spec:
replicas: 2
selector:
matchLabels:
app: myapp
template:
metadata:
labels:
app: myapp
spec:
serviceAccountName: myapp-sa
securityContext:
runAsNonRoot: true
runAsUser: 1000
fsGroup: 2000
containers:
- name: myapp
image: myapp:1.0
ports:
- containerPort: 8080
env:
- name: LOG_LEVEL
valueFrom:
configMapKeyRef:
name: app-config
key: LOG_LEVEL
- name: DB_PASSWORD
valueFrom:
secretKeyRef:
name: app-secrets
key: DB_PASSWORD
securityContext:
allowPrivilegeEscalation: false
readOnlyRootFilesystem: true
capabilities:
drop:
- ALL
resources:
requests:
cpu: 100m
memory: 128Mi
limits:
cpu: 500m
memory: 512Mi📊 Résumé
| Concept | Utilisation | Sensibilité |
|---|---|---|
| ConfigMap | Configuration non-sensible | Public |
| Secret | Données sensibles | Privé |
| ServiceAccount | Identité pour l'app | Normal |
| Role | Permissions limitées | Normal |
| Security Context | Restrictions conteneur | Normal |
| Pod Security Standard | Politique de sécurité | Normal |
🚀 Prochaines Étapes
- CKAD : Services et Networking - Services, Ingress et DNS
- CKAD : Volumes et Persistance - Stockage et données persistantes