Learning Platform
Глоссарий Troubleshooting
Урок 11.01 · 22 мин
Продвинутый
NetworkPolicyCNIpodSelectorpolicyTypesisolation

NetworkPolicy: основы

NetworkPolicy — это декларативный firewall на уровне L3/L4 (IP-адреса и порты) для Pods в Kubernetes. API группа — networking.k8s.io/v1, существует с 1.7. Идея простая: вы пишете манифест, в котором говорите «к Pod-ам с такими-то labels разрешён трафик только от таких-то источников на такие-то порты» — и кластер должен это применить. На самом деле кластер ничего сам не применяет. Применяет CNI plugin, и тут начинается главный подводный камень всей темы.


Firewalls: stateful vs stateless, iptables, security groups

Critical: NetworkPolicy без CNI с поддержкой — это no-op

В Kubernetes есть две независимые вещи:

  • API-объект NetworkPolicy, который вы создаёте через kubectl apply;
  • его enforcement — реальное применение iptables/eBPF правил на узлах.

API-сервер примет любой валидный YAML и положит его в etcd. На этом ответственность core Kubernetes заканчивается. Если ваш CNI plugin не умеет читать NetworkPolicy — объект существует, kubectl get netpol показывает его, describe показывает правила, но в сети не происходит ничего. Pods как общались, так и общаются.

CNI плагины и поддержка NetworkPolicy
Поддержка естьЭти CNI читают NetworkPolicy через informer, переводят в правила своего dataplane и применяют на узлах. Поддерживают как минимум стандартные L3/L4 правила.
ЧастичноWeave Net поддерживает большинство правил, но с историческими ограничениями (особенно вокруг IPv6, некоторых комбинаций селекторов). Перед production-использованием — читать release notes.
Не поддерживаетFlannel — это просто overlay сеть, dataplane без policy engine. NetworkPolicy будет создаваться в API, но ни на что не повлияет. Решение в production — пара Flannel + Calico для policy enforcement (Canal).
Не поддерживаетLinux bridge без kube-router или другого policy engine — это базовый docker0-style мост, никакой логики netpol в нём нет.
DANGER

Первое, что нужно проверять на CKAD и в production при отладке NetworkPolicy — это CNI. Если в kube-system нет ни одного из Calico/Cilium/Antrea/Weave — вы пишете правила в пустоту.

Быстрая проверка:

kubectl get pods -n kube-system | grep -E 'calico|cilium|antrea|weave'

Если выводится пусто — скорее всего, policy не работает. Дополнительно: kubectl describe node | grep -i cni или ls /etc/cni/net.d/ на самом узле покажет имя активного plugin.


Default behavior: open by default

Базовая модель Kubernetes сети — трафик между Pod-ами разрешён по умолчанию. Любой Pod может достучаться до любого другого Pod в любом namespace на любой порт. Это противоположно тому, как обычно работают firewall (default-deny).

Это сделано специально: чтобы кластер «просто работал» без обязательной настройки. Микросервисы видят друг друга, init-контейнеры могут дёрнуть API, миграции БД проходят. Но это же означает, что из коробки кластер не изолирован: скомпрометированный Pod может сканировать весь под-CIDR.

NetworkPolicy переключает эту модель в selective deny: для конкретных Pods вы говорите «вот этому Pod-у разрешено только то-то и то-то, остальное — запрещено».


Isolation: что значит «policy применилась к Pod»

Ключевое понятие — isolation. Pod считается isolated в направлении (ingress или egress), если в его namespace существует хотя бы одна NetworkPolicy, чей spec.podSelector matches его labels, и в policyTypes указано это направление.

  • Не isolated — default behavior, всё разрешено в этом направлении.
  • Isolated — разрешено только то, что явно перечислено в ingress/egress rules всех применимых policies.
Logical OR между policies в одном namespace
policy AПрименяется к Pod (podSelector matches). Разрешает ingress от podSelector с label role=web на port 80.
policy BТоже применяется к тому же Pod (другой policy, но pod selector matches). Разрешает ingress от podSelector с label role=monitoring на port 9100.
union (OR)
effectivePod становится isolated. Эффективное правило — объединение всех applicable policies: web → :80 ИЛИ monitoring → :9100. Всё остальное (любой источник, любой другой порт) запрещено.

Несколько policies, применимых к одному Pod, объединяются логическим OR. Это и хорошее свойство (легко добавлять новые правила), и опасное (нет способа сказать «запрети, даже если другая policy разрешает» — для этого нужен AdminNetworkPolicy (beta на v1.35, требует enable feature-gate и CRDs из k/networking-policy-api проекта) или CNI-specific CRD).


Структура манифеста

apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: api-allowlist
  namespace: production
spec:
  podSelector:
    matchLabels:
      app: api
  policyTypes:
  - Ingress
  - Egress
  ingress:
  - from:
    - podSelector:
        matchLabels:
          app: web
    ports:
    - port: 8080
      protocol: TCP
  egress:
  - to:
    - podSelector:
        matchLabels:
          app: postgres
    ports:
    - port: 5432
      protocol: TCP

Что делает этот манифест:

  • podSelector: к каким Pod-ам применяется policy. Здесь — Pods с label app=api в namespace production.
  • policyTypes: какие направления policy контролирует. Здесь — оба.
  • ingress: список разрешённых источников и портов входящего трафика.
  • egress: список разрешённых направлений и портов исходящего трафика.

Pods, у которых нет label app=api, этой policy не затронуты. Они остаются non-isolated (если на них не действует другая policy).


podSelector — что и куда

Поле spec.podSelector определяет, к каким Pod-ам в namespace применяется policy. Это не «откуда трафик» и не «куда» — это «кого policy защищает».

# Применяется ко всем Pods в namespace
spec:
  podSelector: {}

# Применяется к Pods с label tier=backend
spec:
  podSelector:
    matchLabels:
      tier: backend

# Применяется к Pods с одним из двух labels
spec:
  podSelector:
    matchExpressions:
    - key: tier
      operator: In
      values: [backend, db]
NOTE

podSelector: {} — это «все Pods в namespace». Это самый частый паттерн для policy уровня namespace (deny-all, allow-dns). Не путайте с from: [] (никто не разрешён) и отсутствием поля (все разрешены).

NetworkPolicy — namespaced объект. podSelector всегда работает в namespace самой policy. Чтобы выбрать Pods в другом namespace, нужны namespaceSelector внутри from/to — это про разрешённые peers, не про targets.


policyTypes: убийственная ловушка CKAD

Поле spec.policyTypes — список направлений, которые контролирует policy. Возможные значения: Ingress, Egress, либо оба.

Главное правило: если policyTypes не указан явно — Kubernetes выводит его по эвристике: всегда добавляет Ingress, и плюс Egress, если в манифесте есть секция egress. Звучит спасительно, но ловушка остаётся: если вы явно указали policyTypes: [Ingress] и при этом написали egress: секцию — секция просто игнорируется, без diagnostic, без warning. Always-safe правило: указывайте policyTypes явно — [Ingress], [Egress], либо [Ingress, Egress] — это исключает любые сюрпризы.

Что считается isolation в зависимости от policyTypes
policyTypes: [Ingress]Pod становится isolated по ingress. Любой egress остаётся default-allow. Даже если вы написали egress блок в spec — он не применится, потому что Egress не в policyTypes.
policyTypes: [Egress]Симметрично: контролируется только egress, ingress остаётся default-allow.
policyTypes: [Ingress, Egress]Оба направления контролируются policy. Это требование для любой policy, которая ограничивает egress.
# ПЛОХО: egress блок написан, но не указан в policyTypes
# (если policyTypes отсутствует, K8s по эвристике добавит Egress —
#  но на CKAD проще не полагаться, а указать явно)
spec:
  podSelector:
    matchLabels:
      app: api
  egress:                       # эти правила
  - to:
    - podSelector:
        matchLabels: {app: db}
  # policyTypes отсутствует — рискованно

# ХОРОШО: явно указано
spec:
  podSelector:
    matchLabels:
      app: api
  policyTypes:
  - Egress
  egress:
  - to:
    - podSelector:
        matchLabels: {app: db}
WARNING

На CKAD всегда указывайте policyTypes явно. Это снимает половину ошибок и не зависит от того, какую логику вывода применяет конкретная версия API server. И никогда не пишите egress без Egress в policyTypes.


Killer момент: ingress vs egress, кто куда смотрит

«Ingress» и «egress» — с точки зрения Pod, к которому применяется policy (то есть подходящий под podSelector).

  • ingress — трафик, входящий в этот Pod. Поле from — источник этого трафика.
  • egress — трафик, исходящий из этого Pod. Поле to — назначение этого трафика.

Звучит банально, но на CKAD легко перепутать, если думать «policy для Pod web, разрешает доступ к db» — это egress (web смотрит наружу к db), а не ingress (db получает от web). Симметричную policy на стороне db (если она тоже isolated) — придётся писать отдельно как ingress на её манифесте.


Проверка знанийKnowledge check
Вы применили NetworkPolicy, которая должна запретить весь ingress в namespace. Pods продолжают общаться. Первое, что проверить?
ОтветAnswer
Какой CNI plugin установлен в кластере. Flannel в vanilla режиме и default bridge не реализуют NetworkPolicy — объект существует, но enforcement нет. Команда: kubectl get pods -n kube-system и поиск Calico/Cilium/Antrea/Weave. Без них policy — пустой YAML.
Проверка знанийKnowledge check
В манифесте указан только egress блок, но policyTypes не указан явно. Что произойдёт?
ОтветAnswer
Поведение зависит от API server: обычно он по эвристике добавит Egress в policyTypes, если есть egress блок. Но это полагается на implicit. На CKAD надёжнее указывать policyTypes явно. Если бы policyTypes был [Ingress] (например, скопировали и не поменяли), egress блок был бы тихо проигнорирован — Pod не получил бы egress isolation.
Проверка знанийKnowledge check
К Pod применяются две NetworkPolicy: policy-A разрешает ingress от web на :80, policy-B разрешает ingress от monitoring на :9100. Что эффективно разрешено?
ОтветAnswer
Объединение: web → :80 ИЛИ monitoring → :9100. Несколько policies, применимых к одному Pod, объединяются логическим OR. Pod становится isolated, и принимает только перечисленный трафик. Способа сказать 'deny over allow' через стандартный NetworkPolicy нет — для этого AdminNetworkPolicy или CNI-specific policy CRD.
Проверка знанийKnowledge check
podSelector: {} в spec NetworkPolicy — что это значит?
ОтветAnswer
Пустой селектор matches все Pods в namespace policy. Это типичный паттерн для policy уровня namespace — например, deny-all-ingress или allow-dns-egress. Не путать с from: [] (никто не разрешён) и отсутствием поля from (любой разрешён).

Проверьте понимание

Результат: 0 из 0
Прикладной
Вопрос 1 из 5. Вы создали NetworkPolicy с правильным YAML, kubectl apply прошёл успешно, kubectl describe показывает все rules. Но Pods продолжают общаться так, будто policy нет. Самая вероятная причина?

Закончили урок?

Отметьте его как пройденный, чтобы отслеживать свой прогресс

Войдите чтобы оценить урок

Прогресс модуля
0 из 5