Skip to content

Détection d'Intrusions Runtime avec Falco et Falcosidekick

Détection d'Intrusions Runtime avec Falco et Falcosidekick

Défense en profondeur : Filtrage de périmètre vs Détection runtime

La sécurité du système est organisée en couches étanches : 1. Filtrage de périmètre (L7) : Traefik et CrowdSec analysent les requêtes HTTP/HTTPS entrantes et bloquent les scanners et attaques Web. 2. Surveillance d'exécution (Runtime) : Falco inspecte directement les appels système (syscalls) émis vers le noyau Linux par l'intermédiaire de sondes eBPF et de tracepoints du kernel.

Si un attaquant parvient à compromettre une application (par exemple via une vulnérabilité RCE ou une injection de commande dans un conteneur), CrowdSec ne voit plus rien car le trafic initial a déjà été acquitté. Falco intervient alors en détection d'exécution (runtime) en détectant les comportements anormaux au sein du conteneur (spawn d'un shell, lecture de /etc/shadow, exécution de binaire téléchargé, reverse-shell).


1. Architecture du Pipeline de Détection

graph TD
    subgraph Host_Kernel["Noyau Linux - Espace Kernel"]
        Trace["Sondes eBPF / Kernel Tracepoints"]
        Syscalls["Appels Système (syscalls)"]
        Syscalls --> Trace
    end

    Trace -->|"Flux d'événements"| Falco["Conteneur Falco (Mode Privilégié)"]

    subgraph Falco_Engine["Moteur de Règles Falco"]
        DefaultRules["Règles Officielles Falco"]
        CustomRules["Règles Locales Personnalisées"]
        Engine["Moteur de Corrélation Heuristique"]
        DefaultRules --> Engine
        CustomRules --> Engine
    end

    Falco --> Falco_Engine
    Falco_Engine -->|"Flux HTTP JSON"| Sidekick["Falcosidekick"]

    Sidekick -->|"Notification Discord"| Discord["Salon Discord d'alertes"]
    Sidekick -->|"SMTP Local"| Mailrise["Mailrise (Notifications Sysadmin)"]

2. Déploiement Docker Compose (docker-compose.yaml)

Falco s'exécute dans un conteneur privilégié pour lui permettre de communiquer directement avec le sous-système de traçage du noyau de la machine hôte :

services:
  falco:
    stdin_open: true
    tty: true
    image: falcosecurity/falco:latest
    container_name: falco
    privileged: true
    restart: always
    environment:
      - TZ=${TIME_ZONE}
    volumes:
      # Accès aux points de traçage du noyau
      - /sys/kernel/tracing:/sys/kernel/tracing:ro
      # Corrélation des conteneurs via le socket Docker
      - /var/run/docker.sock:/host/var/run/docker.sock
      # Espaces de nommage des processus et arborescence système hôte
      - /proc:/host/proc:ro
      - /etc:/host/etc:ro
      # Règles locales personnalisées
      - $INFRASTRUCTURE_FOLDER_LOCATION/variable-falco_rules.local.yaml:/etc/falco/falco_rules.local.yaml
    command:
      - /usr/bin/falco
      - -o
      - json_output=true
      - -o
      - json_include_output_property=true
      - -o
      - http_output.enabled=true
      - -o
      - http_output.url=http://falcosidekick:2801/
      - -o
      - plugins[0].init_config.engine_timeout=60
    networks:
      internal-net:
        ipv4_address: 10.2.1.44
    depends_on:
      - falcosidekick

  falcosidekick:
    container_name: falcosidekick
    image: falcosecurity/falcosidekick:latest
    restart: always
    environment:
      - DISCORD_WEBHOOKURL=${FALCOSIDEKICK_DISCORD_WEBHOOKURL}
      - DISCORD_MINIMUMPRIORITY=notice
    networks:
      internal-net:
        ipv4_address: 10.2.1.45

Timeout Engine et Métadonnées Docker

Le paramètre engine_timeout=60 évite les faux positifs et les alertes intempestives lors du redémarrage d'autres conteneurs : il laisse le temps à Falco de collecter les métadonnées Docker (nom du conteneur, image) avant de statuer sur la légitimité d'un événement.


3. Personnalisation des Règles : variable-falco_rules.local.yaml

Les règles standard de Falco sont conçues pour des clusters Kubernetes stricts. Dans d'autre contexte multi-services avec Docker Compose, certains comportements légitimes déclenchent naturellement des alertes s'ils ne sont pas calibrés : * L'exécution de shells légitimes dans les conteneurs administratifs (cronjob, open-terminal, scripts de build MkDocs). * Les healthchecks réseau internes (ping google.fr dans les conteneurs WireGuard/Transmission). * Les sockets réseau bruts créés par Home Assistant pour la découverte IoT. * Les pilotes NVIDIA Container Runtime (nvidia-ctk) créant des exécutables anonymes en mémoire (memfd).

Le fichier de règles locales adapte Falco sans abaisser le niveau de vigilance :

# 1. Autoriser les tests de connectivité (healthchecks) de Transmission et Traefik
- macro: transmission_healthcheck
  condition: ((container.name = "transmission" or container.name endswith "_transmission") and proc.name = "ping")

- macro: traefik_healthcheck
  condition: (container.image.repository = "traefik" and proc.name = "ping")

- macro: user_known_stand_streams_redirect_activities
  override:
    condition: append
  condition: or (transmission_healthcheck or traefik_healthcheck)

# 2. Whitelisting des binaires administratifs du conteneur de maintenance (cronjob)
- macro: cronjob_safe_bins
  condition: ((container.name = "cronjob" or container.image.repository = "cytopia/ansible" or proc.aname in (cron-wrapper, supercronic)) and proc.name in (curl, rsync, xargs, supercronic, find, jq, docker))

- macro: known_drop_and_execute_activities
  override:
    condition: append
  condition: or (cronjob_safe_bins or open_terminal_drop_and_execute)

# 3. Autorisation des shells interactifs attendus (Open WebUI Terminal & Cronjob)
- macro: cronjob_shell
  condition: ((container.name = "cronjob" or container.image.repository = "cytopia/ansible") and proc.name in (bash, sh))

- macro: open_terminal_shell
  condition: (container.name = "open-terminal" or container.image.repository = "ghcr.io/open-webui/open-terminal")

- macro: user_expected_terminal_shell_in_container_conditions
  override:
    condition: append
  condition: or (cronjob_shell or open_terminal_shell)

# 4. Autoriser les bibliothèques GPU NVIDIA CTK
- macro: nvidia_ctk_memfd_ldconfig
  condition: (proc.pname = "nvidia-ctk" and proc.exepath startswith "memfd:runc_cloned:" and proc.exepath endswith "ldconfig")

- macro: known_memfd_execution_processes
  override:
    condition: append
  condition: or (nvidia_ctk_memfd_ldconfig)

# 5. Autoriser les paquets bruts pour la découverte réseau domotique (Home Assistant)
- macro: homeassistant_packet_socket
  condition: ((container.image.repository = "ghcr.io/home-assistant/home-assistant" or proc.cmdline contains "homeassistant") and proc.name = "python3")

- rule: Packet socket created in container
  override:
    condition: append
  condition: and not homeassistant_packet_socket

4. Exemple Concret d'Alerte de Sécurité

Lorsqu'une commande hostile non autorisée est lancée (par exemple, un attaquant ouvrant un shell interactif dans le conteneur Nextcloud) : 1. Le noyau Linux transmet l'appel système execve("/bin/bash") à la sonde eBPF de Falco. 2. Falco évalue la règle Terminal shell in container. 3. Le conteneur n'étant pas dans la liste d'exceptions (open-terminal, cronjob), Falco émet un événement JSON de priorité Notice ou Warning. 4. falcosidekick reçoit le payload et poste instantanément dans Discord #alerte :

{
  "output": "10:14:22.183742419: Notice A shell was spawned in a container with an attached terminal (user=www-data user_loginuid=-1 k8s.ns=<NA> k8s.pod=<NA> container=nextcloud image=nextcloud:latest connection=<NA> shell=bash parent=apache2 cmdline=bash)",
  "priority": "Notice",
  "rule": "Terminal shell in container",
  "time": "2026-09-26T10:14:22.183742419Z"
}
  1. Un webhook ou agent de supervision intercepte le message et notifie immédiatement les administrateurs pour investigation.

5. Maintenance Automatisée

Chaque matin à 06h00, un script de vérification peut contrôler l'état opérationnel des conteneurs :

for container in falco falcosidekick; do
    if ! docker ps --format '{{.Names}}' | grep -q "^${container}$"; then
        echo "Conteneur ${container} inactif ! Redémarrage..."
        docker start "$container"
    fi
done
Cette supervision permet de s'assurer que le moteur de détection d'intrusions reste actif 24h/24 sans interruption de service.


6. Playbook Ansible Prêt à l'Emploi (playbook-falco.yaml)

Ce playbook autonome installe et orchestre la stack de détection runtime : création du dossier /opt/falco, déploiement des règles locales personnalisées, génération du docker-compose.yaml, lancement des conteneurs et mise en place de la surveillance quotidienne :

---
- name: Déploiement de la Détection Runtime Falco et Falcosidekick
  hosts: all
  become: true
  vars:
    # Répertoire d'installation de la stack
    falco_dir: "/opt/falco"
    # Webhook Discord pour la réception des alertes (remplacer par votre URL)
    discord_webhook_url: "https://discord.com/api/webhooks/VOTRE_WEBHOOK_ICI"
    # Priorité minimale d'alerte (notice, warning, error, critical)
    discord_min_priority: "notice"

  tasks:
    # -------------------------------------------------------------------------
    # 1. CONTRÔLE DES PRÉREQUIS DOCKER
    # -------------------------------------------------------------------------
    - name: Vérifier la présence de Docker
      ansible.builtin.command: which docker
      register: docker_check
      changed_when: false
      failed_when: false

    - name: Interrompre si Docker n'est pas installé
      ansible.builtin.meta: end_host
      when: docker_check.rc != 0

    - name: Créer le répertoire de configuration Falco
      ansible.builtin.file:
        path: "{{ falco_dir }}"
        state: directory
        mode: '0755'
        owner: root
        group: root

    # -------------------------------------------------------------------------
    # 2. DÉPLOIEMENT DES RÈGLES LOCALES PERSONNALISÉES
    # -------------------------------------------------------------------------
    - name: Déployer le fichier de règles locales /opt/falco/falco_rules.local.yaml
      ansible.builtin.copy:
        dest: "{{ falco_dir }}/falco_rules.local.yaml"
        mode: '0644'
        owner: root
        group: root
        content: |
          # 1. Autoriser les tests de connectivité (healthchecks) de conteneurs
          - macro: app_healthcheck
            condition: (proc.name = "ping")

          - macro: user_known_stand_streams_redirect_activities
            override:
              condition: append
            condition: or (app_healthcheck)

          # 2. Whitelisting des binaires de maintenance administrative
          - macro: admin_safe_bins
            condition: (proc.name in (curl, rsync, xargs, find, jq, docker))

          - macro: known_drop_and_execute_activities
            override:
              condition: append
            condition: or (admin_safe_bins)

          # 3. Autoriser les shells interactifs pour les conteneurs d'administration
          - macro: admin_shell
            condition: (container.name in ("open-terminal", "cronjob") and proc.name in (bash, sh))

          - macro: user_expected_terminal_shell_in_container_conditions
            override:
              condition: append
            condition: or (admin_shell)

          # 4. Autoriser les paquets bruts pour la domotique (Home Assistant)
          - macro: homeassistant_packet_socket
            condition: ((container.image.repository = "ghcr.io/home-assistant/home-assistant" or proc.cmdline contains "homeassistant") and proc.name = "python3")

          - rule: Packet socket created in container
            override:
              condition: append
            condition: and not homeassistant_packet_socket

    # -------------------------------------------------------------------------
    # 3. DÉPLOIEMENT DU FICHIER DOCKER COMPOSE
    # -------------------------------------------------------------------------
    - name: Déployer le fichier docker-compose.yaml pour Falco & Falcosidekick
      ansible.builtin.copy:
        dest: "{{ falco_dir }}/docker-compose.yaml"
        mode: '0644'
        owner: root
        group: root
        content: |
          services:
            falco:
              stdin_open: true
              tty: true
              image: falcosecurity/falco:latest
              container_name: falco
              privileged: true
              restart: always
              volumes:
                - /sys/kernel/tracing:/sys/kernel/tracing:ro
                - /var/run/docker.sock:/host/var/run/docker.sock
                - /proc:/host/proc:ro
                - /etc:/host/etc:ro
                - ./falco_rules.local.yaml:/etc/falco/falco_rules.local.yaml:ro
              command:
                - /usr/bin/falco
                - -o
                - json_output=true
                - -o
                - json_include_output_property=true
                - -o
                - http_output.enabled=true
                - -o
                - http_output.url=http://falcosidekick:2801/
                - -o
                - plugins[0].init_config.engine_timeout=60
              depends_on:
                - falcosidekick

            falcosidekick:
              container_name: falcosidekick
              image: falcosecurity/falcosidekick:latest
              restart: always
              environment:
                - DISCORD_WEBHOOKURL={{ discord_webhook_url }}
                - DISCORD_MINIMUMPRIORITY={{ discord_min_priority }}

    # -------------------------------------------------------------------------
    # 4. DÉMARRAGE DE LA STACK AVEC DOCKER COMPOSE
    # -------------------------------------------------------------------------
    - name: Lancer la stack Falco avec Docker Compose
      ansible.builtin.shell: |
        docker compose -f {{ falco_dir }}/docker-compose.yaml up -d
      register: compose_up
      changed_when: "'Started' in compose_up.stdout or 'Running' in compose_up.stdout or 'Created' in compose_up.stdout"

    # -------------------------------------------------------------------------
    # 5. DÉPLOIEMENT DU SCRIPT DE SURVEILLANCE AUTOMATISÉE
    # -------------------------------------------------------------------------
    - name: Déployer le script de maintenance /usr/local/bin/check_falco.sh
      ansible.builtin.copy:
        dest: /usr/local/bin/check_falco.sh
        mode: '0755'
        owner: root
        group: root
        content: |
          #!/bin/bash
          # Surveillance et relance automatique des conteneurs
          for container in falco falcosidekick; do
              if ! docker ps --format '{{ "{{" }}.Names{{ "}}" }}' | grep -q "^$container$"; then
                  echo "[$(date)] Conteneur $container inactif, relance..."
                  docker compose -f {{ falco_dir }}/docker-compose.yaml up -d "$container"
              fi
          done

    - name: Mettre en place la tâche cron quotidienne de surveillance à 06h00
      ansible.builtin.cron:
        name: "Supervision quotidienne Falco et Falcosidekick"
        minute: "0"
        hour: "6"
        job: "/usr/local/bin/check_falco.sh > /dev/null 2>&1"
        user: root

    # -------------------------------------------------------------------------
    # 6. VALIDATION DE L'ÉTAT OPÉRATIONNEL
    # -------------------------------------------------------------------------
    - name: Vérifier que les conteneurs Falco sont actifs
      ansible.builtin.shell: |
        docker ps --filter "name=falco" --format '{{ "{{" }}.Names{{ "}}" }}: {{ "{{" }}.Status{{ "}}" }}'
      register: falco_status
      changed_when: false

    - name: Afficher le statut des conteneurs
      ansible.builtin.debug:
        msg: "{{ falco_status.stdout_lines }}"

Comment l'exécuter :

ansible-playbook -i "mon_serveur," -u root playbook-falco.yaml -e "discord_webhook_url=https://discord.com/api/webhooks/VOTRE_WEBHOOK"
Ce playbook est autonome : il permet de déployer et configurer la stack complète de détection d'intrusions kernel eBPF en une seule commande.