Aller au contenu

Module 3d · Sécurité

Objectifs

  • Durcir un pod : securityContext, non-root, capabilities, lecture seule.
  • Cloisonner le réseau avec les NetworkPolicies (deny par défaut).
  • Aller plus loin sur le RBAC (least privilege, ServiceAccounts).
  • Connaître les bonnes pratiques images/secrets et savoir auditer (:popeye).
  • Durée : ~2 h · Pré-requis : Module 3c.

1. Durcir le pod — securityContext

Par défaut, un conteneur tourne souvent en root : à éviter.

yaml spec: securityContext: runAsNonRoot: true runAsUser: 10001 fsGroup: 10001 containers: - name: app image: monapp:1.0 securityContext: allowPrivilegeEscalation: false readOnlyRootFilesystem: true capabilities: drop: ["ALL"] # on retire tout, on rajoute le strict nécessaire

Réglage Pourquoi
runAsNonRoot empêche l'exécution en root
readOnlyRootFilesystem le conteneur ne peut pas se modifier (limite la persistance d'un attaquant)
drop: ["ALL"] retire toutes les capabilities Linux superflues
allowPrivilegeEscalation: false bloque l'escalade via setuid

2. Cloisonner le réseau — NetworkPolicy

Par défaut, tout pod peut parler à tout pod. Une NetworkPolicy restreint ce trafic. Le motif sain : tout interdire, puis autoriser au cas par cas.

```yaml

Deny par défaut tout le trafic ENTRANT du namespace

apiVersion: networking.k8s.io/v1 kind: NetworkPolicy metadata: name: default-deny-ingress spec: podSelector: {} # tous les pods policyTypes: ["Ingress"] ```

```yaml

Puis autoriser : seuls les pods "front" peuvent joindre les pods "api" sur 8080

apiVersion: networking.k8s.io/v1 kind: NetworkPolicy metadata: name: front-vers-api spec: podSelector: matchLabels: { app: api } ingress: - from: - podSelector: matchLabels: { app: front } ports: - port: 8080 ```

Le CNI doit supporter les NetworkPolicies

Les NetworkPolicies ne font effet que si le plugin réseau les implémente (Calico, Cilium…). Sur certains clusters de lab/vcluster, elles peuvent être ignorées silencieusement : teste toujours l'effet réel (cf. exercice).

3. RBAC — least privilege

Rappel du module 3, version sécurité : on donne le minimum.

  • Un ServiceAccount dédié par application (jamais default).
  • Un Role namespacé plutôt qu'un ClusterRole quand c'est possible.
  • On vérifie toujours :

bash kubectl auth can-i --list --as=system:serviceaccount:demo:monapp kubectl auth can-i delete pods --as=system:serviceaccount:demo:monapp -n demo

text :rbac ← inspecter les règles RBAC dans k9s

4. Images & secrets

  • Images : tag fixe (pas latest), idéalement digest, base slim/distroless.
  • Scanner les images (Trivy, Grype) en CI avant déploiement.
  • Secrets : jamais en clair dans un manifest ; un Secret k8s est seulement base64 (≠ chiffré) → chiffrer au repos (etcd) et/ou utiliser un gestionnaire externe (Sealed Secrets, Vault, SOPS).

5. Auditer le cluster — Popeye

text :popeye ← audit : pods sans limits, en root, RBAC trop large, images en latest…

C'est l'outil idéal pour mesurer l'effet des bonnes pratiques de ce module : on audite, on corrige, on ré-audite, le score monte.

6. Exercices

Exercice 3d.1 — Non-root

  1. Déploie un nginx standard, exec dedans, id → tu es root.
  2. Ajoute un securityContext runAsNonRoot: true + runAsUser : le pod refuse de démarrer (image nginx veut root). Comprends pourquoi, puis utilise nginxinc/nginx-unprivileged.

Exercice 3d.2 — Deny par défaut

  1. Déploie deux pods front et api (+ Service api). Vérifie que front joint api (wget).
  2. Applique default-deny-ingress : front ne joint plus api.
  3. Ajoute front-vers-api : la communication revient, uniquement depuis front.
  4. (Si rien ne change après le deny : ton CNI n'applique pas les NetworkPolicies — note-le.)

Exercice 3d.3 — Audit

Lance :popeye, corrige deux findings (ex. limits manquantes, image latest), ré-audite.

7. Ce qu'il faut retenir

  • Non-root + drop capabilities + rootfs en lecture seule = base du durcissement pod.
  • NetworkPolicy : deny par défaut, puis autoriser finement (si le CNI le supporte).
  • RBAC = least privilege, un ServiceAccount par app, on vérifie avec auth can-i.
  • Un Secret k8s n'est pas chiffré par défaut : prévoir chiffrement/gestionnaire externe.
  • :popeye pour mesurer et progresser.

➡️ Suite : Module 3e — GitOps avec ArgoCD