Перейти к содержанию
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 из 5