Détecter et confiner avec Falco et Falco Talon¶
Objectifs pédagogiques¶
À la fin de ce TP, vous devez être capables de :
- déployer Falco sur un cluster dont les nœuds partagent le même noyau, sans angle mort
- écrire, valider et tester des règles de détection propres à une application
- router les événements vers Alertmanager, Loki et un moteur de réponse
- confiner automatiquement un pod suspect tout en conservant les preuves
- maintenir une matrice de couverture reliée à MITRE ATT&CK et un runbook de réponse
Prérequis¶
- La plateforme de lab : cluster k3d
securepay(1 server, 2 agents), ArgoCD, kube-prometheus-stack, Loki - L'API SecurePay déployée dans
securepay-stagingetsecurepay-prod, avec le labelapp.kubernetes.io/name: securepay-api - Des NetworkPolicies actives (k3s les applique nativement)
- Docker sur le poste pour valider les règles
Testé
Les ateliers 1 à 4 ont été joués avec le chart Falco 9.2.2 (Falco 0.45.2, sonde eBPF moderne), Falcosidekick et le chart Falco Talon 0.5.0 : déclenchement des trois règles maison, quarantaine appliquée par Talon en moins d'une seconde, pod isolé par la NetworkPolicy et remplacé par le ReplicaSet.
Contexte¶
Chez un partenaire de SecurePay, un conteneur compromis a miné de la cryptomonnaie pendant trois jours sans être détecté. La configuration était pourtant conforme à toutes les politiques d'admission. Vous ajoutez la couche qui manquait : la détection à l'exécution, et une réponse automatique proportionnée.
flowchart LR
K["Noyau (eBPF)"] --> F["Falco\n(DaemonSet)"]
F --> S["Falcosidekick"]
S -->|"error et plus"| AM["Alertmanager"]
S -->|"tout"| L["Loki"]
S -->|"critical"| T["Falco Talon"]
T -->|"label quarantine=true"| P["Pod suspect"]
NP["NetworkPolicy\nquarantine-deny-all"] --> P Atelier 1 : Déployer Falco sur tous les nœuds¶
Travail demandé¶
- Ajoutez le dépôt Helm et épinglez une version vérifiée du chart :
helm repo add falcosecurity https://falcosecurity.github.io/charts
helm repo update
helm show values falcosecurity/falco --version <version> | less
- Rédigez
security/falco/values.yamlet déployez Falco par ArgoCD (namespacefalco) :
- Vérifiez dans les journaux de chaque pod Falco la sonde utilisée et le chargement des règles :
Un noyau partagé, mais un enrichissement local
Les nœuds k3d sont des conteneurs qui partagent le noyau de la VM : chaque pod Falco voit les appels système de tous les nœuds. En revanche, il ne sait enrichir (pod, namespace, labels) que les conteneurs de son nœud, car son plugin n'interroge que le runtime local. En test, un shell ouvert dans un pod d'un agent n'est signalé que par le Falco de cet agent. Gardez donc le DaemonSet sur tous les nœuds, et conditionnez vos règles aux métadonnées Kubernetes.
Critère de réussite¶
Un pod Falco tourne sur chacun des trois nœuds, avec la sonde eBPF moderne.
Atelier 2 : Règles maison SecurePay¶
Travail demandé¶
- Rédigez
security/falco/securepay-rules.yamlavec au moins trois règles, reliées chacune à une technique ATT&CK :
- list: securepay_namespaces
items: [securepay-staging, securepay-prod]
- rule: SecurePay - Shell dans un conteneur applicatif
desc: Un shell est lancé dans un conteneur de l'API SecurePay
condition: >
spawned_process and container and proc.name in (shell_binaries)
and k8s.ns.name in (securepay_namespaces)
output: >
Shell dans l'API SecurePay (user=%user.name cmd=%proc.cmdline
pod=%k8s.pod.name ns=%k8s.ns.name image=%container.image.repository)
priority: CRITICAL
tags: [securepay, mitre_execution, T1059]
- rule: SecurePay - Lecture du jeton de ServiceAccount
desc: Un processus lit le jeton de ServiceAccount monté dans le conteneur
condition: >
open_read and container and k8s.ns.name in (securepay_namespaces)
and fd.name startswith /var/run/secrets/kubernetes.io/serviceaccount
output: >
Lecture du jeton de ServiceAccount (proc=%proc.name file=%fd.name
pod=%k8s.pod.name ns=%k8s.ns.name)
priority: WARNING
tags: [securepay, mitre_credential_access, T1528]
- rule: SecurePay - Connexion sortante hors réseau privé
desc: Une connexion sortante vise une adresse publique
condition: >
outbound and container and k8s.ns.name in (securepay_namespaces)
and not fd.snet in (rfc_1918_addresses)
output: >
Connexion sortante inattendue (proc=%proc.name connection=%fd.name
pod=%k8s.pod.name ns=%k8s.ns.name)
priority: ERROR
tags: [securepay, mitre_exfiltration, T1041]
- Validez le fichier en local avec la même version de Falco que le cluster, sans driver ni cluster :
docker run --rm -v "$PWD/security/falco:/w" falcosecurity/falco:<version> \
falco -V /etc/falco/falco_rules.yaml -V /w/securepay-rules.yaml
-
Chargez-le par la clé
customRulesdes valeurs du chart, puis ajoutez cette validation à la CI desecurepay-platform. -
Si une règle par défaut est trop bruyante pour un namespace d'outillage, ajustez-la sans la copier :
- rule: Terminal shell in container
condition: and not k8s.ns.name = "debug-tools"
override:
condition: append
Critère de réussite¶
Les règles sont versionnées, validées en CI, et le journal de Falco indique schema validation: ok pour votre fichier.
Atelier 3 : Router les événements¶
Travail demandé¶
- Complétez la configuration de Falcosidekick :
falcosidekick:
enabled: true
config:
alertmanager:
hostport: http://kube-prometheus-stack-alertmanager.monitoring:9093
minimumpriority: error
loki:
hostport: http://loki-gateway.monitoring
minimumpriority: debug
talon:
address: http://falco-talon:2803
minimumpriority: critical
Adaptez les adresses à vos services (kubectl get svc -A).
-
Dans Alertmanager, routez les alertes Falco critiques vers l'astreinte et le reste vers un canal de sécurité.
-
Dans Grafana (Explore, source Loki), repérez les labels posés par Falcosidekick et construisez un panneau des événements par règle et par priorité.
Critère de réussite¶
Un événement critique arrive dans Alertmanager, et tous les événements sont consultables dans Loki.
Atelier 4 : Quarantaine automatique avec Talon¶
Travail demandé¶
- Créez, dans chaque namespace applicatif, la NetworkPolicy qui isolera tout pod mis en quarantaine :
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: quarantine-deny-all
namespace: securepay-prod
spec:
podSelector:
matchLabels:
quarantine: "true"
policyTypes: [Ingress, Egress]
- Déployez Falco Talon (chart
falcosecurity/falco-talon) dansfalco, avec l'action et la règle de quarantaine :
config:
rulesOverride: |
- action: Quarantaine du pod
actionner: kubernetes:label
parameters:
labels:
quarantine: "true"
app.kubernetes.io/name: ""
- rule: Quarantaine SecurePay
match:
rules:
- SecurePay - Shell dans un conteneur applicatif
actions:
- action: Quarantaine du pod
Une valeur vide retire le label : le pod sort du sélecteur de son ReplicaSet (qui crée un remplaçant) et de son Service, mais il reste en vie pour l'analyse.
-
Restreignez les droits de Talon. Par défaut, son chart lui accorde un ClusterRole large (y compris la suppression de namespaces). Ne gardez que ce qu'exigent l'actionneur
label, le notificateur d'événements et l'élection de leader : lecture etpatchdes pods, création d'événements, gestion desleases. Vérifiez ensuite dans ses journaux qu'aucun accès n'est refusé. -
Déclenchez la règle depuis un pod de staging :
POD=$(kubectl -n securepay-staging get pod -l app.kubernetes.io/name=securepay-api -o name | head -1)
kubectl -n securepay-staging exec "$POD" -- sh -c 'id'
kubectl -n securepay-staging get pods -L app.kubernetes.io/name,quarantine
- Vérifiez l'isolation : le pod en quarantaine n'est plus joignable depuis ses voisins et ne peut plus sortir, tandis que les autres pods continuent de servir.
L'actionneur networkpolicy
Talon propose aussi un actionneur kubernetes:networkpolicy. Il construit sa politique à partir du sélecteur du propriétaire du pod : elle s'applique à toutes les répliques du Deployment, pas seulement au pod compromis. La quarantaine par label limite le rayon d'impact au seul pod suspect.
Ce que vous devez observer¶
- Talon journalise la correspondance, l'action exécutée et sa notification
- Le pod suspect porte
quarantine=trueet n'a plus de propriétaire ; un nouveau pod l'a remplacé - Le service reste disponible pendant toute l'opération
Critère de réussite¶
Un shell dans un conteneur applicatif provoque, sans intervention humaine, l'isolation du pod concerné et rien d'autre.
Atelier 5 : Tests de détection et matrice de couverture¶
Travail demandé¶
- Écrivez
security-tests/runtime-detection.sh. Il déclenche chaque règle sur un pod de staging, puis vérifie l'arrivée de l'alerte :
#!/usr/bin/env bash
set -u
NS=securepay-staging
POD=$(kubectl -n "$NS" get pod -l app.kubernetes.io/name=securepay-api -o name | head -1)
SINCE=$(date -u +%Y-%m-%dT%H:%M:%SZ)
kubectl -n "$NS" exec "$POD" -- cat /var/run/secrets/kubernetes.io/serviceaccount/token > /dev/null
kubectl -n "$NS" exec "$POD" -- wget -q -T 3 -O /dev/null http://1.1.1.1 || true
kubectl -n "$NS" exec "$POD" -- sh -c 'id' > /dev/null
sleep 10
fail=0
for rule in "Lecture du jeton" "Connexion sortante inattendue" "Shell dans l'API SecurePay"; do
if kubectl -n falco logs ds/falco -c falco --since-time="$SINCE" 2>/dev/null | grep -q "$rule"; then
echo "OK $rule"
else
echo "ABSENT $rule"; fail=1
fi
done
exit "$fail"
kubectl logs ds/falco ne lit qu'un seul pod du DaemonSet : bouclez sur tous les pods Falco, ou interrogez Loki, pour couvrir les trois nœuds.
-
Planifiez son exécution (pipeline planifiée sur le runner self-hosted).
-
Tenez à jour la matrice de couverture dans
docs/securite-runtime.md:
| Règle | Technique ATT&CK | Test | Réponse | Preuve |
|---|---|---|---|---|
| Shell dans l'API | T1059 Exécution | exec sh -c id | quarantaine | docs/preuves/... |
| Lecture du jeton | T1528 Accès aux identifiants | exec cat token | alerte | docs/preuves/... |
| Connexion sortante | T1041 Exfiltration | exec wget 1.1.1.1 | alerte | docs/preuves/... |
Ajoutez au moins une ligne pour une technique non couverte, en expliquant pourquoi.
Critère de réussite¶
Chaque règle maison a son test, et la matrice distingue clairement ce qui est couvert de ce qui ne l'est pas.
Atelier 6 : Runbook et exercice de réponse¶
Travail demandé¶
-
Rédigez
docs/runbooks/incident-securite-runtime.md: confirmer, contenir, préserver, éradiquer, rétablir, apprendre. -
Un coéquipier joue l'attaquant sur staging (shell, lecture du jeton, connexion sortante), sans prévenir. Appliquez le runbook :
- chronométrez le temps de détection et le temps de confinement ;
- préservez les preuves du pod isolé (journaux, processus, fichiers modifiés) avant de le supprimer ;
- établissez la cause racine et la chronologie.
-
Rédigez le postmortem blameless de l'exercice.
Critère de réussite¶
La réponse est menée de bout en bout avec le runbook, et les temps de détection et de confinement sont mesurés.
Questions de synthèse¶
- Pourquoi une configuration conforme à toutes les politiques d'admission n'exclut-elle pas une compromission ?
- Pourquoi garder Falco sur tous les nœuds quand ils partagent le même noyau ?
- Pourquoi isoler plutôt que tuer un pod suspect ?
- Quels risques fait courir un moteur de réponse automatique, et comment les limiter ?
- Comment démontrer à un auditeur qu'une règle de détection fonctionne réellement ?