Protege una puerta de enlace


En esta página, se explica cómo puedes proteger una puerta de enlace mediante varias características de seguridad:

  • Políticas de SSL para garantizar que la puerta de enlace use los protocolos y algoritmos seguros requeridos

  • Certificados para proteger el tráfico de cliente a puerta de enlace y de puerta de enlace a backends con TLS

  • Política de seguridad de Google Cloud Armor para proteger los servicios de los ataques de DSD

  • Identity-Aware Proxy (IAP) para proporcionar una capa de autenticación y autorización antes de permitir el acceso a un servicio

Para obtener más información sobre la seguridad de las puertas de enlace, consulta Seguridad de las puertas de enlace.

Antes de comenzar

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

  • Habilita la API de Kubernetes Engine de Google.
  • Habilitar la API de Kubernetes Engine de Google
  • Si deseas usar Google Cloud CLI para esta tarea, instala y, luego, inicializa gcloud CLI. Si ya instalaste gcloud CLI, ejecuta gcloud components update para obtener la versión más reciente.

Requisitos del controlador de la puerta de enlace de GKE

  • Para Standard, la versión 1.24 de GKE o una posterior.
  • Para Autopilot, versión 1.26 de GKE o posterior.
  • Versión 407.0.0 o posterior de Google Cloud CLI.
  • La API de la puerta de enlace solo es compatible con clústeres nativos de VPC.
  • Si usas las GatewayClasses internas, 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

Además de las restricciones y limitaciones del GKE Gateway Controller, se aplican específicamente las siguientes limitaciones a la seguridad de la puerta de enlace:

  • No puedes usar la anotación networking.gke.io/certmap con un tls.certificateRefs en el mismo recurso de puerta de enlace. Si haces referencia a CertificateMap en una puerta de enlace, GKE lo considerará como un error.
  • El Administrador de certificados admite certificados autoadministrados y administrados por Google, pero no es compatible con las puertas de enlace regionales.
  • Cuando usas certificados SSL administrados por Google, debes crear los certificados SSL fuera de GKE antes de adjuntarlos a tu puerta de enlace.

  • Los certificados SSL administrados por Google no son compatibles con las puertas de enlace regionales. Para obtener más información sobre los métodos de finalización de TLS para cada GatewayClass, consulta Compatibilidad con TLS de GatewayClass.

  • El controlador de Gateway no admite el recurso ManagedCertificate.

  • La API de Gateway no admite la anotación networking.gke.io/managed-certificates.

  • El campo appProtocol en la configuración del Service solo acepta letras mayúsculas para el valor del protocolo (HTTP, HTTPS o HTTP2). El uso de letras minúsculas da como resultado el uso de HTTP como el protocolo con los backends.

Protege una puerta de enlace mediante un Secret de Kubernetes

En este ejemplo, debes configurar una puerta de enlace mediante un Secret de Kubernetes.

Almacena un certificado en un Secret de Kubernetes

Puedes usar un certificado emitido y validado por la autoridad certificadora (CA) o crear un certificado autofirmado. En los siguientes pasos, se usa un certificado autofirmado.

  1. Crea una clave privada:

    openssl genrsa -out PRIVATE_KEY_FILE 2048
    

    Reemplaza PRIVATE_KEY_FILE por el nombre de tu archivo de claves privadas, como private-key.pem. Para obtener más información, consulta Selecciona o crea una clave privada.

  2. Crea un archivo de configuración de OpenSSL:

    cat <<EOF >CONFIG_FILE
    [req]
    default_bits              = 2048
    req_extensions            = extension_requirements
    distinguished_name        = dn_requirements
    prompt                    = no
    
    [extension_requirements]
    basicConstraints          = CA:FALSE
    keyUsage                  = nonRepudiation, digitalSignature, keyEncipherment
    subjectAltName            = @sans_list
    
    [dn_requirements]
    0.organizationName        = example
    commonName                = store.example.com
    
    [sans_list]
    DNS.1                     = store.example.com
    EOF
    

    Reemplaza CONFIG_FILE con el nombre del archivo de configuración nuevo, como config-file.cnf.

  3. Crea un archivo de solicitud de firma de certificado (CSR):

    openssl req -new -key PRIVATE_KEY_FILE \
        -out CSR_FILE \
        -config CONFIG_FILE
    

    Reemplaza CSR_FILE con el nombre del archivo CSR nuevo, como cert.pem. Para obtener más información, consulta Crea una CSR.

  4. Firma la CSR:

    openssl x509 -req \
        -signkey PRIVATE_KEY_FILE \
        -in CSR_FILE \
        -out CERTIFICATE_FILE \
        -extfile CONFIG_FILE \
        -extensions extension_requirements \
        -days 30
    

    Reemplaza CERTIFICATE_FILE por la ruta de acceso y el nombre del archivo que genera el comando, como cert-file.pem. Para obtener más información, consulta Firma la CSR.

  5. Crea un Secret TLS de Kubernetes mediante la clave y el archivo de certificado que creaste:

    kubectl create secret tls store-example-com \
        --cert=CERTIFICATE_FILE \
        --key=PRIVATE_KEY_FILE
    

    GKE guarda el certificado y la clave como un recurso de Kubernetes que puedes adjuntar a tu puerta de enlace.

Crea una puerta de enlace y una HTTPRoute

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

    kind: Gateway
    apiVersion: gateway.networking.k8s.io/v1beta1
    metadata:
      name: external-http
    spec:
      gatewayClassName: gke-l7-global-external-managed
      listeners:
      - name: https
        protocol: HTTPS
        port: 443
        tls:
          mode: Terminate
          certificateRefs:
          - name: store-example-com
    

    En este manifiesto, se describe una puerta de enlace con las siguientes propiedades:

    • gatewayClassName: gke-l7-global-external-managed: implementa un balanceador de cargas de aplicaciones externo global.
    • protocol: HTTPS y port: 443: obligatorios para habilitar TLS.
    • tls: hace referencia al Secret de Kubernetes creado en el paso anterior.
  2. Aplica el manifiesto al clúster:

    kubectl apply -f external-gateway.yaml
    
  3. Guarda el siguiente manifiesto como store-external-route.yaml:

    kind: HTTPRoute
    apiVersion: gateway.networking.k8s.io/v1beta1
    metadata:
      name: store-external
      labels:
        gateway: external-http
    spec:
      parentRefs:
      - name: external-http
      hostnames:
      - "store.example.com"
      rules:
      - backendRefs:
        - name: store-v1
          port: 8080
    

    En este manifiesto, se describe una HTTPRoute que coincide con el tráfico para store.example.com y lo envía al Service store-v1.

  4. Aplica el manifiesto al clúster:

    kubectl apply -f store-external-route.yaml
    

Verifica la puerta de enlace

Envía una solicitud a través de Internet para verificar que la puerta de enlace funcione.

  1. Obtén la dirección IP de la puerta de enlace:

    kubectl get gateway external-http -o=jsonpath="{.status.addresses[0].value}"
    

    El resultado es similar a este:

    203.0.113.12
    

    Este resultado es una dirección IP pública, lo que significa que cualquier cliente con acceso a Internet puede conectarse a ella.

  2. Accede al dominio de la puerta de enlace mediante curl:

    curl https://store.example.com --resolve store.example.com:443:GATEWAY_IP_ADDRESS --cacert CERTIFICATE_FILE -v
    

    Reemplaza lo siguiente:

    • GATEWAY_IP_ADDRESS es la dirección IP del balanceador de cargas de puerta de enlace.
    • CERTIFICATE_FILE: El archivo de certificado que generaste. Debes guardar este archivo en la máquina que usas para conectarte a la puerta de enlace. Se requiere el certificado para autenticar la puerta de enlace porque esta usa un certificado autofirmado.

    La opción --resolve resuelve el nombre de dominio a la dirección IP de la puerta de enlace, que es necesaria porque el DNS no está configurado para este dominio

    El resultado es similar a este:

    ...
    * TLSv1.2 (OUT), TLS handshake, Client hello (1):
    * TLSv1.2 (IN), TLS handshake, Server hello (2):
    * TLSv1.2 (IN), TLS handshake, Certificate (11):
    * TLSv1.2 (IN), TLS handshake, Server key exchange (12):
    * TLSv1.2 (IN), TLS handshake, Server finished (14):
    * TLSv1.2 (OUT), TLS handshake, Client key exchange (16):
    * TLSv1.2 (OUT), TLS change cipher, Change cipher spec (1):
    * TLSv1.2 (OUT), TLS handshake, Finished (20):
    * TLSv1.2 (IN), TLS change cipher, Change cipher spec (1):
    * TLSv1.2 (IN), TLS handshake, Finished (20):
    * SSL connection using TLSv1.2 / ECDHE-RSA-CHACHA20-POLY1305
    * ALPN, server accepted to use h2
    * Server certificate:
    *  subject: O=example; CN=store.example.com
    *  start date: Apr 19 15:54:50 2021 GMT
    *  expire date: Apr 19 15:54:50 2022 GMT
    *  common name: store.example.com (matched)
    *  issuer: O=example; CN=store.example.com
    *  SSL certificate verify ok.
    ...
    {
      "cluster_name": "gw",
      "host_header": "store.example.com",
      "metadata": "store-v1",
      "node_name": "gke-gw-default-pool-51ccbf30-yya8.c.agmsb-k8s.internal",
      "pod_name": "store-v1-84b47c7f58-tj5mn",
      "pod_name_emoji": "😍",
      "project_id": "agmsb-k8s",
      "timestamp": "2021-04-19T16:30:08"
      # Several lines of output omitted here.
    }
    

    En esta salida, se incluye un protocolo de enlace TLS exitoso seguido de una respuesta de la aplicación. La conexión TLS finaliza en la puerta de enlace y la aplicación responde al cliente de forma segura.

Protege una puerta de enlace mediante un certificado SSL

En este ejemplo, configurarás una puerta de enlace con un certificado SSL administrado por Google.

Crear un certificado SSL

  1. Crea un recurso SslCertificate global administrado por Google:

    gcloud compute ssl-certificates create store-example-com \
        --domains=store.example.com \
        --global
    

Crea una puerta de enlace y una HTTPRoute

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

    kind: Gateway
    apiVersion: gateway.networking.k8s.io/v1beta1
    metadata:
      name: external-http
    spec:
      gatewayClassName: gke-l7-global-external-managed
      listeners:
      - name: https
        protocol: HTTPS
        port: 443
        tls:
          mode: Terminate
          options:
            networking.gke.io/pre-shared-certs: store-example-com
    

    En este manifiesto, se describe una puerta de enlace con las siguientes propiedades:

    • gatewayClassName: gke-l7-global-external-managed: implementa un balanceador de cargas de aplicaciones externo global.
    • protocol:HTTPS y port:443: obligatorios para habilitar TLS.
    • tls.mode:Terminate: finaliza TLS con tu certificado SSL.
  2. Aplica el manifiesto al clúster:

    kubectl apply -f external-gateway.yaml
    
  3. Guarda el siguiente manifiesto de HTTPRoute como store-external-route.yaml:

    kind: HTTPRoute
    apiVersion: gateway.networking.k8s.io/v1beta1
    metadata:
      name: store-external
      labels:
        gateway: external-http
    spec:
      parentRefs:
      - name: external-http
      hostnames:
      - "store.example.com"
      rules:
      - backendRefs:
        - name: store-v1
          port: 8080
    
  4. Implementa la HTTPRoute en tu clúster:

    kubectl apply -f store-external-route.yaml
    

    GKE puede tardar varios minutos en implementar la puerta de enlace.

Verifica la puerta de enlace

  1. Obtén la dirección IP de la puerta de enlace:

    kubectl get gateway external-http -o=jsonpath="{.status.addresses[0].value}"
    

    El resultado es similar a este:

    203.0.113.12
    

    Este resultado es una dirección IP pública, lo que significa que cualquier cliente con acceso a Internet puede conectarse a ella.

  2. Actualiza un registro A o AAAA para dirigir el dominio a la dirección IP de la puerta de enlace.

    Este paso solo es necesario si configuras un certificado SSL administrado por Google. Si configuras un certificado autoadministrado, puedes omitir este paso.

    Después de que se actualizan los registros DNS, el balanceador de cargas puede tardar hasta 10 minutos en comenzar a usar el certificado administrado por Google.

  3. Envía una solicitud a través de Internet con curl para verificar que la puerta de enlace funcione:

    curl https://store.example.com -v
    

    El resultado es similar a este:

    ...
    * TLSv1.2 (OUT), TLS handshake, Client hello (1):
    * TLSv1.2 (IN), TLS handshake, Server hello (2):
    * TLSv1.2 (IN), TLS handshake, Certificate (11):
    * TLSv1.2 (IN), TLS handshake, Server key exchange (12):
    * TLSv1.2 (IN), TLS handshake, Server finished (14):
    * TLSv1.2 (OUT), TLS handshake, Client key exchange (16):
    * TLSv1.2 (OUT), TLS change cipher, Change cipher spec (1):
    * TLSv1.2 (OUT), TLS handshake, Finished (20):
    * TLSv1.2 (IN), TLS change cipher, Change cipher spec (1):
    * TLSv1.2 (IN), TLS handshake, Finished (20):
    * SSL connection using TLSv1.2 / ECDHE-RSA-CHACHA20-POLY1305
    * ALPN, server accepted to use h2
    * Server certificate:
    *  subject: O=example; CN=store.example.com
    *  start date: Apr 19 15:54:50 2021 GMT
    *  expire date: Apr 19 15:54:50 2022 GMT
    *  common name: store.example.com (matched)
    *  issuer: O=example; CN=store.example.com
    *  SSL certificate verify ok.
    ...
    {
      "cluster_name": "gw",
      "host_header": "store.example.com",
      "metadata": "store-v1",
      "node_name": "gke-gw-default-pool-51ccbf30-yya8.c.agmsb-k8s.internal",
      "pod_name": "store-v1-84b47c7f58-tj5mn",
      "pod_name_emoji": "😍",
      "project_id": "agmsb-k8s",
      "timestamp": "2021-04-19T16:30:08",
      "zone": "us-west1-a"
    }
    

    Este resultado incluye un protocolo de enlace TLS exitoso y una respuesta de la aplicación. La TLS se finaliza correctamente en la puerta de enlace y la aplicación responde al cliente de forma segura.

Protege una puerta de enlace con Certificate Manager

En este ejemplo, se configura una puerta de enlace con el Administrador de certificados.

Crea una CertificateMap

  1. Crea una CertificateMap.

    gcloud certificate-manager maps create store-example-com-map
    
  2. Carga la clave y el certificado autoadministrado en un Certificate:

    gcloud certificate-manager certificates create store-example-com-cert \
        --certificate-file="cert.pem" \
        --private-key-file="PRIVATE_KEY_FILE"
    
  3. Crea una CertificateMapEntry que asigne el certificado a CertificateMap:

    gcloud certificate-manager maps entries create store-example-com-map-entry \
        --map=store-example-com-map \
        --hostname=store.example.com \
        --certificates=store-example-com-cert
    

Crea una puerta de enlace y una HTTPRoute

  1. Guarda el siguiente manifiesto como cert-map-gateway.yaml:

    kind: Gateway
    apiVersion: gateway.networking.k8s.io/v1beta1
    metadata:
      name: external-http
      annotations:
        networking.gke.io/certmap: store-example-com-map
    spec:
      gatewayClassName: gke-l7-global-external-managed
      listeners:
      - name: https
        protocol: HTTPS
        port: 443
    

    En este manifiesto, se describe una puerta de enlace con las siguientes propiedades:

    • gatewayClassName: gke-l7-global-external-managed: implementa un balanceador de cargas de aplicaciones externo global.
    • protocol: HTTPS y port: 443: obligatorios para habilitar TLS.

    No hay sección TLS porque TLS se configura con el Administrador de certificados mediante la anotación networking.gke.io/certmap.

  2. Aplica el manifiesto al clúster:

    kubectl apply -f cert-map-gateway.yaml
    

    GKE puede tardar varios minutos en implementar la puerta de enlace.

  3. Guarda el siguiente manifiesto como cert-map-http-route.yaml:

    apiVersion: gateway.networking.k8s.io/v1beta1
    kind: HTTPRoute
    metadata:
      name: foo
      namespace: default
    spec:
      parentRefs:
      - name: external-http
      hostnames:
      - foo.example.com
      rules:
      - matches:
        - path:
            value: /
        backendRefs:
        - name: foo-v1
          port: 8080
    
  4. Aplica el manifiesto al clúster:

    kubectl apply -f cert-map-http-route.yaml
    

Verifica la puerta de enlace

  1. Obtén la dirección IP de la puerta de enlace:

    kubectl get gateway external-http -o=jsonpath="{.status.addresses[0].value}"
    

    El resultado es similar a este:

    203.0.113.12
    

    Este resultado es una dirección IP pública, lo que significa que cualquier cliente con acceso a Internet puede conectarse a ella.

  2. Actualiza un registro A o AAAA para dirigir el dominio a la dirección IP de la puerta de enlace.

    Este paso solo es necesario si configuras un certificado SSL administrado por Google. Si configuras un certificado autoadministrado, puedes omitir este paso.

    Después de que se actualizan los registros DNS, el balanceador de cargas puede tardar hasta 10 minutos en comenzar a usar el certificado administrado por Google.

  3. Accede al dominio de la puerta de enlace mediante curl:

    curl https://store.example.com -v
    

    El resultado es similar a este:

    ...
    * TLSv1.2 (OUT), TLS handshake, Client hello (1):
    * TLSv1.2 (IN), TLS handshake, Server hello (2):
    * TLSv1.2 (IN), TLS handshake, Certificate (11):
    * TLSv1.2 (IN), TLS handshake, Server key exchange (12):
    * TLSv1.2 (IN), TLS handshake, Server finished (14):
    * TLSv1.2 (OUT), TLS handshake, Client key exchange (16):
    * TLSv1.2 (OUT), TLS change cipher, Change cipher spec (1):
    * TLSv1.2 (OUT), TLS handshake, Finished (20):
    * TLSv1.2 (IN), TLS change cipher, Change cipher spec (1):
    * TLSv1.2 (IN), TLS handshake, Finished (20):
    * SSL connection using TLSv1.2 / ECDHE-RSA-CHACHA20-POLY1305
    * ALPN, server accepted to use h2
    * Server certificate:
    *  subject: O=example; CN=store.example.com
    *  start date: Apr 19 15:54:50 2021 GMT
    *  expire date: Apr 19 15:54:50 2022 GMT
    *  common name: store.example.com (matched)
    *  issuer: O=example; CN=store.example.com
    *  SSL certificate verify ok.
    ...
    {
      "cluster_name": "gw",
      "host_header": "store.example.com",
      "metadata": "store-v1",
      "node_name": "gke-gw-default-pool-51ccbf30-yya8.c.agmsb-k8s.internal",
      "pod_name": "store-v1-84b47c7f58-tj5mn",
      "pod_name_emoji": "😍",
      "project_id": "agmsb-k8s",
      "timestamp": "2021-04-19T16:30:08",
      "zone": "us-west1-a"
    }
    

    Este resultado incluye un protocolo de enlace TLS exitoso y una respuesta de la aplicación. La TLS se finaliza correctamente en la puerta de enlace y la aplicación responde al cliente de forma segura.

Protege el tráfico del balanceador de cargas a la aplicación con TLS

Puedes encriptar el tráfico del balanceador de cargas a los Pods de backend mediante el campo ports[].appProtocol. Los campos compatibles con appProtocol son HTTP, HTTPS y HTTP2.

En el siguiente manifiesto, se describe un Service que especifica que el balanceador de cargas debe usar tráfico HTTPS para comunicarse con los Pods de backend:

apiVersion: v1
kind: Service
metadata:
  name: store-v2
spec:
  selector:
    app: store
    version: v2
  ports:
  - port: 8080
    targetPort: 8080
    appProtocol: HTTPS

El balanceador de cargas no verifica el certificado que usan los Pods de backend. Es tu responsabilidad asegurarte de que el certificado que se usa en los Pods de backend sea válido.

Protege el cliente para el tráfico del balanceador de cargas mediante políticas de SSL

Cuando tus aplicaciones están expuestas a través de una puerta de enlace externa que usa HTTPS, es importante usar los protocolos más recientes o especificar la versión mínima de SSL o TLS. Puedes asegurar el cliente para que cargue tráfico de balanceador de cargas mediante políticas de SSL.

Para obtener más información sobre las políticas de SSL que se pueden adjuntar a tu puerta de enlace y cómo crearlas, consulta Configura políticas de SSL para proteger el tráfico del cliente al balanceador de cargas.

Protege tus backends con Google Cloud Armor

Las políticas de seguridad de Google Cloud Armor te ayudan a proteger las aplicaciones con balanceo de cargas de los ataques basados en la Web. Una vez que configuraste una política de seguridad de Google Cloud Armor, puedes hacer referencia a ella en un GCPBackendPolicy aplicado a tus servicios de Kubernetes.

Si deseas configurar las políticas de Google Cloud Armor con Gateway, consulta Configura la política de seguridad de Google Cloud Armor para proteger tus servicios de backend.

Autentica solicitudes para tus backends mediante Identity-Aware Proxy

Identity-Aware Proxy te ayuda a proteger tus backends del tráfico no deseado mediante la autenticación de los clientes que envían solicitudes a tus aplicaciones y la aplicación de la autorización de tráfico basada en roles. Después de habilitar Identity-Aware Proxy para GKE, puedes hacer referencia a tus credenciales de OAuth en una GCPBackendPolicy aplicada a los Services de Kubernetes.

Para configurar Identity-Aware Proxy con Gateway, consulta Configura Identity-Aware Proxy.

¿Qué sigue?