Публикация приложений средствами Kubernetes Gateway API
Публикация приложения возможна через общекластерный шлюз (ClusterALBInstance, создаёт администратор кластера) или через отдельный шлюз в неймспейсе приложения (ALBInstance).
Создание управляемого Gateway (ClusterALBInstance или ALBInstance, инлеты, включение модуля) — задача администратора. Настройка инфраструктуры описана в разделе «Включение модуля и создание Gateway».
Этот сценарий предполагает, что объект ClusterALBInstance или ALBInstance уже создан и перешёл в состояние Ready. Запросите у администратора имя и неймспейс управляемого Gateway или получите имя Gateway из поля status.gateway инстанса:
d8 k get clusteralbinstance <CLUSTER_ALB_INSTANCE_NAME> \
-o jsonpath='{.status.gateway}{"\n"}'
d8 k -n <NAMESPACE> get albinstance <ALB_INSTANCE_NAME> \
-o jsonpath='{.status.gateway}{"\n"}'
Для ClusterALBInstance управляемый Gateway обычно находится в неймспейсе d8-alb. Для ALBInstance — в том же неймспейсе, что и объект ALBInstance. Описание полей статуса — в status.
Администратор неймспейса создаёт ListenerSet, привязанный к этому Gateway (spec.parentRef). Разработчики приложения создают объекты HTTPRoute, привязанные к ListenerSet.
Слушатели d8-http и d8-https предназначены для служебных задач — например, для проверки доступности шлюза или запросов HTTP-01 от cert-manager. Не привязывайте к ним маршруты приложений — для публикации приложений используйте ListenerSet.
Публикация приложения с ListenerSet и HTTPRoute
Пример ListenerSet и HTTPRoute для публикации приложения через управляемый Gateway:
apiVersion: gateway.networking.k8s.io/v1
kind: ListenerSet
metadata:
name: app-listeners
namespace: prod
spec:
parentRef:
name: public-gw # Имя объекта Gateway из status ClusterALBInstance, предоставленное администратором.
namespace: d8-alb
listeners:
- name: app-http
port: 80 # В ListenerSet для HTTP указывайте порт 80. Это не параметр hostPort.httpPort инлета HostPort на узле.
protocol: HTTP
hostname: app.example.com
- name: app-https
port: 443 # В ListenerSet для HTTPS указывайте порт 443. Это не параметр hostPort.httpsPort инлета HostPort на узле.
protocol: HTTPS
hostname: app.example.com
tls:
mode: Terminate
certificateRefs:
- name: app-tls # Secret с TLS-сертификатом (выпустите через cert-manager или создайте вручную).
namespace: prod
---
# Маршрут для HTTP-трафика
apiVersion: gateway.networking.k8s.io/v1
kind: HTTPRoute
metadata:
name: app-http-route
namespace: prod
spec:
parentRefs:
- name: app-listeners # Имя ListenerSet.
namespace: prod
kind: ListenerSet
group: gateway.networking.k8s.io
sectionName: app-http
port: 80
hostnames:
- app.example.com
rules:
- backendRefs:
- name: app-svc # Наименование сервиса приложения.
port: 8080
---
# Маршрут для HTTPS-трафика
apiVersion: gateway.networking.k8s.io/v1
kind: HTTPRoute
metadata:
name: app-https-route
namespace: prod
spec:
parentRefs:
- name: app-listeners # Имя ListenerSet.
namespace: prod
kind: ListenerSet
group: gateway.networking.k8s.io
sectionName: app-https
port: 443
hostnames:
- app.example.com
rules:
- backendRefs:
- name: app-svc # Наименование сервиса приложения.
port: 8080
Проверка публикации
После применения ListenerSet и HTTPRoute проверьте статус объектов:
d8 k -n <NAMESPACE> get listenerset
d8 k -n <NAMESPACE> describe listenerset <LISTENERSET_NAME>
d8 k -n <NAMESPACE> get httproute
d8 k -n <NAMESPACE> describe httproute <HTTPROUTE_NAME>
Проверьте следующее:
- В статусе ListenerSet слушатели в состоянии
ProgrammedилиAccepted. - У HTTPRoute в
parentRefsуказан нужный ListenerSet и условияAcceptedвыполнены. - Адрес точки входа и DNS для hostname согласованы с администратором (для инлета
LoadBalancerадрес обычно берётся из Service в неймспейсеd8-alb).
Проверьте доступность приложения с клиента, подставив адрес точки входа и hostname (успешный ответ — код 200 или другой ожидаемый код приложения):
curl -vk \
--resolve app.example.com:443:<ENTRY_POINT_ADDRESS> \
https://app.example.com/
Если маршрут не принимается, проверьте имя Gateway из status инстанса, неймспейс ListenerSet, порт и sectionName в parentRefs. Конфликты hostname и порта с другими объектами ListenerSet видны в выводе команды describe listenerset из предыдущего шага — в статусе конфликтующего слушателя появляется условие с описанием причины.
Работа с объектами GRPCRoute, TLSRoute, TCPRoute и UDPRoute
Помимо HTTPRoute, для публикации приложений можно использовать GRPCRoute (gRPC-трафик), TLSRoute (сквозная передача TLS) и TCPRoute/UDPRoute (произвольный TCP и UDP-трафик).
GRPCRoute для gRPC-трафика
Объект GRPCRoute предназначен для маршрутизации gRPC-трафика. Для него создаётся объект ListenerSet со слушателем HTTPS, а затем добавляется объект GRPCRoute:
apiVersion: gateway.networking.k8s.io/v1
kind: ListenerSet
metadata:
name: grpc-listeners
namespace: prod
spec:
parentRef:
name: app-gw # Имя объекта Gateway из поля status ALBInstance.
namespace: prod
listeners:
- name: grpc-https
port: 443 # В ListenerSet для HTTPS указывайте порт 443. Это не параметр hostPort.httpsPort инлета HostPort на узле.
protocol: HTTPS
hostname: grpc.example.com
tls:
mode: Terminate
certificateRefs:
- name: grpc-tls # Наименование объекта Secret, содержащего необходимый TLS-сертификат.
namespace: prod
---
apiVersion: gateway.networking.k8s.io/v1
kind: GRPCRoute
metadata:
name: grpc-route
namespace: prod
spec:
parentRefs:
- name: grpc-listeners # Имя ListenerSet.
namespace: prod
kind: ListenerSet
group: gateway.networking.k8s.io
sectionName: grpc-https
port: 443
hostnames:
- grpc.example.com
rules:
- backendRefs:
- name: grpc-svc # Наименование сервиса приложения.
port: 9090
Сквозная передача TLS с TLSRoute
Для сквозной передачи TLS (passthrough), когда расшифровка трафика должна выполняться на стороне приложения, можно использовать либо слушателя TLS, либо слушателя HTTPS.
Дополнительные порты задаются в spec.inlet.additionalPorts объекта, который владеет шлюзом:
- для общекластерного Gateway — в ClusterALBInstance (это делает администратор кластера);
- для шлюза в неймспейсе — в ALBInstance (администратор неймспейса или вы, если есть права на объект).
Пример для ClusterALBInstance — в разделе «Открытие дополнительного TCP/UDP-порта на общекластерном Gateway». Ниже показан пример для ALBInstance.
- Слушатель TLS
- Слушатель HTTPS
Поскольку в этом примере слушатель TLS использует дополнительный порт, попросите администратора добавить additionalPorts в объект, владеющий шлюзом (ClusterALBInstance или ALBInstance), или добавьте параметр сами, если у вас есть права:
apiVersion: network.deckhouse.io/v1alpha1
kind: ALBInstance
metadata:
name: app-gw
namespace: prod
spec:
gatewayName: app-gw
inlet:
type: LoadBalancer
additionalPorts:
- port: 8443 # Дополнительный TCP-порт для TLS-трафика.
protocol: TCP
Далее настройте объекты ListenerSet и TLSRoute:
apiVersion: gateway.networking.k8s.io/v1
kind: ListenerSet
metadata:
name: tls-pass-listeners
namespace: prod
spec:
parentRef:
name: app-gw # Имя объекта Gateway из поля status ALBInstance.
namespace: prod
listeners:
- name: tls-pass
port: 8443 # В данном примере для TLS-трафика переиспользуется порт 8443.
protocol: TLS
hostname: pass.example.com
tls:
mode: Passthrough # Режим TLS — сквозной.
---
apiVersion: gateway.networking.k8s.io/v1
kind: TLSRoute
metadata:
name: tls-pass-route
namespace: prod
spec:
parentRefs:
- name: tls-pass-listeners # Имя ListenerSet.
namespace: prod
kind: ListenerSet
group: gateway.networking.k8s.io
sectionName: tls-pass
port: 8443 # В данном примере для TLS-трафика переиспользуется порт 8443.
hostnames:
- pass.example.com
rules:
- backendRefs:
- name: tls-pass-svc # Наименование сервиса приложения.
port: 8443
Вариант со слушателем HTTPS удобен, когда нужно использовать стандартный обработчик на порту 443. Дополнительный порт для сквозной передачи TLS открывать не требуется.
apiVersion: gateway.networking.k8s.io/v1
kind: ListenerSet
metadata:
name: https-pass-listeners
namespace: prod
spec:
parentRef:
name: app-gw # Имя объекта Gateway из поля status ALBInstance.
namespace: prod
listeners:
- name: https-pass
port: 443 # В данном примере для TLS-трафика переиспользуется порт 443.
protocol: HTTPS
hostname: pass.example.com
tls:
mode: Passthrough # Режим TLS — сквозной.
---
apiVersion: gateway.networking.k8s.io/v1
kind: TLSRoute
metadata:
name: https-pass-route
namespace: prod
spec:
parentRefs:
- name: https-pass-listeners # Имя ListenerSet.
namespace: prod
kind: ListenerSet
group: gateway.networking.k8s.io
sectionName: https-pass
port: 443 # В данном примере для TLS-трафика переиспользуется порт 443.
hostnames:
- pass.example.com
rules:
- backendRefs:
- name: tls-pass-svc # Наименование сервиса приложения.
port: 8443
TLS-терминация на шлюзе с TCPRoute
Если TLS нужно терминировать на шлюзе, а затем передать трафик дальше как TCP-поток к бэкенду (например, когда приложение принимает уже расшифрованный TCP, а не HTTPS), создайте объект ListenerSet со слушателем TLS и режимом Terminate, после чего подключите объект TCPRoute:
apiVersion: gateway.networking.k8s.io/v1
kind: ListenerSet
metadata:
name: tls-term-listeners
namespace: prod
spec:
parentRef:
name: app-gw # Имя объекта Gateway из поля status ALBInstance.
namespace: prod
listeners:
- name: tls-term
port: 443 # В данном примере для TLS-трафика переиспользуется порт 443.
protocol: TLS
hostname: term.example.com
tls:
mode: Terminate # Режим TLS — терминация.
certificateRefs:
- name: term-tls # Наименование объекта Secret, содержащего необходимый TLS-сертификат.
namespace: prod
---
apiVersion: gateway.networking.k8s.io/v1alpha2
kind: TCPRoute
metadata:
name: tls-term-route
namespace: prod
spec:
parentRefs:
- name: tls-term-listeners # Имя ListenerSet.
namespace: prod
kind: ListenerSet
group: gateway.networking.k8s.io
sectionName: tls-term
port: 443
rules:
- backendRefs:
- name: tls-svc # Наименование сервиса приложения.
port: 8080
Дополнительные TCP- и UDP-порты
Для портов TCP и UDP из additionalPorts маршрут привязывается напрямую к слушателю управляемого Gateway, без отдельного ListenerSet. Иначе контроллер отклонит конфигурацию из-за пересечения обработчиков.
Дополнительные порты задаются в объекте, который владеет шлюзом: в ClusterALBInstance для общекластерного Gateway или в ALBInstance для шлюза в неймспейсе. Для ClusterALBInstance используйте пример в разделе «Открытие дополнительного TCP/UDP-порта на общекластерном Gateway».
- TCP
- UDP
Для публикации TCP-сервиса попросите администратора открыть дополнительный TCP-порт в объекте, владеющем шлюзом (ClusterALBInstance или ALBInstance), или откройте его сами, если у вас есть права:
apiVersion: network.deckhouse.io/v1alpha1
kind: ALBInstance
metadata:
name: app-gw
namespace: prod
spec:
gatewayName: app-gw
inlet:
type: LoadBalancer
additionalPorts:
- port: 9000
protocol: TCP
Контроллер модуля alb автоматически создаёт на управляемом объекте Gateway TCP-слушатель на основе spec.inlet.additionalPorts. Привяжите объект TCPRoute к этому слушателю:
apiVersion: gateway.networking.k8s.io/v1alpha2
kind: TCPRoute
metadata:
name: tcp-route
namespace: prod
spec:
parentRefs:
- name: app-gw # Имя объекта Gateway из поля status ALBInstance.
namespace: prod
kind: Gateway
group: gateway.networking.k8s.io
sectionName: tcp-port-9000
port: 9000
rules:
- backendRefs:
- name: tcp-svc # Наименование сервиса приложения.
port: 9000
Для публикации UDP-сервиса попросите администратора открыть дополнительный UDP-порт в объекте, владеющем шлюзом (ClusterALBInstance или ALBInstance), или откройте его сами, если у вас есть права:
apiVersion: network.deckhouse.io/v1alpha1
kind: ALBInstance
metadata:
name: app-gw
namespace: prod
spec:
gatewayName: app-gw
inlet:
type: LoadBalancer
additionalPorts:
- port: 5353
protocol: UDP
Контроллер модуля alb автоматически создаёт на управляемом объекте Gateway UDP-слушатель на основе spec.inlet.additionalPorts. Привяжите объект UDPRoute к этому слушателю:
apiVersion: gateway.networking.k8s.io/v1
kind: UDPRoute
metadata:
name: udp-route
namespace: prod
spec:
parentRefs:
- name: app-gw # Имя объекта Gateway из поля status ALBInstance.
namespace: prod
kind: Gateway
group: gateway.networking.k8s.io
sectionName: udp-port-5353
port: 5353
rules:
- backendRefs:
- name: udp-svc # Наименование сервиса приложения.
port: 5353
Перевод приложения на публикацию через другой Gateway
Если приложение нужно опубликовать через другой объект Gateway, выполните следующие шаги:
- Получите у администратора кластера новый управляемый Gateway (новый ClusterALBInstance или ALBInstance), чтобы контроллер создал новый объект Gateway. Создание управляемых Gateway описано в разделе «Включение модуля и создание Gateway».
- Создайте объект ListenerSet с теми же именами хостов, портами и TLS-настройками. В
spec.parentRefукажите новый объект Gateway. - В существующий объект HTTPRoute, в
parentRefsдобавьте ещё один объект, который указывает на новый объект ListenerSet. - Проверьте доступность приложения через новый шлюз.
- После проверки удалите из
parentRefsобъекта HTTPRoute ссылку на неактуальные ListenerSet.
Привязка маршрута к ListenerSet в другом неймспейсе
Gateway API по умолчанию запрещает маршрутам ссылаться на объекты в чужих неймспейсах — такую привязку нужно разрешить явно. Если HTTPRoute и целевой ListenerSet находятся в разных неймспейсах, добавьте ReferenceGrant рядом с ListenerSet.
В примере ниже — общий ListenerSet в shared-gw, прикладной HTTPRoute в prod и ReferenceGrant в shared-gw, разрешающий такую привязку:
apiVersion: gateway.networking.k8s.io/v1
kind: ListenerSet
metadata:
name: shared-listeners
namespace: shared-gw
spec:
parentRef:
name: public-gw
namespace: d8-alb
listeners:
- name: app-https
port: 443
protocol: HTTPS
hostname: app.example.com
tls:
mode: Terminate
certificateRefs:
- name: app-tls
namespace: shared-gw
---
apiVersion: gateway.networking.k8s.io/v1
kind: ReferenceGrant
metadata:
name: allow-prod-httproute-to-shared-listeners
namespace: shared-gw
spec:
from:
- group: gateway.networking.k8s.io
kind: HTTPRoute
namespace: prod
to:
- group: gateway.networking.k8s.io
kind: ListenerSet
name: shared-listeners
---
apiVersion: gateway.networking.k8s.io/v1
kind: HTTPRoute
metadata:
name: app-route
namespace: prod
spec:
parentRefs:
- name: shared-listeners
namespace: shared-gw
kind: ListenerSet
group: gateway.networking.k8s.io
sectionName: app-https
port: 443
hostnames:
- app.example.com
rules:
- backendRefs:
- name: app-svc
port: 8080
Настройка параметров TLS через BackendTLSPolicy
Если трафик от шлюза к бэкенду должен идти по TLS, создайте BackendTLSPolicy в неймспейсе бэкенд-объекта Service. В примере ниже — HTTPRoute, бэкенд-объект Service с именованным портом, ConfigMap с CA bundle и BackendTLSPolicy с TLS-валидацией для этого бэкенда:
apiVersion: gateway.networking.k8s.io/v1
kind: HTTPRoute
metadata:
name: app-route
namespace: prod
spec:
parentRefs:
- name: app-listeners
namespace: prod
kind: ListenerSet
group: gateway.networking.k8s.io
sectionName: app-https
port: 443
hostnames:
- app.example.com
rules:
- backendRefs:
- name: app-svc
port: 8443
---
apiVersion: v1
kind: Service
metadata:
name: app-svc
namespace: prod
spec:
selector:
app: app
ports:
- name: https
port: 8443
targetPort: 8443
---
apiVersion: v1
kind: ConfigMap
metadata:
name: app-backend-ca
namespace: prod
data:
ca.crt: |
-----BEGIN CERTIFICATE-----
...
-----END CERTIFICATE-----
---
apiVersion: gateway.networking.k8s.io/v1
kind: BackendTLSPolicy
metadata:
name: app-svc-tls
namespace: prod
spec:
targetRefs:
- group: ""
kind: Service
name: app-svc
sectionName: https
validation:
hostname: app.internal.example.com
caCertificateRefs:
- group: ""
kind: ConfigMap
name: app-backend-ca
GeoIP и трассировку OpenTelemetry настраивает администратор на ClusterALBInstance или ALBInstance, по инструкциям «Использование GeoIP и GeoLite2» и «Настройка трассировки OpenTelemetry».
Поддерживаемые аннотации HTTPRoute
Так как текущая спецификация Gateway API пока не покрывает все возможности, нужные для работы кластера Deckhouse Platform (DP), модуль предоставляет аннотации HTTPRoute для недостающих параметров. Контроллер читает эти ключи из HTTPRoute.metadata.annotations.
| Аннотация | Описание |
|---|---|
alb.network.deckhouse.io/tls-disable-protocol |
Отключает протокол обработчика для маршрута с указанным именем хоста (например, значение http2). Может быть необходимо в редких случаях, когда используется общий сертификат с несколькими DNS-именами в сочетании с перенаправлением запросов |
alb.network.deckhouse.io/whitelist-source-range |
Список подсетей в формате CIDR через запятую. Задаёт фильтр по IP на уровне маршрута и переопределяет глобальный whitelist (например, 10.1.1.10/32, 10.2.2.2/32) |
alb.network.deckhouse.io/response-headers-to-add |
JSON-объект дополнительных заголовков ответа (например, {"Strict-Transport-Security": "max-age=31536000; includeSubDomains"}) |
alb.network.deckhouse.io/session-affinity |
JSON для закрепления сессии (session affinity) с режимом cookie (mode, path, cookieName, ttl и др.); не все поля обязательны (например, {"mode": "cookie", "path": "/path", "cookieName": "mycookie", "ttl": 0}) |
alb.network.deckhouse.io/hash-key |
Ключ консистентного хеширования Envoy для выбора бэкенда Service у объекта HTTPRoute; например, source-ip — хеширование по IP-адресу клиента |
alb.network.deckhouse.io/service-upstream |
"true": трафик к upstream идёт через соответствующий сервис, а не напрямую к подам |
alb.network.deckhouse.io/basic-auth-secret |
namespace/secret с данными htpasswd для HTTP Basic Auth на этом маршруте |
alb.network.deckhouse.io/satisfy |
all или any: определяет, нужно ли пройти обе проверки (whitelist и basic-auth) или достаточно одной (по умолчанию all) |
alb.network.deckhouse.io/auth-url |
Определяет URL внешнего сервиса аутентификации |
alb.network.deckhouse.io/auth-signin |
Определяет URL редиректа для авторизации в случае получения 401 от внешней аутентификации |
alb.network.deckhouse.io/auth-response-headers |
Список через запятую: дополнительные заголовки из ответа сервиса аутентификации для передачи в upstream (поверх стандартного allowlist) |
alb.network.deckhouse.io/mod-security |
JSON-конфигурация для WAF ModSecurity/Coraza на уровне маршрута |
alb.network.deckhouse.io/rewrite-target |
Позволяет переопределять URL-путь для правил с типом RegularExpression с использованием совпавших частей регулярного выражения (например, /my-path/\1) |
alb.network.deckhouse.io/buffer-max-request-bytes |
Максимальный размер буфера для буферизации запроса, в байтах (целое число). По умолчанию Envoy Proxy не буферизует запросы |
alb.network.deckhouse.io/limit-rps |
Лимит RPS на маршрут |
alb.network.deckhouse.io/backend-tls-settings |
Например, {"mode": "SIMPLE", "insecureSkipVerify": true, "clientCertificate": "", "privateKey": "", "caCertificates": "", "sni": "example.com", "secret": "<NAMESPACE>/<SECRET_NAME>"}; позволяет явно указать параметры TLS подключения к upstream. <NAMESPACE> — неймспейс Secret; <SECRET_NAME> — имя Secret |
alb.network.deckhouse.io/idle-timeout |
Устанавливает idle_timeout Envoy на уровне маршрута, в секундах. Аналогично тайм-аутам proxy-read-timeout/proxy-send-timeout в ingress-nginx. Это тайм-аут неактивности, а не тайм-аут общей длительности запроса |
alb.network.deckhouse.io/proxy-buffer-size |
Задаёт максимальный размер заголовков ответа в настройках upstream-кластера; при превышении этого значения Envoy возвращает 503. Аналогично nginx.ingress.kubernetes.io/proxy-buffer-size |
Публикация приложения при включённом Istio-сайдкаре
Если для прокси шлюза включён Istio-сайдкар с помощью параметра istioSidecar объекта ALBInstance или ClusterALBInstance, трафик к бэкенду должен попадать в сайдкар через Service и содержать FQDN этого Service в заголовке Host.
Настройте HTTPRoute следующим образом:
- Добавьте аннотацию
alb.network.deckhouse.io/service-upstream: "true", чтобы трафик шёл через объект Service, а не напрямую к подам. Это эквивалент аннотацииnginx.ingress.kubernetes.io/service-upstream: "true"изingress-nginx. - Добавьте фильтр
URLRewrite, который задаёт в полеhostnameFQDN объекта бэкенд-сервиса. Он заменяет аннотациюnginx.ingress.kubernetes.io/upstream-vhostизingress-nginx.
Пример HTTPRoute для шлюза с Istio-сайдкаром:
apiVersion: gateway.networking.k8s.io/v1
kind: HTTPRoute
metadata:
name: myservice
namespace: myns
annotations:
alb.network.deckhouse.io/service-upstream: "true" # Трафик идёт через объект Service, чтобы его мог обработать Istio-сайдкар.
spec:
parentRefs:
- name: app-listeners # Имя объекта ListenerSet.
namespace: myns
kind: ListenerSet
group: gateway.networking.k8s.io
sectionName: app-https
port: 443
hostnames:
- myservice.example.com
rules:
- filters:
- type: URLRewrite
urlRewrite:
hostname: myservice.myns.svc # FQDN объекта backend-сервиса, чтобы сайдкар определил назначение.
backendRefs:
- name: myservice
port: 80
WAF на HTTPRoute
Аннотация alb.network.deckhouse.io/mod-security позволяет включить WAF (Web Application Firewall) на базе ModSecurity/Coraza для отдельного HTTPRoute. Конфигурация WAF применяется только к маршруту, для которого указана аннотация, и не влияет на остальные маршруты.
Аннотация поддерживает следующие поля:
| Поле | Описание |
|---|---|
mode |
Режим работы WAF: on, off, либо любое другое значение для DetectionOnly |
preset |
Необязательный набор правил. Сейчас поддерживается только owasp-crs. Если поле не указано, набор правил не загружается |
paranoiaLevel |
Необязательный уровень CRS paranoia от 1 до 4. Применяется только если preset равен owasp-crs |
configRef.namespace |
Необязательный неймспейс ConfigMap с пользовательскими правилами. По умолчанию используется неймспейс HTTPRoute |
configRef.name |
Имя ConfigMap с пользовательскими правилами |
configRef.key |
Необязательный ключ в ConfigMap. Если не указан, читаются все ключи в отсортированном порядке |
directives |
Необязательный список директив ModSecurity/Coraza, заданных непосредственно в аннотации; они добавляются после правил из набора и ConfigMap |
Директивы и правила применяются в следующем порядке:
- Базовые директивы, поставляемые модулем (
@coraza.conf,SecRuleEngine,SecResponseBodyAccess Off). - Правила из набора, заданного в
preset. - Пользовательские правила из ConfigMap, указанного в
configRef. - Директивы из поля
directivesаннотации.
Директивы из аннотации применяются последними и могут переопределять набор правил или правила из ConfigMap.
Ниже — примеры аннотации alb.network.deckhouse.io/mod-security для HTTPRoute.
- mode: on
- OWASP CRS
- ConfigMap
Минимальная конфигурация: WAF включён без набора правил и без пользовательских директив.
apiVersion: gateway.networking.k8s.io/v1
kind: HTTPRoute
metadata:
name: app
namespace: prod
annotations:
alb.network.deckhouse.io/mod-security: |
{
"mode": "on"
}
spec:
hostnames:
- app.example.com
parentRefs:
- group: gateway.networking.k8s.io
kind: ListenerSet
name: app-listeners
namespace: prod
sectionName: app-https
port: 443
rules:
- matches:
- path:
type: PathPrefix
value: /
backendRefs:
- name: app-svc
port: 8080
WAF с предустановленным набором правил OWASP CRS и уровнем paranoiaLevel:
metadata:
annotations:
alb.network.deckhouse.io/mod-security: |
{
"mode": "on",
"preset": "owasp-crs",
"paranoiaLevel": 1
}
WAF с OWASP CRS, пользовательскими правилами из ConfigMap и дополнительными директивами в аннотации:
apiVersion: v1
kind: ConfigMap
metadata:
name: waf-rules
namespace: prod
data:
rules.conf: |
SecRule ARGS:test "@streq block" \
"id:1000001,phase:2,deny,status:403,msg:'test waf block'"
---
apiVersion: gateway.networking.k8s.io/v1
kind: HTTPRoute
metadata:
name: app
namespace: prod
annotations:
alb.network.deckhouse.io/mod-security: |
{
"mode": "on",
"preset": "owasp-crs",
"paranoiaLevel": 1,
"configRef": {
"name": "waf-rules",
"key": "rules.conf"
},
"directives": [
"SecResponseBodyAccess Off"
]
}
Подробнее о синтаксисе правил и директив в документации Coraza и ModSecurity:
- синтаксис правил Coraza и директива
SecRule; - переменные ModSecurity;
- операторы ModSecurity;
- директива
SecRuleEngineи другие директивы ModSecurity.
Текущие особенности и ограничения WAF:
- Поддерживается только набор правил
owasp-crs. - Параметр
paranoiaLevelприменяется только при использованииpreset: owasp-crs. Если параметрpresetне указан или имеет другое значение, параметрparanoiaLevelигнорируется. - Допустимые значения
paranoiaLevel: от1до4. На практике рекомендуется начинать со значения1. - WAF проверяет только входящие запросы к приложению и при необходимости блокирует их. Ответы приложения клиенту не анализируются.
- Правила, заданные через ConfigMap, могут быть многострочными: строки, завершающиеся символом
\, автоматически объединяются.