Container Forensics: Enqueter sur les Compromissions Kubernetes
Comment l'equipe Basilisk collecte des preuves dans les pods, le runtime et le control plane apres une suspicion d'incident sur des clusters Kubernetes en production.

Dans cet article
Trois heures du matin, alerte Falco: un pod du namespace payments lance /bin/sh apres avoir ouvert un socket reverse vers une IP etrangere. L'equipe d'astreinte isole le node, mais la premiere question du CISO est brutale: vous avez des preuves qui survivent au kubectl delete pod ?. Dans la majorite des clusters que Basilisk audite, la reponse honnete est non. Le container forensics sur Kubernetes n'est pas une variante de la forensique host classique, c'est une discipline a part entiere: le runtime recycle layers, cgroups et namespaces plus vite que n'importe quel analyste n'ouvre Wireshark. Ce guide decrit une chaine de collecte reproductible qui commence avant l'incident et se termine par une remise de preuves signee.
Pourquoi le container forensics est different#
Un container n'est pas un petit serveur, c'est un processus dans des namespaces isoles partageant un seul kernel. Son filesystem racine est un overlay de couches d'image en lecture seule plus une fine couche superieure inscriptible (l'upperdir) qui est jetee a la mort du pod. Pas de /var/log persistant, pas de contexte d'uptime stable, et rarement un journald dans le container. Si vous ne collectez pas la preuve la ou elle vit, vous la perdez: le scheduler peut deplacer le pod sur un autre node, un CrashLoopBackOff reinitialise l'etat, et un simple kubectl rollout restart efface entierement le contexte volatile. La maturite forensique d'un cluster ne se mesure pas en outils, elle se mesure au temps entre l'alerte et la premiere copie immuable.
Modele de menace: vecteurs dans le cluster#
Avant de collecter, priorisez. Les vecteurs les plus courants sont: un container applicatif vulnerable avec RCE, un token de ServiceAccount vole ou sur-privilegie depuis /var/run/secrets, un breakout du container via privileged: true, des montages hostPath ou un bug kernel, et une supply chain compromise dans l'image elle-meme. Chaque vecteur laisse des traces sur une couche differente: vecteurs applicatifs dans la memoire du pod, abus de token dans l'audit log du kube-apiserver, breakout sur le node et son arbre de processus, compromission supply chain dans les couches de l'image. Le modele de menace decide quelle couche vous gelez en premier, car le temps est limite et les couches overlay disparaissent en premier.
Preparation avant l'incident#
La forensique la plus efficace est celle qui est preparee. Activez l'audit policy du kube-apiserver au moins au niveau Metadata, en RequestResponse pour les verbes sensibles (exec, attach, portforward, create d'objets RBAC), et envoyez les logs vers une destination externe et immuable. Planifiez des snapshots horaires d'etcd (etcdctl snapshot save) pour reconstruire l'etat RBAC avant et apres. Gardez une image de toolkit forensique prete (binaires statiques de busybox, lsof, ss, tcpdump, avml) dans un registry separe, et ecrivez un role RBAC limite aux seuls repondeurs d'incident. Sans ce socle, chaque collecte est improvisee et contestable au tribunal.
Pas a pas: triage vivant sur le pod#
La premiere couche de preuves vit dans le pod et elle est volatile par conception. L'ordre compte: marquez d'abord le node avec un taint NoExecute personnalise pour que le scheduler n'evince rien, mais ne faites pas cordon immediatement, car cordon seul n'arrete aucun processus en cours. Declenchez un snapshot de disque via CSI (sur EKS un snapshot EBS, sur GKE gcloud compute disks snapshot), et seulement ensuite entrez dans le container cible avec kubectl debug en utilisant une image ephemere avec des binaires statiques. Capturez /proc/[pid]/exe, /proc/[pid]/maps, /proc/[pid]/environ, les sockets ouvertes via ss -tanp, et le contenu de /tmp et /dev/shm avant tout redemarrage. Qui a deja fait du DFIR sous Linux: Triage Vivant avec UAC et Velociraptor sur VM classique doit changer de mindset: ici la couche superieure disparait des que le pod meurt.
Acquisition de la memoire du container#
La memoire du container est le vrai tresor car le malware fileless et le code injecte n'existent que la. Avec un runtime containerd ou CRI-O, le PID du processus dans le pod est visible sur l'hote (via crictl inspect ou ctr task ls), donc vous lancez avml --pid <host_pid> ou utilisez LiME compile contre le kernel exact du node pour produire un dump complet. Ce dump alimente directement le flux de Memory Forensics avec Volatility 3 : Analyser des Dumps en Lab Reproductible, ou linux.pslist, linux.malfind et linux.check_syscall revelent des injections que l'EDR de l'hote a manquees parce qu'elles etaient confinees au namespace du container. Chaque hash SHA-256 rejoint une chain of custody signee avec Sigstore, en lien avec la discipline de Supply Chain Security: Signature Sigstore et SBOM Reels en CI/CD.
Control plane et audit logs#
En remontant la stack, l'enquete devient vraiment revelatrice. Le kube-apiserver avec audit au niveau RequestResponse enregistre chaque exec, attach et portforward en JSON structure, avec user, sourceIPs, userAgent et objectRef. Sur un cas reel de 2025, on a recupere la preuve decisive: l'attaquant avait cree un ServiceAccount nomme monitoring-helper avec cluster-admin via un heredoc kubectl apply -f -; l'audit log montrait user-agent kubectl/v1.29.2 depuis une IP residentielle a 3h47. Croisez avec des snapshots horaires d'etcd pour reconstruire l'etat RBAC avant et apres. Ce travail de timeline rejoint Timeline Forensics sur Windows : Plaso, Log2Timeline et KAPE en Pratique, mais applique a des ressources declaratives.
Runtime forensics avec eBPF#
Le runtime forensics demande un outillage specifique. Deployez Tetragon ou gardez Falco avec des regles personnalisees exportant vers un SIEM externe, jamais dans le cluster compromis. Pour la capture live, tracee-ebpf d'Aqua enregistre les syscalls avec contexte container_id, et sysdig inspect lit des fichiers .scap comme des pcaps kernel. Attention aux faux negatifs: si l'attaquant a adapte des techniques de direct syscalls de Evasion EDR pour la Recherche: Direct Syscalls Expliques sans Romance pour Linux, ou invoque des syscalls en contournant la libc, un hook purement userspace ne voit rien. Un capteur eBPF au tracepoint kernel, lui, voit le syscall reel. Combine avec du hunting Sigma dans l'esprit de Threat Hunting avec Sigma et Elastic: De l'Indicateur a la Regle de Detection, vos chances d'attraper le pivot se multiplient.
Network forensics dans le CNI#
Le network forensics sur Kubernetes differe du reseau classique parce que le CNI fait du NAT et de l'encapsulation et que l'IP du pod est recyclee apres sa mort. Capturez le trafic au niveau du veth pair du pod avec tcpdump -i any sur l'hote, filtre par l'IP du pod attribuee par l'IPAM. Si le cluster utilise Cilium, hubble observe --pod payments/checkout-7f4 affiche des flux L7 decodes avec contexte de processus. Pour un C2 persistant, comparez avec les IOC de votre lab Construire une Infra C2 avec Sliver en Lab Isole pour la Recherche Defensive et inspectez le DNS sur CoreDNS via les query logs. Exportez toujours les pcap vers un stockage write-once (WORM ou object-lock), parce que les avocats adorent contester l'integrite.
Dissequer les images compromises#
Les images compromises meritent un chapitre dedie. Avant de detruire quoi que ce soit, faites docker save (ou skopeo copy) de l'image suspecte vers un registry forensique isole, puis lancez dive et trivy fs pour cartographier les fichiers ajoutes au runtime via kubectl cp ou docker exec contre les couches originales. Dans 60% des cas observes, l'attaquant n'a pas modifie l'image originale; il a depose des binaires dans /tmp ou /dev/shm en pariant que personne ne snapshoterait l'overlay. Quand on suspecte une compromission upstream, envoyez les couches vers un lab Analyse de Malware en Lab Isole: Setup Securise avec FlareVM et REMnux adapte pour ELF, avec Remnux sur une VM air-gapped.
Chaine de custody et anti-forensique#
La valeur probante monte et descend avec la chaine de collecte. Documentez pour chaque artefact: quoi, quand, de quel node/pod, avec quelle commande, qui l'a collecte, SHA-256 avant et apres le transfert, et stockez tout de facon immuable. Attendez-vous a de l'anti-forensique: les attaquants effacent /tmp, manipulent le temps du container via libfaketime, cachent des processus avec un rootkit LD_PRELOAD, ou utilisent memfd_create pour une execution fileless qui ne touche jamais le disque. C'est precisement pourquoi le dump memoire est non negociable: un processus sans fichier sur disque reste visible en RAM. Signez chaque artefact avec Sigstore/cosign et gardez la cle privee hors du cluster.
Pieges frequents#
Les erreurs les plus couteuses sont procedurales, pas techniques. kubectl delete pod avant le snapshot detruit la couche overlay de maniere irreversible. kubectl exec dans le container vivant laisse vos propres traces et altere les timestamps. Telecharger des outils par le reseau sur le node compromis previent l'attaquant de votre presence. Faire confiance a l'EDR de l'hote comme seule source rate tout ce qui se passe dans le namespace du container. Et stocker les preuves dans le meme cluster que l'attaquant controle est naif. Repetez l'ordre avant que le vrai incident n'arrive.
Checklist#
Version courte pour le mur du runbook: (1) Taint du node NoExecute, geler le scheduling. (2) Declencher un snapshot disque CSI. (3) Dump memoire via avml/LiME contre le kernel du node. (4) Capturer les volatiles du pod: /proc/[pid]/*, sockets, /tmp, /dev/shm. (5) Exporter l'audit log du kube-apiserver et un snapshot etcd. (6) Enregistrer un pcap reseau au veth. (7) Sauver l'image suspecte via skopeo copy, lancer trivy/dive. (8) Hasher tout, signer avec Sigstore, stocker en WORM. (9) Ecrire la chaine de custody. (10) Seulement ensuite, contenir (isoler/supprimer).
FAQ#
Puis-je geler un container en cours sans le tuer ?#
Oui. Utilisez kubectl debug avec un container ephemere plutot que exec, car il partage le namespace de processus sans toucher l'entrypoint cible. Au niveau hote, vous pouvez mettre le processus en pause avec SIGSTOP (via le PID hote), tirer un dump memoire, puis decider de reprendre ou de contenir. Important: documentez le SIGSTOP, car il gele l'etat et la defense voudra le voir dans le rapport.
L'EDR de l'hote suffit-il pour les incidents container ?#
Non. Un EDR d'hote voit les processus et les syscalls, mais sans conscience des namespaces il ne les attribue pas proprement au bon pod et rate les injections fileless dans la RAM du container. Ajoutez toujours un capteur eBPF avec contexte container_id et un dump memoire. Ne vous fiez jamais a une seule couche.
Conclusion#
Takeaway pratique: repetez la procedure avant l'incident. Montez un cluster kind ou k3d, simulez un pod attaquant qui ouvre un reverse shell, et chronometrez le temps entre l'alerte et le dump memoire signe. Si ca depasse 20 minutes, automatisez avec un operator qui reagit aux evenements Falco en appliquant le taint, en declenchant le snapshot CSI et en lancant un job de collecte. Le container forensics, ce n'est pas une affaire d'outils exotiques, c'est une choregraphie repetee avant que la scene ne s'embrase.


