CiliumNetworkPolicy: модель default-deny и allowlist
Published: 2026-02-28
Kubernetes NetworkPolicy — хорошая идея с неудачной реализацией: синтаксис многословный, семантика запутанная (ingress/egress — с точки зрения пода), а кластерный DNS работает загадочным образом. CiliumNetworkPolicy расширяет стандартный API правилами на основе идентичностей, L7-фильтрацией и egress по FQDN.
Проблема отсутствия политик
По умолчанию каждый под может достучаться до любого другого в кластере. Скомпрометированное приложение свободно обращается к:
- Vault API
- Prometheus API (в лейблах метрик — внутренние имена сервисов)
- базам данных из других неймспейсов
- внешним эндпоинтам без ограничений
Сеть по модели zero trust начинается с default-deny. Радиус поражения любого скомпрометированного пода ограничен тем, что явно разрешено политикой.
Шаг 1: default-deny для namespace
yamlapiVersion: "cilium.io/v2"
kind: CiliumNetworkPolicy
metadata:
name: default-deny
namespace: app
specs:
- description: "Default deny all ingress and egress"
endpointSelector: {}
ingress:
- {}
egress:
- {}
ingress: [{}] выглядит как «разрешить всё», но в семантике CiliumNetworkPolicy пустой список — это deny all. Один {} без fromEndpoints или fromCIDR не соответствует ничему. В результате весь ingress- и egress-трафик в неймспейсе отбрасывается.
После применения поды не смогут обращаться даже к DNS. Исправляем следующим правилом.
Шаг 2: разрешить DNS
yamlapiVersion: "cilium.io/v2"
kind: CiliumNetworkPolicy
metadata:
name: allow-dns
namespace: app
spec:
endpointSelector: {}
egress:
- toEndpoints:
- matchLabels:
"k8s:io.kubernetes.pod.namespace": kube-system
"k8s:k8s-app": kube-dns
toPorts:
- ports:
- port: "53"
protocol: UDP
- port: "53"
protocol: TCP
Без этого ломается service discovery — поды не стартуют из-за ошибок резолва DNS.
Шаг 3: разрешить ingress от ingress controller
yamlapiVersion: "cilium.io/v2"
kind: CiliumNetworkPolicy
metadata:
name: allow-from-ingress
namespace: app
spec:
endpointSelector:
matchLabels:
app: my-service
ingress:
- fromEndpoints:
- matchLabels:
"k8s:io.kubernetes.pod.namespace": ingress-apisix
До my-service может достучаться только ingress-контроллер APISIX. Прямой трафик между подами из других неймспейсов заблокирован.
Шаг 4: межсервисное взаимодействие
Frontend должен обращаться к backend:
yamlapiVersion: "cilium.io/v2"
kind: CiliumNetworkPolicy
metadata:
name: allow-frontend-to-backend
namespace: app
spec:
endpointSelector:
matchLabels:
app: backend
ingress:
- fromEndpoints:
- matchLabels:
app: frontend
toPorts:
- ports:
- port: "8080"
protocol: TCP
Только поды frontend и только порт 8080.
Шаг 5: egress к базам данных
yamlapiVersion: "cilium.io/v2"
kind: CiliumNetworkPolicy
metadata:
name: allow-backend-to-postgres
namespace: app
spec:
endpointSelector:
matchLabels:
app: backend
egress:
- toEndpoints:
- matchLabels:
"k8s:io.kubernetes.pod.namespace": databases
app: postgresql
toPorts:
- ports:
- port: "5432"
protocol: TCP
Egress по FQDN (внешние API)
yamlapiVersion: "cilium.io/v2"
kind: CiliumNetworkPolicy
metadata:
name: allow-external-api
namespace: app
spec:
endpointSelector:
matchLabels:
app: my-service
egress:
- toFQDNs:
- matchName: "api.stripe.com"
- matchName: "api.sendgrid.com"
- matchPattern: "*.s3.amazonaws.com"
toPorts:
- ports:
- port: "443"
protocol: TCP
Cilium резолвит FQDN на лету и обновляет eBPF-карты. Поды могут достучаться только до явно разрешённых внешних эндпоинтов.
L7-политика для HTTP
Cilium умеет применять политику на уровне HTTP:
yamlegress:
- toEndpoints:
- matchLabels:
app: payment-service
toPorts:
- ports:
- port: "8080"
protocol: TCP
rules:
http:
- method: "POST"
path: "/api/v1/charge"
Попытка GET /admin будет отброшена на сетевом уровне, до того как запрос достигнет пода.
Отладка через Hubble
bash# Все отброшенные соединения в неймспейсе
hubble observe --namespace app --verdict DROPPED
# Трафик в реальном времени
hubble observe --namespace app -f
# Что отбрасывается у конкретного пода
hubble observe --namespace app --from-pod app/my-service --verdict DROPPED
Hubble показывает под-источник, под-цель или FQDN, порт и политику с вердиктом POLICY_DENIED. Добавлять логирование в приложения не нужно.
Постепенное внедрение
Не применяйте default-deny к продакшен-неймспейсам сразу. Рабочий процесс:
- Применить
default-denyк непродакшен-неймспейсу - Наблюдать за потоками
DROPPEDв Hubble - Добавить разрешающие правила для каждого легитимного потока
- Повторять, пока неожиданные дропы не исчезнут
- Перенести политики в продакшен
Cilium поддерживает режим audit на уровне политики — трафик разрешается, а нарушения логируются. Используйте его для инвентаризации потоков перед включением блокировки.