Aller au contenu

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-staging et securepay-prod, avec le label app.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é

  1. 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
  1. Rédigez security/falco/values.yaml et déployez Falco par ArgoCD (namespace falco) :
driver:
  kind: modern_ebpf
tty: true
falcosidekick:
  enabled: true
  1. Vérifiez dans les journaux de chaque pod Falco la sonde utilisée et le chargement des règles :
kubectl -n falco logs ds/falco -c falco | grep -E "modern BPF|Loading rules|schema validation"

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é

  1. Rédigez security/falco/securepay-rules.yaml avec 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]
  1. 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
  1. Chargez-le par la clé customRules des valeurs du chart, puis ajoutez cette validation à la CI de securepay-platform.

  2. 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é

  1. 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).

  1. Dans Alertmanager, routez les alertes Falco critiques vers l'astreinte et le reste vers un canal de sécurité.

  2. 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é

  1. 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]
  1. Déployez Falco Talon (chart falcosecurity/falco-talon) dans falco, 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.

  1. 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 et patch des pods, création d'événements, gestion des leases. Vérifiez ensuite dans ses journaux qu'aucun accès n'est refusé.

  2. 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
  1. 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=true et 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é

  1. É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.

  1. Planifiez son exécution (pipeline planifiée sur le runner self-hosted).

  2. 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é

  1. Rédigez docs/runbooks/incident-securite-runtime.md : confirmer, contenir, préserver, éradiquer, rétablir, apprendre.

  2. 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.
  3. 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 ?