Выберите продукт

Kubernetes egress: Egress Gateway, SNAT и static IP для контроля исходящего трафика

Исходящий трафик (egress) в Kubernetes часто «прыгает» по IP из-за SNAT на нодах. Разберём путь пакета, варианты NAT по умолчанию и Egress Gateway в Cilium/Calico, egress control через NetworkPolicy, а также диагностику и аудит: кто, куда и с какого адреса ходит.
Kubernetes egress: Egress Gateway, SNAT и static IP для контроля исходящего трафика

В Kubernetes входящий трафик обычно быстро приводят в порядок через Ingress/LoadBalancer. А вот исходящий (egress) часто оставляют «как есть» — до первого требования от внешнего API или службы безопасности: нужен один static IP для allowlist, нужен egress control по namespace, нужен audit traffic (кто и куда ходит), и всё это не должно ломаться при пересоздании Pod или смене ноды.

Ниже — практическая шпаргалка, как именно в Kubernetes формируется egress, где появляется SNAT, какие есть варианты «выдать» подам стабильный внешний IP, и чем обычно отличаются подходы в Cilium и Calico.

Базовая анатомия egress: от Pod до интернета

Типовой путь пакета «Pod → внешний адрес» выглядит так:

  • Приложение в Pod открывает соединение на внешний IP/домен.
  • Трафик выходит из сетевого неймспейса Pod в CNI (veth/bridge/overlay).
  • Дальше пакет попадает на ноду и уходит через её маршрут по умолчанию.
  • Если сеть Pod не маршрутизируема во внешнюю сеть (что почти всегда так), где-то выполняется NAT, чаще всего SNAT (подмена source IP на внешний IP ноды или другого «шлюза»).

Ключевой вывод: «какой внешний IP увидит интернет» определяется точкой, где выполняется SNAT. Если SNAT делается на каждой ноде — внешний IP будет равен IP ноды, на которой прямо сейчас запущен Pod. Отсюда и «прыгание» адреса.

Проблема egress почти всегда сводится к одному: вам нужно управлять тем, где именно выполняется SNAT и каким адресом он подменяет source IP.

Почему одного NetworkPolicy обычно недостаточно

NetworkPolicy отвечает за «кому можно, кому нельзя» на уровне L3/L4 (иногда L7 — если ваш CNI это поддерживает). Но NetworkPolicy не решает задачу static IP: она не «собирает» трафик в одну точку и не гарантирует исходный адрес.

Поэтому в проде часто нужны две составляющие:

  • Policy: ограничения egress по направлениям (CIDR/порты/DNS/FQDN).
  • Gateway/NAT: стабильная точка выхода (Egress Gateway) и предсказуемый SNAT.

Вариант 1: SNAT на нодах (быстро, но IP не фиксированный)

Во многих кластерах egress работает «сам» благодаря NAT на нодах. Реализация зависит от дистрибутива, CNI и сетевой схемы, но результат обычно такой: внешние системы видят исходящие подключения с IP ноды.

Плюсы:

  • Ничего дополнительно не настраивать.
  • Нет единой точки отказа (egress распределён).
  • Часто максимальная производительность — трафик выходит локально с ноды.

Минусы:

  • Нет static IP: IP меняется при переселении Pod.
  • Сложнее audit traffic: нужно собирать логи/flow с множества нод.
  • Ограничения egress усложняются: можно запретить, но трудно «направить через один шлюз».

Как быстро понять, откуда реально идёт SNAT

Проверка «какой IP видит интернет» изнутри кластера:

kubectl run -it --rm nettest --image=curlimages/curl -- sh
curl -s ifconfig.me

Если вы видите IP ноды (или разные IP в разные запуски/после рескейла) — SNAT «размазан» по нодам.

Если под egress-ноды планируются отдельные инстансы (с фиксированными адресами и предсказуемыми маршрутами), практично держать их на отдельном пуле виртуальных машин: VDS удобно масштабировать и обслуживать независимо от рабочих нод кластера.

FastFox VDS
Облачный VDS-сервер в России
Аренда виртуальных серверов с моментальным развертыванием инфраструктуры от 195₽ / мес

Чтобы оффер не мешал чтению, ниже — схема, а уже затем продолжим настройку.

Схема: поды на рабочих нодах, а исходящий трафик направляется на отдельные egress-ноды

Вариант 2: Egress Gateway — централизованный выход и предсказуемый static IP

Egress Gateway — это архитектурный паттерн и/или функция CNI, которая делает так, чтобы выбранные Pod/namespace/сервисы выходили наружу через выделенный набор нод-шлюзов. На этих нодах вы:

  • выполняете SNAT на заранее заданный адрес;
  • получаете управляемый egress control;
  • упрощаете audit traffic (одна точка агрегации).

Ключевая идея: отделяем «рабочие» ноды от «egress» нод

Обычно делают отдельный пул egress-нод (например, 2–3 штуки), помечают их label’ом и настраивают CNI так, чтобы трафик выбранных подов туннелировался или маршрутизировался к этим нодам, а уже там делался SNAT.

Чтобы IP был действительно «статичным», у egress-нод должен быть:

  • стабильный публичный IPv4 (или несколько, если нужен шардинг);
  • предсказуемый маршрут в аплинк;
  • отсутствие автозамены адреса при пересоздании (в облаках это Elastic/Floating IP; в собственной инфраструктуре — резервирование адреса).

Cilium Egress Gateway: типовая схема

Cilium Egress Gateway — один из самых практичных способов сделать управляемый egress без ручных «простыней» iptables. Что обычно используют:

  • выбор источников (по label Pod/namespace);
  • выбор назначения (CIDR; FQDN обычно решается через политики/механизмы уровня Cilium отдельно);
  • привязка к конкретному egress-node;
  • наблюдаемость (например, через Hubble) для audit traffic.

Набросок конфигурации (логика, не «копипаста в прод»)

Логика: поды с label egress=internet должны выходить через egress-ноды с label role=egress-gw, а SNAT делать на конкретный адрес.

kubectl label node node-1 role=egress-gw
kubectl label node node-2 role=egress-gw
apiVersion: cilium.io/v2
kind: CiliumEgressGatewayPolicy
metadata:
  name: egress-internet
spec:
  selectors:
  - podSelector:
      matchLabels:
        egress: internet
  destinationCIDRs:
  - 0.0.0.0/0
  egressGateway:
    nodeSelector:
      matchLabels:
        role: egress-gw
    egressIP: 203.0.113.10

Смысл: вы фиксируете точку выхода и IP для SNAT. При этом «рабочие» ноды могут быть сколько угодно динамичными.

Что проверить, если после включения Egress Gateway «ничего не работает»

  • Есть ли у egress-ноды маршрут по умолчанию и доступ во внешнюю сеть.
  • Разрешён ли форвардинг и не режется ли трафик хостовым firewall.
  • Совпадают ли PodCIDR/ServiceCIDR с тем, что ожидает CNI.
  • Не конфликтуют ли политики egress (например, NetworkPolicy запрещает DNS или 443).
  • Есть ли наблюдаемость по потокам (flow logs), чтобы быстро понять, где пакет «пропал».

Calico: natOutgoing и контроль egress

В мире Calico часто встречается запрос «calico nat outgoing»: включить или выключить NAT для пула IP и добиться предсказуемого поведения исходящего трафика.

В Calico есть IPPool и флаг natOutgoing, который определяет, будет ли трафик из этого пула «маскараден» при выходе из кластера.

apiVersion: projectcalico.org/v3
kind: IPPool
metadata:
  name: pod-pool
spec:
  cidr: 10.244.0.0/16
  natOutgoing: true
  vxlanMode: Always

Это решает базовую задачу «подам нужен интернет», но обычно не решает static IP, потому что SNAT происходит на той ноде, где трафик вышел наружу.

Как в Calico обычно приходят к static IP для egress

Чаще всего используют один из подходов:

  • Выделенные egress-ноды + policy based routing и SNAT на них (ручная схема, требует дисциплины и тестов).
  • Внешний NAT Gateway (маршрутизатор/фаервол), через который идёт весь egress кластера.
  • Маршрутизация без NAT (обычно для корпоративных сетей, реже — для выхода в интернет).
FastFox SSL
Надежные SSL-сертификаты
Мы предлагаем широкий спектр SSL-сертификатов от GlobalSign по самым низким ценам. Поможем с покупкой и установкой SSL бесплатно!

NetworkPolicy для egress control: практичные паттерны

Частая ошибка — добавить одну «разрешающую» egress-политику и думать, что «теперь всё контролируется». На практике egress control начинается с default deny и аккуратного разрешения нужного.

Паттерн 1: default deny egress в namespace

apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: default-deny-egress
  namespace: app
spec:
  podSelector: {}
  policyTypes:
  - Egress
  egress: []

Дальше добавляете точечные разрешения. Минимальный набор почти всегда включает DNS.

Паттерн 2: разрешить DNS (иначе «сломается всё»)

apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: allow-dns
  namespace: app
spec:
  podSelector: {}
  policyTypes:
  - Egress
  egress:
  - to:
    - namespaceSelector:
        matchLabels:
          kubernetes.io/metadata.name: kube-system
    ports:
    - protocol: UDP
      port: 53
    - protocol: TCP
      port: 53

В некоторых кластерах DNS работает не из kube-system или с нестандартными label’ами. Это частая причина «всё упало после default deny».

Паттерн 3: разрешить только конкретные CIDR и порты

apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: allow-external-api
  namespace: app
spec:
  podSelector:
    matchLabels:
      role: backend
  policyTypes:
  - Egress
  egress:
  - to:
    - ipBlock:
        cidr: 198.51.100.0/24
    ports:
    - protocol: TCP
      port: 443

Так вы закрываете «куда угодно», но оставляете доступ к нужному API. В комбинации с Egress Gateway это даёт и ограничения, и фиксированный источник.

SNAT, static IP и почему внешний сервис всё равно видит разные адреса

Даже если вы уверены, что настроили SNAT, внешняя система может фиксировать разные IP по нескольким причинам:

  • Несколько egress-нод: трафик распределяется, и у каждой свой публичный IP.
  • Разные пути: часть трафика идёт через gateway, часть — напрямую (часто из-за selector’ов или отсутствия политики на некоторых Pod).
  • IPv6: приложение может выходить по AAAA, и внешний сервис видит IPv6-адрес или другой egress-путь.
  • Прокси/sidecar: egress идёт не из Pod напрямую, а через прокси, который расположен иначе и NAT’ится по-другому.
  • Conntrack и долгоживущие соединения: вы поменяли правила, а старые TCP-сессии ещё живут с прежними параметрами NAT.

Практическая диагностика: где именно «теряется» контроль

Минимальный набор проверок (на тестовом стенде или аккуратно в проде):

kubectl exec -it -n app deploy/backend -- sh -c "getent hosts example.com || nslookup example.com"
kubectl exec -it -n app deploy/backend -- sh -c "curl -s ifconfig.me"
conntrack -L | head

Если вам важно не только «разрешить/запретить», но и учитывать TLS-нюансы (цепочки, сроки, исключения), полезно заранее выстроить процесс управления сертификатами; см. также автоматизацию wildcard SSL через DNS-01.

Диагностика egress: проверка внешнего IP из пода и просмотр conntrack на ноде

Audit traffic: что логировать и как не утонуть в данных

Задача audit для egress обычно отвечает на вопросы:

  • какой Pod/namespace ходил наружу;
  • куда именно (IP/порт, иногда домен);
  • сколько трафика и как часто;
  • что было заблокировано политиками.

Практичный подход: сначала включить наблюдаемость на egress-ноды или на внешнем NAT (там меньше точек), затем при необходимости детализировать до namespace/Pod.

Главная ошибка в audit — пытаться логировать «всё и сразу». Начните с точки egress и событий deny, а уже потом увеличивайте детализацию.

Рекомендованные схемы для продакшена

Схема A: нужен static IP для внешних API + базовый контроль

  • Egress Gateway (Cilium или внешний NAT) с 1–2 публичными IP.
  • NetworkPolicy: default deny egress в чувствительных namespace.
  • Разрешения: DNS + конкретные CIDR/порты.

Схема B: разные приложения — разные внешние IP

  • Несколько egress IP (или несколько egress-нод) и политики маршрутизации по label.
  • Раздельный allowlist у внешних поставщиков.
  • Отдельный учёт и лимиты трафика по направлениям.

Схема C: жёсткий egress control и соответствие требованиям ИБ

  • Default deny egress почти везде.
  • Централизованный egress gateway и прокси (если требуется L7-контроль).
  • Регулярный отчёт deny/allow и ревизия исключений.

Чек-лист внедрения: чтобы не «положить» кластер

  1. Описываем требования: один IP или несколько, какие направления разрешены, нужен ли FQDN-контроль.
  2. Делаем тестовый namespace и прогоняем типовые запросы (DNS, HTTPS, обновления пакетов, внешние API).
  3. Включаем default deny egress только после того, как есть явные allow для DNS и критичных направлений.
  4. Внедряем Egress Gateway по меткам, начиная с одного сервиса.
  5. Добавляем наблюдаемость: где смотреть allow/deny и как быстро понять, что сломалось.
  6. Фиксируем операционные процедуры: как добавлять новое направление и кто утверждает исключения.

Итог

SNAT на нодах даёт «просто интернет», но почти никогда не даёт стабильный static IP и удобный audit traffic. Для управляемого выхода чаще всего нужен Egress Gateway (функция CNI или выделенная NAT-инфраструктура). А NetworkPolicy закрывает вопрос «куда можно ходить», но не «с какого IP выйдем».

Как только вы осознанно выбираете точку SNAT и делаете её управляемой, egress перестаёт быть источником сюрпризов — и для внешних allowlist, и для внутренней ИБ-отчётности.

Поделиться статьей

Вам будет интересно

Debian/Ubuntu: как исправить Device is busy у Docker network, volume и namespace OpenAI Статья написана AI (GPT 5)

Debian/Ubuntu: как исправить Device is busy у Docker network, volume и namespace

Если Docker на Debian или Ubuntu отвечает Device is busy при удалении сети, тома или namespace, причина обычно в живом процессе, о ...
Debian/Ubuntu: как исправить Host key verification failed в Ansible при смене IP OpenAI Статья написана AI (GPT 5)

Debian/Ubuntu: как исправить Host key verification failed в Ansible при смене IP

Ошибка Host key verification failed в Ansible на Debian и Ubuntu обычно возникает после переустановки сервера, смены IP или повтор ...
Debian/Ubuntu: duplicate address detected, DAD failed IPv6 — причины и исправление OpenAI Статья написана AI (GPT 5)

Debian/Ubuntu: duplicate address detected, DAD failed IPv6 — причины и исправление

Сообщения duplicate address detected и DAD failed в Debian/Ubuntu означают, что IPv6-адрес не прошёл проверку уникальности в локал ...