Runtime et détection
Comment détecter une compromission après coup : Falco et l'analyse des syscalls, les audit logs de l'API server, et la checklist de réponse à incident sur un conteneur compromis.
Table des matières
Pourquoi la détection runtime change la donne
Jusqu'ici, la sécurité Kubernetes que nous avons couverte est essentiellement préventive : RBAC restreint qui peut faire quoi, les NetworkPolicies limitent qui parle à qui, les admission controllers bloquent les manifestes non conformes avant leur application. Ces contrôles opèrent à la création ou à la modification d'un objet. Ils ne voient rien de ce qui se passe à l'intérieur d'un conteneur une fois qu'il tourne.
Or un conteneur compromis ne le devient jamais au moment du kubectl apply. Il le devient plus tard : une dépendance vulnérable exploitée, un secret exfiltré via une requête sortante inhabituelle, un attaquant qui ouvre un shell dans un pod via une CVE applicative. Aucune politique déclarative ne capte ces événements, parce qu'ils ne passent pas par l'API server. Ils se produisent au niveau du noyau Linux qui héberge le conteneur.
La détection runtime comble ce vide : elle observe le comportement effectif des processus en cours d'exécution — appels système, ouvertures de fichiers, connexions réseau, exécutions de binaires — et déclenche une alerte quand ce comportement correspond à un pattern suspect. Elle ne remplace pas la prévention, elle la complète pour le cas où celle-ci a échoué.
La détection runtime part du principe que la prévention va échouer un jour. Ce n'est pas un aveu d'échec du reste de votre posture de sécurité, c'est une hypothèse de travail réaliste : aucun ensemble de contrôles statiques ne couvre 100 % des vecteurs d'attaque, en particulier ceux qui exploitent une vulnérabilité 0-day dans le code applicatif lui-même.
Falco : observer le noyau, pas l'application
Falco, projet open source hébergé par la CNCF, est aujourd'hui l'outil de référence pour la détection runtime dans l'écosystème Kubernetes. Son principe est simple à énoncer, plus subtil à exploiter correctement.
Falco s'installe généralement en DaemonSet, avec une instance par nœud. Chaque instance capte les appels système (syscalls) émis par tous les processus du nœud, y compris ceux exécutés dans des conteneurs. Deux mécanismes de capture coexistent selon la version et le noyau cible :
- Module noyau (
falco-driver) — historique, performant, mais nécessite de compiler un module spécifique à la version du kernel. - eBPF — approche moderne, ne requiert pas de module signé, portable entre versions de noyau, et c'est aujourd'hui le mode par défaut recommandé.
Chaque syscall capté est enrichi avec le contextefenêtre de contexteIAQuantité de texte qu'un modèle peut prendre en compte simultanément : question, documents fournis et historique. Au-delà, les éléments les plus anciens sortent du champ.Voir dans le glossaire Kubernetes (namespace, pod, conteneur, image) grâce à un plugin qui interroge l'API du kubelet ou le container runtime. C'est ce qui permet à une alerte Falco de dire « processus nc exécuté dans le pod payment-service-7f9d du namespace prod » plutôt qu'un simple PID sans contexte exploitable.
Falco évalue ensuite chaque événement contre un ensemble de règles. Une règle définit une condition logique, une priorité, et un message de sortie.
- rule: Terminal shell in container
desc: Détecte l'ouverture d'un shell interactif dans un conteneur
condition: >
spawned_process and container
and shell_procs and proc.tty != 0
and container.image.repository != "debug-toolbox"
output: >
Shell ouvert dans un conteneur
(user=%user.name container=%container.name image=%container.image.repository
command=%proc.cmdline)
priority: WARNING
tags: [container, shell, mitre_execution]
Cette règle illustre un piège classique : sans l'exclusion debug-toolbox, chaque kubectl exec légitime effectué par un membre de l'équipe SRE déclenche l'alerte. La qualité d'un déploiement Falco se mesure moins à la quantité de règles activées qu'à la précisionprécisionIAProportion des alertes émises par un modèle qui sont justifiées. Elle s'oppose au rappel : améliorer l'une dégrade l'autre.Voir dans le glossaire de leurs exclusions.
Anatomie d'une alerte
Écrire des règles qui tiennent la route en production
Une règle Falco brute génère un bruit ingérable si elle n'est pas affinée. Trois techniques réduisent ce bruit sans réduire la couverture :
- Macros — factorisent une sous-condition réutilisée dans plusieurs règles (par exemple
user_known_login_binaries). - Listes — énumèrent des valeurs (images de confiance, comptes de service applicatifs) maintenues séparément de la logique des règles, donc modifiables sans toucher au moteur de détection.
- Exceptions par règle — les versions récentes de Falco permettent d'attacher des exceptions directement à une règle existante sans la dupliquer, ce qui facilite la maintenance lors des mises à jour du ruleset upstream.
Ne modifiez jamais directement les règles fournies par défaut (
falco_rules.yaml). Créez un fichiercustom_rules.yamlséparé et surchargez ou étendez les règles existantes avecappend: true. Une mise à jour du package Falco écrasera le fichier par défaut ; vos personnalisations survivront si elles sont ailleurs.
Les règles les plus utiles en environnement de production ciblent des comportements rarement légitimes plutôt que des binaires précis — un attaquant renomme facilement un binaire, il change plus difficilement son intention :
| Comportement détecté | Pourquoi c'est un signal fort |
|---|---|
| Écriture dans un binaire système existant | Les images immuables ne devraient jamais être modifiées après démarrage |
| Ouverture de socketsocketRéseauxAssociation d'une adresse IP et d'un port, qui identifie une extrémité de communication. Le quadruplet formé par les deux sockets d'une connexion la distingue de toutes les autres.Voir dans le glossaire réseau sortant depuis un processus inattendu | Signature typique d'exfiltration ou de commande-et-contrôle |
Lecture de /var/run/secrets/kubernetes.io par un processus hors service account attendu |
Tentative de vol de tokentokenIAFragment de texte manipulé par un modèle de langage, généralement plus court qu'un mot — trois à quatre caractères en français. La tarification et la limite de contexte se comptent en tokens.Voir dans le glossaire de service account |
Montée de privilège via setuid/setgid inattendue |
Souvent liée à une tentative d'évasion de conteneur |
Exécution d'un shell sans processus kubectl parent tracé |
Accès non passé par les canaux d'audit habituels |
Les audit logs Kubernetes : la mémoire du control plane
Falco voit ce qui se passe dans les conteneurs. Les audit logs de l'API server voient ce qui se passe contre le cluster : chaque requête adressée à l'API — création, lecture, suppression d'un objet, y compris les sous-ressources comme pods/exec ou pods/portforward.
L'audit logging se configure via une Policy, qui définit un niveau de journalisation par règle, du plus léger au plus complet :
None— la requête n'est pas journalisée.Metadata— journalise l'utilisateur, l'horodatage, la ressource, le verbe, mais pas le corps de la requête ni la réponse.Request— ajoute le corps de la requête, utile pour savoir quoi a été envoyé.RequestResponse— journalise tout, y compris la réponse complète ; volumineux, à réserver aux ressources sensibles.
apiVersion: audit.k8s.io/v1
kind: Policy
rules:
- level: RequestResponse
resources:
- group: ""
resources: ["pods/exec", "pods/portforward", "pods/attach"]
- level: Metadata
resources:
- group: ""
resources: ["secrets", "configmaps"]
- level: None
users: ["system:kube-scheduler", "system:kube-controller-manager"]
RequestResponsesur toutes les ressources produit un volume de logs qui peut saturer votre pipeline d'ingestion en quelques heures sur un cluster actif. Réservez ce niveau aux sous-ressources sensibles (exec,portforward,secrets) et utilisezMetadataouNoneailleurs. Un audit policy mal calibré est aussi dangereux qu'absent : soit il coûte trop cher et on le désactive sous pression budgétaire, soit il noie le signal utile dans du bruit.
Un point souvent manqué : pods/exec dans les audit logs journalise que la commande d'exec a été lancée, avec les arguments passés à kubectl exec, mais ne journalise pas ce qui se passe dans la session interactive elle-même. Pour ça, il faut Falco ou un outil équivalent côté runtime (Tetragon, Sysdig). Les deux sources sont complémentaires, jamais redondantes.
Corréler runtime et control plane
La vraie valeur apparaît à la corrélation. Un kubectl exec légitime effectué par un ingénieur SRE identifié dans l'audit log, suivi d'une alerte Falco « shell ouvert » dans le même pod à la même seconde, est un non-événement. La même alerte Falco sans entrée d'audit log correspondante — ou avec un user.name qui ne correspond à aucune identité RBAC connue — est un signal fort d'accès par une voie non standard, par exemple un token de service account volé utilisé directement contre le kubelet, en contournant l'API server.
Une équipe reçoit une alerte Falco : exécution de
curlvers une IP externe depuis un podworker-batch. L'audit log du cluster ne montre aucunpods/execsur ce pod dans la fenêtre concernée. En croisant avec les logs applicatifs, l'équipe découvre que le processuscurla été lancé par le code applicatif lui-même, compromis via une dépendance npm piégée installée la veille. Sans Falco, cette exfiltration serait passée inaperçue puisqu'elle ne transitait jamais par l'API Kubernetes.
Cette corrélation se fait rarement à la main : elle repose sur l'envoi des deux flux — alertes Falco via falcosidekick, audit logs via le backend webhook de l'API server — vers un SIEM commun ou, à minima, une stack de logs partagée où les identifiants de pod, namespace et horodatage permettent la jointure.
Réponse à incident : la checklist
Détecter sans plan de réponse ne produit qu'une notification anxiogène. La séquence suivante, adaptée du cadre NIST à l'environnement conteneur, structure la réaction :
- Isoler — appliquer une NetworkPolicy
deny-allciblant spécifiquement le pod suspect via un label distinct, sans suppression immédiate, ou utiliserkubectl cordonsur le nœud si la compromission peut s'être propagée horizontalement. - Préserver la preuve — avant toute action destructive, capturer l'état :
kubectl logs,kubectl describe pod, export de l'image en cours d'exécution, et si l'outillage le permet, snapshot mémoire ou dump du système de fichiers overlay. - Ne pas supprimer le pod immédiatement — un
kubectl delete poddéclenche généralement un redémarrage via le contrôleur parent, et détruit l'état runtime nécessaire à l'investigation. - Analyser — reconstituer la chronologie à partir des alertes Falco, de l'audit log et des logs applicatifs. Identifier le vecteur d'entrée : image vulnérable, dépendance compromise, credential exposé.
- Éradiquer — révoquer les secrets et tokens de service account potentiellement exposés, reconstruire l'image depuis une base saine, patcher la vulnérabilité identifiée.
- Restaurer — redéployer depuis l'image corrigée, en validant que les contrôles d'admission bloquent bien la version vulnérable.
- Post-mortem — traduire ce qui a été appris en règle Falco ou en politique d'audit ajustée, pour raccourcir le temps de détection la prochaine fois.
L'étape 3 est régulièrement sautée par réflexe opérationnel — le premier instinct est de « nettoyer » en supprimant le pod compromis. C'est exactement l'inverse de ce qu'il faut faire tant que la preuve n'est pas préservée. Un playbook d'incident container doit explicitement interdire la suppression avant capture, sans quoi l'équipe de garde reproduira le réflexe sous pression.
Pièges courants et faux positifs
La fatigue d'alerte est le principal facteur d'échec des déploiements Falco en production. Quelques causes récurrentes :
- Règles par défaut trop larges — le ruleset fourni par défaut est pensé pour être exhaustif, pas silencieux. Il doit être taillé à l'environnement réel avant la mise en production, pas après.
- Absence de contexte « outilstool callingIACapacité d'un agent ou d'un LLM à invoquer des outils externes (API, calcul, recherche) pendant le raisonnement.Voir dans le glossaire de debug » — les images de diagnostic (type
netshoot, oubusyboxpour du troubleshooting) déclenchent systématiquement les règles liées aux shells et aux outils réseau si elles ne sont pas explicitement exclues. - Sondes de liveness ou readiness mal comprises — certaines sondes exécutent des commandes shell à haute fréquence ; sans exclusion, elles génèrent une alerte à chaque intervalle de sonde.
- DérivedériveIADégradation progressive des performances d'un modèle après son déploiement, causée par l'évolution des comportements ou du contexte. Elle impose surveillance et réentraînement.Voir dans le glossaire entre règles et topologie réelle — une règle qui référence un namespace ou un nom de service account renommé depuis continue de matcher, ou cesse de matcher, silencieusement ; elle nécessite une revue périodique, pas un déploiement figé.
Un déploiement Falco qui génère plus de cinquante alertes par jour sur un cluster de taille moyenne n'est pas exploité, il est ignoré. L'objectif n'est pas la couverture maximale immédiate mais un ensemble de règles restreint et fiable, sur lequel l'équipe de garde agit systématiquement sans lassitude.
Ce qu'il faut retenir
La détection runtime et les audit logs répondent à deux questions différentes : Falco répond à « que fait ce processus, là, maintenant, dans le noyau », l'audit log répond à « qui a demandé quoi à l'API server, et quand ». Aucun des deux ne remplace l'autre, et aucun des deux ne remplace un plan de réponse à incident testé avant qu'il ne serve pour de vrai. Le tuning des règles et de la politique d'audit est un travail continu, pas une configuration que l'on pose une fois puis que l'on oublie. Un cluster sans détection runtime n'est pas plus sûr qu'un cluster avec Falco mal réglé et ignoré — dans les deux cas, l'incident sera découvert par le client ou par la presse, pas par l'équipe.
L'essentiel à retenir
Ce chapitre couvre la détection runtime avec Falco : capture des syscalls via eBPF ou module noyau, écriture de règles précises et maintenables, distinction entre macros, listes et exceptions. Il détaille la configuration des audit logs Kubernetes (niveaux None, Metadata, Request, RequestResponse) et la corrélation entre événements runtime et control plane pour distinguer un accès légitime d'un accès suspect. Il se termine par une checklist opérationnelle de réponse à incident container, de l'isolation à la préservation de preuve jusqu'au post-mortem, ainsi que les pièges classiques de fatigue d'alerte.
- Détection runtime versus prévention statique
- Capture des syscalls via eBPF ou module noyau
- Règles Falco : condition, priorité, output
- Macros, listes et exceptions pour réduire le bruit
- Niveaux d'audit logs Kubernetes (None, Metadata, Request, RequestResponse)
- Corrélation runtime et control plane
- Préservation de preuve avant remédiation
- Boucle de réponse à incident container
Questions fréquentes
Falco peut-il bloquer une action malveillante, ou se contente-t-il de l'observer ?
Faut-il choisir entre Falco et les audit logs Kubernetes, ou les deux sont-ils nécessaires ?
Combien de temps faut-il prévoir pour tuner un déploiement Falco avant qu'il soit réellement exploitable en production ?
Les audit logs Kubernetes remplacent-ils un SIEM ?
Quelle est la différence entre Falco et un outil comme Tetragon ?
Un attaquant qui obtient un accès root dans un conteneur peut-il désactiver Falco pour masquer ses traces ?
Que faire si l'équipe de garde ne dispose pas des compétences forensic pour analyser un conteneur compromis ?
Progression sauvegardée dans votre navigateur.
Quiz de validation
Quiz Player
Quiz de validation
Plusieurs réponses possibles — validez ensuite.
Vrai ou faux.
Quiz indisponible (données invalides).