Gateway API и Cilium Network Policies. Как ресурсы влияют друг на друга
Одновременная работа Gateway API и Cilium Network Policies в кластере, почему публикация через Gateway может внезапно сломаться после настройки политик, и что нужно знать, чтобы этого избежать.
В кластере могут быть одновременно настроены:
- Gateway API — управляет входящим трафиком: какие запросы и куда направлять.
- Cilium Network Policies — управляют безопасностью: кому можно общаться с кем. Сетевые политики Cilium в GUI.
Gateway проводит трафик через свой прокси, а политики решают, можно ли этому трафику пройти дальше. В платформе «Штурвал» используется Cilium с его встроенным контроллером Gateway API на основе Envoy. Поэтому описанная ниже модель с идентичностью reserved:ingress работает именно для этого сценария. Если вы используете сторонний Gateway-контроллер (например, Traefik, Istio, Envoy Gateway), механизмы будут другими — см. Настройка политик, если контроллер не Сilium.
Если настроить Gateway, но не создавать сетевых политик — трафик будет проходить. Проблемы могут возникнуть, когда на бэкенд уже действует запрещающая политика, а разрешение для Gateway не добавлено.
Подробнее о Gateway API на страницах:
- Gateway API — обзор модели, CRD, включение контроллера.
- Gateway Classes —
GatewayClass. - Gateways — точки входа
Gateway, listeners. - Маршруты Gateway API —
HTTPRoute/GRPCRoute. - CRD модуля Gateway API — установка CRD.
- Модуль управления сетями —
gatewayAPI.enabledв Cilium. - Ingress NGINX умер, да здравствует Gateway API — зачем уходить с Ingress.
1. Как это устроено
1.1. Что происходит с трафиком, когда он проходит через Gateway
Обычный Ingress-контроллер (например, Nginx) работает так: есть отдельные поды контроллера, которые принимают запросы и перенаправляют их в бэкенд. Политики безопасности в этом случае пишутся в стиле: “разрешить подам контроллера общаться с подами приложения”.
В Cilium Gateway API встроен в сетевой стек:
- Запрос от клиента приходит на Service Gateway.
- Cilium перехватывает этот трафик через eBPF и направляет его во встроенный прокси Envoy, который работает на каждом узле кластера.
- Envoy применяет правила маршрутизации из HTTPRoute/GRPCRoute.
- Трафик, который прошёл через Gateway, Cilium присваивает специальную идентичность —
reserved:ingress(или простоingress).
Если вы не используете Gateway для публикации приложения — идентичность ingress не нужна. Она существует, чтобы связать Gateway API с сетевыми политиками.
Что это значит для политик:
- Для бэкенда (вашего приложения) источником трафика становится Gateway, а не IP-адрес клиента.
- Поэтому правило “разрешить доступ с IP-адреса клиента” на бэкенде не сработает — политика увидит источник
ingress, а не клиентский IP. - Чтобы разрешить доступ от Gateway к бэкенду, нужно написать политику, которая разрешает идентичность
ingress.
1.2. Два уровня контроля
При использовании Gateway API возможно контролировать трафик политиками Cilium в двух точках:
| Уровень | Что контролируем | Какую политику использовать |
|---|---|---|
| 1. Доступ к Gateway | Кто может обращаться к самому Gateway (например, только из определённых сетей) | CiliumClusterwideNetworkPolicy на reserved:ingress |
| 2. Доступ от Gateway к бэкенду | К каким бэкендам Gateway может направлять трафик | CiliumNetworkPolicy с fromEntities: [ingress] |
Если политика выбирает поды бэкенда, для входящего трафика включается режим default-deny. В этом случае трафик от Gateway будет разрешён только при наличии явного правила fromEntities: [ingress] в секции ingress политики. Без этого правила запросы от Gateway будут отклоняться.
2. Влияние ресурсов
| Ситуация | Что происходит | Почему |
|---|---|---|
| Есть Gateway и HTTPRoute, но нет сетевых политик | Публикация работает | По умолчанию, если не создано никаких политик, весь трафик разрешён |
Добавили политику default-deny на бэкенд, но забыли разрешить ingress | Публикация через Gateway ломается | Политика блокирует весь трафик, включая от Gateway |
Добавили кластерную политику “запретить внешний трафик” (world) без исключения для Gateway | Внешний доступ к Gateway даёт ошибку | Cilium блокирует трафик из интернета |
| Включили изоляцию неймспейса, но забыли разрешить DNS | Приложение не может резолвить имена, даже если Gateway работает | DNS-запросы блокируются политикой |
Пытаетесь ограничить доступ к бэкенду по IP-адресу клиента через fromCIDR | Не работает | Источником для политики становится ingress, а не клиент |
| Запрос изнутри кластера (pod → Service Gateway) идёт через Gateway | Трафик тоже получает identity ingress | Трафик через Gateway также маскируется |
Сменили GatewayClass с cilium на сторонний контроллер | Политики перестают работать | Модель reserved:ingress действует только для Cilium Gateway |
Модель, основанная на идентичности reserved:ingress, является внутренней функцией Cilium и не работает для других реализаций Gateway API.
3. Identity reserved:ingress
Это ключевая концепция:
| Вопрос | Ответ |
|---|---|
| Кто является источником для бэкенда за Cilium Gateway? | Identity ingress, а не исходный IP-адрес клиента |
Можно ли использовать стандартный Kubernetes NetworkPolicy? | Ограниченно. Он может сработать через селекторы по меткам, но это ненадёжно. Лучше использовать CiliumNetworkPolicy |
| Одна identity на все Gateway? | Да. reserved:ingress — общая для всех Gateway прокси в кластере |
| Где увидеть реальный IP клиента? | В заголовках X-Forwarded-For или X-Envoy-External-Address, но не как L3-источник в политике |
Нельзя через одну entity ingress сказать "разрешить только Gateway A, но не Gateway B". fromEntities: [ingress] разрешает трафик от всех Gateway прокси в кластере, а не от конкретного Gateway.
Особенности настройки при использовании стороннего GatewayClass
Если в качестве GatewayClass выбран не cilium, а сторонний контроллер (например, Traefik, Istio, Envoy Gateway), в этом случае:
- Идентичность
reserved:ingressне применяется — трафик идёт от обычных подов контроллера со своими метками. - Политики Cilium с
fromEntities: [ingress]перестают работать — их нужно переписать под селекторы нового контроллера.
Как переписать политики
Было (для Cilium Gateway):
apiVersion: cilium.io/v2
kind: CiliumNetworkPolicy
metadata:
name: allow-from-gateway
namespace: my-app
spec:
endpointSelector:
matchLabels:
app: my-backend
ingress:
- fromEntities:
- ingress # ← не работает для стороннего контроллера
Стало (для стороннего контроллера):
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: allow-from-gateway
namespace: my-app
spec:
podSelector:
matchLabels:
app: my-backend
ingress:
- from:
- namespaceSelector:
matchLabels:
kubernetes.io/metadata.name: gateway-system # неймспейс контроллера
podSelector:
matchLabels:
app: my-gateway-controller # метки подов контроллера
Альтернативный вариант — через CiliumNetworkPolicy с селекторами
Если вы хотите остаться в рамках CiliumNetworkPolicy, используйте селекторы по меткам вместо fromEntities:
apiVersion: cilium.io/v2
kind: CiliumNetworkPolicy
metadata:
name: allow-from-gateway
namespace: my-app
spec:
endpointSelector:
matchLabels:
app: my-backend
ingress:
- fromEndpoints:
- matchLabels:
app: my-gateway-controller
io.kubernetes.pod.namespace: gateway-system
Что остаётся без изменений
| Компонент | Нужно ли переделывать |
|---|---|
| DNS-правила (порт 53) | Нет |
FQDN-правила (toFQDNs) | Нет |
| Политики между микросервисами | Нет |
| Egress к внешним API | Нет |
При смене GatewayClass с Cilium на сторонний контроллер все политики, использующие fromEntities: [ingress], перестают действовать. Их необходимо переписать на селекторы по меткам подов контроллера или по неймспейсу.
4. Рекомендации
4.1. Для бэкенда: всегда разрешать ingress
Основной способ: разрешить доступ от Gateway к приложению при настроенных политиках Cilium.
apiVersion: cilium.io/v2
kind: CiliumNetworkPolicy
metadata:
name: allow-from-gateway
namespace: my-app
spec:
description: "Разрешить трафик от Cilium Gateway"
endpointSelector:
matchLabels:
app: my-backend
ingress:
- fromEntities:
- ingress
toPorts:
- ports:
- port: "8080"
protocol: TCP
4.2. Для Gateway: контролировать, кто может до него достучаться
Пример: разрешить доступ к Gateway только из определённой подсети
apiVersion: cilium.io/v2
kind: CiliumClusterwideNetworkPolicy
metadata:
name: allow-cidr-to-ingress
spec:
description: "Разрешить доступ к Gateway только из подсети X"
endpointSelector:
matchExpressions:
- key: reserved:ingress
operator: Exists
ingress:
- fromCIDRSet:
- cidr: 203.0.113.10/32
4.3. Для Gateway: разрешить ходить в кластер
Если в кластере включена изоляция, Gateway должен иметь возможность направлять трафик к бэкендам:
apiVersion: cilium.io/v2
kind: CiliumClusterwideNetworkPolicy
metadata:
name: allow-ingress-to-cluster
spec:
description: "Разрешить Gateway ходить в кластер"
endpointSelector:
matchExpressions:
- key: reserved:ingress
operator: Exists
egress:
- toEntities:
- cluster
4.4. Вводить изоляцию по шагам
Не включайте жёсткую изоляцию сразу:
- Сначала добейтесь рабочего пути Gateway → бэкенд.
- Добавьте политику
allow from ingress. - Включите default-deny или примените селекторы.
- Проверяйте Hubble до и после каждого шага.
4.5. Отлаживать через Hubble
Hubble показывает реальные потоки трафика и вердикты политик:
# Посмотреть все заблокированные потоки в неймспейсе
hubble observe --verdict DROPPED --namespace my-app --last 50
# Посмотреть трафик от Gateway (identity ingress)
hubble observe --identity ingress --last 50
# Проверить статусы ресурсов
kubectl get gateway -A
kubectl get httproute -A
kubectl get cnp -n my-app
Ищите, на каком этапе обрыв: world ↔ ingress или ingress ↔ app.
4.6. Чего не стоит делать
| Не делайте | Почему |
|---|---|
Контролировать трафик Cilium Gateway → бэкенд через стандартный NetworkPolicy | Нет identity reserved:ingress, работает ненадёжно |
Применять endpointSelector: {} и fromEntities: [world] на весь кластер без необходимости | Открываете внешний доступ слишком широко |
| Включать deny-all до того, как подготовлены все allow-правила (Gateway, DNS, зависимости) | Получите простой outage |
Пытаться фильтровать клиентов по IP на бэкенде через fromCIDR | Источник в политике — ingress, а не клиент. Фильтруйте клиентов на уровне Gateway или по HTTP-заголовкам (X-Forwarded-For, X-Envoy-External-Address) в приложении |
Пытаться разграничить Gateway A и Gateway B только через fromEntities: [ingress] | Одна общая identity на все Gateway |
5. Примеры: манифесты для типовых сценариев
5.1. Gateway
apiVersion: gateway.networking.k8s.io/v1
kind: Gateway
metadata:
name: my-gateway
namespace: gateway-system
spec:
gatewayClassName: cilium
listeners:
- name: http
protocol: HTTP
port: 80
allowedRoutes:
namespaces:
from: Selector
selector:
matchLabels:
gateway-access: "true"
- name: https
protocol: HTTPS
port: 443
hostname: app.example.com
tls:
mode: Terminate
certificateRefs:
- name: app-tls
kind: Secret
allowedRoutes:
namespaces:
from: Same
5.2. HTTPRoute
apiVersion: gateway.networking.k8s.io/v1
kind: HTTPRoute
metadata:
name: my-route
namespace: my-app
spec:
parentRefs:
- name: my-gateway
namespace: gateway-system
sectionName: https
hostnames:
- "app.example.com"
rules:
- matches:
- path:
type: PathPrefix
value: /api
backendRefs:
- name: api-service
port: 8080
5.3. Изоляция неймспейса с доступом от Gateway + DNS
apiVersion: cilium.io/v2
kind: CiliumNetworkPolicy
metadata:
name: isolate-allow-gateway
namespace: my-app
spec:
description: "Default deny для неймспейса; разрешены Gateway и DNS"
endpointSelector: {}
ingress:
- fromEntities:
- ingress
toPorts:
- ports:
- port: "8080"
protocol: TCP
egress:
- toEndpoints:
- matchLabels:
io.kubernetes.pod.namespace: kube-system
k8s-app: kube-dns
toPorts:
- ports:
- port: "53"
protocol: UDP
- port: "53"
protocol: TCP
rules:
dns:
- matchPattern: "*"
5.4. Минимальный набор “Gateway + политики”
# Бэкенд принимает трафик от Cilium Gateway
apiVersion: cilium.io/v2
kind: CiliumNetworkPolicy
metadata:
name: app-allow-gateway
namespace: my-app
spec:
endpointSelector:
matchLabels:
app: my-app
ingress:
- fromEntities:
- ingress
egress:
- toEndpoints:
- matchLabels:
io.kubernetes.pod.namespace: kube-system
k8s-app: kube-dns
toPorts:
- ports:
- port: "53"
protocol: UDP
rules:
dns:
- matchPattern: "*"
---
# Gateway может ходить в кластер
apiVersion: cilium.io/v2
kind: CiliumClusterwideNetworkPolicy
metadata:
name: allow-ingress-to-cluster
spec:
endpointSelector:
matchExpressions:
- key: reserved:ingress
operator: Exists
egress:
- toEntities:
- cluster
6. Проверки после настройки
| Что проверяем | Как проверить | Ожидаемый результат |
|---|---|---|
| Gateway | kubectl get gateway -A | Статус Programmed / Ready |
| HTTPRoute | kubectl get httproute -A | Accepted, ResolvedRefs |
| Политики | kubectl get cnp -n <ns>, kubectl get ccnp | Объекты на месте |
| Доступ через Gateway | curl -vk https://<gateway-host>/... | Ожидаемый HTTP-код приложения |
| Прямой доступ к pod IP | curl <pod-ip>:8080 | Timeout / DROP (если включена изоляция) |
| Трафик от Gateway | hubble observe --identity ingress | ALLOW к бэкенду |
| Нет лишних блокировок | hubble observe --verdict DROPPED -n <ns> | Нет неожиданных DROP |
| DNS работает | kubectl exec -it <pod> -- nslookup kubernetes | Резолвится |
7. Коротко
- Gateway API и Cilium Network Policies — одна система datapath, а не два независимых слоя.
- Между клиентом и приложением появляется промежуточное звено — Gateway-контроллер с identity
ingress. Нужно разрешать трафик на двух участках: доступ к Gateway и доступ от Gateway к бэкенду. - Для бэкенда используйте
CiliumNetworkPolicyсfromEntities: [ingress]. СтандартныйNetworkPolicyработает ограниченно и ненадёжно. - Не фильтруйте клиентов по IP на бэкенде — источником для политики становится
ingress. Делайте это на уровне Gateway, внешнего firewall или по HTTP-заголовкам (X-Forwarded-For,X-Envoy-External-Address) в приложении. - Не ожидайте per-Gateway разграничения через одну entity
ingress— в текущей модели Cilium это пока невозможно. - Применяйте политики постепенно и проверяйте путь в Hubble.
Рекомендуется сначала добиться рабочего Gateway-пути, затем добавьте точечный allow от ingress, при необходимости делайте строже изоляцию.
Справка
Identity (сущности Cilium)
| Что это | Identity |
|---|---|
| Внешний мир (интернет) | world |
| Cilium Ingress/Gateway прокси | ingress / reserved:ingress |
| Любой под в кластере | cluster |
| Kubernetes API Server | kube-apiserver |
| Узел кластера | host |
API-версии ресурсов
| Ресурс | API Group |
|---|---|
| CiliumNetworkPolicy | cilium.io/v2 |
| CiliumClusterwideNetworkPolicy | cilium.io/v2 |
| GatewayClass, Gateway, HTTPRoute, GRPCRoute | gateway.networking.k8s.io/v1 |
Примеры команд
# Проверка политик
kubectl get cnp -A
kubectl get ccnp
# Проверка Gateway
kubectl get gateway,httproute -A
kubectl describe gateway <name> -n <ns>
# Отладка через Hubble
hubble observe --verdict DROPPED --namespace <ns>
hubble observe --identity ingress --last 50