Saltar al contenido

Falco y eBPF: detección en tiempo de ejecución para contenedores y hosts

    Falco y eBPF:

    detección en tiempo de ejecución para contenedores y hosts

    Serie Blue Team  |  unfantasmaenelsistema.com

    El hardening de una imagen, las políticas de admisión de Kubernetes y el escaneo de vulnerabilidades trabajan antes de que el contenedor arranque. Pero cuando el proceso ya está corriendo y alguien abre una shell dentro de él, escribe en `/etc/`, monta el socket de Docker o abre una conexión saliente que ese servicio nunca hace, hace falta algo que lo vea mientras ocurre. Esa capa se llama seguridad en tiempo de ejecución (runtime security), y en el mundo open source la referencia es Falco.

    Falco es un proyecto de la CNCF (graduado en 2024) que observa las llamadas al sistema del kernel, las compara con un conjunto de reglas y emite una alerta cuando algo se sale de lo esperado. La pieza que hace esa observación posible sin parchear el kernel ni cargar módulos propietarios es eBPF. Este artículo explica qué es eBPF y por qué cambia las reglas del juego, cómo está montado Falco por dentro, qué detectan sus reglas de referencia, cómo se afina para que no se convierta en ruido, y cómo encaja con Tetragon, Tracee y el control de admisión.

    Qué aprenderás en este artículo

    Qué es eBPF y por qué permite observar el kernel de forma segura, sin módulos propietarios · La arquitectura de Falco: fuente de eventos (driver), motor de reglas y salidas · Las reglas de referencia y qué actividad real detectan en contenedores y en el host · Cómo se afinan los falsos positivos con listas de excepciones y macros · Alternativas y complementos: Tetragon, Tracee, y dónde termina la detección y empieza el bloqueo · El encaje con el control de admisión (OPA/Gatekeeper, Kyverno) y el coste real de tenerlo

    1. eBPF: ejecutar código en el kernel sin romperlo

    eBPF (siglas de extended Berkeley Packet Filter) es una máquina virtual dentro del kernel de Linux que permite cargar y ejecutar pequeños programas en respuesta a eventos del propio kernel: una llamada al sistema, la entrada o salida de una función, la recepción de un paquete, un cambio de contexto. El programa se engancha a un punto de interés (un «hook»), se ejecuta cuando ese evento sucede y puede enviar datos al espacio de usuario a través de estructuras compartidas llamadas «mapas».

    Lo relevante para seguridad es cómo consigue eBPF hacer esto sin comprometer la estabilidad del sistema. Antes de cargar un programa eBPF, el kernel lo pasa por un verificador: analiza todos los caminos de ejecución posibles y rechaza el programa si puede entrar en un bucle infinito, acceder a memoria fuera de límites o dejar el kernel en un estado inconsistente. Un programa que pasa el verificador no puede colgar la máquina. Esa garantía es lo que diferencia a eBPF de un módulo de kernel tradicional, donde un fallo de puntero es un cuelgue total del sistema (kernel panic).

    EnfoqueCómo obtiene los eventosRiesgo / coste
    Módulo de kernel clásicoCódigo nativo cargado en el kernel (el driver kmod histórico de Falco)Un fallo tumba el host; hay que recompilar por versión de kernel
    eBPF moderno (CO-RE)Programa eBPF verificado, portable entre kernels vía BTFBajo: el verificador acota el programa; sin recompilar por kernel
    Auditoría del kernel (auditd)Subsistema audit del kernel, reglas de syscallUn solo consumidor del socket de audit por host; formato verboso
    Polling desde espacio de usuario (p. ej. leer /proc)Consultas periódicas al estado del sistemaCiego entre consultas; no ve actividad efímera

    El término CO-RE (compilar una vez, ejecutar en todas partes) merece una nota: junto con la información de tipos del kernel (BTF), permite compilar el programa eBPF una vez y ejecutarlo en kernels con estructuras internas distintas, sin recompilar en cada equipo. Es lo que hace que un agente basado en eBPF moderno se despliegue como un binario normal y no como un proyecto de compilación en cada nodo.

    eBPF no es solo seguridad

    La misma tecnología está detrás de la observabilidad de red (Cilium), del perfilado de rendimiento (bpftrace, los flame graphs de Brendan Gregg), del balanceo de carga (Katran) y de herramientas de diagnóstico como `execsnoop` u `opensnoop` del paquete bcc. Falco es una aplicación concreta de una capacidad de propósito general.

    2. La arquitectura de Falco

    Falco se compone de tres bloques: de dónde saca los eventos, cómo decide si un evento importa, y qué hace cuando importa.

    2.1 La fuente de eventos: el driver

    Falco necesita ver las llamadas al sistema de toda la máquina. Para conseguirlas usa un driver, y hoy hay tres opciones:

    • eBPF moderno (`modern_ebpf`): la opción recomendada. Se carga como un programa eBPF CO-RE, no requiere módulo ni compilación, y necesita un kernel razonablemente reciente (5.8 o superior) con BTF.
    • eBPF con sonda legada (`ebpf`): una sonda eBPF que se compila para el kernel del host; opción intermedia para kernels antiguos.
    • Módulo de kernel (`kmod`): el driver histórico, un módulo que se inserta en el kernel. Sigue disponible pero se desaconseja para despliegues nuevos por el riesgo que implica.

    El driver entrega un flujo de eventos crudos (syscalls con sus argumentos, más metadatos de proceso y de contenedor) a la librería libsinsp, que los enriquece: resuelve el nombre del contenedor y la imagen, el pod y el namespace de Kubernetes, el árbol de proceso padre, el usuario. Ese contexto es lo que hace que una regla pueda decir «shell dentro de un contenedor» en lugar de solo «execve de /bin/bash».

    2.2 El motor de reglas

    Las reglas de Falco se escriben en YAML y tienen tres piezas: una condición (la expresión que se evalúa contra cada evento), una salida (el texto de la alerta, con campos interpolados) y una prioridad (`EMERGENCY` … `DEBUG`). Para no repetir expresiones, Falco usa macros (condiciones con nombre, reutilizables) y listas (conjuntos de valores). El conjunto oficial, `falco_rules.yaml`, trae decenas de macros como `container`, `spawned_process` o `shell_procs` que las reglas combinan.

    # Estructura de una regla de Falco (ejemplo del conjunto de referencia, resumido)
    - macro: container
      condition: (container.id != host)
     
    - macro: spawned_process
      condition: (evt.type in (execve, execveat) and evt.dir=<)
     
    - list: shell_binaries
      items: [ash, bash, csh, ksh, sh, tcsh, zsh, dash]
     
    - rule: Terminal shell in container
      desc: Se ha iniciado una shell interactiva dentro de un contenedor
      condition: >
        spawned_process and container
        and proc.name in (shell_binaries)
        and proc.tty != 0
      output: >
        Shell abierta en contenedor
        (user=%user.name container=%container.name image=%container.image.repository
         proc=%proc.cmdline parent=%proc.pname)
      priority: NOTICE
      tags: [container, shell, mitre_execution, T1059]

    Los campos disponibles (`proc.*`, `container.*`, `fd.*`, `k8s.*`, `user.*`, `evt.*`) son los mismos que expone Sysdig, el proyecto del que nació Falco. La condición se evalúa en el propio proceso de Falco, en espacio de usuario, sobre el flujo que sube el driver.

    2.3 Las salidas

    Cuando una regla dispara, Falco emite la alerta por los canales que tenga configurados: la salida estándar (formato texto o JSON), syslog, un fichero, o un HTTP POST a un endpoint. Ese endpoint suele ser Falcosidekick, un componente que abre el abanico a más de 50 destinos: Slack, Teams, un SIEM (Elastic, Splunk), Prometheus/Alertmanager, un bucket de almacenamiento, una función serverless, o Falco Talon como motor de respuesta. En Kubernetes se despliega como DaemonSet (un pod de Falco por nodo) mediante el chart de Helm oficial.

    ComponenteFunciónDónde vive
    driver (modern_ebpf)Captura las syscalls de todo el hostKernel, cargado por Falco
    libsinsp / libscapParseo y enriquecimiento (contenedor, k8s, árbol de proceso)Proceso de Falco
    motor de reglasEvalúa condiciones YAML contra cada eventoProceso de Falco
    FalcosidekickEnruta las alertas a destinos externosPod aparte / DaemonSet
    Falcosidekick-UIPanel web para revisar alertasDespliegue opcional
    Falco TalonRespuesta automatizada (matar pod, aislar, etiquetar)Despliegue opcional

    3. Qué detectan las reglas de referencia

    El valor inmediato de Falco está en su conjunto de reglas por defecto, mantenido por la comunidad y publicado por separado del binario (el artefacto `falco-rules`, versionado). Estas son las categorías que cubre, con ejemplos de reglas reales:

    Actividad detectadaRegla de ejemploPor qué importa
    Shell interactiva en contenedorTerminal shell in containerUn contenedor de aplicación no debería tener a nadie escribiendo comandos dentro
    Escritura en directorios del sistemaWrite below etc / Write below root / Write below binary dirModificar /etc, /bin o /usr/bin en caliente es señal de manipulación o persistencia
    Lectura de datos sensiblesRead sensitive file untrusted (p. ej. /etc/shadow)Acceso a credenciales locales por un proceso que no es el habitual
    Conexión saliente inesperadaUnexpected outbound connection / Outbound connection to C2 serversUn servicio que solo debería recibir tráfico y de pronto llama a fuera
    Montaje del socket de DockerLaunch privileged container / Docker socket mounted / mount from containerAcceso al socket de Docker desde un contenedor equivale a root en el host
    Contenedor privilegiado o con capacidadesLaunch privileged container / Change namespace via setnsRuptura de aislamiento; camino habitual de escape de contenedor
    Modificación de binarios o herramientas de redLaunch remote file copy tools / Netcat remote code executionDescarga de herramientas (curl, wget) o uso de netcat dentro de un contenedor
    Cambios en la configuración de Falco o del kernelModify container entrypoint / Linux kernel module injectionIntento de cegar la propia telemetría o cargar un rootkit
    Actividad sospechosa en el plano de KubernetesK8s Serviceaccount created / Attach/Exec Pod (audit)Con el plugin de k8s audit, `kubectl exec` y creación de cuentas de servicio

    Falco puede consumir dos fuentes además de las syscalls, mediante su sistema de plugins: el registro de auditoría de la API de Kubernetes (para ver `exec`, `attach`, creación de roles y secretos) y registros de proveedores cloud (CloudTrail de AWS, Okta, GitHub). Con eso, una sola herramienta cubre actividad en el nodo y en el plano de control.

    El conjunto por defecto está pensado para dispararse poco… si el clúster es limpio

    Reglas como «Write below etc» o «Read sensitive file» son ruidosas en clústeres donde las imágenes escriben en /etc al arrancar o hacen apt-get en el arranque del contenedor. Eso no es un fallo de Falco: es que esas prácticas son exactamente lo que la regla busca. El afinado (sección 4) es parte del despliegue, no un extra.

    4. Afinado: convivir con los falsos positivos

    Una regla de Falco que genera cien alertas al día por comportamiento legítimo se ignora en una semana. El afinado consiste en describir con precisión qué es «normal» en tu entorno para que solo quede lo anómalo. Hay varias herramientas, de menos a más invasiva:

    • Listas de excepciones dentro de la regla (`exceptions`): el mecanismo recomendado desde Falco 0.28. Permite añadir a una regla concreta combinaciones de campos que no deben disparar (por ejemplo, «este proceso, en esta imagen, escribiendo en esta ruta») sin reescribir la condición.
    • Macros y listas propias: si varias reglas comparten una excepción (una lista de imágenes de confianza, un conjunto de puertos internos), se define una vez como lista y se referencia.
    • Anular la regla completa: redefinir una regla del conjunto oficial con el mismo nombre en tu fichero local para cambiar su condición, su prioridad o desactivarla (`enabled: false`).
    • Reglas propias: para lo que el conjunto por defecto no cubre — un binario que nunca debería ejecutarse en producción, una ruta concreta que solo escribe un proceso concreto.
    # Excepción a una regla del conjunto oficial, en un fichero local (rules.d/)
    # Se carga DESPUÉS de falco_rules.yaml y solo aporta la excepción.
    - rule: Write below etc
      exceptions:
        - name: proc_writer_conocido
          fields: [proc.name, fd.directory, container.image.repository]
          comps: [=, =, =]
          values:
            - [config-reloader, /etc/nginx, miorg/nginx-sidecar]
            - [update-ca-certificates, /etc/ssl/certs, miorg/base-debian]
     
    # Regla propia: en producción, /app nunca ejecuta un intérprete nuevo
    - rule: Interprete inesperado en pod de produccion
      desc: Ejecucion de python/perl/ruby en un contenedor de la app en prod
      condition: >
        spawned_process and container
        and k8s.ns.name = "produccion"
        and proc.name in (python3, perl, ruby, node)
        and not proc.pname in (supervisord, tini)
      output: >
        Interprete lanzado en prod (pod=%k8s.pod.name img=%container.image.repository
         proc=%proc.cmdline parent=%proc.pname user=%user.name)
      priority: WARNING
      tags: [container, mitre_execution]

    El flujo de trabajo habitual: desplegar Falco en modo observación una o dos semanas, recoger todo lo que dispara, clasificar cada alerta recurrente como «esto es normal aquí» (excepción) o «esto habría que arreglarlo» (hallazgo), y solo entonces conectar las salidas al canal donde alguien las va a mirar. Falco trae `falco –validate` para comprobar la sintaxis de las reglas antes de aplicarlas.

    Herramientas de afinado

    falcoctl gestiona la instalación y actualización de los conjuntos de reglas y plugins desde artefactos OCI. El proyecto falco-testing permite escribir pruebas para tus reglas. Y los playground en línea de falco.org ayudan a probar condiciones contra eventos de ejemplo sin desplegar nada.

    5. Alternativas y complementos

    Falco no es la única herramienta de runtime security basada en eBPF, y las demás resuelven matices distintos.

    ProyectoEnfoqueDiferencia con Falco
    Tetragon (Isovalent/Cilium, CNCF)Observabilidad y bloqueo (enforcement) en el kernel vía eBPFPuede bloquear (matar el proceso, SIGKILL) desde el propio kernel, no solo alertar; políticas TracingPolicy
    Tracee (Aqua)Detección en runtime y forense, eBPF CO-REFuerte en firmas de comportamiento y en análisis de eventos; también detección de explotación de CVE conocidas
    FalcoDetección y alerta, motor de reglas YAML muy legibleEl ecosistema más maduro de reglas, salidas y comunidad; el enforcement es externo (Talon) y reactivo
    KubeArmorEnforcement a nivel de pod con LSM (BPF-LSM, AppArmor)Orientado a políticas de menor privilegio por workload, más que a detección de anomalías
    Auditd + Sysmon for LinuxAuditoría del kernel clásicaSin conciencia nativa de contenedor/k8s; más pesado de correlacionar; útil como capa host

    La distinción importante es detección frente a prevención. Falco observa y avisa: entre que la regla dispara y que alguien (o Talon) actúa, pasa un tiempo durante el cual el proceso sospechoso sigue vivo. Tetragon y KubeArmor pueden cortar la acción en el momento, a costa de un modelo de políticas más rígido y del riesgo de bloquear algo legítimo. Muchas organizaciones despliegan Falco para tener visibilidad amplia y añaden enforcement selectivo solo en los workloads críticos.

    5.1 Dónde encaja el control de admisión

    El control de admisión de Kubernetes (OPA/Gatekeeper, Kyverno) actúa en un momento anterior y complementario: rechaza el pod antes de crearlo si viola una política — imagen sin firmar, `privileged: true`, `hostPath` a rutas sensibles, ausencia de `securityContext`. Es prevención estática en el momento del despliegue. Falco entra después, cuando el pod ya admitido hace algo que su manifiesto no revelaba. Son capas distintas de la misma defensa:

    • Admisión (Kyverno/Gatekeeper): «este pod no puede ser privilegiado» — se evalúa al crear el recurso.
    • Runtime (Falco): «este pod, que no es privilegiado, acaba de intentar un `setns` o de montar el socket de Docker» — se evalúa mientras se ejecuta.
    • Enforcement runtime (Tetragon/Talon): «y por tanto lo matamos / aislamos el nodo / etiquetamos el pod para cuarentena».

    6. Coste y cobertura

    Instrumentar todas las syscalls de un host tiene un precio, y conviene medirlo antes de prometer despliegue en flota.

    • CPU y memoria: el DaemonSet de Falco con driver eBPF moderno suele consumir del orden de una fracción de núcleo y 128–512 MB de RAM por nodo en cargas normales; sube con el volumen de syscalls (nodos con mucha actividad de red o de proceso) y con reglas caras. Es comparable a otros agentes de nodo, pero hay que dimensionarlo, no darlo por gratis.
    • Requisitos de kernel: el driver `modern_ebpf` necesita kernel 5.8+ con `CONFIG_DEBUG_INFO_BTF`. Distribuciones recientes (Ubuntu 20.04+ con HWE, Amazon Linux 2023, Bottlerocket, GKE/EKS/AKS actuales) lo cumplen; kernels viejos obligan al driver legado o al módulo.
    • Entornos gestionados restringidos: en algunos contenedores serverless (Fargate, Cloud Run) no tienes acceso al kernel del nodo y Falco no puede desplegarse como DaemonSet; ahí la detección se apoya en los logs de auditoría de la plataforma.
    • Cobertura de la telemetría: Falco ve syscalls y, con plugins, k8s audit y logs cloud. No ve tráfico de red descifrado, ni el contenido de la memoria de un proceso, ni actividad que no pase por una syscall.
    • Punto ciego durante el arranque: si Falco arranca después que un pod, se pierde lo que ese pod hizo en sus primeros segundos. En un DaemonSet bien configurado la ventana es pequeña, pero existe.

    La parada del agente es en sí misma un evento

    Un atacante con privilegios en el nodo puede intentar parar el DaemonSet de Falco o descargar el programa eBPF. Que el pod de Falco deje de reportar debe generar una alerta en el sistema que recibe sus salidas (una alarma por ausencia de latido: si no llega telemetría en X minutos, avisa). Falco no se protege a sí mismo de root en el host.

    7. Puesta en marcha en un laboratorio

    Para practicar sin arriesgar nada, un clúster local (kind, minikube o k3d) y el chart oficial bastan. El objetivo del laboratorio es doble: ver una alerta de principio a fin y aprender a afinar una regla ruidosa.

    # 1) Instalar Falco con salidas a stdout en JSON y la UI (laboratorio)
    helm repo add falcosecurity https://falcosecurity.github.io/charts
    helm install falco falcosecurity/falco \
      --namespace falco --create-namespace \
      --set driver.kind=modern_ebpf \
      --set falcosidekick.enabled=true \
      --set falcosidekick.webui.enabled=true
     
    # 2) Ver el flujo de alertas
    kubectl logs -n falco -l app.kubernetes.io/name=falco -c falco -f
     
    # 3) Disparar la regla 'Terminal shell in container' a propósito
    kubectl run demo --image=nginx --restart=Never
    kubectl exec -it demo -- bash        # <-- Falco debe emitir un NOTICE
     
    # 4) Validar la sintaxis de un fichero de reglas propio antes de aplicarlo
    falco --validate /etc/falco/rules.d/local_rules.yaml

    A partir de ahí, ejercicios útiles: montar `/var/run/docker.sock` en un pod y ver qué reglas saltan; escribir en `/etc/` desde un contenedor; lanzar `curl` a una IP externa desde un pod que no debería; y luego escribir la excepción que silencia el caso legítimo sin silenciar el malicioso. El proyecto event-generator de falcosecurity automatiza la generación de actividad sospechosa controlada para probar el despliegue.

    Marco legal y ámbito de uso

    Falco procesa datos que reflejan la actividad de personas: comandos que ejecuta cada usuario dentro de los contenedores, sesiones, accesos a ficheros, conexiones de red. Desplegarlo sobre sistemas corporativos exige cumplir la normativa de protección de datos y laboral: información previa y por escrito a la plantilla sobre qué se registra y con qué finalidad, proporcionalidad, minimización y plazos de conservación (RGPD y LOPDGDD, y el art. 20.3 del Estatuto de los Trabajadores en cuanto al control empresarial). El acceso o la interceptación no autorizados de sistemas y datos ajenos están tipificados en los arts. 197 bis, 197 ter y 264 del Código Penal. Todo lo de este artículo se aplica a infraestructura propia o a una organización que te ha autorizado por escrito a monitorizarla; las pruebas se hacen en un laboratorio aislado.

    Conclusión

    Falco cubre un hueco que las capas previas — imagen endurecida, escaneo, control de admisión — dejan abierto por diseño: lo que un contenedor o un host hace después de arrancar. eBPF es lo que hace esa vigilancia asumible: un verificador del kernel garantiza que el programa de observación no puede tumbar la máquina, y CO-RE lo convierte en un binario que se despliega sin compilar nada en cada nodo.

    El trabajo real no está en instalarlo — el chart lo pone en marcha en minutos — sino en el afinado: describir qué es normal en tu entorno hasta que cada alerta que llega merezca una mirada. Y en tener claro el perímetro de la herramienta: Falco detecta y avisa. Cortar la acción en el momento es trabajo de Tetragon, KubeArmor o un motor de respuesta como Talon; impedir que el pod inseguro llegue a crearse, del control de admisión. Falco es la pieza que te dice que algo pasó, con contexto suficiente para actuar.

    Referencias y recursos

    falco.org — documentación oficial, y falco.org/docs/rules para la sintaxis del motor de reglas · github.com/falcosecurity/rules — el conjunto de reglas de referencia, versionado · github.com/falcosecurity/falcosidekick y falcosecurity/falco-talon — salidas y respuesta · github.com/falcosecurity/event-generator — generador de actividad sospechosa para probar el despliegue · ebpf.io — introducción a eBPF, el verificador y CO-RE; y los proyectos Tetragon y Tracee · Nuestros artículos sobre seguridad en Docker, seguridad en Kubernetes, auditd, osquery y cómo funciona un EDR — el contexto donde encaja Falco

    unfantasmaenelsistema.com | Seguridad, sistemas y todo lo que no debería funcionar (pero funciona)

    Resumen de privacidad

    Esta web utiliza cookies para que podamos ofrecerte la mejor experiencia de usuario posible. La información de las cookies se almacena en tu navegador y realiza funciones tales como reconocerte cuando vuelves a nuestra web o ayudar a nuestro equipo a comprender qué secciones de la web encuentras más interesantes y útiles.