← Kubernetes: сеть
6 мин · средне · Урок 6 из 8

NetworkPolicy: кто с кем может общаться

Как правилами по меткам закрыть Pod от лишнего трафика и где прячется ошибка с одним дефисом.

Что такое NetworkPolicy

NetworkPolicy - объект Kubernetes, который задаёт правила сетевого трафика между Pod. Pod - наименьшая единица, которую запускает Kubernetes; внутри Pod работает один или несколько контейнеров. NetworkPolicy работает как файрвол, но выбирает Pod по их меткам (labels), а не по IP-адресам.

Сам объект NetworkPolicy ничего не блокирует. Правила применяет CNI-плагин (Container Network Interface, компонент кластера, отвечающий за сеть Pod). Calico, Cilium и Kube-router умеют NetworkPolicy, а вот у простых плагинов вроде flannel такой поддержки нет: там правила создаются в API и молча игнорируются. Проверять эффект политики нужно именно на том кластере, где она будет работать.

По умолчанию разрешено всё

без NetworkPolicy client-a client-b client-c Pod app: web трафик открыт с NetworkPolicy на app: web role: allowed role: blocked Pod из другого ns ✕ ✕ Pod app: web разрешено только перечисленное
Первая же политика на Pod меняет умолчание: пройдёт только то, что перечислено.

Если в namespace нет ни одной NetworkPolicy, трафик открыт. Любой Pod ходит куда угодно. namespace - область внутри кластера, которая отделяет одни объекты от других.

Как только на Pod вешают NetworkPolicy, для него включается правило: запрещено всё, что явно не разрешено. После этого в политике перечисляют, какой трафик пропускать.

Анатомия манифеста

apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: web-only-from-allowed
spec:
  podSelector:
    matchLabels:
      app: web
  policyTypes:
    - Ingress
  ingress:
    - from:
        - podSelector:
            matchLabels:
              role: allowed
      ports:
        - protocol: TCP
          port: 8080

podSelector - к каким Pod применяются правила. Здесь это Pod с меткой app: web. Пустой {} означает все Pod в namespace.

policyTypes - какой трафик регулирует политика. Ingress - входящий трафик, Egress - исходящий. Можно указать один тип или оба.

ingress.from - откуда разрешён входящий трафик. Источник задают через podSelector (Pod с такими метками), namespaceSelector (Pod из namespace с такими метками) или ipBlock (диапазон IP).

ports - какие порты открыты. Без этого блока открыты все порты.

AND и OR в селекторах

Внутри одного элемента списка from селекторы связаны через AND. Pod с такой меткой И в namespace с такой меткой. Разные элементы списка связаны через OR.

AND - один элемент, два селектора (Pod с меткой role: allowed И в namespace с меткой team: a):

ingress:
  - from:
      - podSelector:
          matchLabels:
            role: allowed
        namespaceSelector:
          matchLabels:
            team: a

OR - два элемента (Pod с меткой role: allowed ИЛИ любой Pod из namespace с меткой team: a):

ingress:
  - from:
      - podSelector:
          matchLabels:
            role: allowed
      - namespaceSelector:
          matchLabels:
            team: a

Разница - один дефис. Это самая частая ошибка в NetworkPolicy.

Запись в fromЛогикаКто пройдёт
два селектора в одном элементе спискаANDPod с меткой role: allowed из namespace team: a
два отдельных элемента спискаORPod с меткой role: allowed или любой Pod из team: a

Проверка эффекта

Самый надёжный способ проверить политику - попробовать подключиться с двух сторон. Для примера рядом с Pod web держат два клиента: client-allowed с меткой role: allowed и client-blocked с меткой role: blocked.

# Из разрешённого клиента
kubectl exec client-allowed -- nc -zv -w 2 web 8080
# connection succeeded

# Из заблокированного
kubectl exec client-blocked -- nc -zv -w 2 web 8080
# timeout

Разрешённый клиент подключится, заблокированный зависнет до таймаута и упадёт. Обратите внимание на порт: политика открывает 8080, поэтому и проверяют 8080, а не 80.

Разобраться, что именно применилось, помогают три команды:

# Список политик в namespace
kubectl get networkpolicy

# Как политика разложена на селекторы и порты
kubectl describe networkpolicy web-only-from-allowed

# Метки Pod, чтобы понимать, что ловит matchLabels
kubectl get pods --show-labels

Домашка

Теорию закрепляет задание на своём кластере: 2 шага с проверкой. Кластер поднимается по треку Kubernetes локально, задания лежат в репозитории k8s-practice.

./run.sh start k8s-network-policy     # развернуть стартовое состояние
./run.sh verify k8s-network-policy    # проверить текущий шаг

Коротко

Прошли материал до конца? Отметьте урок пройденным.