Cilium Network Policies (сегментация сети)

Сегментация сети и контроль трафика в кластере с помощью Cilium Network Policies.

Введение

Cilium Network Policies — это механизм сегментации сети в Kubernetes-кластере на базе Cilium. Политики определяют, какой трафик разрешён между подами, неймспейсами, сервисами, узлами кластера и внешними адресами. Всё, что не разрешено политиками для выбранного направления, Cilium блокирует.

В платформе «Штурвал» сеть кластера обеспечивает Модуль управления сетями кластера (shturval-networking, Cilium CNI). Для управления политиками используются:

  • CiliumNetworkPolicy — неймспейсная политика Cilium;
  • CiliumClusterwideNetworkPolicy — кластерная политика Cilium;
  • Kubernetes NetworkPolicy — стандартная политика Kubernetes с меньшим набором возможностей.

Официальная документация Cilium описывает эти форматы в разделе Network Policy и общий язык политик в разделе Overview of Network Policy.


Когда использовать

Используйте Cilium Network Policies, когда нужно:

  • изолировать приложения в разных неймспейсах;
  • разрешить доступ к приложению только от Ingress Controller или конкретных подов;
  • ограничить исходящий трафик приложения к DNS, KubeAPI, внутренним сервисам или внешним доменам;
  • описать правила на уровнях L3/L4: поды, неймспейсы, CIDR, entities, сервисы, порты и протоколы;
  • добавить L7-ограничения, например, HTTP-метод и путь или DNS-имя;
  • явно запретить часть трафика с помощью deny-политик.

Где настраивать

В платформе доступны два основных способа настройки:

  • Графический интерфейс — в целевом кластере откройте раздел Администрирование кластера → Сетевые политики Cilium. В нём можно создавать, просматривать и изменять кластерные и неймспейсные политики, а также отслеживать их состояние. Графический редактор не отображает Kubernetes NetworkPolicy.
  • Манифесты — политики можно применять через импорт манифеста или через kubectl, если у пользователя есть необходимые права.

Для управления исходящим трафиком через выделенный egress-IP в платформе также есть отдельная страница Egress Gateway для ресурсов CiliumEgressGatewayPolicy. Это не замена CiliumNetworkPolicy: Egress Gateway управляет маршрутизацией исходящего трафика, а Cilium Network Policies управляют разрешением или запретом потоков.

Подробнее о работе в интерфейсе см. страницу Сетевые политики Cilium.

Скриншот: статус сетевой политики

Статус сетевой политики

Скриншот: редактор кластерных сетевых политик

Редактор кластерных сетевых политик

Скриншот: редактор неймспейсных сетевых политик

Редактор неймспейсных сетевых политик


Форматы политик

ФорматОбласть действияВозможностиКогда использовать
NetworkPolicyНеймспейсСтандартные Kubernetes-правила L3/L4 для ingress и egressЕсли достаточно стандартного Kubernetes API
CiliumNetworkPolicyНеймспейсРасширенные правила Cilium: L3-L7, entities, FQDN, HTTP/DNS, deny-правилаДля изоляции приложения или неймспейса
CiliumClusterwideNetworkPolicyВесь кластерТа же спецификация, что у CiliumNetworkPolicy, но без metadata.namespace; дополнительно может использовать nodeSelectorДля общих правил уровня кластера, например, DNS или доступ к системным endpoints

Обратите внимание! Начинайте с неймспейсных CiliumNetworkPolicy. Кластерные политики затрагивают весь кластер, поэтому ошибка в селекторе или deny-правиле может повлиять на несколько приложений сразу.

Когда в кластере Gateway API

Когда в кластере развернут Cilium Gateway APIРеализация стандарта Kubernetes Gateway API, где в качестве контроллера выступает Cilium, при написании сетевых политик для бэкенд-приложений учитывайте:

  • Трафик от Cilium Gateway приходит с идентичностью reserved:ingress.
  • Для разрешения доступа к бэкенду обязательно используйте CiliumNetworkPolicy с правилом fromEntities: [ingress].
  • Стандартный Kubernetes NetworkPolicy не подходит для контроля трафика от Cilium Gateway, так как он не умеет выбирать идентичность ingress.
  • Без явного правила fromEntities: [ingress] трафик от Gateway будет заблокирован механизмом default-deny, даже если Gateway и HTTPRoute имеют статус Programmed/Accepted.

Gateway API и Cilium Network Policies — взаимосвязанные механизмы. Изменение политик напрямую влияет на доступность Gateway-маршрутов. Подробнее о совместной настройке Gateway API и сетевых политик см. статью Gateway API и Cilium Network Policies. Как ресурсы влияют друг на друга.

Как Cilium применяет политики

Поведение по умолчанию

В режиме Cilium по умолчанию pod имеет неограниченный ingress и egress, пока его не выбрала политика. После этого для выбранного направления включается модель default deny:

СитуацияПоведение
Pod не выбран ни одной политикойIngress и egress разрешены
Pod выбран политикой с секцией ingressДля ingress разрешён только трафик, который совпал с allow-правилами
Pod выбран политикой с секцией egressДля egress разрешён только трафик, который совпал с allow-правилами
Pod выбран политиками с ingress и egressОба направления ограничены независимо

Политики Cilium работают по allowlist-модели: правило разрешает совпавший трафик, а несовпавший трафик отбрасывается в соответствии с режимом enforcement. Если несколько allow-правил применяются к одному pod, разрешается объединение всех совпавших правил.

Режимы enforcement

Cilium поддерживает три режима применения политик:

  • default — стандартный режим: endpoints не ограничены, пока их не выбрала политика;
  • always — политики включены для всех endpoints, даже если их не выбрали правила;
  • never — политики не применяются, даже если правила существуют.

В платформенной документации и примерах ниже предполагается стандартное поведение Cilium: без политик трафик разрешён, после выбора pod политикой разрешены только явно описанные потоки.

Allow и deny

Обычные секции ingress и egress разрешают трафик. Секции ingressDeny и egressDeny явно запрещают трафик и имеют приоритет над allow-правилами. Это значит, что deny-правило заблокирует совпавший поток даже тогда, когда другая политика его разрешает.

Ограничения deny-политик Cilium:

  • deny не поддерживает L7-запреты, например, запрет конкретного HTTP URL;
  • deny не поддерживает toFQDNs, то есть запрет конкретного доменного имени через FQDN-правило.

Особенности при использовании Gateway API

Если в кластере настроен Cilium Gateway API, при написании сетевых политик учитывайте:

  • Трафик от Gateway приходит с идентичностью reserved:ingress. Для бэкенд-приложений, публикуемых через Gateway, обязательно добавляйте правило:
ingress:
  - fromEntities:
      - ingress
  • Без этого правила трафик от Gateway будет заблокирован механизмом default-deny, даже если Gateway и HTTPRoute имеют статус Programmed/Accepted.
  • reserved:ingress — общая идентичность для всех Gateway в кластере. Разграничить доступ к разным Gateway через одну политику нельзя.
  • При смене GatewayClass с cilium на сторонний контроллер политики с fromEntities: [ingress] перестают работать — их нужно переписать на селекторы по меткам.

Структура CiliumNetworkPolicy

Минимальная политика содержит apiVersion, kind, metadata и spec. В spec задаются селектор endpoints и правила ingress/egress:

apiVersion: cilium.io/v2
kind: CiliumNetworkPolicy
metadata:
  name: example-policy
  namespace: app
spec:
  description: "Allow ingress from frontend to backend"
  endpointSelector:
    matchLabels:
      app: backend
  ingress:
    - fromEndpoints:
        - matchLabels:
            app: frontend

Ключевые поля:

ПолеНазначение
metadata.nameИмя политики в Kubernetes
metadata.namespaceНеймспейс, к которому относится CiliumNetworkPolicy; у CiliumClusterwideNetworkPolicy поле не задаётся
spec.descriptionЧеловекочитаемое описание назначения политики; Cilium не интерпретирует это поле
spec.endpointSelectorВыбирает pods, к которым применяется политика
spec.nodeSelectorВыбирает nodes; доступно только для CiliumClusterwideNetworkPolicy
spec.ingressAllow-правила для входящего трафика к выбранным endpoints
spec.egressAllow-правила для исходящего трафика от выбранных endpoints
spec.ingressDenyDeny-правила для входящего трафика
spec.egressDenyDeny-правила для исходящего трафика

Селекторы и неймспейсы

endpointSelector

endpointSelector выбирает pods, на которые распространяется политика. Селектор основан на Kubernetes LabelSelector.

Примеры:

# Все pods в неймспейсе политики
endpointSelector: {}
# Только pods с app.kubernetes.io/name=backend
endpointSelector:
  matchLabels:
    app.kubernetes.io/name: backend

Для CiliumNetworkPolicy селектор endpointSelector всегда применяется только внутри неймспейса, где создана политика. Указывать неймспейс в endpointSelector нельзя: это нарушило бы namespace isolation в Kubernetes.

fromEndpoints и toEndpoints

fromEndpoints выбирает источники ingress-трафика, а toEndpoints — назначения egress-трафика. В этих селекторах можно использовать label неймспейса pod:

fromEndpoints:
  - matchLabels:
      io.kubernetes.pod.namespace: frontend
      app.kubernetes.io/name: web

Если нужно разрешить трафик между неймспейсами, явно указывайте namespace label в fromEndpoints или toEndpoints. Без этого пустой селектор обычно означает endpoints в области действия политики, а не весь кластер.

Namespace labels

Cilium поддерживает выбор endpoints по лейблам неймспейса через labels вида io.cilium.k8s.namespace.labels.<label-name>. Это удобно, если нужно разрешить трафик не в конкретный неймспейс, а во все неймспейсы с заданной ролью, например, env=prod или team=payments.


Уровни фильтрации

L3: источники и назначения

L3-правила определяют, какие endpoints или внешние адреса могут взаимодействовать. Cilium поддерживает несколько способов описания L3:

СпособПоляДля чего использовать
EndpointsfromEndpoints, toEndpointsТрафик между Cilium-managed pods по labels
ServicestoServicesEgress к Kubernetes Service без ручного перечисления IP
EntitiesfromEntities, toEntitiesСпециальные категории Cilium: world, cluster, host, remote-node, kube-apiserver и другие
NodesfromNodes, toNodes, nodeSelectorТрафик с учётом узлов кластера
CIDRfromCIDR, toCIDR, toCIDRSetВнешние сети со стабильными IP или подсетями
DNS/FQDNtoFQDNsВнешние сервисы по DNS-имени

Обратите внимание! CIDR-правила зависят от стабильности IP-адресов. Для внешних сервисов с меняющимися IP чаще используйте toFQDNs вместе с правилом доступа к DNS.

L4: порты и протоколы

L4-правила ограничивают трафик по портам и протоколам через поле toPorts. Если L4-правило не задано, совпавший L3-трафик разрешается на всех портах и протоколах. Если L4-правило задано, разрешаются только указанные порты и протоколы.

Пример egress только на TCP-порт 443:

egress:
  - toFQDNs:
      - matchName: api.example.com
    toPorts:
      - ports:
          - port: "443"
            protocol: TCP

Cilium также поддерживает диапазоны портов через endPort. Для TLS-трафика можно ограничивать SNI через serverNames, если включено L7 proxy enforcement.

L7: HTTP, DNS и Kafka

L7-правила задаются внутри L4-правил. Cilium поддерживает:

  • HTTP — метод, путь, Host и заголовки;
  • DNS — matchName и matchPattern;
  • Kafka — правила Kafka находятся в beta/deprecated-статусе в документации Cilium и не рекомендуются для новых сценариев без отдельной проверки совместимости.

При нарушении L7-правила Cilium обычно возвращает ответ уровня приложения, например, HTTP 403 или DNS REFUSED, а не просто отбрасывает пакет.

Пример HTTP-правила:

apiVersion: cilium.io/v2
kind: CiliumNetworkPolicy
metadata:
  name: allow-public-api
  namespace: app
spec:
  description: "Allow GET /public from frontend to backend"
  endpointSelector:
    matchLabels:
      app: backend
  ingress:
    - fromEndpoints:
        - matchLabels:
            app: frontend
      toPorts:
        - ports:
            - port: "80"
              protocol: TCP
          rules:
            http:
              - method: "GET"
                path: "/public$"

DNS и FQDN-политики

toFQDNs разрешает egress к внешним ресурсам по DNS-имени. Cilium получает IP-адреса для FQDN-правил из DNS-ответов, которые видит DNS proxy, и учитывает TTL DNS-записей.

Для FQDN-политик обычно нужны два egress-правила:

  1. Разрешить DNS-запросы к кластерному DNS.
  2. Разрешить подключение к домену через toFQDNs.

Пример: разрешить приложению ходить только к api.github.com:

apiVersion: cilium.io/v2
kind: CiliumNetworkPolicy
metadata:
  name: allow-api-github
  namespace: app
spec:
  description: "Allow egress to api.github.com and DNS"
  endpointSelector:
    matchLabels:
      app: mediabot
  egress:
    - toEndpoints:
        - matchLabels:
            io.kubernetes.pod.namespace: kube-system
            k8s-app: kube-dns
      toPorts:
        - ports:
            - port: "53"
              protocol: ANY
          rules:
            dns:
              - matchPattern: "*"
    - toFQDNs:
        - matchName: api.github.com
      toPorts:
        - ports:
            - port: "443"
              protocol: TCP

Особенности matchName и matchPattern:

  • matchName: api.github.com совпадает только с точным именем;
  • matchPattern: "*.github.com" совпадает с поддоменами, например, support.github.com, но не с github.com;
  • matchPattern: "*" разрешает DNS-запросы к любым именам и добавляет IP из ответов в DNS cache Cilium.

Обратите внимание! Для DNS/L7-политик Cilium рекомендует перехватывать DNS-трафик только к доверенному кластерному DNS, например, kube-dns. Если направить DNS proxy на недоверенный резолвер, он сможет влиять на IP-адреса, которые Cilium считает разрешёнными для toFQDNs.


Базовые сценарии

Разрешить доступ к KubeAPI

Для operators и controllers, которым нужен Kubernetes API, используйте entity kube-apiserver:

apiVersion: cilium.io/v2
kind: CiliumNetworkPolicy
metadata:
  name: allow-kube-apiserver
  namespace: operators
spec:
  description: "Allow egress to kube-apiserver"
  endpointSelector: {}
  egress:
    - toEntities:
        - kube-apiserver

Разрешить DNS в платформе

DNS нужен приложениям, которые обращаются к Kubernetes Service или внешним FQDN. В платформе обычно нужно разрешить egress к kube-dns и shturval-caching-dns:

apiVersion: cilium.io/v2
kind: CiliumNetworkPolicy
metadata:
  name: allow-dns
  namespace: app
spec:
  description: "Allow egress to kube-dns and shturval-caching-dns"
  endpointSelector: {}
  egress:
    - toEndpoints:
        - matchLabels:
            io.kubernetes.pod.namespace: kube-system
            k8s-app: kube-dns
      toPorts:
        - ports:
            - port: "53"
              protocol: UDP
            - port: "53"
              protocol: TCP
            - port: "9153"
              protocol: TCP
    - toEndpoints:
        - matchLabels:
            io.kubernetes.pod.namespace: kube-system
            app.kubernetes.io/name: shturval-caching-dns
      toPorts:
        - ports:
            - port: "53"
              protocol: UDP
            - port: "9253"
              protocol: TCP

Разрешить входящий трафик от Ingress Controller

Для приложения, опубликованного через Ingress, разрешите ingress от Ingress Controller:

Схема allow-ingress

Схема allow-ingress

apiVersion: cilium.io/v2
kind: CiliumNetworkPolicy
metadata:
  name: allow-ingress
  namespace: app
spec:
  description: "Allow ingress from ingress-controller"
  endpointSelector: {}
  ingress:
    - fromEndpoints:
        - matchLabels:
            app.kubernetes.io/name: shturval-ingress-controller
            io.kubernetes.pod.namespace: ingress

Разрешить egress к backend-приложению

Схема allow-egress

Схема allow-egress

apiVersion: cilium.io/v2
kind: CiliumNetworkPolicy
metadata:
  name: allow-egress-to-backend
  namespace: frontend
spec:
  description: "Allow egress to backend app only"
  endpointSelector: {}
  egress:
    - toEndpoints:
        - matchLabels:
            io.kubernetes.pod.namespace: backend
            app.kubernetes.io/name: api
      toPorts:
        - ports:
            - port: "8080"
              protocol: TCP

Если frontend обращается к backend по DNS-имени Service, добавьте отдельное правило для DNS.

Разрешить трафик внутри неймспейса

Схема allow-in-namespace

Схема allow-in-namespace

apiVersion: cilium.io/v2
kind: CiliumNetworkPolicy
metadata:
  name: allow-in-namespace
  namespace: app
spec:
  description: "Allow all traffic within namespace"
  endpointSelector: {}
  ingress:
    - fromEndpoints: [{}]
  egress:
    - toEndpoints: [{}]

Полная изоляция неймспейса

Такая политика переводит все pods в неймспейсе в default-deny для ingress и egress. Применяйте её только после того, как подготовили нужные разрешающие правила.

Схема deny-all

Схема deny-all

apiVersion: cilium.io/v2
kind: CiliumNetworkPolicy
metadata:
  name: deny-all
  namespace: app
spec:
  description: "Deny all traffic in this namespace"
  endpointSelector: {}
  ingress:
    - {}
  egress:
    - {}

Явно запретить внешний ingress

Пример кластерной deny-политики: запретить ingress из entity world, но оставить остальной allow-трафик по другим правилам:

apiVersion: cilium.io/v2
kind: CiliumClusterwideNetworkPolicy
metadata:
  name: external-lockdown
spec:
  description: "Deny ingress from world to all Cilium-managed endpoints"
  endpointSelector: {}
  ingressDeny:
    - fromEntities:
        - world
  ingress:
    - fromEntities:
        - all

Пошаговый пример: веб-приложение с Ingress и DNS

Сценарий: приложение my-app работает в неймспейсе my-app, доступно извне через Ingress Controller и использует DNS.

1. Определите нужные потоки

НаправлениеИсточник или назначениеЗачем
IngressIngress ControllerПользователи заходят в приложение
Egresskube-dns и shturval-caching-dnsРезолв Kubernetes Service и внешних имён
Egress, опциональноkube-apiserverТолько если приложение является operator/controller
Egress, опциональноВнутренний backend или внешний FQDNЕсли приложение вызывает другие сервисы

2. Проверьте labels

Проверьте labels приложения:

kubectl get pods -n my-app --show-labels

Проверьте labels Ingress Controller:

kubectl get pods -n ingress -l app.kubernetes.io/name=shturval-ingress-controller --show-labels

3. Примените политику

apiVersion: cilium.io/v2
kind: CiliumNetworkPolicy
metadata:
  name: my-app-policy
  namespace: my-app
spec:
  description: "Web app: ingress from controller and DNS egress"
  endpointSelector: {}
  ingress:
    - fromEndpoints:
        - matchLabels:
            app.kubernetes.io/name: shturval-ingress-controller
            io.kubernetes.pod.namespace: ingress
  egress:
    - toEndpoints:
        - matchLabels:
            io.kubernetes.pod.namespace: kube-system
            k8s-app: kube-dns
      toPorts:
        - ports:
            - port: "53"
              protocol: UDP
            - port: "53"
              protocol: TCP
            - port: "9153"
              protocol: TCP
    - toEndpoints:
        - matchLabels:
            io.kubernetes.pod.namespace: kube-system
            app.kubernetes.io/name: shturval-caching-dns
      toPorts:
        - ports:
            - port: "53"
              protocol: UDP
            - port: "9253"
              protocol: TCP

4. Проверьте работу

kubectl get ciliumnetworkpolicy -n my-app
kubectl get pods -n my-app
kubectl logs -n my-app <pod-name>

Проверьте доступ к приложению через Ingress. Если приложение перестало резолвить имена или отвечать на запросы, проверьте labels и наличие DNS-правил.


Типичные ошибки

ОшибкаЧто происходитКак исправить
Добавили ingress-политику и забыли DNS egressПриложение принимает входящий трафик, но не может резолвить именаДобавить egress к kube-dns и shturval-caching-dns
Не указали namespace label в fromEndpoints или toEndpointsПравило не совпадает с pod из другого неймспейсаДобавить io.kubernetes.pod.namespace: <namespace>
Использовали кластерную политику вместо неймспейснойПравило затронуло больше приложений, чем ожидалосьДля прикладных сценариев использовать CiliumNetworkPolicy
Смешали много policy types без схемыИтоговый allow-набор сложно понятьДокументировать назначение политики в description и группировать правила по приложениям
Применили deny-all до разрешающих правилПриложение потеряло входящий или исходящий доступСначала подготовить allow-правила, затем включать изоляцию
Использовали toFQDNs, но не разрешили DNSFQDN-правило не получает DNS-данныеДобавить egress к кластерному DNS с rules.dns
Ожидали, что *.example.com разрешит example.comДомен верхнего уровня не совпал с wildcard-паттерномДобавить отдельный matchName: example.com
Указали только UDP/53 для DNSЧасть DNS-запросов может не работатьРазрешить UDP/53 и TCP/53, а для платформенных DNS-компонентов учесть нужные порты

Наблюдаемость и проверка

Для отладки сетевого трафика и политик можно включить Cilium Hubble. Hubble UI визуализирует сетевые потоки и помогает понять, какое правило разрешило или заблокировало соединение.

Инструкция по включению: Как включить Hubble UI.

Также используйте:

kubectl get ciliumnetworkpolicy -A
kubectl get ciliumclusterwidenetworkpolicy
kubectl describe ciliumnetworkpolicy -n <namespace> <policy-name>

При проблемах с сетевым взаимодействием см. Траблшутинг сетевого модуля.


Ссылки