Sécurité runtime cloud-native : détecter les menaces dans vos conteneurs avec Falco et Tetragon (eBPF)
Le scan d'image ne voit rien de ce qui se passe à l'exécution. Guide sur la sécurité runtime conteneurs eBPF avec Falco et Tetragon : règles, exemples et pièges à éviter.
Une équipe scanne consciencieusement ses images avec Grype ou Trivy avant chaque déploiement. Le pipeline CI bloque les images contenant des CVE critiques. Et pourtant, le jour où un attaquant obtient un shell interactif dans un pod de production, personne ne le voit venir. Le scan d'image répond à une question statique ("qu'est-ce qu'il y a dans cette image ?"), pas à la question qui compte à l'exécution : "que fait ce conteneur en ce moment ?". C'est exactement le trou que comble la sécurité runtime, et c'est là où l'eBPF a changé la donne ces dernières années.
Ce que le scan d'image ne voit jamais
Un scan de vulnérabilités inspecte les couches d'une image, la liste des paquets et leurs versions, avant que le conteneur ne tourne. Il ne voit strictement rien de ce qui se passe après le docker run ou le démarrage du pod. Trois exemples concrets de ce qui échappe totalement à cette approche :
- Un exec anormal : un processus lancé dans le conteneur qui ne fait pas partie de l'image d'origine (un attaquant qui pousse un binaire via une vulnérabilité applicative, puis l'exécute).
- Un shell interactif dans un conteneur :
bash,shouncinvoqués dans un conteneur applicatif qui n'a jamais été conçu pour être débogué en direct. C'est un des signaux les plus fiables de compromission active. - Un montage ou une écriture inattendue sous
/etc: modification de fichiers de configuration système depuis l'intérieur du conteneur, souvent une étape de persistance ou d'escalade. - Un egress réseau inattendu : un pod qui n'a jamais communiqué qu'avec la base de données interne se met soudain à établir des connexions sortantes vers une IP inconnue.
Aucun de ces signaux n'existe dans un SBOM. Ils n'existent qu'à l'exécution, et seule une instrumentation au niveau du noyau peut les capturer sans ré-instrumenter chaque application.
eBPF : l'instrumentation sans agent intrusif
L'eBPF (extended Berkeley Packet Filter) permet d'attacher des programmes de supervision directement dans le noyau Linux, sur des appels système, des événements réseau ou des événements de sécurité, sans modifier le code des applications ni déployer un agent lourd dans chaque conteneur. C'est ce qui rend la détection runtime pratique à grande échelle sur Kubernetes : un seul point d'observation par nœud voit tout ce qui se passe dans tous les conteneurs de ce nœud.
Deux projets dominent ce terrain, avec des philosophies différentes.
Falco vs Tetragon : deux modèles de règles, deux usages
Falco fonctionne sur un modèle déclaratif proche du SIEM : une règle YAML définit une condition (l'événement à surveiller), un output (le format d'alerte) et une priority (le niveau de gravité). Falco est fondamentalement un moteur de détection et d'alerting : il observe et prévient, il ne bloque pas nativement.
- rule: Terminal shell in container
desc: A shell was spawned by a program in a container with an attached terminal.
condition: >
spawned_process and container
and shell_procs and proc.tty != 0
and container_entrypoint
output: >
A shell was spawned in a container with an attached terminal
(user=%user.name container_id=%container.id
container_name=%container.name
shell=%proc.name parent=%proc.pname cmdline=%proc.cmdline)
priority: NOTICE
tags: [container, shell, mitre_execution]Tetragon, basé également sur eBPF mais avec un objectif différent, s'appuie sur une TracingPolicy au format Kubernetes CRD. La différence structurante : Tetragon peut appliquer une action d'enforcement in-kernel, c'est-à-dire bloquer l'appel système avant même qu'il ne s'exécute, pas seulement l'observer après coup.
apiVersion: cilium.io/v1alpha1
kind: TracingPolicy
metadata:
name: write-below-etc
spec:
kprobes:
- call: "security_file_permission"
syscall: false
args:
- index: 0
type: "file"
- index: 1
type: "int"
selectors:
- matchArgs:
- index: 0
operator: "Prefix"
values:
- "/etc"
matchActions:
- action: SigkillEn résumé : Falco répond à "je veux savoir", Tetragon peut répondre à "je veux empêcher". Les deux sont complémentaires dans une architecture mature, l'un couvre la visibilité large et l'alerting opérationnel, l'autre couvre l'enforcement ciblé sur les chemins critiques où le risque justifie une action immédiate.
Pourquoi la règle par défaut fait du bruit en production
La règle "Terminal shell in container" ci-dessus est l'exemple canonique des jeux de règles par défaut. Elle est juste, elle détecte réellement un shell interactif, et c'est précisément le problème en production : de nombreuses équipes ouvrent légitimement un shell dans un conteneur pour du débogage, un pod de CI exécute des scripts shell par design, un sidecar d'observabilité invoque parfois sh pour ses propres besoins. Déployée telle quelle sur un cluster réel, cette règle génère un volume d'alertes largement dominé par du trafic légitime.
L'angle mort des workloads IA sur Kubernetes
C'est un terrain que les SIEM classiques et même beaucoup de politiques Falco par défaut couvrent mal : les pods d'inférence. Un pod GPU qui sert un modèle de langage ou de vision a un profil comportemental très différent d'un pod applicatif classique, et c'est justement ce qui le rend difficile à surveiller avec des règles génériques :
- Montage de modèles : les poids de modèle sont souvent chargés depuis un volume monté ou un bucket objet au démarrage, un accès en écriture inattendu sur ce volume après le chargement initial est un signal fort.
- Appels sortants vers des API IA externes : un pod d'inférence qui, normalement, ne parle qu'à son registre de modèles interne et se met à établir des connexions vers un service tiers non référencé constitue un signal d'exfiltration ou de détournement (utilisation non autorisée du GPU, appel à une API tierce pour du proxying).
- Élévation de privilèges sur le device GPU : les accès au device
/dev/nvidia*sortent du périmètre de la plupart des politiques RBAC standards, et un accès inattendu depuis un processus qui n'est pas le runtime d'inférence mérite d'être tracé.
Ces workloads sont récents, déployés vite, souvent sans hardening dédié, et représentent un point d'entrée que peu d'organisations savent surveiller aujourd'hui à l'exécution. C'est un axe de détection distinct, pas une simple variante des règles conteneur génériques.
Le piège des faux positifs : ne jamais désactiver, toujours exempter
La réaction naturelle face au bruit de la règle par défaut est de la désactiver. C'est l'erreur à ne jamais commettre : désactiver une règle, c'est perdre définitivement la visibilité sur la classe d'événements qu'elle couvre, y compris le jour où l'événement légitime devient malveillant.
La bonne pratique consiste à exempter le comportement connu, pas à supprimer la détection :
- rule: Terminal shell in container
desc: A shell was spawned by a program in a container with an attached terminal.
condition: >
spawned_process and container
and shell_procs and proc.tty != 0
and container_entrypoint
and not user_expected_terminal_shell_in_container_conditions
output: >
A shell was spawned in a container with an attached terminal
(user=%user.name container=%container.name shell=%proc.name)
priority: NOTICE
- list: user_expected_containers
items: [ci-runner, debug-sidecar]
- macro: user_expected_terminal_shell_in_container_conditions
condition: (container.image.repository in (user_expected_containers))En complément, l'autre levier structurant est le minimum priority par sink. Toutes les alertes ne méritent pas le même canal : router les événements NOTICE vers un flux Elastic consultable à froid, réserver PagerDuty aux priorités CRITICAL et EMERGENCY, et Slack aux niveaux intermédiaires pour une revue humaine rapide. C'est ce qui évite la fatigue d'alerte sans jamais sacrifier la couverture : la règle reste active, seul son acheminement change selon la gravité réelle du contexte.
En résumé
La sécurité runtime avec Falco et Tetragon comble un angle mort que le scan d'image ne couvrira jamais : ce qui se passe réellement pendant l'exécution, exec anormal, shell interactif, écriture sous /etc, egress inattendu. La méthode qui fonctionne en production tient en trois principes : partir de règles éprouvées plutôt que de copier des exemples bruts, prouver leur taux de faux positifs sur un corpus bénin avant de les déployer, et router intelligemment par priorité et par sink plutôt que de désactiver ce qui dérange. Sur les workloads d'inférence IA en particulier, cette discipline change la donne : c'est un périmètre que peu d'outils couvrent aujourd'hui.
C'est exactement le travail déjà fait dans le pack de règles runtime cloud-native ThreatClaw : des règles Falco et des TracingPolicy Tetragon prêtes à déployer, exemptions et routage par priorité déjà calibrés, incluant la couverture des workloads GPU et inférence.
Articles liés
Google observe des clusters attaqués en 18 minutes et des évasions via pods privilégiés. Voici la détection Falco au runtime et les garde-fous OPA à l'admission.
Falco et Tetragon détectent l'agent IA en conteneur qui sort de son enveloppe : appel d'outil anormal, spawn de process, escalade par prompt malveillant.
Détection cryptojacking Kubernetes Falco : la règle qui repère un binaire lancé depuis /tmp, les connexions vers un pool de minage, et ce qui reste en HITL.
Le policy as code OPA Rego Kubernetes permet de refuser un pod privilégié avant qu'il ne démarre. OPA/Rego vs Kyverno, exemples, tests, et preuve NIS2/DORA.