ebfw: eBPF-файервол исходящего трафика подов Kubernetes

Логотип ebfw

ebfw — это единственный eBPF-агент уровня узла, который показывает — и контролирует — к каким ресурсам разрешено обращаться каждому поду на узле Kubernetes. Одна программа cgroup_skb, прикреплённая к корневой cgroup узла, видит весь исходящий DNS, TLS SNI, HTTP и новые TCP-соединения от каждого пода; uprobe на SSL_write восстанавливает пути HTTPS-запросов до шифрования. Каждое событие привязывается к конкретному поду (namespace/name). Те же хуки ядра разрешают или запрещают исходящий трафик (egress) для каждого пода по домену / IP / CIDR / порту, управляясь нативными Kubernetes-ресурсами EgressPolicy (CRD). Агент также видит HTTP-пути и заголовки и позволяет политикам фильтровать по методу и пути (проверка уже работает; применение на уровне L7 запланировано в roadmap).

Как это работает

  • Одна программа cgroup_skb/egress в корневой cgroup v2 узла видит исходящий трафик каждого пода на узле — DNS, TLS ClientHello SNI, обычный HTTP и новые TCP-соединения — без sidecar-контейнера на каждый под.

  • Uprobe на SSL_write читает открытый текст HTTPS-запроса до шифрования, восстанавливая пути, которые пакетный уровень увидеть не может. Автоматически обнаруживается для libssl каждого контейнера, работает непрерывно (без семплирования).

  • Атрибуция пода выполняется прямо в ядре по идентификатору cgroup источника, а затем обогащается до namespace/name через Pods informer уровня узла. Те же карты (maps) возвращают вердикты политик обратно в ядро для применения.

flowchart LR
    pods["Pods on node"]

    subgraph kernel["in-kernel (eBPF)"]
        egress["cgroup_skb/egress<br/>DNS, TLS SNI, HTTP, CONNECT"]
        uprobe["SSL_write uprobe<br/>HTTPS path + headers"]
    end

    agent["ebfw agent (Go)<br/>attribute + policy engine"]
    informer["k8s Pods informer"]
    out["text / JSON<br/>Prometheus /metrics"]

    pods --> egress
    pods --> uprobe
    egress -- "+ cgroup id" --> agent
    uprobe -- "+ cgroup id" --> agent
    informer -- "namespace/name" --> agent
    agent --> out
    agent -. "allow / deny verdicts" .-> kernel

Что видно

DNS      10.42.0.9 ? example.com (TypeA)  pod=default/probe
TLS      10.42.0.9 -> example.com  (104.20.23.154:443)  pod=default/probe
HTTP     10.42.0.9 -> GET example.com/foo/bar  pod=default/probe
HTTPS  [pid=2550689 curl] GET example.com/secret/path?token=abc123  pod=default/probe
CONNECT  10.42.0.9 -> 104.20.23.154:443  pod=default/probe

Или структурированный JSON (EBFW_OUTPUT=json, один объект на строку):

{"ts":"2026-06-28T09:14:01Z","kind":"https","domain":"example.com","method":"GET","path":"/secret/path","pid":2550689,"comm":"curl","pod":{"namespace":"default","name":"probe","uid":"be31e934-…","container":"ad68e835…","qos":"besteffort","node":"k3d-ebfw-server-0"}}

Управление

Описывайте политики исходящего трафика как Kubernetes-ресурсы — EgressPolicy (с привязкой к namespace) и ClusterEgressPolicy (на весь кластер) — агент применяет их в трёх режимах: off (наблюдение без действий), log (добавляет вердикты в журнал, без блокировок) или enforce (блокирует запрещённый исходящий трафик). Сочетание defaultAction: Deny с podSelector ограничивает выбранный набор подов строгим списком разрешённых адресов. Подробнее: docs/egresspolicy.md.

Быстрый старт

helm install ebfw ./helm/ebfw -n ebfw --create-namespace \
  --set agent.enforceMode=log        # сначала наблюдайте вердикты; переключите на enforce, когда будете готовы

kubectl apply -f config/samples/ebfw_v1_egresspolicy.yaml

Полная инструкция → docs/install.md.

Чем это отличается от Cilium?

Cilium — это CNI, он управляет сетью всего кластера. ebfw работает рядом с тем, что у вас уже есть. Он прикрепляется к корневой cgroup узла, поэтому DaemonSet можно установить на любой узел (с любым CNI или вовсе без Kubernetes), понаблюдать за трафиком в режиме log и убрать его без единого последствия для связности — плоскость данных он не трогает.

Главное отличие: ebfw читает пути и заголовки HTTPS-запросов через uprobe на SSL_write — до шифрования, без прокси и без MITM TLS. Cilium для той же цели требует терминирующий Envoy и подменённые сертификаты.

ebfw — это лёгкий межсетевой экран исходящего трафика и слой видимости L7 на уровне пода; Cilium — полноценная сетевая платформа (с поддержкой применения L7-политик уже сейчас, чего в ebfw пока нет). Полное сравнение по функциям → docs/comparison.md.

Хосты с контейнерами (без Kubernetes)

ebfw не привязан к Kubernetes. Тот же агент — в виде привилегированного контейнера или единственного бинарника на хосте — наблюдает и контролирует исходящий трафик каждого контейнера на обычном хосте Docker / containerd, используя YAML-файл политик вместо CRD (те же возможности видимости, то же применение на уровне узла, без API-сервера и оператора). Подробнее: Запуск в автономном режиме.

Лицензия

MIT © dvrkn.


Создано с использованием eBPF skill для ориентирования в хуках, картах и верификаторе, а также cilium/ebpf (ebpf-go, MIT) в качестве загрузчика.

© 2026 meganuke