Integra IAP en Cloud Service Mesh

En esta guía, se describe cómo integrar Identity-Aware Proxy (IAP) en Cloud Service Mesh. La integración de IAP en Cloud Service Mesh te permite acceder de forma segura a los servicios según los principios de BeyondCorp de Google. IAP verifica la identidad del usuario y el contexto de la solicitud para determinar si el usuario debe tener acceso a una aplicación o un recurso. La integración de IAP en Cloud Service Mesh te brinda los siguientes beneficios:

  • Completa el control de acceso adaptado al contexto en las cargas de trabajo que se ejecutan en Cloud Service Mesh. Puedes configurar políticas de acceso detalladas según los atributos de la solicitud de origen, como la identidad del usuario, la dirección IP y el tipo de dispositivo. Puedes combinar tus políticas de acceso con restricciones según el nombre de host y la ruta de acceso de una URL de solicitud.

  • Habilita la compatibilidad con reclamaciones contextuales en la autorización de Cloud Service Mesh.

  • Proporciona acceso escalable, seguro y con alta disponibilidad a tu aplicación a través de un balanceador de cargas de Google Cloud. El balanceo de cargas de alto rendimiento proporciona protección integrada contra ataques de denegación de servicio distribuido (DSD) y compatibilidad con direcciones IP Anycast globales.

Requisitos previos

Sigue los pasos que se indican en Instala herramientas dependientes y valida el clúster para hacer lo siguiente:

Además, en esta guía se supone que cuentas con lo siguiente:

Configura un clúster con Cloud Service Mesh

En esta sección, se explica cómo configurar la integración de IAP para instalaciones nuevas de Cloud Service Mesh y actualizaciones.

Instalaciones nuevas

  1. Habilita iap.googleapis.com. En el siguiente comando, reemplaza PROJECT_ID por el proyecto en el que instalarás Cloud Service Mesh:

    gcloud services enable \
      --project=PROJECT_ID \
      iap.googleapis.com
    
  2. El clúster que actualizas debe tener establecida la opción --addons=HttpLoadBalancing. El complemento HttpLoadBalancing habilita un controlador de balanceo de cargas de HTTP (L7) para el clúster. Ejecuta el siguiente comando para actualizar el clúster con las opciones que requiere Cloud Service Mesh. A menos que hayas configurado una zona o región predeterminada, debes proporcionar la región (--region=REGION) o la zona (--zone=ZONE) en el comando.

    gcloud container clusters update CLUSTER_NAME \
      --project=PROJECT_ID \
      --update-addons=HttpLoadBalancing=ENABLED
    
  3. De forma predeterminada, el archivo iap-operator.yaml tiene el puerto 31223 como el puerto de estado y el puerto 31224 configurado como el puerto http. Si el puerto 31223 ya está en uso en tu clúster, ejecuta el siguiente comando para configurar otro puerto de estado:

    kpt cfg set asm gcloud.container.cluster.ingress.statusPort STATUS_PORT
    

    Si el puerto 31224 ya está en uso en tu clúster, ejecuta el siguiente comando para configurar otro puerto http:

    kpt cfg set asm gcloud.container.cluster.ingress.httpPort HTTP_PORT
    
  4. Sigue los pasos en Instala las funciones predeterminadas y la AC de Mesh para usar la secuencia de comandos que proporciona Google a fin de instalar Cloud Service Mesh. Cuando ejecutes la secuencia de comandos, incluye la siguiente opción:

    --option iap-operator
    

    Por ejemplo:

    ./asmcli install \
      --project_id "PROJECT_ID" \
      --cluster_name "CLUSTER_NAME" \
      --cluster_location "CLUSTER_LOCATION" \
      --fleet_id FLEET_PROJECT_ID \
      --output_dir DIR_PATH \
      --enable_all \
      --option iap-operator
    

    Cuando instalas Cloud Service Mesh, el archivo iap-operator.yaml configura el campo type en el servicio istio-ingressgateway como NodePort, que configura la puerta de enlace para abrir un puerto específico en la malla de servicios. Esto te permite configurar un balanceador de cargas, que enruta el tráfico enviado a tu nombre de dominio a este puerto.

  5. Si instalas Cloud Service Mesh administrado, completa también los siguientes pasos:

    1. Aplica la etiqueta de revisión al espacio de nombres istio-system.

    2. Descarga la especificación del servicio de puerta de enlace de entrada de Istio para IAP y asígnale el nombre iap_operator.yaml.

    3. Instala el objeto ingress como un servicio de NodePort. Si quieres obtener más información, consulta Migra desde IstioOperator.

      asmcli experimental mcp-migrate-check -f iap_operator.yaml
      
      istioctl install -f /asm-generated-configs/gateways-istiooperator/"GATEWAY_NAME".yaml
      

Después de instalar Cloud Service Mesh, regresa a esta guía y continúa con la siguiente sección para configurar la integración con IAP.

Actualizaciones

En esta sección, se abarcan los siguientes casos de uso de actualización:

  • Ya configuraste la integración de IAP y realizas la actualización de Cloud Service Mesh. En este caso, ya habilitaste iap.googleapis.com en tu proyecto y el complemento HttpLoadBalancing en tu clúster. Omite el paso 3 para descargar el paquete asm y actualizar Cloud Service Mesh.

  • Estás actualizando Cloud Service Mesh y quieres configurar la integración con IAP por primera vez. En este caso, debes completar todos los pasos siguientes, actualizar Cloud Service Mesh y volver a esta guía después de la actualización para completar la integración.

  1. Habilita iap.googleapis.com. En el siguiente comando, reemplaza PROJECT_ID por el proyecto en el que instalarás Cloud Service Mesh.

    gcloud services enable \
      --project=PROJECT_ID \
      iap.googleapis.com
    
  2. El clúster que actualizas debe tener establecida la opción --addons=HttpLoadBalancing. El complemento HttpLoadBalancing habilita un controlador de balanceo de cargas de HTTP (L7) para el clúster. Ejecuta el siguiente comando para actualizar el clúster con las opciones que requiere Cloud Service Mesh. A menos que hayas configurado una zona o región predeterminada, debes proporcionar la región (--region=REGION) o la zona (--zone=ZONE) en el comando.

    gcloud container clusters update CLUSTER_NAME \
      --project=PROJECT_ID
      --update-addons=HttpLoadBalancing=ENABLED
    
  3. Si quieres actualizar un balanceador de cargas HTTP existente de Cloud Run, ejecuta lo siguiente para preservar los puertos HTTP y de estado existentes:

    kpt cfg set asm gcloud.container.cluster.ingress.httpPort $(kubectl -n istio-system get service istio-ingressgateway -o jsonpath='{.spec.ports[?(@.name=="http2")].nodePort}')
    
    kpt cfg set asm gcloud.container.cluster.ingress.statusPort $(kubectl -n istio-system get service istio-ingressgateway -o jsonpath='{.spec.ports[?(@.name=="status-port")].nodePort}')
    
  4. Sigue los pasos en Actualiza Cloud Service Mesh para usar la secuencia de comandos que proporciona Google a fin de actualizar Cloud Service Mesh.

    Cuando actualizas Cloud Service Mesh, el archivo iap-operator.yaml establece el campo type en el servicio istio-ingressgateway en NodePort, que configura la puerta de enlace para abrir un puerto específico en la malla de servicios. Esto te permite configurar un balanceador de cargas, que enruta el tráfico enviado a tu nombre de dominio a este puerto.

    De forma predeterminada, el archivo iap-operator.yaml tiene el puerto 31223 como el puerto de estado y el puerto 31224 configurado como el puerto http.

    Cuando ejecutes la secuencia de comandos, incluye la siguiente opción:

    --option iap-operator
    

    Por ejemplo:

    ./asmcli install \
      --project_id "PROJECT_ID" \
      --cluster_name "CLUSTER_NAME" \
      --cluster_location "CLUSTER_LOCATION" \
      --fleet_id FLEET_PROJECT_ID \
      --output_dir DIR_PATH \
      --enable_all \
      --option iap-operator
    
  5. Para completar la actualización, activa la inserción automática de proxy de sidecar en las cargas de trabajo. Para obtener más información, consulta Implementa y vuelve a implementar cargas de trabajo.

    Después de completar la actualización, regresa a esta guía y continúa con la siguiente sección para configurar la integración con IAP.

Reserva una dirección IP estática y configura el DNS

Para integrar Identity-Aware Proxy en Cloud Service Mesh, debes configurar un balanceador de cargas HTTP(S) de Google Cloud, que requiere un nombre de dominio que apunte a una dirección IP estática. Puedes reservar una dirección IP externa estática, que asigna la dirección a tu proyecto de forma indefinida hasta que se libere de manera explícita.

  1. Reserva una dirección IP externa estática:

    gcloud compute addresses create example-static-ip --global
    
  2. Obtén la dirección IP estática:

    gcloud compute addresses describe example-static-ip --global
    
  3. En tu registrador de nombres de dominio, configura un nombre de dominio completamente calificado (FQDN) con la dirección IP estática. Por lo general, agregas un registro A a tu configuración de DNS. Los pasos de configuración y la terminología necesarias a fin de agregar un registro A para un FQDN varían según el registrador de nombres de dominio.

    La propagación de la configuración de DNS puede llevar entre 24 y 48 horas. Puedes seguir con los otros ajustes en esta guía, pero no podrás probarla hasta que se propague la configuración del DNS.

Implementa una aplicación de muestra

Antes de habilitar IAP, necesitas una aplicación que se ejecute en tu clúster de GKE para que puedas verificar que todas las solicitudes tengan una identidad. En esta guía, se usa el ejemplo de Bookinfo para demostrar cómo configurar el balanceador de cargas de HTTP(S) y habilitar IAP.

Sigue los pasos para implementar Bookinfo. Hasta que implementes el balanceador de cargas, la aplicación Bookinfo no será accesible fuera de tu clúster de GKE (por ejemplo, desde un navegador).

Solicitudes externas

El recurso de puerta de enlace de Bookinfo (definido en samples/bookinfo/networking/bookinfo-gateway.yaml) usa istio-ingressgateway preconfigurado. Recuerda que cuando implementaste Cloud Service Mesh, especificaste NodePort para istio-ingressgateway, que abre un puerto específico en la malla de servicios. Aunque los nodos de tu clúster tienen direcciones IP externas, las reglas de firewall de Google Cloud bloquean las solicitudes que provienen de afuera del clúster. Con IAP, la forma correcta de exponer las aplicaciones a la Internet pública es mediante un balanceador de cargas. No expongas las direcciones del nodo mediante reglas de firewall, que podrían omitir IAP.

Para enrutar solicitudes a Bookinfo, configura un balanceador de cargas de HTTP(S) en tu proyecto de Google Cloud. Debido a que el balanceador de cargas está en tu proyecto, está dentro del firewall y puede acceder a los nodos en tu clúster. Después de configurar el balanceador de cargas con la dirección IP estática y tu nombre de dominio, puedes enviar solicitudes al nombre de dominio, y el balanceador de cargas reenviará las solicitudes a los nodos del clúster.

Habilita IAP

En los siguientes pasos, se describe cómo habilitar IAP.

  1. Para verificar si ya tienes una marca existente, usa el comando list. Solo puedes tener una marca por proyecto.

    gcloud iap oauth-brands list

    El siguiente es un ejemplo de respuesta de gcloud, si la marca existe:

    name: projects/[PROJECT_NUMBER]/brands/[BRAND_ID]
    applicationTitle: [APPLICATION_TITLE]
    supportEmail: [SUPPORT_EMAIL]
    orgInternalOnly: true
    
  2. Si no existe una marca, usa el comando create:

    gcloud iap oauth-brands create --application_title=APPLICATION_TITLE --support_email=SUPPORT_EMAIL

    Los campos anteriores son obligatorios cuando se llama a esta API:

    • supportEmail: Es el correo electrónico de asistencia que se muestra en la pantalla de consentimiento de OAuth. Esta dirección de correo electrónico puede ser la dirección de un usuario o un alias de Grupos de Google. Si bien las cuentas de servicio también tienen una dirección de correo electrónico, no son direcciones de correo electrónico válidas reales y no se pueden usar cuando se crea una marca. Sin embargo, una cuenta de servicio puede ser propietaria de un Grupo de Google. Crea un Grupo de Google nuevo o configura un grupo existente y configura la cuenta de servicio deseada como propietaria del grupo.

    • applicationTitle: Es el nombre de la aplicación que se muestra en la pantalla de consentimiento de OAuth.

    La respuesta contiene los siguientes campos:

    name: projects/[PROJECT_NUMBER]/brands/[BRAND_ID]
    applicationTitle: [APPLICATION_TITLE]
    supportEmail: [SUPPORT_EMAIL]
    orgInternalOnly: true
    

Crea un cliente de OAuth para IAP

  1. Usa el comando create para crear un cliente. Usa la marca name del paso anterior:

    gcloud iap oauth-clients create projects/PROJECT_NUMBER/brands/BRAND-ID --display_name=NAME

    La respuesta contiene los siguientes campos:

    name: projects/[PROJECT_NUMBER]/brands/[BRAND_NAME]/identityAwareProxyClients/[CLIENT_ID]
    secret: [CLIENT_SECRET]
    displayName: [NAME]
    
  2. Usa el ID de cliente (CLIENT_ID en el paso anterior) y CLIENT_SECRET para habilitar IAP. Crea un secreto de Kubernetes con los materiales de tu cliente de OAuth:

    kubectl create secret generic -n istio-system my-secret --from-literal=client_id=CLIENT_ID \
    --from-literal=client_secret=CLIENT_SECRET

Implementa el balanceador de cargas

Puedes usar un recurso Ingress para crear un balanceador de cargas de HTTP(S) con certificados SSL configurados de forma automática. Los certificados SSL administrados se aprovisionan, renuevan y administran para tu dominio.

  1. Crea un recurso ManagedCertificate. Este recurso especifica el dominio para el certificado SSL. La lista spec.domains debe contener solo un dominio. No se admiten dominios comodines. En el siguiente YAML, reemplaza DOMAIN_NAME por el nombre de dominio que configuraste para la dirección IP estática externa.

    cat <<EOF | kubectl apply -f -
    apiVersion: networking.gke.io/v1
    kind: ManagedCertificate
    metadata:
      name: example-certificate
      namespace: istio-system
    spec:
      domains:
        - DOMAIN_NAME
    EOF
  2. Crea un recurso BackendConfig. Este recurso le indica a GCLB cómo realizar verificaciones de estado en la puerta de enlace de entrada y cómo configurar Identity-Aware Proxy. Primero, recopila algunos valores de la puerta de enlace de entrada sobre las verificaciones de estado:

    • Puerto de entrada de la verificación de estado: Este es el puerto de verificación de estado de istio-ingress.

      export HC_INGRESS_PORT=$(kubectl -n istio-system get service istio-ingressgateway -o jsonpath='{.spec.ports[?(@.name=="status-port")].nodePort}')

    • Ruta de acceso de la verificación de estado del Ingress: Esta es la ruta de acceso de la verificación de estado de istio-ingress.

      export HC_INGRESS_PATH=$(kubectl get pods -n istio-system -l app=istio-ingressgateway -o jsonpath='{.items[0].spec.containers[?(@.name=="istio-proxy")].readinessProbe.httpGet.path}')

    cat <<EOF | kubectl apply -n istio-system -f -
    apiVersion: cloud.google.com/v1
    kind: BackendConfig
    metadata:
      name: http-hc-config
    spec:
      healthCheck:
        checkIntervalSec: 2
        timeoutSec: 1
        healthyThreshold: 1
        unhealthyThreshold: 10
        port: ${HC_INGRESS_PORT}
        type: HTTP
        requestPath: ${HC_INGRESS_PATH}
      iap:
        enabled: true
        oauthclientCredentials:
          secretName: my-secret
    EOF
  3. Anota el servicio de entrada con tu BackendConfig.

        kubectl annotate -n istio-system service/istio-ingressgateway --overwrite \
          cloud.google.com/backend-config='{"default": "http-hc-config"}' \
          cloud.google.com/neg='{"ingress":false}'
    
  4. Crea el balanceador de cargas mediante la definición del recurso Ingress.

    • Configura la anotación networking.gke.io/managed-certificates con el nombre del certificado que creaste en el paso anterior, example-certificate.

    • Configura la anotación kubernetes.io/ingress.global-static-ip-name con el nombre de la dirección IP estática que reservaste, example-static-ip.

    • Configura serviceName como istio-ingressgateway, que se usa en el recurso Gateway para la muestra de Bookinfo.

    cat <<EOF | kubectl apply -f -
    apiVersion: networking.k8s.io/v1
    kind: Ingress
    metadata:
      name: example-ingress
      namespace: istio-system
      annotations:
        kubernetes.io/ingress.global-static-ip-name: example-static-ip
        networking.gke.io/managed-certificates: example-certificate
    spec:
      defaultBackend:
        service:
          name: istio-ingressgateway
          port:
            number: 80
    EOF
  5. En la consola de Google Cloud, ve a la página Kubernetes Engine > Ingress y servicios.

    Ir a la página Ingress y servicios

    Deberías ver el mensaje “Creando Ingress” en la columna Estado. Espera a que GKE aprovisione por completo el Ingress antes de continuar. Actualiza la página cada pocos minutos para obtener el estado más actualizado del Ingress. Después de aprovisionar el Ingress, es posible que veas el estado “Ok” o el error “Todos los servicios de backend están en EN MAL ESTADO”. Uno de los recursos que GKE aprovisiona es una verificación de estado predeterminada. Si ves el mensaje de error, significa que se aprovisiona el Ingress y que se ejecutó la verificación de estado predeterminada. Cuando veas el estado “Ok” o el error, continúa con la siguiente sección para configurar las verificaciones de estado del balanceador de cargas.

Configura la lista de acceso de IAP

Agrega un usuario a la política de acceso de IAP:

gcloud beta iap web add-iam-policy-binding \
    --member=user:EMAIL_ADDRESS \
    --role=roles/iap.httpsResourceAccessor

En el ejemplo anterior, EMAIL_ADDRESS es la dirección de correo electrónico completa del usuario, como alice@example.com.

  1. Prueba el balanceador de cargas. Apunta el navegador con el siguiente comando:

    http://DOMAIN_NAME/productpage

    En el ejemplo anterior, DOMAIN_NAME es el nombre de dominio que configuraste con la dirección IP estática externa.

    Deberías ver la productpage de la aplicación Bookinfo. Si actualizas la página varias veces, deberías ver diferentes reseñas, en un estilo round robin: estrellas rojas, estrellas negras, sin estrellas.

    También debes probar el acceso de https a Bookinfo.

Habilita la compatibilidad con RCToken en la malla de servicios

De forma predeterminada, IAP genera un token web JSON (JWT) con alcance para el cliente de OAuth. Para Cloud Service Mesh, puedes configurar IAP para generar un RequestContextToken (RCToken), que es un JWT, pero con un público configurable. Los RCToken te permiten configurar el público del JWT en una cadena arbitraria, que se puede usar en las políticas de Cloud Service Mesh para obtener una autorización detallada.

Para configurar el RCToken, haz lo siguiente:

  1. Crea una variable de entorno para el público del RCToken. Puede ser cualquier string que desees:

    export RCTOKEN_AUD="your-rctoken-aud"
    
  2. Opcional: En el siguiente paso, se requiere BACKEND_SERVICE_ID. Si necesitas averiguar BACKEND_SERVICE_ID, ejecuta el siguiente comando:

    kubectl -n istio-system get Ingress example-ingress -o json | jq \
     '.metadata.annotations."ingress.kubernetes.io/backends"'
    

    El resultado esperado es similar a "{\"BACKEND_SERVICE_ID\":\"HEALTHY\"}". Por ejemplo, "ingress.kubernetes.io/backends": "{\"k8s-be-31224--51f3b55cd1457fb6\":\"HEALTHY\"}". El BACKEND_SERVICE_ID en este ejemplo es k8s-be-31224--51f3b55cd1457fb6.

  3. Recupera la configuración de IAP existente.

    gcloud iap settings get --format json \
    --project=${PROJECT_ID} --resource-type=compute --service=BACKEND_SERVICE_ID > iapSettings.json
    
  4. Actualiza IapSettings con el público del RCToken:

    cat iapSettings.json | jq --arg RCTOKEN_AUD_STR $RCTOKEN_AUD \
    '. + {applicationSettings: {csmSettings: {rctokenAud: $RCTOKEN_AUD_STR}}}' \
    > updatedIapSettings.json
    
    gcloud iap settings set updatedIapSettings.json --format json \
    --project=${PROJECT_ID} --resource-type=compute --service=BACKEND_SERVICE_ID
    
  5. Habilita la autenticación de RCToken en la puerta de enlace de entrada de Istio:

    cat <<EOF | kubectl apply -f -
    apiVersion: "security.istio.io/v1beta1"
    kind: "RequestAuthentication"
    metadata:
      name: "ingressgateway-jwt-policy"
      namespace: "istio-system"
    spec:
      selector:
        matchLabels:
          app: istio-ingressgateway
      jwtRules:
      - issuer: "https://cloud.google.com/iap"
        jwksUri: "https://www.gstatic.com/iap/verify/public_key-jwk"
        audiences:
        - $RCTOKEN_AUD
        fromHeaders:
        - name: ingress-authorization
          prefix: "Istio "
        outputPayloadToHeader: "verified-jwt"
        forwardOriginalToken: true
    EOF
    
  6. Opcional: Asegúrate de que se rechacen las solicitudes que no tienen JWT válidos:

      cat <<EOF | kubectl apply -f -
      apiVersion: security.istio.io/v1beta1
      kind: AuthorizationPolicy
      metadata:
        name: iap-gateway-require-jwt
        namespace: istio-system
      spec:
        selector:
          matchLabels:
            app: istio-iap-ingressgateway
        action: DENY
        rules:
          - from:
              - source:
                  notRequestPrincipals: ["*"]
      EOF
      

  7. Asegúrate de que las solicitudes a la productpage de Bookinfo aún tengan éxito:

    http://DOMAIN_NAME/productpage

Para probar la política, haz lo siguiente:

  1. Crea un objeto de solicitud IapSettings, pero establece rctokenAud en una string diferente:

    cat iapSettings.json | jq --arg RCTOKEN_AUD_STR wrong-rctoken-aud \
    '. + {applicationSettings: {csmSettings: {rctokenAud: $RCTOKEN_AUD_STR}}}' \
    > wrongIapSettings.json
    
  2. Llama a la API de IapSettings para configurar el público del RCToken:

    gcloud beta iap settings set wrongIapSettings.json --project=PROJECT_ID --resource-type=compute --service=BACKEND_SERVICE
  3. Realiza una solicitud a la productpage de Bookinfo, que debería fallar:

    http://DOMAIN_NAME/productpage

Realiza una limpieza

Después de completar este instructivo, quita los siguientes recursos para evitar que se realicen cargos no deseados en tu cuenta:

  1. Borra el certificado administrado:

    kubectl delete managedcertificates example-certificate
  2. Borra el Ingress, lo que quita la asignación de los recursos del balanceo de cargas:

    kubectl -n istio-system delete ingress example-ingress

  3. Borra la dirección IP estática:

    gcloud compute addresses delete example-static-ip --global

    Si haces esto, asegúrate de borrar la dirección IP del registrador de tu dominio.

  4. Borra el clúster, lo que borrará los recursos que conforman el clúster, como las instancias de procesamiento, los discos y los recursos de red:

    gcloud container clusters delete CLUSTER_NAME