Стадия жизненного цикла модуля: Preview
У модуля есть требования для установки

В этом разделе приведены базовые примеры публикации приложений через модуль alb.

Публикация приложения через объект ClusterALBInstance

Этот сценарий предполагает, что объект ClusterALBInstance уже создан администратором кластера и перешёл в состояние Ready. Имя и неймспейс управляемого объекта Gateway нужно взять из поля status объекта ClusterALBInstance.

Затем создайте объект ListenerSet, который будет привязан к нужному Gateway (параметр spec.parentRef.name) и объекты (маршруты) HTTPRoute для маршрутизации входящих запросов к приложению. Пример:

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 # Для HTTP трафика необходимо указывать 80 порт.
      protocol: HTTP
      hostname: app.example.com
    - name: app-https
      port: 443 # Для HTTPS трафика необходимо указывать 443 порт.
      protocol: HTTPS
      hostname: app.example.com
      tls:
        mode: Terminate
        certificateRefs:
          - name: app-tls   # Наименование секрета, содержащего необходимый TLS-сертификат.
            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

Публикация приложения через объект ALBInstance

В этом сценарии объекты ALBInstance, Gateway, ListenerSet и HTTPRoute находятся в одном неймспейсе.

Для публикации приложения через объект ALBInstance выполните следующие действия:

  1. Создайте объект ALBInstance с учетом необходимых настроек:

    apiVersion: network.deckhouse.io/v1alpha1
    kind: ALBInstance
    metadata:
      name: app-gw
      namespace: prod
    spec:
      gatewayName: app-gw
      inlet:
        type: LoadBalancer
        loadBalancer: {}
  2. После того как объект ALBInstance перейдёт в состояние Ready, создайте объекты ListenerSet и HTTPRoute:

    apiVersion: gateway.networking.k8s.io/v1
    kind: ListenerSet
    metadata:
      name: app-listeners
      namespace: prod
    spec:
      parentRef:
        name: app-gw   # Имя объекта Gateway из поля status ALBInstance.
        namespace: prod
      listeners:
        - name: app-https
          port: 443 # Для HTTPS трафика необходимо указывать 443 порт.
          protocol: HTTPS
          hostname: app.example.com
          tls:
            mode: Terminate
            certificateRefs:
              - name: app-tls   # Наименование секрета содержащего необходимый TLS-сертификат.
                namespace: prod
    ---
    apiVersion: gateway.networking.k8s.io/v1
    kind: HTTPRoute
    metadata:
      name: app-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

Объекты GRPCRoute, TLSRoute, TCPRoute и UDPRoute

GRPCRoute

Объект 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 # Для HTTPS трафика необходимо указывать 443 порт.
      protocol: HTTPS
      hostname: grpc.example.com
      tls:
        mode: Terminate
        certificateRefs:
          - name: grpc-tls   # Наименование секрета содержащего необходимый 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

TLSRoute

Для TLS passthrough, когда расшифровка трафика должна выполняться на стороне приложения, можно использовать либо TLS listener, либо HTTPS listener. Ниже показан вариант с TLS listener.

Так как TLS listener в этом примере использует дополнительный порт, сначала настройте в объекте ALBInstance параметр additionalPorts:

apiVersion: network.deckhouse.io/v1alpha1
kind: ALBInstance
metadata:
  name: app-gw
  namespace: prod
spec:
  gatewayName: app-gw
  inlet:
    type: LoadBalancer
    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/v1alpha3
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 listener. Этот вариант особенно удобен, когда нужно использовать стандартный обработчик на порту 443, так как не требуется открывать дополнительный порт для TLS passthrough:

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/v1alpha3
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 нужно терминировать на шлюзе, а затем передать трафик дальше как обычный TCP-поток, создайте объект 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
        certificateRefs:
          - name: term-tls  # Наименование секрета содержащего необходимый 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

TCPRoute

Для публикации TCP-сервиса сначала откройте дополнительный TCP-порт в ALBInstance:

apiVersion: network.deckhouse.io/v1alpha1
kind: ALBInstance
metadata:
  name: app-gw
  namespace: prod
spec:
  gatewayName: app-gw
  inlet:
    type: LoadBalancer
    loadBalancer: {}
    additionalPorts:
      - port: 9000
        protocol: TCP

Контроллер ALB создаёт TCP listener на управляемом Gateway автоматически из spec.inlet.additionalPorts. Для TCP нужно привязывать TCPRoute напрямую к этому listener-у Gateway, а не создавать отдельный ListenerSet, иначе admission отклонит конфигурацию из-за overlap:

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

UDPRoute

Для публикации UDP-сервиса сначала откройте дополнительный UDP-порт в ALBInstance:

apiVersion: network.deckhouse.io/v1alpha1
kind: ALBInstance
metadata:
  name: app-gw
  namespace: prod
spec:
  gatewayName: app-gw
  inlet:
    type: LoadBalancer
    loadBalancer: {}
    additionalPorts:
      - port: 5353
        protocol: UDP

Контроллер ALB создаёт UDP listener на управляемом Gateway автоматически из spec.inlet.additionalPorts. Для UDP нужно привязывать UDPRoute напрямую к этому listener-у Gateway, а не создавать отдельный ListenerSet, иначе admission отклонит конфигурацию из-за overlap:

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, выполните следующие шаги:

  1. Создайте новый объект ClusterALBInstance или ALBInstance, чтобы контроллер создал новый объект Gateway.
  2. Создайте объект ListenerSet с теми же именами хостов, портами и TLS-настройками. В spec.parentRef укажите новый объект Gateway.
  3. В существующий объект HTTPRoute в parentRefs добавьте ещё один объект, который указывает на новый объект ListenerSet.
  4. Проверьте доступность приложения через новый шлюз.
  5. После проверки удалите из parentRefs объекта HTTPRoute ссылку на неактуальный ListenerSet.

Привязка маршрута в одном неймспейсе к ListenerSet объекту в другом неймспейсе

Если объект HTTPRoute создаётся в одном неймспейсе и должен подключаться к объекту ListenerSet в другом неймспейсе, в неймспейсе целевого объекта ListenerSet добавьте объект ReferenceGrant. В примере ниже показаны общий объект ListenerSet в неймспейсе shared-gw, прикладной объект HTTPRoute в неймспейсе prod и объект ReferenceGrant, который разрешает такую привязку:

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

Если трафик от шлюза к backend должен идти по TLS, необходимо создать объект BackendTLSPolicy в неймспейсе backend-объекта Service. В примере ниже показаны объект HTTPRoute, backend-объект Service с именованным портом, ConfigMap с CA bundle и объект BackendTLSPolicy, который задаёт TLS-валидацию для этого backend:

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

Настройка сертификата клиента по умолчанию для backend mTLS

Полная настройка backend mTLS состоит из объектов выше (BackendTLSPolicy и её ConfigMap с CA), а также Secret с клиентским сертификатом и настройки ALB ниже.

Укажите spec.backendTLS.clientCertificateRef в ALBInstance или ClusterALBInstance, чтобы передать клиентский сертификат в управляемый Gateway как spec.tls.backend.clientCertificateRef. Secret должен иметь тип kubernetes.io/tls и содержать tls.crt и tls.key. Добавлять ca.crt в клиентский Secret не требуется: доверие к backend настраивается через BackendTLSPolicy. Backend должен запрашивать клиентские сертификаты, подписанные тем же CA.

Аннотация маршрута alb.network.deckhouse.io/backend-tls-settings является полным переопределением на уровне маршрута и имеет приоритет над настройкой по умолчанию. Если в аннотации используется поле secret, Secret должен содержать tls.crt, tls.key и ca.crt (или cacert). Это отдельное требование аннотации. Для spec.backendTLS.clientCertificateRef поле ca.crt не требуется.

Контроллер автоматически создает ReferenceGrant объект в случае если Secret находится в другом неймспейсе.

Для ALBInstance не указывайте namespace, если Secret находится в неймспейсе ALBInstance:

apiVersion: v1
kind: Secret
metadata:
  name: backend-client
  namespace: prod
type: kubernetes.io/tls
data:
  tls.crt: <base64-клиентский-сертификат>
  tls.key: <base64-приватный-ключ-клиента>
---
apiVersion: network.deckhouse.io/v1alpha1
kind: ALBInstance
metadata:
  name: app-gw
  namespace: prod
spec:
  gatewayName: app-gw
  inlet:
    type: LoadBalancer
    loadBalancer: {}
  backendTLS:
    clientCertificateRef:
      name: backend-client

То же поле используется для ClusterALBInstance.

apiVersion: network.deckhouse.io/v1alpha1
kind: ClusterALBInstance
metadata:
  name: public-gw
spec:
  gatewayName: public-gw
  inlet:
    type: LoadBalancer
    loadBalancer: {}
  backendTLS:
    clientCertificateRef:
      name: backend-client

Все экземпляры, управляющие одним Gateway, должны использовать один и тот же клиентский сертификат. Создание или обновление с конфликтующей настройкой принимается с предупреждением. Авторитетным является самый старый экземпляр, а настройка нового игнорируется. Конфликт отображается в status.conflictBackendTLS и status.conflictBackendTLSOwner. Контроллер конфигурирует Gateway по настройкам наиболее старого ClusterALBInstance/ALBInstance.

Настройка frontend mTLS на Gateway

spec.frontendTLS передаёт настройки Gateway.spec.tls.frontend в управляемый Gateway. Эта настройка проверяет клиентский сертификат на входящем HTTPS- соединении. Контроллер сохраняет ссылки на исходные ConfigMap в Gateway.

Настройка применяется к HTTPS-listener в режиме Terminate. ListenerSet всё равно должен указать серверный сертификат в tls.certificateRefs. frontendTLS не заменяет этот сертификат.

Для отдельных HTTPS-портов вместо настройки default можно использовать frontendTLS.perPort. Структура perPort[].tls.validation такая же. Порт сопоставляется точно, а настройки perPort полностью заменяют default для этого порта и не объединяются с ним. В стандартном LoadBalancer настройка для порта 443 применяется к HTTPS-listener, а настройка для порта 80 не влияет на обычный HTTP-listener.

Все экземпляры, управляющие одним Gateway, должны использовать одинаковый frontendTLS. Конфликтующая конфигурация принимается с предупреждением. Авторитетным является самый старый экземпляр, а настройка нового игнорируется. Конфликт отображается в status.conflictFrontendTLS и status.conflictFrontendTLSOwner. Контроллер конфигурирует Gateway по настройкам наиболее старого ClusterALBInstance/ALBInstance.

apiVersion: v1
kind: ConfigMap
metadata:
  name: frontend-client-ca
  namespace: prod
data:
  ca.crt: <PEM CA, которым подписаны клиентские сертификаты>
---
apiVersion: network.deckhouse.io/v1alpha1
kind: ALBInstance
metadata:
  name: app-gw
  namespace: prod
spec:
  gatewayName: app-gw
  inlet:
    type: LoadBalancer
    loadBalancer: {}
  frontendTLS:
    default:
      validation:
        mode: AllowValidOnly
        caCertificateRefs:
          - name: frontend-client-ca

Для ConfigMap в другом неймспейсе укажите namespace в caCertificateRefs — контроллер автоматически создаст необходимый ReferenceGrant. Можно указать до 16 ConfigMap; каждый должен содержать PEM-сертификаты в ключе ca.crt. Все сертификаты объединяются в единый trust bundle для соответствующей default- или perPort-конфигурации.

AllowValidOnly режим требует клиентский сертификат, подписанный указанным CA, в то время как AllowInsecureFallback режим допускает подключения без сертификата и предназначен только для временной диагностики.

Поддерживаемые аннотации HTTPRoute

Так как текущая спецификация Gateway API пока не покрывает все возможности, необходимые для корректной работы кластера DKP, модуль предоставляет постепенно расширяющийся набор аннотаций объекта HTTPRoute, который добавляет недостающие параметры конфигурации. Контроллер читает эти ключи из HTTPRoute.metadata.annotations.

Аннотация Описание
alb.network.deckhouse.io/tls-disable-protocol Отключает версию протокола TLS для обработчика с именем хоста этого маршрута (например значение 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 для cookie session affinity (mode, path, cookieName, ttl и др.); не все поля обязательны, (например {“mode”: “cookie”, “path”: “/path”, “cookieName”: “mycookie”, “ttl”: 0})
alb.network.deckhouse.io/hash-key Например source-ip: консистентный хеш для бэкендов Service у объекта HTTPRoute
alb.network.deckhouse.io/service-upstream "true": трафик к upstream идёт через соответствующий сервис, а не напрямую к подам. При включённом istioSidecar.enabled также используйте фильтр URLRewrite в HTTPRoute с FQDN backend-сервиса в поле hostname
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 Список через запятую: дополнительные заголовки из ответа auth для передачи в upstream (поверх стандартного allowlist)
alb.network.deckhouse.io/mod-security JSON-конфигурация для WAF ModSecurity/Coraza на уровне маршрута
alb.network.deckhouse.io/rewrite-target Позволяет переопределять пути для правил с типом RegularExpression используя regex capture groups (например /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”: “default/mysecret”}. Полное переопределение параметров TLS к upstream на уровне маршрута. Если аннотация отсутствует, для backend, выбранных BackendTLSPolicy, используется клиентский сертификат Gateway по умолчанию
alb.network.deckhouse.io/idle-timeout Устанавливает per-route Envoy idle_timeout, в секундах. Схоже с ingress-nginx proxy-read-timeout / proxy-send-timeout; это таймаут неактивности, а не таймаут общей длительности запроса
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, который задаёт в поле hostname FQDN объекта backend-Service. Он заменяет аннотацию nginx.ingress.kubernetes.io/upstream-vhost из ingress-nginx.
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
  hostnames:
    - myservice.example.com
  rules:
    - filters:
        - type: URLRewrite
          urlRewrite:
            hostname: myservice.myns.svc # FQDN объекта backend-Service, чтобы сайдкар определил назначение.
      backendRefs:
        - name: myservice
          port: 80

WAF на HTTPRoute

Аннотация alb.network.deckhouse.io/mod-security включает WAF ModSecurity/Coraza для конкретного HTTPRoute. Конфигурация применяется на уровне маршрута и не затрагивает другие маршруты, если на них нет такой же аннотации.

Эта функция доступна в следующих редакциях: EE, BE, SE, SE+ и CSE.

Поддерживаемые поля аннотации:

Поле Описание
mode Режим работы WAF: on, off, либо любое другое значение для DetectionOnly.
preset Опциональный preset правил. Сейчас поддерживается только owasp-crs. Если поле не указано, preset-правила не загружаются.
paranoiaLevel Опциональный уровень CRS paranoia от 1 до 4. Применяется только если preset равен owasp-crs.
configRef.namespace Опциональный неймспейс ConfigMap с пользовательскими правилами. По умолчанию используется неймспейс HTTPRoute.
configRef.name Имя ConfigMap с пользовательскими правилами.
configRef.key Опциональный ключ в ConfigMap. Если не указан, читаются все ключи в отсортированном порядке.
directives Опциональный список директив ModSecurity/Coraza, заданных непосредственно в аннотации; они добавляются после правил из preset и ConfigMap.

Порядок применения директив:

  1. Базовые директивы, поставляемые модулем (@coraza.conf, SecRuleEngine, SecResponseBodyAccess Off).
  2. Preset-правила из preset.
  3. Правила из configRef.
  4. Встроенные директивы из поля directives.

Встроенные директивы применяются последними и могут переопределять preset или правила из ConfigMap.

Минимальный пример:

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

Пример с preset OWASP CRS:

metadata:
  annotations:
    alb.network.deckhouse.io/mod-security: |
      {
        "mode": "on",
        "preset": "owasp-crs",
        "paranoiaLevel": 1
      }

Пример с пользовательскими правилами из 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"
        ]
      }

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

Текущие особенности и ограничения:

  • поддерживается только preset owasp-crs;
  • параметр paranoiaLevel применяется только при использовании preset: owasp-crs. Если preset не указан или имеет другое значение, параметр paranoiaLevel игнорируется;
  • допустимые значения paranoiaLevel: от 1 до 4. На практике рекомендуется начинать со значения 1;
  • WAF проверяет только входящие запросы к приложению и при необходимости блокирует их. Ответы приложения клиенту не анализируются;
  • правила, заданные через ConfigMap, могут быть многострочными: строки, завершающиеся символом \, автоматически объединяются.

Использование GeoIP и GeoLite2

Модуль alb поддерживает обогащение входящих HTTP-запросов заголовками на основе данных баз MaxMind GeoIP/GeoLite2.

На данный момент возможно подключение следующих редакций баз:

  • GeoIP2-Anonymous-IP;
  • GeoIP2-City;
  • GeoIP2-ISP;
  • GeoIP2-ASN;
  • GeoLite2-ASN;
  • GeoLite2-City.

Текущая интеграция GeoIP поддерживает одновременное использование до 4 баз.

Скачивание баз GeoIP с MaxMind

Для подключения GeoIP и скачивания баз непосредственно с серверов MaxMind необходимо предварительно создать секрет, содержащий лицензионный ключ, например:

d8 k -n prod create secret generic geoip-license --from-literal=licenseKey='<MAXMIND_LICENSE_KEY>'

При настройке GeoIP для ClusterALBInstance секрет может быть размещен в любом неймспейсе, но рекомендуется разместить его в d8-alb.

Для объектов ALBInstance секрет должен располагаться строго в том же неймспейсе, что и объект ALBInstance.

После создания секрета необходимо указать его в объекте ClusterALBInstance или ALBInstance, например:

apiVersion: network.deckhouse.io/v1alpha1
kind: ALBInstance
metadata:
  name: main
  namespace: prod
spec:
  envoyLogLevel: Warning
  gatewayName: custom-gateway
  geoIP:
    licenseKeySecretRef:
      name: geoip-license

Скачивание баз GeoIP с локального зеркала

Для подключения GeoIP и скачивания баз с локального зеркала необходимо указать адрес зеркала в формате URL, например:

apiVersion: network.deckhouse.io/v1alpha1
kind: ALBInstance
metadata:
  name: main
  namespace: prod
spec:
  envoyLogLevel: Warning
  gatewayName: custom-gateway
  geoIP:
    maxmindMirror:
      url: "https://local.geoip:8443"

В качестве URL допускается указание адреса локального кеширующего сервера GeoIP в другом неймспейсе, например:

apiVersion: network.deckhouse.io/v1alpha1
kind: ALBInstance
metadata:
  name: main
  namespace: prod
spec:
  envoyLogLevel: Warning
  gatewayName: custom-gateway
  geoIP:
    maxmindMirror:
      url: "http://geoproxy-cluster.d8-alb.svc:8080/download"

Использование заголовков GeoIP

В результате настройки GeoIP в неймспейсе, в котором располагается ClusterALBInstance или ALBInstance, будет запущен сервер кеширования и обновления баз GeoIP, а поды Envoy Proxy будут поочередно перезапущены с добавлением функциональности скачивания баз GeoIP с локального сервера GeoIP.

Для добавления данных на основе GeoIP в HTTP-запросы необходимо указать имена HTTP-заголовков, которые будут содержать соответствующую информацию, например:

apiVersion: network.deckhouse.io/v1alpha1
kind: ALBInstance
metadata:
  name: main
  namespace: prod
spec:
  envoyLogLevel: Warning
  gatewayName: custom-gateway
  geoIP:
    headers:
      city: geoip_city
      country: geoip_country
    licenseKeySecretRef:
      name: geoip-license
    maxmindEditionIDs:
      - GeoLite2-City

Если GeoIP-заголовки не передаются на бэкенд, убедитесь, что запросы поступают с публичных IP-адресов.

Обновление баз GeoIP осуществляется раз в сутки как на кеширующем сервере, так и в каждом отдельном поде Envoy Proxy с использованием кеширующего сервера.

Настройка OpenTelemetry Tracing

Модуль alb поддерживает экспорт трассировок OpenTelemetry из Envoy-прокси.

Для включения экспорта укажите адрес целевого OpenTelemetry Collector в формате URL. Трассировки могут передаваться по OTLP/HTTP или OTLP/gRPC. При необходимости можно настроить подключение с использованием TLS.

При использовании TLS рекомендуется явно задать параметр SNI, если OpenTelemetry Collector находится за прокси или балансировщиком, который выбирает upstream на основе Server Name Indication.

Настройка TLS для OpenTelemetry tracing

Если данные OpenTelemetry tracing нужно отправлять по TLS, создайте Kubernetes Secret с CA-сертификатом и укажите его в spec.openTelemetry.tracing.tls.caSecretName.

Для ClusterALBInstance и шлюза DKP по умолчанию разместите Secret в неймспейсе d8-alb. Secret должен содержать ключ cacert.

apiVersion: v1
kind: Secret
metadata:
  name: otel-tracing-ca
  namespace: d8-alb
type: Opaque
stringData:
  cacert: |
    -----BEGIN CERTIFICATE-----
    ...
    -----END CERTIFICATE-----
---
apiVersion: network.deckhouse.io/v1alpha1
kind: ClusterALBInstance
metadata:
  name: proxy-gw
spec:
  gatewayName: proxy-gw
  openTelemetry:
    tracing:
      service:
        name: otel-collector
        namespace: monitoring
      port: 4318
      protocol: HTTP
      path: /v1/traces
      tls:
        sni: otel-collector.monitoring.svc.cluster.local
        caSecretName: otel-tracing-ca