Implementa una puerta de enlace de transferencia de TLS

En este documento, se muestra cómo implementar un recurso de puerta de enlace de Kubernetes configurado para la transferencia de TLS para habilitar el enrutamiento basado en la indicación de nombre del servidor (SNI) en Google Kubernetes Engine (GKE). Este enfoque conserva la encriptación de extremo a extremo y la TLS mutua (mTLS) entre los clientes y los Pods de backend, admite protocolos basados en TLS que no son HTTP y conserva las direcciones IP.

Este documento está dirigido a arquitectos de Cloud, especialistas en herramientas de redes y desarrolladores que diseñan, implementan y administran redes encriptadas para cargas de trabajo en contenedores. Para obtener más información sobre los roles comunes y las tareas de ejemplo, consulta Roles y tareas comunes del usuario de GKE.

Descripción general

Además de los balanceadores de cargas de aplicaciones HTTP y HTTPS de capa 7, el controlador de puerta de enlace de GKE admite balanceadores de cargas de red de proxy de capa 4 (balanceadores de cargas de proxy TCP) configurados con transferencia de TLS.

Con la transferencia de TLS, el balanceador de cargas no finaliza ni desencripta la sesión de TLS. En cambio, cuando un cliente inicia un protocolo de enlace TLS, el balanceador de cargas inspecciona el mensaje ClientHello sin encriptar para leer el nombre de host de la indicación del nombre del servidor (SNI). Según este nombre de host de SNI, el balanceador de cargas enruta el flujo de TCP encriptado sin procesar al Service de Kubernetes de backend adecuado, en el que los Pods de tu aplicación finalizan TLS directamente.

Cuando usas la transferencia de TLS con la API de Gateway, puedes hacer lo siguiente:

  • Mantén la encriptación de extremo a extremo y admite el cumplimiento de confianza cero: Mantén el tráfico completamente encriptado desde el cliente hasta el Pod de backend sin otorgar al balanceador de cargas acceso a claves privadas o datos de texto simple.
  • Usa la autenticación de TLS mutua (mTLS): Autentica a los clientes directamente en la capa de aplicación del backend.
  • Conserva las direcciones IPv4: Multiplexa varios servicios de TLS independientes en distintos dominios o subdominios con una sola dirección IP y un puerto de puerta de enlace (como 443).
  • Admite protocolos basados en TLS que no sean HTTP: Enruta el tráfico encriptado para cargas de trabajo con estado, bases de datos, servicios de gRPC personalizados o protocolos de propiedad que se ejecutan en TLS.

GatewayClasses compatibles

Las siguientes GatewayClasses de GKE admiten objetos de escucha de transferencia de TLS y recursos TLSRoute:

  • gke-l7-regional-external-managed
  • gke-l7-regional-external-managed-mc
  • gke-l7-rilb
  • gke-l7-rilb-mc
  • gke-l7-cross-regional-internal-managed-mc

Para obtener una comparación completa de las capacidades de GatewayClass, consulta Capacidades de GatewayClass.

Antes de comenzar

Antes de comenzar, asegúrate de haber realizado las siguientes tareas:

  • Habilita la API de Google Kubernetes Engine.
  • Habilitar la API de Google Kubernetes Engine
  • Para usar Google Cloud CLI en esta tarea, instala y, luego, inicializa la gcloud CLI. Si ya instalaste gcloud CLI, ejecuta el comando gcloud components update para obtener la versión más reciente. Es posible que las versiones anteriores de gcloud CLI no admitan la ejecución de los comandos de este documento.
  • Verifica que tengas un clúster de Autopilot o Standard existente que ejecute la versión 1.35 o posterior de GKE con la API de Gateway habilitada. Para crear un clúster, consulta Crea un clúster de Autopilot. Para habilitar la API de Gateway en un clúster existente, consulta Habilita la API de Gateway en tu clúster.
  • Verifica que tengas instalada la herramienta de línea de comandos de OpenSSL. Usa esta herramienta para generar certificados TLS autofirmados para las aplicaciones de ejemplo.

Requisitos del controlador de la puerta de enlace de GKE

  • La API de Gateway solo es compatible con clústeres nativos de VPC.
  • Si usas las GatewayClasses regionales o entre regiones, debes habilitar una subred de solo proxy.
  • El clúster debe tener el complemento HttpLoadBalancing habilitado.
  • Si usas Istio, debes actualizarlo a una de las siguientes versiones:
    • 1.15.2 o una versión posterior
    • 1.14.5 o una versión posterior
    • 1.13.9 o una versión posterior.
  • Si usas una VPC compartida, en el proyecto host, debes asignar el rol Compute Network User a la cuenta de servicio de GKE para el proyecto de servicio.

Restricciones y limitaciones

Cuando implementes puertas de enlace de transferencia de TLS y recursos TLSRoute, ten en cuenta las siguientes limitaciones:

  • Cuando configuras el parámetro protocol: TLS en un objeto de escucha, debes establecer de forma explícita el campo tls.mode en el valor Passthrough. GKE no admite el modo Terminate predeterminado para los objetos de escucha TLS.
  • En un objeto de escucha TLS, no configures el campo certificateRefs. La validación del certificado de cliente a nivel de puerta de enlace (el campo spec.tls.frontendValidation) no se aplica a los objetos de escucha TLS. Para usar mTLS, valida los certificados de cliente en tu backend.
  • Un objeto de escucha TLS puede compartir un puerto solo con otros objetos de escucha TLS. No puedes configurar objetos de escucha HTTP o HTTPS en el mismo puerto que un objeto de escucha TLS.
  • En el campo TLSRoute.spec.hostnames, debes especificar una lista de 1 a 1,024 nombres de host de SNI (nombre de host exacto o prefijo comodín, como *.example.com). Cada entrada no puede superar los 253 caracteres y no puede ser una dirección IP.
  • En el campo TLSRoute.spec.rules, puedes configurar, como máximo, una regla.
  • Cada regla admite exactamente una entrada backendRef. Los backends de proxy de capa 4 no admiten la división del tráfico ponderada en varios backends.
  • Las GatewayClasses de un solo clúster solo admiten backends de Service, y las GatewayClasses de varios clústeres solo admiten backends de ServiceImport.
  • En el campo TLSRoute.spec.rules.backendRefs, establece el campo port en un puerto declarado por el recurso Service o ServiceImport de destino, no en el puerto del contenedor.
  • El Service de Kubernetes de backend (incluidos los Services exportados como un ServiceImport) al que hace referencia un recurso TLSRoute debe usar el valor TCP para su protocolo de puerto.
  • No puedes adjuntar un recurso BackendTLSPolicy, Identity-Aware Proxy o una política de seguridad de Google Cloud Armor a un backend de TLSRoute porque el controlador rechaza las configuraciones de este tipo.
  • Cuando adjuntas un recurso GCPBackendPolicy a un Service o ServiceImport al que hace referencia un recurso TLSRoute, debes establecer el campo spec.protocol en el valor TCP (omitir el campo spec.protocol se establece de forma predeterminada en el valor HTTP, que se aplica solo a los backends de HTTPRoute). Un Service o ServiceImport puede tener una política HTTP y una política TCP adjuntas al mismo tiempo. Si varias políticas con el mismo valor spec.protocol se orientan al mismo Service o ServiceImport, la política más antigua tiene prioridad y las más nuevas no se adjuntan.
  • Un recurso GCPBackendPolicy con el campo spec.protocol establecido en TCP solo admite los siguientes campos en el campo spec.default (cuando se orienta a un recurso ServiceImport, puedes establecer los últimos tres campos por clúster, zona o región en el campo spec.default.scopes):

    • timeoutSec
    • connectionDraining
    • logging.enabled y logging.sampleRate
    • sessionAffinity.type (los valores válidos son CLIENT_IP o NONE)
    • capacityScalerPercent
    • balancingMode: CONNECTION
    • maxConnectionsPerEndpoint

    No puedes crear una política TCP que incluya otros campos ni una política HTTP que incluya campos solo de TCP (balancingMode: CONNECTION y maxConnectionsPerEndpoint). El servidor de la API de Kubernetes rechaza la política cuando se crea. Para obtener más información, consulta Configura recursos de puerta de enlace con políticas.

  • Si un recurso HTTPRoute y un recurso TLSRoute hacen referencia al mismo Service o ServiceImport, adjuntar un recurso HealthCheckPolicy a ese destino reemplaza las verificaciones de estado predeterminadas independientes y aplica la misma configuración de verificación de estado a los backends de ambas rutas. Para configurar las verificaciones de estado de forma independiente (como las verificaciones de estado de HTTP para los backends de HTTPRoute y las verificaciones de estado de SSL o TCP para los backends de TLSRoute), crea un Service independiente para cada ruta y adjunta un recurso HealthCheckPolicy a cada Service. Ambos Services pueden seleccionar los mismos Pods.

  • Las funciones de la capa 7 (como las reescrituras de URL, el enrutamiento basado en rutas de acceso y las transformaciones de encabezados HTTP) no se aplican a los balanceadores de cargas de proxy TCP de la capa 4.

Configura una subred de solo proxy

Una puerta de enlace regional requiere una subred de solo proxy (purpose=REGIONAL_MANAGED_PROXY) en cada región en la que la implementes. Una subred de solo proxy entrega todos los balanceadores de cargas regionales basados en Envoy en esa región. Si tu región aún no tiene una, consulta Configura una subred de solo proxy.

Reserva una dirección IP estática

Antes de implementar la puerta de enlace, reserva una dirección IP estática regional para que la dirección de la puerta de enlace no cambie y puedas resolver tus nombres de host de muestra en ella. Para obtener instrucciones sobre cómo crear una dirección IP estática, consulta Crea una puerta de enlace HTTP(S) regional externa.

Implementa una puerta de enlace con objetos de escucha de transferencia de TLS

La puerta de enlace de esta sección configura dos objetos de escucha TLS que comparten el puerto 443. Cada objeto de escucha coincide con un nombre de host de SNI diferente y reenvía las conexiones en modo de transferencia a los recursos TLSRoute adjuntos.

  1. Guarda el siguiente manifiesto como store-gateway.yaml:

    kind: Gateway
    apiVersion: gateway.networking.k8s.io/v1
    metadata:
      name: store-tls
    spec:
      gatewayClassName: gke-l7-regional-external-managed
      listeners:
      # Accept TLS connections for store.example.com without decrypting them.
      - name: store
        protocol: TLS
        port: 443
        hostname: "store.example.com"
        tls:
          mode: Passthrough
        allowedRoutes:
          kinds:
          - kind: TLSRoute
      # A second listener on the same port, selected by a different SNI name.
      - name: store-german
        protocol: TLS
        port: 443
        hostname: "store-de.example.com"
        tls:
          mode: Passthrough
        allowedRoutes:
          kinds:
          - kind: TLSRoute
      addresses:
      - type: NamedAddress
        value: IP_ADDRESS_NAME
    

    Reemplaza IP_ADDRESS_NAME por el nombre de la dirección IP estática que reservaste.

    Ten en cuenta que el bloque tls no tiene un campo certificateRefs. En el modo Passthrough, el certificado TLS reside en los Pods de backend, en lugar de en el balanceador de cargas.

  2. Aplica el manifiesto de Gateway:

    kubectl apply -f store-gateway.yaml
    
  3. Verifica que la puerta de enlace esté programada:

    kubectl get gateway store-tls
    

    El aprovisionamiento del balanceador de cargas tarda unos minutos. El resultado es similar a lo siguiente:

    NAME        CLASS                              ADDRESS         PROGRAMMED   AGE
    store-tls   gke-l7-regional-external-managed   35.118.32.224   True         53s
    

Usa una Gateway interna

Para mantener el tráfico dentro de tu red de VPC, cambia el valor del campo gatewayClassName a gke-l7-rilb y quita el campo addresses del manifiesto de la puerta de enlace. Luego, GKE crea un balanceador de cargas de red del proxy interno regional y asigna una dirección IP interna de la subred del clúster. Los pasos restantes de esta página no se modificaron. Envía tus solicitudes de prueba desde una instancia de Compute Engine en la misma red de VPC, ya que no se puede acceder a la dirección IP interna desde Internet.

Implementa aplicaciones de TLS de muestra

En esta sección, implementarás dos implementaciones de NGINX (store-v1 y store-german) que finalizan TLS en el puerto 8443. Cada Deployment entrega un certificado TLS diferente y, además, informa el nombre de host de SNI que recibió, lo que te permite verificar que el enrutamiento se haya realizado en función de la SNI.

  1. Genera un certificado TLS autofirmado y una clave privada para cada nombre de host:

    openssl req -x509 -newkey rsa:2048 -nodes -sha256 -days 365 \
        -keyout store.key -out store.crt \
        -subj '/CN=store.example.com' \
        -addext 'subjectAltName=DNS:store.example.com'
    openssl req -x509 -newkey rsa:2048 -nodes -sha256 -days 365 \
        -keyout store-de.key -out store-de.crt \
        -subj '/CN=store-de.example.com' \
        -addext 'subjectAltName=DNS:store-de.example.com'
    

    Usa certificados de tu autoridad certificadora en producción. Los certificados autofirmados mantienen este ejemplo autónomo.

  2. Ejecuta los siguientes comandos para almacenar cada certificado y clave en un Secret de Kubernetes:

    kubectl create secret tls store-cert \
        --cert=store.crt --key=store.key
    kubectl create secret tls store-de-cert \
        --cert=store-de.crt --key=store-de.key
    
  3. Guarda el siguiente manifiesto como store-tls-app.yaml:

    apiVersion: v1
    kind: ConfigMap
    metadata:
      name: store-nginx
    data:
      default.conf: |
        server {
          listen 8443 ssl;
          ssl_certificate     /etc/nginx/ssl/tls.crt;
          ssl_certificate_key /etc/nginx/ssl/tls.key;
          default_type text/plain;
          # Report which Pod answered and which SNI name it received.
          return 200 "backend: $hostname\nsni: $ssl_server_name\n";
        }
    ---
    apiVersion: apps/v1
    kind: Deployment
    metadata:
      name: store-v1
    spec:
      replicas: 2
      selector:
        matchLabels:
          app: store-v1
      template:
        metadata:
          labels:
            app: store-v1
        spec:
          containers:
          - name: nginx
            image: nginx:1.27
            ports:
            - containerPort: 8443
            volumeMounts:
            - name: config
              mountPath: /etc/nginx/conf.d
            - name: cert
              mountPath: /etc/nginx/ssl
              readOnly: true
          volumes:
          - name: config
            configMap:
              name: store-nginx
          - name: cert
            secret:
              secretName: store-cert
    ---
    apiVersion: v1
    kind: Service
    metadata:
      name: store-v1
    spec:
      selector:
        app: store-v1
      ports:
      - port: 443
        targetPort: 8443
    ---
    apiVersion: apps/v1
    kind: Deployment
    metadata:
      name: store-german
    spec:
      replicas: 2
      selector:
        matchLabels:
          app: store-german
      template:
        metadata:
          labels:
            app: store-german
        spec:
          containers:
          - name: nginx
            image: nginx:1.27
            ports:
            - containerPort: 8443
            volumeMounts:
            - name: config
              mountPath: /etc/nginx/conf.d
            - name: cert
              mountPath: /etc/nginx/ssl
              readOnly: true
          volumes:
          - name: config
            configMap:
              name: store-nginx
          - name: cert
            secret:
              secretName: store-de-cert
    ---
    apiVersion: v1
    kind: Service
    metadata:
      name: store-german
    spec:
      selector:
        app: store-german
      ports:
      - port: 443
        targetPort: 8443
    

    Los Services no necesitan un campo appProtocol. GKE reenvía el tráfico de TLSRoute al backend como TCP, por lo que el campo no tiene efecto.

  4. Aplica el manifiesto al clúster:

    kubectl apply -f store-tls-app.yaml
    
  5. Verifique que los pods se estén ejecutando:

    kubectl get pods -l 'app in (store-v1,store-german)'
    

    El resultado es similar a lo siguiente:

    NAME                            READY   STATUS    RESTARTS   AGE
    store-german-7d9f8c5b47-2xqkd   1/1     Running   0          41s
    store-german-7d9f8c5b47-h6tzn   1/1     Running   0          41s
    store-v1-6c4b9d8f65-kp8vr       1/1     Running   0          41s
    store-v1-6c4b9d8f65-wm2ls       1/1     Running   0          41s
    

Implementa recursos TLSRoute para el enrutamiento basado en SNI

Un recurso TLSRoute se conecta a un objeto de escucha de Gateway y enruta las conexiones que coinciden con sus nombres de host a un solo Service de backend.

  1. Guarda el siguiente manifiesto como store-tls-routes.yaml:

    kind: TLSRoute
    apiVersion: gateway.networking.k8s.io/v1
    metadata:
      name: store
    spec:
      parentRefs:
      - kind: Gateway
        name: store-tls
        sectionName: store
      hostnames:
      - "store.example.com"
      rules:
      - backendRefs:
        - name: store-v1
          port: 443
    ---
    kind: TLSRoute
    apiVersion: gateway.networking.k8s.io/v1
    metadata:
      name: store-german
    spec:
      parentRefs:
      - kind: Gateway
        name: store-tls
        sectionName: store-german
      hostnames:
      - "store-de.example.com"
      rules:
      - backendRefs:
        - name: store-german
          port: 443
    

    El campo sectionName selecciona el objeto de escucha de destino en la puerta de enlace. El campo port especifica el puerto del Service (443), no el puerto del contenedor.

  2. Aplica el manifiesto de TLSRoute:

    kubectl apply -f store-tls-routes.yaml
    
  3. Verifica que el controlador de Gateway haya aceptado la ruta:

    kubectl get tlsroute store -o yaml
    

    El campo status es similar al siguiente:

    status:
      parents:
      - controllerName: networking.gke.io/gateway
        parentRef:
          name: store-tls
          sectionName: store
        conditions:
        - type: ResolvedRefs
          status: "True"
          reason: ResolvedRefs
        - type: Accepted
          status: "True"
          reason: Accepted
        - type: Reconciled
          status: "True"
          reason: ReconciliationSucceeded
    

    La condición Reconciled es una condición de estado específica de GKE que informa si el controlador de Gateway creó los recursos Google Cloud subyacentes.

  4. Verifica que el objeto de escucha de la puerta de enlace haya aceptado la ruta:

    kubectl get gateway store-tls -o yaml
    

    Cada entrada en el campo status.listeners es similar a la siguiente:

    - name: store
      supportedKinds:
      - group: gateway.networking.k8s.io
        kind: TLSRoute
      attachedRoutes: 1
      conditions:
      - type: ResolvedRefs
        status: "True"
        reason: ResolvedRefs
      - type: Accepted
        status: "True"
        reason: Accepted
      - type: Programmed
        status: "True"
        reason: Programmed
    

Verifica el enrutamiento del tráfico

GKE verifica el estado de un backend de transferencia de TLS completando un protocolo de enlace TLS con él. Es posible que los Pods tarden unos minutos en pasar la verificación de estado inicial.

  1. Recupera la dirección IP de la puerta de enlace:

    kubectl get gateway store-tls -o jsonpath='{.status.addresses[0].value}'
    
  2. Envía una solicitud a cada nombre de host y reemplaza GATEWAY_IP por la dirección IP del paso anterior:

    curl --resolve store.example.com:443:GATEWAY_IP \
        --cacert store.crt https://store.example.com
    curl --resolve store-de.example.com:443:GATEWAY_IP \
        --cacert store-de.crt https://store-de.example.com
    

    Cada respuesta nombra el Pod que respondió y repite el nombre de host de SNI que lo alcanzó:

    backend: store-v1-6c4b9d8f65-kp8vr
    sni: store.example.com
    backend: store-german-7d9f8c5b47-2xqkd
    sni: store-de.example.com
    

    Debido a que cada solicitud usó un archivo de autoridad certificadora diferente y ambas se realizaron correctamente, cada backend entregó su propio certificado. El balanceador de cargas reenvió la conexión encriptada sin finalizarla.

  3. Confirma que el enrutamiento se produce durante el protocolo de enlace TLS, antes de que el cliente envíe cualquier solicitud HTTP:

    openssl s_client -connect GATEWAY_IP:443 \
        -servername store-de.example.com </dev/null 2>/dev/null \
        | openssl x509 -noout -subject
    

    En el resultado, se muestra el certificado del backend store-german:

    subject=CN=store-de.example.com
    

    Cambiar solo el valor de la marca -servername modifica el certificado que se devuelve, lo que confirma que el balanceador de cargas seleccionó el backend solo en función de la SNI.

  4. Envía una solicitud con un nombre de host de SNI que no coincida con ningún objeto de escucha:

    curl --resolve other.example.com:443:GATEWAY_IP \
        https://other.example.com
    

    La conexión se cierra porque ningún objeto de escucha en el puerto 443 coincide con el nombre de host de SNI other.example.com.

Configura la capacidad de conexión del backend

Para los Services de GKE a los que hacen referencia los recursos de TLSRoute, el controlador de Gateway de GKE configura un servicio de backend de TCP con el modo de balanceo CONNECTION y establece el valor predeterminado del campo maxConnectionsPerEndpoint en 100,000,000 (1e8).

Debido a que el controlador de Gateway no puede determinar de forma automática el límite de conexiones simultáneas de un contenedor, puedes usar un recurso GCPBackendPolicy para anular el valor predeterminado del campo maxConnectionsPerEndpoint (de 1 a 1,000,000,000). Para determinar el límite de conexiones óptimo para tus Pods de backend, evalúa lo siguiente:

  • Límites de software: Verifica la configuración del servidor o de la aplicación, como la directiva MaxRequestWorkers de Apache, la configuración de worker_processes * worker_connections de NGINX, el atributo maxConnections de Tomcat o los límites del grupo de conexiones de la base de datos.
  • Pruebas de carga: Aumenta de forma gradual las conexiones simultáneas en un Pod aislado mientras supervisas la CPU, la memoria, la latencia y los límites de sockets o descriptores de archivos.

Aplica una GCPBackendPolicy personalizada

Para anular el valor predeterminado del campo maxConnectionsPerEndpoint en un Service de backend de TLSRoute, adjunta un recurso GCPBackendPolicy con el campo spec.protocol establecido en TCP y el campo balancingMode establecido en CONNECTION:

  1. Guarda el siguiente manifiesto como backend-policy.yaml:

    apiVersion: networking.gke.io/v1
    kind: GCPBackendPolicy
    metadata:
      name: store-v1-backend-policy
    spec:
      protocol: TCP
      default:
        balancingMode: CONNECTION
        maxConnectionsPerEndpoint: 1000
      targetRef:
        group: ""
        kind: Service
        name: store-v1
    
  2. Aplica la política:

    kubectl apply -f backend-policy.yaml
    

Para obtener más información sobre cómo configurar las políticas de backend, consulta Configura los recursos de Gateway con políticas.

Configura verificaciones de estado para la transferencia de TLS

De forma predeterminada, para los servicios de backend asociados con los recursos de TLSRoute de transferencia de TLS, el controlador de Gateway de GKE aprovisiona automáticamente una verificación de estado del tipo SSL.

Controla la ausencia de extensiones de SNI de los agentes de sondeo

Cuando configures verificaciones de estado para backends de transferencia de TLS, debes tener en cuenta cómo interactúan los sistemas de sondeo de verificación de estado de Google Cloud con los extremos de TLS.

Si tus aplicaciones de backend requieren un nombre de host de SNI válido para completar un protocolo de enlace TLS, las verificaciones de estado de SSL predeterminadas fallarán. Para resolver este problema, usa uno de los siguientes enfoques:

  • Configura certificados de resguardo: Configura tu servidor de backend o Pod para que entregue un certificado TLS de resguardo predeterminado cuando llegue una conexión TLS sin una extensión de SNI.
  • Usa verificaciones de estado de TCP con HealthCheckPolicy: Adjunta un recurso HealthCheckPolicy (con el campo config.type configurado como TCP) a tu Service para verificar la conectividad del puerto TCP sin procesar y evitar el protocolo de enlace TLS.

Aplica una HealthCheckPolicy personalizada

Para configurar parámetros de verificación de estado personalizados o cambiar a la verificación de estado de TCP, usa un recurso HealthCheckPolicy:

  1. Guarda el siguiente manifiesto como health-check-policy.yaml:

    apiVersion: networking.gke.io/v1
    kind: HealthCheckPolicy
    metadata:
      name: store-health-check
    spec:
      default:
        checkIntervalSec: 10
        timeoutSec: 5
        healthyThreshold: 2
        unhealthyThreshold: 3
        config:
          type: TCP
          tcpHealthCheck:
            port: 8443
      targetRef:
        group: ""
        kind: Service
        name: store-service
    
  2. Aplica la política:

    kubectl apply -f health-check-policy.yaml
    

Para obtener más información sobre cómo configurar las verificaciones de estado, consulta Configura los recursos de la puerta de enlace con políticas.

Configuración avanzada

En esta sección, se describen los patrones de enrutamiento avanzados, las configuraciones multiusuario y las implementaciones de varios clústeres compatibles con las puertas de enlace de transferencia de TLS y los recursos TLSRoute.

Coincidencia de nombre de host con comodín

Los recursos TLSRoute admiten la coincidencia de prefijos comodín para los nombres de host y siguen reglas de prioridad deterministas cuando varias rutas coinciden con el mismo tráfico entrante.

Guarda el siguiente manifiesto para definir una TLSRoute comodín:

apiVersion: gateway.networking.k8s.io/v1
kind: TLSRoute
metadata:
  name: wildcard-tls-route
spec:
  parentRefs:
  - name: store-tls
    sectionName: store
  hostnames:
  - "*.example.com"
  rules:
  - backendRefs:
    - name: store-v1
      port: 443

Reglas de precedencia y resolución de conflictos

Cuando varios recursos TLSRoute se conectan al mismo objeto de escucha de Gateway y reclaman nombres de host superpuestos o idénticos, el controlador de Gateway de GKE resuelve los conflictos con la misma especificidad de nombre de host y las mismas reglas de marca de tiempo de creación que otras rutas de Gateway:

  • Las coincidencias exactas de nombres de host (como store.example.com) tienen prioridad sobre las coincidencias con comodines (como *.example.com), y las coincidencias con comodines más largas tienen prioridad sobre las coincidencias con comodines más amplias (como *.com).
  • Si dos o más recursos TLSRoute declaran exactamente el mismo nombre de host, la ruta con la marca de tiempo de creación más antigua (metadata.creationTimestamp) tiene prioridad. Si las marcas de tiempo de creación coinciden, el identificador <namespace>/<name> lexicográficamente más pequeño desempata. El controlador de Gateway no acepta rutas en conflicto, que informan una condición Accepted: False con el motivo Conflicted.

Para obtener más información sobre la prioridad de rutas, consulta Combinación, prioridad y validación de rutas.

Enrutamiento entre espacios de nombres con ReferenceGrant

En entornos multiusuario, un equipo de plataforma centralizado puede administrar la puerta de enlace en un espacio de nombres de infraestructura (como gateway-infra), mientras que los equipos de aplicaciones administran los recursos TLSRoute y Service en los espacios de nombres de los desarrolladores (como store-ns).

  1. En el objeto de escucha de la puerta de enlace, permite rutas de todos los espacios de nombres (o de los espacios de nombres seleccionados):

    apiVersion: gateway.networking.k8s.io/v1
    kind: Gateway
    metadata:
      name: shared-tls-gateway
      namespace: gateway-infra
    spec:
      gatewayClassName: gke-l7-regional-external-managed
      listeners:
      - name: tls-passthrough
        protocol: TLS
        port: 443
        tls:
          mode: Passthrough
        allowedRoutes:
          namespaces:
            from: All
          kinds:
          - kind: TLSRoute
    
  2. En el espacio de nombres de la aplicación (store-ns), crea un recurso ReferenceGrant que permita que la puerta de enlace en el espacio de nombres gateway-infra haga referencia al recurso TLSRoute o Service:

    apiVersion: gateway.networking.k8s.io/v1beta1
    kind: ReferenceGrant
    metadata:
      name: allow-gateway-infra
      namespace: store-ns
    spec:
      from:
      - group: gateway.networking.k8s.io
        kind: Gateway
        namespace: gateway-infra
      to:
      - group: ""
        kind: Service
    
  3. En el espacio de nombres de la aplicación (store-ns), crea el recurso TLSRoute que hace referencia a la puerta de enlace compartida:

    apiVersion: gateway.networking.k8s.io/v1
    kind: TLSRoute
    metadata:
      name: store-tls-route
      namespace: store-ns
    spec:
      parentRefs:
      - name: shared-tls-gateway
        namespace: gateway-infra
        sectionName: tls-passthrough
      hostnames:
      - "store.example.com"
      rules:
      - backendRefs:
        - name: store-service
          port: 443
    

Puerta de enlace de transferencia de TLS de varios clústeres

Puedes implementar puertas de enlace de varios clústeres con transferencia de TLS en varios clústeres de GKE de una flota:

  1. Usa una GatewayClass de varios clústeres compatible (gke-l7-regional-external-managed-mc, gke-l7-rilb-mc o gke-l7-cross-regional-internal-managed-mc).
  2. Exporta tu Service de backend a toda la flota con un recurso ServiceExport.
  3. En tu recurso TLSRoute, haz referencia al backend de varios clústeres con un recurso ServiceImport:

    apiVersion: gateway.networking.k8s.io/v1
    kind: TLSRoute
    metadata:
      name: mc-store-tls-route
    spec:
      parentRefs:
      - name: mc-tls-gateway
        sectionName: tls-passthrough
      hostnames:
      - "store.example.com"
      rules:
      - backendRefs:
        - group: net.gke.io
          kind: ServiceImport
          name: store-service
          port: 443
    

Varias direcciones IP en Gateways de varios clústeres

Cuando implementas Gateways de varios clústeres interregionales (como cuando usas la GatewayClass gke-l7-cross-regional-internal-managed-mc), puedes definir varias direcciones IP en el campo spec.addresses para exponer una VIP interna en diferentes regiones.

Cuando configuras varias direcciones IP en una sola puerta de enlace, el controlador de puerta de enlace de GKE traduce cada dirección IP en una regla de reenvío independiente. Al mismo tiempo, el controlador hace referencia a un proxy de destino compartido y vuelve a usar la misma configuración de enrutamiento subyacente. El controlador no multiplica los recursos de TLSRoute subyacentes por la cantidad de direcciones IP, lo que ayuda a evitar la duplicación de rutas y el agotamiento de la cuota.

En el siguiente ejemplo, se muestra una puerta de enlace de varios clústeres configurada con direcciones IP efímeras en dos regiones:

kind: Gateway
apiVersion: gateway.networking.k8s.io/v1
metadata:
  name: internal-cross-region-tls-gateway
spec:
  gatewayClassName: gke-l7-cross-regional-internal-managed-mc
  addresses:
  - type: networking.gke.io/ephemeral-ipv4-address/us-west1
    value: "us-west1"
  - type: networking.gke.io/ephemeral-ipv4-address/us-east1
    value: "us-east1"
  listeners:
  - name: tls-passthrough
    protocol: TLS
    port: 443
    tls:
      mode: Passthrough
    allowedRoutes:
      kinds:
      - kind: TLSRoute

Para obtener más información sobre cómo implementar Gateways internas de varios clústeres, consulta Implementa una Gateway interna de varios clústeres.

Unión de conexiones HTTP

Según RFC 7540 (Sección 9.1.1), los navegadores web y los clientes HTTP/2 pueden volver a usar una conexión TLS establecida para varias solicitudes si se cumplen las dos condiciones siguientes:

  • Los nombres de host de destino se resuelven en la misma dirección IP.
  • El certificado TLS presentado por el servidor es autoritativo para ambos nombres de host. Por ejemplo, un certificado puede abarcar varios nombres de host cuando usas certificados comodín, como *.example.com, o nombres alternativos de sujeto (SAN) de varios dominios.

Debido a que un balanceador de cargas de proxy TCP de capa 4 no inspecciona los encabezados de la solicitud HTTP después del protocolo de enlace TLS inicial, el balanceador de cargas reenvía las solicitudes unidas a través de la conexión existente al Pod de backend que coincidió inicialmente.

Para evitar problemas de fusión de conexiones, haz lo siguiente:

  • Usa certificados TLS distintos que no se superpongan: No compartas certificados comodín ni identidades de SAN comunes en diferentes servicios de backend multiplexados detrás de la misma dirección IP de la puerta de enlace.
  • Retorna HTTP 421 Misdirected Request: Configura tus servidores HTTPS de backend para que verifiquen el encabezado HTTP :authority (o Host). Si el host solicitado no coincide con el dominio esperado del servidor, devuelve un código de estado HTTP 421 Misdirected Request, que solicita al cliente que abra una conexión nueva.
  • Habilita el marco ORIGIN de HTTP/2: Adopta la compatibilidad con el marco ORIGIN de RFC 8336 en tus servidores de origen y declara de forma explícita qué nombres de host son válidos para la reutilización de conexiones.

Realiza una limpieza

Para evitar que se apliquen cargos a tu cuenta de Google Cloud por los recursos que usaste en esta página, bórralos:

  1. Borra los recursos TLSRoute:

    kubectl delete tlsroute store store-german
    
  2. Borra el recurso de Gateway:

    kubectl delete gateway store-tls
    
  3. Borra los recursos de Deployment, Service y Secret de ejemplo:

    kubectl delete -f store-tls-app.yaml
    kubectl delete secret store-cert store-de-cert
    

¿Qué sigue?