Usar pasarelas de salida de Cloud Service Mesh en clústeres de GKE: tutorial


En este tutorial se explica cómo usar las pasarelas de salida de Cloud Service Mesh y otros Google Cloud controles para proteger el tráfico saliente de las cargas de trabajo desplegadas en un clúster de Google Kubernetes Engine. Este tutorial es un complemento de las prácticas recomendadas para usar pasarelas de salida de Cloud Service Mesh en clústeres de GKE.

Este tutorial está dirigido a ingenieros de redes, plataformas y seguridad que administran clústeres de Google Kubernetes Engine utilizados por uno o varios equipos de lanzamiento de software. Los controles que se describen en este artículo son especialmente útiles para las organizaciones que deben demostrar que cumplen las normativas, como el RGPD y el PCI.

Objetivos

  • Configura la infraestructura para ejecutar Cloud Service Mesh:
  • Instala Cloud Service Mesh.
  • Instala proxies de pasarela de salida que se ejecuten en un grupo de nodos dedicado.
  • Configura reglas de enrutamiento multitenant para el tráfico externo a través de la pasarela de salida:
    • Las aplicaciones del espacio de nombres team-x pueden conectarse a example.com
    • Las aplicaciones del espacio de nombres team-y pueden conectarse a httpbin.org
  • Usa el recurso Sidecar para restringir el ámbito de la configuración de salida del proxy adicional de cada espacio de nombres.
  • Configura políticas de autorización para aplicar reglas de salida.
  • Configura la puerta de enlace de salida para actualizar las solicitudes HTTP a TLS (creación de TLS).
  • Configura la pasarela de salida para que transfiera el tráfico TLS.
  • Configura políticas de red de Kubernetes como control de salida adicional.
  • Configura el acceso directo a las APIs de Google mediante el acceso privado a Google y los permisos de gestión de identidades y accesos (IAM).

Costes

En este documento, se utilizan los siguientes componentes facturables de Google Cloud:

Para generar una estimación de costes basada en el uso previsto, utiliza la calculadora de precios.

Los usuarios nuevos Google Cloud pueden disfrutar de una prueba gratuita.

Cuando termines este tutorial, puedes evitar costes continuos eliminando los recursos que hayas creado. Para obtener más información, consulta la sección Limpieza.

Antes de empezar

  1. In the Google Cloud console, on the project selector page, select or create a Google Cloud project.

    Roles required to select or create a project

    • Select a project: Selecting a project doesn't require a specific IAM role—you can select any project that you've been granted a role on.
    • Create a project: To create a project, you need the Project Creator (roles/resourcemanager.projectCreator), which contains the resourcemanager.projects.create permission. Learn how to grant roles.

    Go to project selector

  2. Verify that billing is enabled for your Google Cloud project.

  3. In the Google Cloud console, activate Cloud Shell.

    Activate Cloud Shell

  4. Crea un directorio de trabajo para seguir el tutorial:

    mkdir -p ~/WORKING_DIRECTORY
    cd ~/WORKING_DIRECTORY
    
  5. Crea un shell script para inicializar tu entorno para el tutorial. Sustituye y edita las variables según tu proyecto y tus preferencias. Ejecuta esta secuencia de comandos con el comando source para reinicializar tu entorno si tu sesión de shell caduca:

    cat << 'EOF' > ./init-egress-tutorial.sh
    #! /usr/bin/env bash
    PROJECT_ID=YOUR_PROJECT_ID
    REGION=REGION
    ZONE=ZONE
    
    gcloud config set project ${PROJECT_ID}
    gcloud config set compute/region ${REGION}
    gcloud config set compute/zone ${ZONE}
    
    EOF
    
  6. Habilitar compute.googleapis.com:

    gcloud services enable compute.googleapis.com --project=YOUR_PROJECT_ID
    
  7. Haz que la secuencia de comandos sea ejecutable y ejecútala con el comando source para inicializar tu entorno. Selecciona Y si se te pide que habilites compute.googleapis.com:

    chmod +x ./init-egress-tutorial.sh
    source ./init-egress-tutorial.sh
    
  8. Configurar la infraestructura

    Crear una red VPC y una subred

    1. Crea una red de VPC:

      gcloud compute networks create vpc-network \
          --subnet-mode custom
      
    2. Crea una subred en la que se ejecute el clúster con intervalos de direcciones IP secundarias preasignados para pods y servicios. Acceso privado de Google está habilitado para que las aplicaciones que solo tienen direcciones IP internas puedan acceder a las APIs y los servicios de Google:

      gcloud compute networks subnets create subnet-gke \
          --network vpc-network \
          --range 10.0.0.0/24 \
          --secondary-range pods=10.1.0.0/16,services=10.2.0.0/20 \
          --enable-private-ip-google-access
      

    Configurar Cloud NAT

    Cloud NAT permite que las cargas de trabajo sin direcciones IP externas se conecten a destinos en Internet y reciban respuestas entrantes de esos destinos.

    1. Crea un router de Cloud Router:

      gcloud compute routers create nat-router \
          --network vpc-network
      
    2. Añade una configuración de NAT al router:

      gcloud compute routers nats create nat-config \
          --router nat-router \
          --nat-all-subnet-ip-ranges \
          --auto-allocate-nat-external-ips
      

    Crear cuentas de servicio para cada grupo de nodos de GKE

    Crea dos cuentas de servicio para que las usen los dos grupos de nodos de GKE. Se asigna una cuenta de servicio independiente a cada grupo de nodos para que puedas aplicar reglas de cortafuegos de VPC a nodos específicos.

    1. Crea una cuenta de servicio para que la usen los nodos del grupo de nodos predeterminado:

      gcloud iam service-accounts create sa-application-nodes \
          --description="SA for application nodes" \
          --display-name="sa-application-nodes"
      
    2. Crea una cuenta de servicio para que la usen los nodos del grupo de nodos de la pasarela:

      gcloud iam service-accounts create sa-gateway-nodes \
          --description="SA for gateway nodes" \
          --display-name="sa-gateway-nodes"
      

    Conceder permisos a las cuentas de servicio

    Añade un conjunto mínimo de roles de gestión de identidades y accesos a las cuentas de servicio de la aplicación y de la pasarela. Estos roles son necesarios para registrar, monitorizar y extraer imágenes de contenedor privadas de Container Registry.

        project_roles=(
            roles/logging.logWriter
            roles/monitoring.metricWriter
            roles/monitoring.viewer
            roles/storage.objectViewer
        )
        for role in "${project_roles[@]}"
        do
            gcloud projects add-iam-policy-binding ${PROJECT_ID} \
                --member="serviceAccount:sa-application-nodes@${PROJECT_ID}.iam.gserviceaccount.com" \
                --role="$role"
            gcloud projects add-iam-policy-binding ${PROJECT_ID} \
                --member="serviceAccount:sa-gateway-nodes@${PROJECT_ID}.iam.gserviceaccount.com" \
                --role="$role"
        done
    

    Crear las reglas de cortafuegos

    En los pasos siguientes, aplicarás una regla de cortafuegos a la red de VPC para que, de forma predeterminada, se rechace todo el tráfico de salida. Se requiere una conectividad específica para que el clúster funcione y para que los nodos de pasarela puedan acceder a destinos fuera de la VPC. Un conjunto mínimo de reglas de cortafuegos específicas anula la regla predeterminada de denegación total para permitir la conectividad necesaria.

    1. Crea una regla de cortafuegos predeterminada (de baja prioridad) para denegar todo el tráfico de salida de la red de VPC:

      gcloud compute firewall-rules create global-deny-egress-all \
          --action DENY \
          --direction EGRESS \
          --rules all \
          --destination-ranges 0.0.0.0/0 \
          --network vpc-network \
          --priority 65535 \
          --description "Default rule to deny all egress from the network."
      
    2. Crea una regla para permitir que solo los nodos con la cuenta de servicio de la pasarela accedan a Internet:

      gcloud compute firewall-rules create gateway-allow-egress-web \
          --action ALLOW \
          --direction EGRESS \
          --rules tcp:80,tcp:443 \
          --target-service-accounts sa-gateway-nodes@${PROJECT_ID}.iam.gserviceaccount.com \
          --network vpc-network \
          --priority 1000 \
          --description "Allow the nodes running the egress gateways to connect to the web"
      
    3. Permite que los nodos accedan al plano de control de Kubernetes:

      gcloud compute firewall-rules create allow-egress-to-api-server \
          --action ALLOW \
          --direction EGRESS \
          --rules tcp:443,tcp:10250 \
          --target-service-accounts sa-application-nodes@${PROJECT_ID}.iam.gserviceaccount.com,sa-gateway-nodes@${PROJECT_ID}.iam.gserviceaccount.com \
          --destination-ranges 10.5.0.0/28 \
          --network vpc-network \
          --priority 1000 \
          --description "Allow nodes to reach the Kubernetes API server."
      
    4. Opcional: Esta regla de cortafuegos no es necesaria si utilizas la malla de servicios de Cloud gestionada.

      Cloud Service Mesh usa webhooks al insertar proxies sidecar en cargas de trabajo. Permite que el servidor de la API de GKE llame a los webhooks expuestos por el plano de control de la malla de servicios que se ejecuta en los nodos:

      gcloud compute firewall-rules create allow-ingress-api-server-to-webhook \
          --action ALLOW \
          --direction INGRESS \
          --rules tcp:15017 \
          --target-service-accounts sa-application-nodes@${PROJECT_ID}.iam.gserviceaccount.com,sa-gateway-nodes@${PROJECT_ID}.iam.gserviceaccount.com \
          --source-ranges 10.5.0.0/28 \
          --network vpc-network \
          --priority 1000 \
          --description "Allow the API server to call the webhooks exposed by istiod discovery"
      
    5. Permite la conectividad de salida entre los nodos y los pods que se ejecutan en el clúster. GKE crea automáticamente una regla de entrada correspondiente. No se necesita ninguna regla para la conectividad de los servicios, ya que la cadena de enrutamiento de iptables siempre convierte las direcciones IP de los servicios en direcciones IP de los pods.

      gcloud compute firewall-rules create allow-egress-nodes-and-pods \
          --action ALLOW \
          --direction EGRESS \
          --rules all \
          --target-service-accounts sa-application-nodes@${PROJECT_ID}.iam.gserviceaccount.com,sa-gateway-nodes@${PROJECT_ID}.iam.gserviceaccount.com \
          --destination-ranges 10.0.0.0/24,10.1.0.0/16 \
          --network vpc-network \
          --priority 1000 \
          --description "Allow egress to other Nodes and Pods"
      
    6. Permite el acceso a los conjuntos reservados de direcciones IP que usa el acceso privado a Google para ofrecer las APIs de Google, Container Registry y otros servicios:

      gcloud compute firewall-rules create allow-egress-gcp-apis \
          --action ALLOW \
          --direction EGRESS \
          --rules tcp \
          --target-service-accounts sa-application-nodes@${PROJECT_ID}.iam.gserviceaccount.com,sa-gateway-nodes@${PROJECT_ID}.iam.gserviceaccount.com \
          --destination-ranges 199.36.153.8/30 \
          --network vpc-network \
          --priority 1000 \
          --description "Allow access to the VIPs used by Google Cloud APIs (Private Google Access)"
      
    7. Permite que el servicio de comprobación del estado de Google Cloud acceda a los pods que se ejecutan en el clúster. Consulta más información sobre las comprobaciones de estado.

      gcloud compute firewall-rules create allow-ingress-gcp-health-checker \
          --action ALLOW \
          --direction INGRESS \
          --rules tcp:80,tcp:443 \
          --target-service-accounts sa-application-nodes@${PROJECT_ID}.iam.gserviceaccount.com,sa-gateway-nodes@${PROJECT_ID}.iam.gserviceaccount.com \
          --source-ranges 35.191.0.0/16,130.211.0.0/22,209.85.152.0/22,209.85.204.0/22 \
          --network vpc-network \
          --priority 1000 \
          --description "Allow workloads to respond to Google Cloud health checks"
      

    Configurar el acceso privado a las APIs de Google Cloud

    Acceso privado de Google permite que las VMs y los pods que solo tienen direcciones IP internas accedan a las APIs y los servicios de Google. Aunque las APIs y los servicios de Google se sirven desde IPs externas, el tráfico de los nodos nunca sale de la red de Google cuando se usa el acceso privado de Google.

    Habilita la API Cloud DNS:

    gcloud services enable dns.googleapis.com
    

    Crea una zona DNS privada, un CNAME y registros A para que los nodos y las cargas de trabajo puedan conectarse a las APIs y los servicios de Google mediante el acceso privado a Google y el nombre de host private.googleapis.com:

    gcloud dns managed-zones create private-google-apis \
        --description "Private DNS zone for Google APIs" \
        --dns-name googleapis.com \
        --visibility private \
        --networks vpc-network
    
    gcloud dns record-sets transaction start --zone private-google-apis
    
    gcloud dns record-sets transaction add private.googleapis.com. \
        --name "*.googleapis.com" \
        --ttl 300 \
        --type CNAME \
        --zone private-google-apis
    
    gcloud dns record-sets transaction add "199.36.153.8" \
    "199.36.153.9" "199.36.153.10" "199.36.153.11" \
        --name private.googleapis.com \
        --ttl 300 \
        --type A \
        --zone private-google-apis
    
    gcloud dns record-sets transaction execute --zone private-google-apis
    

    Configurar el acceso privado a Container Registry

    Crea una zona de DNS privada, un registro CNAME y un registro A para que los nodos puedan conectarse a Container Registry mediante el acceso privado de Google y el nombre de host gcr.io:

    gcloud dns managed-zones create private-gcr-io \
        --description "private zone for Container Registry" \
        --dns-name gcr.io \
        --visibility private \
        --networks vpc-network
    
    gcloud dns record-sets transaction start --zone private-gcr-io
    
    gcloud dns record-sets transaction add gcr.io. \
        --name "*.gcr.io" \
        --ttl 300 \
        --type CNAME \
        --zone private-gcr-io
    
    gcloud dns record-sets transaction add "199.36.153.8" "199.36.153.9" "199.36.153.10" "199.36.153.11" \
        --name gcr.io \
        --ttl 300 \
        --type A \
        --zone private-gcr-io
    
    gcloud dns record-sets transaction execute --zone private-gcr-io
    

    Crear un clúster privado de GKE

    1. Busca la dirección IP externa de tu Cloud Shell para poder añadirla a la lista de redes que tienen permiso para acceder al servidor de la API de tu clúster:

      SHELL_IP=$(dig TXT -4 +short @ns1.google.com o-o.myaddr.l.google.com)
      

      Después de un periodo de inactividad, la dirección IP externa de tu máquina virtual de Cloud Shell puede cambiar. Si esto ocurre, debes actualizar la lista de redes autorizadas de tu clúster. Añade el siguiente comando al script de inicialización:

      cat << 'EOF' >> ./init-egress-tutorial.sh
      SHELL_IP=$(dig TXT -4 +short @ns1.google.com o-o.myaddr.l.google.com)
      gcloud container clusters update cluster1 \
          --enable-master-authorized-networks \
          --master-authorized-networks ${SHELL_IP//\"}/32
      EOF
      
    2. Habilita la API de Google Kubernetes Engine:

      gcloud services enable container.googleapis.com
      
    3. Crea un clúster de GKE privado:

      gcloud container clusters create cluster1 \
          --enable-ip-alias \
          --enable-private-nodes \
          --release-channel "regular" \
          --enable-master-authorized-networks \
          --master-authorized-networks ${SHELL_IP//\"}/32 \
          --master-ipv4-cidr 10.5.0.0/28 \
          --enable-dataplane-v2 \
          --service-account "sa-application-nodes@${PROJECT_ID}.iam.gserviceaccount.com" \
          --machine-type "e2-standard-4" \
          --network "vpc-network" \
          --subnetwork "subnet-gke" \
          --cluster-secondary-range-name "pods" \
          --services-secondary-range-name "services" \
          --workload-pool "${PROJECT_ID}.svc.id.goog" \
          --zone ${ZONE}
      

      El clúster tardará unos minutos en crearse. El clúster tiene nodos privados con direcciones IP internas. A los pods y los servicios se les asignan IPs de los intervalos secundarios con nombre que definiste al crear la subred de VPC.

      Cloud Service Mesh con un plano de control en el clúster requiere que los nodos del clúster usen un tipo de máquina que tenga al menos 4 vCPUs.

      Google recomienda que el clúster esté suscrito al canal de lanzamiento "regular" para asegurarse de que los nodos ejecuten una versión de Kubernetes compatible con Cloud Service Mesh.

      Para obtener más información sobre los requisitos previos para ejecutar Cloud Service Mesh con un plano de control en el clúster, consulta los requisitos previos en el clúster.

      Para obtener más información sobre los requisitos y las limitaciones para ejecutar Cloud Service Mesh gestionado, consulta las funciones compatibles con Cloud Service Mesh gestionado.

      Workload Identity Federation for GKE está habilitado en el clúster. Cloud Service Mesh requiere Workload Identity Federation para GKE y es la forma recomendada de acceder a las APIs de Google desde las cargas de trabajo de GKE.

    4. Crea un grupo de nodos llamado gateway. Este grupo de nodos es donde se implementa la pasarela de salida. El dedicated=gateway:NoSchedule taint se añade a todos los nodos del grupo de nodos de la pasarela.

      gcloud container node-pools create "gateway" \
          --cluster "cluster1" \
          --machine-type "e2-standard-4" \
          --node-taints dedicated=gateway:NoSchedule \
          --service-account "sa-gateway-nodes@${PROJECT_ID}.iam.gserviceaccount.com" \
          --num-nodes "1"
      

      Las tolerancias e intolerancias de Kubernetes ayudan a asegurar que solo los pods de la pasarela de salida se ejecuten en los nodos del pool de nodos de la pasarela.

    5. Descarga las credenciales para poder conectarte al clúster con kubectl:

      gcloud container clusters get-credentials cluster1
      
    6. Verifica que los nodos de la pasarela tengan el taint correcto:

      kubectl get nodes -l cloud.google.com/gke-nodepool=gateway -o yaml \
      -o=custom-columns='name:metadata.name,taints:spec.taints[?(@.key=="dedicated")]'
      

      El resultado debería ser similar al siguiente:

      name                                 taints
      gke-cluster1-gateway-9d65b410-cffs   map[effect:NoSchedule key:dedicated value:gateway]
      

    Instalar y configurar Cloud Service Mesh

    Sigue una de las guías de instalación de Cloud Service Mesh:

    Una vez que hayas instalado Cloud Service Mesh, detente y vuelve a este tutorial sin instalar las pasarelas de entrada o de salida.

    Instalar una pasarela de salida

    1. Crea un espacio de nombres de Kubernetes para la pasarela de salida:

      kubectl create namespace istio-egress
      
    2. Cuando despliegue la pasarela de salida, la configuración se insertará automáticamente en función de una etiqueta que aplique al despliegue o al espacio de nombres. Si la etiqueta predeterminada está configurada, etiqueta tu espacio de nombres con las etiquetas de inyección predeterminadas. De lo contrario, usa la etiqueta de revisión del plano de control que hayas instalado. La etiqueta de revisión que añadas también depende de si has implementado Cloud Service Mesh gestionado o has instalado el plano de control en el clúster.

      Selecciona la pestaña que corresponda a tu tipo de instalación (gestionada o en el clúster).

      gestionados

      Usa el siguiente comando para localizar las revisiones disponibles del plano de control:

      kubectl -n istio-system get controlplanerevision
      

      El resultado debería ser similar al siguiente:

      NAME          RECONCILED   STALLED   AGE
      asm-managed   True         False     112m
      

      Anota el valor de la columna NAME de la revisión del plano de control que quieras usar. Normalmente, el canal de lanzamiento de Cloud Service Mesh se corresponde con el canal de lanzamiento de tu clúster de Google Kubernetes Engine.

      En el clúster

      En el caso de los planos de control en el clúster, istiod Service y Deployment suelen tener una etiqueta de revisión similar a istio.io/rev=, donde identifica la versión de Cloud Service Mesh. La revisión pasa a formar parte del istiodnombre del servicioistiod-.istio-system. Por ejemplo: istiod-.istio-system

      Usa el siguiente comando para localizar la etiqueta de revisión en istiod del plano de control en el clúster:

      kubectl get deploy -n istio-system -l app=istiod \
        -o=jsonpath='{.items[*].metadata.labels.istio\.io\/rev}''{"\n"}'
      
    3. Opcional: Etiqueta el espacio de nombres para que la configuración de la pasarela se inserte automáticamente. Basta con etiquetar el espacio de nombres o la implementación. En este tutorial, etiquetarás ambos para evitar las advertencias de la herramienta istioctl analyze.

      kubectl label namespace istio-egress istio.io/rev=REVISION
      
    4. Crea un manifiesto de operador para la pasarela de salida:

      cat << EOF > egressgateway-operator.yaml
      apiVersion: install.istio.io/v1alpha1
      kind: IstioOperator
      metadata:
        name: egressgateway-operator
        annotations:
          config.kubernetes.io/local-config: "true"
      spec:
        profile: empty
        revision: REVISION
        components:
          egressGateways:
          - name: istio-egressgateway
            namespace: istio-egress
            enabled: true
        values:
          gateways:
            istio-egressgateway:
              injectionTemplate: gateway
              tolerations:
                - key: "dedicated"
                  operator: "Equal"
                  value: "gateway"
              nodeSelector:
                cloud.google.com/gke-nodepool: "gateway"
      EOF
      
    5. Descarga la istioctlherramienta. Debes usar la versión 1.16.2-asm.2 o una posterior, aunque utilices Cloud Service Mesh 1.15 o una versión anterior. Consulta Descargar la versión de istioctl correcta.

    6. Después de extraer el archivo descargado, define una variable de entorno para que contenga la ruta a la herramienta istioctl y añádela a tu script de inicialización:

      ISTIOCTL=$(find "$(pwd -P)" -name istioctl)
      echo "ISTIOCTL=\"${ISTIOCTL}\"" >> ./init-egress-tutorial.sh
      
    7. Crea el manifiesto de instalación de la pasarela de salida con el manifiesto del operador y istioctl:

      ${ISTIOCTL} manifest generate \
          --filename egressgateway-operator.yaml \
          --output egressgateway \
          --cluster-specific
      
    8. Instala la pasarela de salida:

      kubectl apply --recursive --filename egressgateway/
      
    9. Comprueba que la pasarela de salida se esté ejecutando en los nodos del grupo de nodos gateway:

      kubectl get pods -n istio-egress -o wide
      
    10. Los pods de la pasarela de salida tienen affinity para los nodos del grupo de nodos gateway y una tolerancia que les permite ejecutarse en los nodos de pasarela contaminados. Examina la afinidad de nodos y las tolerancias de los pods de la pasarela de salida:

      kubectl -n istio-egress get pod -l istio=egressgateway \
          -o=custom-columns='name:metadata.name,node-affinity:spec.affinity.nodeAffinity.requiredDuringSchedulingIgnoredDuringExecution.nodeSelectorTerms,tolerations:spec.tolerations[?(@.key=="dedicated")]'
      

      El resultado debería ser similar al siguiente:

      name                                   node-affinity                                                                                   tolerations
      istio-egressgateway-754d9684d5-jjkdz   [map[matchExpressions:[map[key:cloud.google.com/gke-nodepool operator:In values:[gateway]]]]]   map[key:dedicated operator:Equal value:gateway]
      

    Habilitar el registro de acceso de Envoy

    Los pasos necesarios para habilitar los registros de acceso de Envoy dependen del tipo de Cloud Service Mesh, ya sea gestionado o en el clúster:

    Preparar la malla y una aplicación de prueba

    1. Asegúrate de que el protocolo TLS mutuo estricto esté habilitado. Aplica una política predeterminada PeerAuthentication a la malla en el espacio de nombres istio-system:

      cat <<EOF | kubectl apply -f -
      apiVersion: "security.istio.io/v1beta1"
      kind: "PeerAuthentication"
      metadata:
        name: "default"
        namespace: "istio-system"
      spec:
        mtls:
          mode: STRICT
      EOF
      

      Puedes anular esta configuración creando recursos PeerAuthentication en espacios de nombres específicos.

    2. Crea espacios de nombres para desplegar cargas de trabajo de prueba. En los pasos posteriores de este tutorial se explica cómo configurar diferentes reglas de enrutamiento de salida para cada espacio de nombres.

      kubectl create namespace team-x
      kubectl create namespace team-y
      
    3. Etiqueta los espacios de nombres para que las políticas de red de Kubernetes puedan seleccionarlos:

      kubectl label namespace team-x team=x
      kubectl label namespace team-y team=y
      
    4. Para que Cloud Service Mesh inserte automáticamente los sidecars proxy, debes definir la etiqueta de revisión del plano de control en los espacios de nombres de las cargas de trabajo:

      kubectl label ns team-x istio.io/rev=REVISION
      kubectl label ns team-y istio.io/rev=REVISION
      
    5. Crea un archivo YAML para hacer implementaciones de prueba:

      cat << 'EOF' > ./test.yaml
      apiVersion: v1
      kind: ServiceAccount
      metadata:
        name: test
      ---
      apiVersion: v1
      kind: Service
      metadata:
        name: test
        labels:
          app: test
      spec:
        ports:
        - port: 80
          name: http
        selector:
          app: test
      ---
      apiVersion: apps/v1
      kind: Deployment
      metadata:
        name: test
      spec:
        replicas: 1
        selector:
          matchLabels:
            app: test
        template:
          metadata:
            labels:
              app: test
          spec:
            serviceAccountName: test
            containers:
            - name: test
              image: gcr.io/google.com/cloudsdktool/cloud-sdk:slim
              command: ["/bin/sleep", "infinity"]
              imagePullPolicy: IfNotPresent
      EOF
      
    6. Despliega la aplicación de prueba en el espacio de nombres team-x:

      kubectl -n team-x create -f ./test.yaml
      
    7. Verifica que la aplicación de prueba se haya desplegado en un nodo del grupo predeterminado y que se haya insertado un contenedor sidecar proxy. Repite el siguiente comando hasta que el estado del pod sea Running:

      kubectl -n team-x get po -l app=test -o wide
      

      El resultado debería ser similar al siguiente:

      NAME                   READY   STATUS    RESTARTS   AGE   IP          NODE                                      NOMINATED NODE   READINESS GATES
      test-d5bdf6f4f-9nxfv   2/2     Running   0          19h   10.1.1.25   gke-cluster1-default-pool-f6c7a51f-wbzj
      

      2 de 2 contenedores están Running. Un contenedor es la aplicación de prueba y el otro es el sidecar proxy.

      El pod se está ejecutando en un nodo del grupo de nodos predeterminado.

    8. Verifica que no se puede hacer una solicitud HTTP desde el contenedor de prueba a un sitio externo:

      kubectl -n team-x exec -it \
          $(kubectl -n team-x get pod -l app=test -o jsonpath={.items..metadata.name}) \
          -c test -- curl -v http://example.com
      

      Se genera un mensaje de error del proxy sidecar porque la regla de cortafuegos global-deny-egress-all deniega la conexión upstream.

    Usar el recurso Sidecar para restringir el ámbito de la configuración del proxy de sidecar

    Puedes usar el recurso Sidecar para restringir el ámbito del receptor de salida configurado para los proxies de Sidecar. Para reducir el exceso de configuración y el uso de memoria, es recomendable aplicar un recurso Sidecar predeterminado a cada espacio de nombres.

    El proxy que ejecuta Cloud Service Mesh en el sidecar es Envoy. En la terminología de Envoy, un cluster es un grupo de puntos finales upstream lógicamente similar que se usa como destino para el balanceo de carga.

    1. Inspecciona los clústeres de salida configurados en el proxy adicional de Envoy del pod de prueba ejecutando el comando istioctl proxy-config:

      ${ISTIOCTL} pc c $(kubectl -n team-x get pod -l app=test \
          -o jsonpath={.items..metadata.name}).team-x --direction outbound
      

      Hay aproximadamente 11 clústeres de Envoy en la lista, incluidos algunos de la pasarela de salida.

    2. Restringe la configuración del proxy a las rutas de salida que se hayan definido explícitamente con entradas de servicio en los espacios de nombres de salida y team-x. Aplica un recurso Sidecar al espacio de nombres team-x:

      cat <<EOF | kubectl apply -f -
      apiVersion: networking.istio.io/v1beta1
      kind: Sidecar
      metadata:
        name: default
        namespace: team-x
      spec:
        outboundTrafficPolicy:
          mode: REGISTRY_ONLY
        egress:
        - hosts:
          - 'istio-egress/*'
          - 'team-x/*'
      EOF
      

      Si se define el modo de política de tráfico saliente como REGISTRY_ONLY, la configuración del proxy solo incluirá aquellos hosts externos que se hayan añadido explícitamente al registro de servicios de la malla mediante la definición de entradas de servicio.

      Al definir egress.hosts, se especifica que el proxy sidecar solo selecciona rutas del espacio de nombres de salida que se ponen a disposición mediante el atributo exportTo. La parte "team-x/*" incluye las rutas que se han configurado localmente en el espacio de nombres team-x.

    3. Consulta los clústeres salientes configurados en el proxy sidecar de Envoy y compáralos con la lista de clústeres que se configuraron antes de aplicar el recurso Sidecar:

      ${ISTIOCTL} pc c $(kubectl -n team-x get pod -l app=test \
          -o jsonpath={.items..metadata.name}).team-x --direction outbound
      

      Verás clústeres para la puerta de enlace de salida y otro para el propio pod de prueba.

    Configurar Cloud Service Mesh para enrutar el tráfico a través de la pasarela de salida

    1. Configura un Gateway para el tráfico HTTP en el puerto 80. Gateway selecciona el proxy de la pasarela de salida que has implementado en el espacio de nombres de salida. La configuración de Gateway se aplica al espacio de nombres de salida y gestiona el tráfico de cualquier host.

      cat <<EOF | kubectl apply -f -
      apiVersion: networking.istio.io/v1beta1
      kind: Gateway
      metadata:
        name: egress-gateway
        namespace: istio-egress
      spec:
        selector:
          istio: egressgateway
        servers:
        - port:
            number: 80
            name: https
            protocol: HTTPS
          hosts:
            - '*'
          tls:
            mode: ISTIO_MUTUAL
      EOF
      
    2. Crea un DestinationRule para la pasarela de salida con TLS mutuo para la autenticación y el cifrado. Usa una sola regla de destino compartida para todos los hosts externos.

      cat <<EOF | kubectl apply -f -
      apiVersion: networking.istio.io/v1beta1
      kind: DestinationRule
      metadata:
        name: target-egress-gateway
        namespace: istio-egress
      spec:
        host: istio-egressgateway.istio-egress.svc.cluster.local
        subsets:
        - name: target-egress-gateway-mTLS
          trafficPolicy:
            tls:
              mode: ISTIO_MUTUAL
      EOF
      
    3. Crea un ServiceEntry en el espacio de nombres de salida para registrar explícitamente example.com en el registro de servicios de la malla para el espacio de nombres team-x:

      cat <<EOF | kubectl apply -f -
      apiVersion: networking.istio.io/v1beta1
      kind: ServiceEntry
      metadata:
        name: example-com-ext
        namespace: istio-egress
        labels:
          # Show this service and its telemetry in the Cloud Service Mesh page of the Google Cloud console
          service.istio.io/canonical-name: example.com
      spec:
        hosts:
        - example.com
        ports:
        - number: 80
          name: http
          protocol: HTTP
        - number: 443
          name: tls
          protocol: TLS
        resolution: DNS
        location: MESH_EXTERNAL
        exportTo:
        - 'team-x'
        - 'istio-egress'
      EOF
      
    4. Crea un VirtualService para enrutar el tráfico a example.com a través de la pasarela de salida. Hay dos condiciones de coincidencia: la primera dirige el tráfico a la pasarela de salida y la segunda dirige el tráfico de la pasarela de salida al host de destino. La propiedad exportTo controla qué espacios de nombres pueden usar el servicio virtual.

      cat <<EOF | kubectl apply -f -
      apiVersion: networking.istio.io/v1beta1
      kind: VirtualService
      metadata:
        name: example-com-through-egress-gateway
        namespace: istio-egress
      spec:
        hosts:
        - example.com
        gateways:
        - istio-egress/egress-gateway
        - mesh
        http:
        - match:
          - gateways:
            - mesh
            port: 80
          route:
          - destination:
              host: istio-egressgateway.istio-egress.svc.cluster.local
              subset: target-egress-gateway-mTLS
              port:
                number: 80
            weight: 100
        - match:
          - gateways:
            - istio-egress/egress-gateway
            port: 80
          route:
          - destination:
              host: example.com
              port:
                number: 80
            weight: 100
        exportTo:
        - 'istio-egress'
        - 'team-x'
      EOF
      
    5. Ejecuta istioctl analyze para comprobar si hay errores de configuración:

      ${ISTIOCTL} analyze -n istio-egress --revision REVISION
      

      El resultado debería ser similar al siguiente:

      ✔ No validation issues found when analyzing namespace: istio-egress.
      
    6. Envía varias solicitudes a través de la pasarela de salida al sitio externo:

      for i in {1..4}
      do
          kubectl -n team-x exec -it $(kubectl -n team-x get pod -l app=test \
              -o jsonpath={.items..metadata.name}) -c test -- \
          curl -s -o /dev/null -w "%{http_code}\n" http://example.com
      done
      

      Verás códigos de estado 200 para las cuatro respuestas.

    7. Comprueba que las solicitudes se hayan dirigido a través de la pasarela de salida consultando los registros de acceso del proxy. Primero, comprueba el registro de acceso del sidecar proxy desplegado con la aplicación de prueba:

      kubectl -n team-x logs -f $(kubectl -n team-x get pod -l app=test \
          -o jsonpath={.items..metadata.name}) istio-proxy
      

      Por cada solicitud que envíes, verás una entrada de registro similar a la siguiente:

      [2020-09-14T17:37:08.045Z] "HEAD / HTTP/1.1" 200 - "-" "-" 0 0 5 4 "-" "curl/7.67.0" "d57ea5ad-90e9-46d9-8b55-8e6e404a8f9b" "example.com" "10.1.4.12:8080" outbound|80||istio-egressgateway.istio-egress.svc.cluster.local 10.1.0.17:42140 93.184.216.34:80 10.1.0.17:60326 - -
      
    8. También puedes consultar el registro de acceso de la pasarela de salida:

      kubectl -n istio-egress logs -f $(kubectl -n istio-egress get pod -l istio=egressgateway \
          -o jsonpath="{.items[0].metadata.name}") istio-proxy
      

      Por cada solicitud que envíes, verás una entrada de registro de acceso de la pasarela de salida similar a la siguiente:

      [2020-09-14T17:37:08.045Z] "HEAD / HTTP/2" 200 - "-" "-" 0 0 4 3 "10.1.0.17" "curl/7.67.0" "095711e6-64ef-4de0-983e-59158e3c55e7" "example.com" "93.184.216.34:80" outbound|80||example.com 10.1.4.12:37636 10.1.4.12:8080 10.1.0.17:44404 outbound_.80_.target-egress-gateway-mTLS_.istio-egressgateway.istio-egress.svc.cluster.local -
      

    Configurar un enrutamiento diferente para un segundo espacio de nombres

    Configura el enrutamiento de un segundo host externo para saber cómo se puede configurar la conectividad externa para diferentes equipos.

    1. Crea un recurso Sidecar para el espacio de nombres team-y:

      cat <<EOF | kubectl apply -f -
      apiVersion: networking.istio.io/v1beta1
      kind: Sidecar
      metadata:
        name: default
        namespace: team-y
      spec:
        outboundTrafficPolicy:
          mode: REGISTRY_ONLY
        egress:
        - hosts:
          - 'istio-egress/*'
          - 'team-y/*'
      EOF
      
    2. Despliega la aplicación de prueba en el espacio de nombres team-y:

      kubectl -n team-y create -f ./test.yaml
      
    3. Registra un segundo host externo y expórtalo a los espacios de nombres team-x y team-y:

      cat <<EOF | kubectl apply -f -
      apiVersion: networking.istio.io/v1beta1
      kind: ServiceEntry
      metadata:
        name: httpbin-org-ext
        namespace: istio-egress
        labels:
          # Show this service and its telemetry in the Cloud Service Mesh page of the Google Cloud console
          service.istio.io/canonical-name: httpbin.org
      spec:
        hosts:
        - httpbin.org
        ports:
        - number: 80
          name: http
          protocol: HTTP
        - number: 443
          name: tls
          protocol: TLS
        resolution: DNS
        location: MESH_EXTERNAL
        exportTo:
        - 'istio-egress'
        - 'team-x'
        - 'team-y'
      EOF
      
    4. Crea un servicio virtual para enrutar el tráfico a httpbin.org a través de la pasarela de salida:

      cat <<EOF | kubectl apply -f -
      apiVersion: networking.istio.io/v1beta1
      kind: VirtualService
      metadata:
        name: httpbin-org-through-egress-gateway
        namespace: istio-egress
      spec:
        hosts:
        - httpbin.org
        gateways:
        - istio-egress/egress-gateway
        - mesh
        http:
        - match:
          - gateways:
            - mesh
            port: 80
          route:
          - destination:
              host: istio-egressgateway.istio-egress.svc.cluster.local
              subset: target-egress-gateway-mTLS
              port:
                number: 80
            weight: 100
        - match:
          - gateways:
            - istio-egress/egress-gateway
            port: 80
          route:
          - destination:
              host: httpbin.org
              port:
                number: 80
            weight: 100
        exportTo:
        - 'istio-egress'
        - 'team-x'
        - 'team-y'
      EOF
      
    5. Ejecuta istioctl analyze para comprobar si hay errores de configuración:

      ${ISTIOCTL} analyze -n istio-egress --revision REVISION
      

      Incluyen la siguiente información:

      ✔ No validation issues found when analyzing namespace: istio-egress.
      
    6. Envía una solicitud a httpbin.org desde la aplicación de prueba team-y:

      kubectl -n team-y exec -it $(kubectl -n team-y get pod -l app=test -o \
          jsonpath={.items..metadata.name}) -c test -- curl -I http://httpbin.org
      

      Verás una respuesta 200 OK.

    7. También puedes hacer una solicitud a httpbin.org desde la team-x aplicación de prueba:

      kubectl -n team-x exec -it $(kubectl -n team-x get pod -l app=test \
          -o jsonpath={.items..metadata.name}) -c test -- curl -I http://httpbin.org
      

      Verás una respuesta 200 OK.

    8. Intenta hacer una solicitud a example.com desde el espacio de nombres team-y:

      kubectl -n team-y exec -it $(kubectl -n team-y get pod -l app=test \
          -o jsonpath={.items..metadata.name}) -c test -- curl -I http://example.com
      

      Se produce un error en la solicitud porque no hay ninguna ruta saliente configurada para el host example.com.

    Usar la política de autorización para tener más control sobre el tráfico

    En este tutorial, las políticas de autorización de la pasarela de salida se crean en el espacio de nombres istio-egress. Puedes configurar el control de acceso basado en roles de Kubernetes para que solo los administradores de red puedan acceder al espacio de nombres istio-egress.

    1. Crea un AuthorizationPolicy para que las aplicaciones del espacio de nombres team-x puedan conectarse a example.com, pero no a otros hosts externos, al enviar solicitudes mediante el puerto 80. El targetPort correspondiente en los pods de la pasarela de salida es 8080.

      cat <<EOF | kubectl apply -f -
      apiVersion: security.istio.io/v1beta1
      kind: AuthorizationPolicy
      metadata:
        name: egress-team-x-to-example-com
        namespace: istio-egress
      spec:
        action: ALLOW
        rules:
          - from:
            - source:
                namespaces:
                - 'team-x'
            to:
            - operation:
                hosts:
                  - 'example.com'
            when:
            - key: destination.port
              values: ["8080"]
      EOF
      
    2. Verifica que puedes enviar una solicitud a example.com desde la aplicación de prueba en el espacio de nombres team-x:

      kubectl -n team-x exec -it $(kubectl -n team-x get pod -l app=test \
          -o jsonpath={.items..metadata.name}) -c test -- curl -I http://example.com
      

      Verás una respuesta 200 OK.

    3. Intenta hacer una solicitud a httpbin.org desde la aplicación de prueba en el espacio de nombres team-x:

      kubectl -n team-x exec -it $(kubectl -n team-x get pod -l app=test \
          -o jsonpath={.items..metadata.name}) -c test -- curl -s -w " %{http_code}\n" \
          http://httpbin.org
      

      La solicitud falla y se muestra un mensaje RBAC: access denied y el código de estado 403 Forbidden. Es posible que tengas que esperar unos segundos, ya que suele haber un breve retraso antes de que se aplique la política de autorización.

    4. Las políticas de autorización proporcionan un control detallado sobre el tráfico que se permite o se deniega. Aplica la siguiente política de autorización para permitir que la aplicación de prueba del espacio de nombres team-y haga solicitudes a httpbin.org mediante una ruta de URL concreta al enviar solicitudes con el puerto 80. El targetPort correspondiente en los pods de la pasarela de salida es 8080.

      cat <<EOF | kubectl apply -f -
      apiVersion: security.istio.io/v1beta1
      kind: AuthorizationPolicy
      metadata:
        name: egress-team-y-to-httpbin-teapot
        namespace: istio-egress
      spec:
        action: ALLOW
        rules:
          - from:
            - source:
                namespaces:
                - 'team-y'
            to:
            - operation:
                hosts:
                - httpbin.org
                paths: ['/status/418']
            when:
            - key: destination.port
              values: ["8080"]
      EOF
      
    5. Intenta conectarte a httpbin.org desde la aplicación de prueba en el espacio de nombres team-y:

      kubectl -n team-y exec -it $(kubectl -n team-y get pod -l app=test \
          -o jsonpath={.items..metadata.name}) -c test -- curl -s -w " %{http_code}\n" \
          http://httpbin.org
      

      La solicitud falla y se muestra un mensaje de RBAC: acceso denegado y un código de estado 403 Forbidden.

    6. Ahora, haz una solicitud a httpbin.org/status/418 desde la misma aplicación:

      kubectl -n team-y exec -it $(kubectl -n team-y get pod -l app=test \
          -o jsonpath={.items..metadata.name}) -c test -- curl http://httpbin.org/status/418
      

      La solicitud se realiza correctamente porque la ruta coincide con el patrón de la política de autorización. El resultado debería ser similar al siguiente:

         -=[ teapot ]=-
            _...._
          .'  _ _ `.
         | ."` ^ `". _,
         \_;`"---"`|//
           |       ;/
           \_     _/
             `"""`
      

    Creación de TLS en la pasarela de salida

    Puede configurar las pasarelas de salida para que upgrade (originen) solicitudes HTTP sin cifrar a TLS o TLS mutuo. Permitir que las aplicaciones hagan solicitudes HTTP sin cifrar tiene varias ventajas cuando se usa con TLS mutuo y origen TLS de Istio. Para obtener más información, consulta la guía de prácticas recomendadas.

    Creación de TLS en la pasarela de salida

    1. Create a DestinationRule. The DestinationRule especifica que la puerta de enlace debe iniciar una conexión TLS con example.com.

      cat <<EOF | kubectl apply -f -
      apiVersion: networking.istio.io/v1beta1
      kind: DestinationRule
      metadata:
        name: example-com-originate-tls
        namespace: istio-egress
      spec:
        host: example.com
        subsets:
          - name: example-com-originate-TLS
            trafficPolicy:
              portLevelSettings:
              - port:
                  number: 443
                tls:
                  mode: SIMPLE
                  sni: example.com
      EOF
      
    2. Actualiza el servicio virtual de example.com para que las solicitudes al puerto 80 de la pasarela se upgraded a TLS en el puerto 443 cuando se envíen al host de destino:

      cat <<EOF | kubectl apply -f -
      apiVersion: networking.istio.io/v1alpha3
      kind: VirtualService
      metadata:
        name: example-com-through-egress-gateway
        namespace: istio-egress
      spec:
        hosts:
        - example.com
        gateways:
        - mesh
        - istio-egress/egress-gateway
        http:
        - match:
          - gateways:
            - mesh
            port: 80
          route:
          - destination:
              host: istio-egressgateway.istio-egress.svc.cluster.local
              subset: target-egress-gateway-mTLS
              port:
                number: 80
        - match:
          - gateways:
            - istio-egress/egress-gateway
            port: 80
          route:
          - destination:
              host: example.com
              port:
                number: 443
              subset: example-com-originate-TLS
            weight: 100
      EOF
      
    3. Haz varias solicitudes a example.com desde la aplicación de prueba en el espacio de nombres team-x:

      for i in {1..4}
      do
          kubectl -n team-x exec -it $(kubectl -n team-x get pod -l app=test \
              -o jsonpath={.items..metadata.name}) -c test -- curl -I http://example.com
      done
      

      Al igual que antes, las solicitudes se completan con respuestas 200 OK.

    4. Consulta el registro de la pasarela de salida para verificar que la pasarela ha enrutado las solicitudes al host de destino mediante conexiones TLS:

      kubectl -n istio-egress logs -f $(kubectl -n istio-egress get pod -l istio=egressgateway \
          -o jsonpath="    {.items[0].metadata.name}") istio-proxy
      

      El resultado debería ser similar al siguiente:

      [2020-09-24T17:58:02.548Z] "HEAD / HTTP/2" 200 - "-" "-" 0 0 6 5 "10.1.1.15" "curl/7.67.0" "83a77acb-d994-424d-83da-dd8eac902dc8" "example.com" "93.184.216.34:443" outbound|443|example-com-originate-TLS|example.com 10.1.4.31:49866 10.1.4.31:8080 10.1.1.15:37334 outbound_.80_.target-egress-gateway-mTLS_.istio-egressgateway.istio-egress.svc.cluster.local -
      

      El sidecar del proxy ha enviado la solicitud a la pasarela mediante el puerto 80 y TLS se ha originado en el puerto 443 para enviar la solicitud al host de destino.

    Transferencia de conexiones HTTPS/TLS

    Es posible que tus aplicaciones ya utilicen conexiones TLS al comunicarse con servicios externos. Puedes configurar la pasarela de salida para que transfiera las conexiones TLS sin descifrarlas.

    tls pass through

    1. Modifica la configuración para que la pasarela de salida use TLS pass-through para las conexiones al puerto 443:

      cat <<EOF | kubectl apply -f -
      apiVersion: networking.istio.io/v1beta1
      kind: Gateway
      metadata:
        name: egress-gateway
        namespace: istio-egress
      spec:
        selector:
          istio: egressgateway
        servers:
        - port:
            number: 80
            name: https
            protocol: HTTPS
          hosts:
            - '*'
          tls:
            mode: ISTIO_MUTUAL
        - port:
            number: 443
            name: tls
            protocol: TLS
          hosts:
          - '*'
          tls:
            mode: PASSTHROUGH
      EOF
      
    2. Actualiza el DestinationRule que apunta a la pasarela de salida para añadir un segundo subconjunto para el puerto 443 en la pasarela. Este nuevo subconjunto no usa TLS mutuo. Istio no admite TLS mutuo para conexiones TLS de transferencia directa. Las conexiones en el puerto 80 siguen usando mTLS:

      cat <<EOF | kubectl apply -f -
      apiVersion: networking.istio.io/v1alpha3
      kind: DestinationRule
      metadata:
        name: target-egress-gateway
        namespace: istio-egress
      spec:
        host: istio-egressgateway.istio-egress.svc.cluster.local
        subsets:
        - name: target-egress-gateway-mTLS
          trafficPolicy:
            portLevelSettings:
            - port:
                number: 80
              tls:
                mode: ISTIO_MUTUAL
        - name: target-egress-gateway-TLS-passthrough
      EOF
      
    3. Actualiza el servicio virtual de example.com para que el tráfico TLS del puerto 443 pase por la pasarela:

      cat <<EOF | kubectl apply -f -
      apiVersion: networking.istio.io/v1alpha3
      kind: VirtualService
      metadata:
        name: example-com-through-egress-gateway
        namespace: istio-egress
      spec:
        hosts:
        - example.com
        gateways:
        - mesh
        - istio-egress/egress-gateway
        http:
        - match:
          - gateways:
            - mesh
            port: 80
          route:
          - destination:
              host: istio-egressgateway.istio-egress.svc.cluster.local
              subset: target-egress-gateway-mTLS
              port:
                number: 80
        - match:
          - gateways:
            - istio-egress/egress-gateway
            port: 80
          route:
          - destination:
              host: example.com
              port:
                number: 443
              subset: example-com-originate-TLS
            weight: 100
        tls:
        - match:
          - gateways:
            - mesh
            port: 443
            sniHosts:
            - example.com
          route:
          - destination:
              host: istio-egressgateway.istio-egress.svc.cluster.local
              subset: target-egress-gateway-TLS-passthrough
              port:
                number: 443
        - match:
          - gateways:
            - istio-egress/egress-gateway
            port: 443
            sniHosts:
            - example.com
          route:
          - destination:
              host: example.com
              port:
                number: 443
            weight: 100
        exportTo:
        - 'istio-egress'
        - 'team-x'
      EOF
      
    4. Actualiza el servicio virtual de httpbin.org para que el tráfico TLS del puerto 443 pase por la puerta de enlace:

      cat <<EOF | kubectl apply -f -
      apiVersion: networking.istio.io/v1beta1
      kind: VirtualService
      metadata:
        name: httpbin-org-through-egress-gateway
        namespace: istio-egress
      spec:
        hosts:
        - httpbin.org
        gateways:
        - istio-egress/egress-gateway
        - mesh
        http:
        - match:
          - gateways:
            - mesh
            port: 80
          route:
          - destination:
              host: istio-egressgateway.istio-egress.svc.cluster.local
              subset: target-egress-gateway-mTLS
              port:
                number: 80
            weight: 100
        - match:
          - gateways:
            - istio-egress/egress-gateway
            port: 80
          route:
          - destination:
              host: httpbin.org
              port:
                number: 80
            weight: 100
        tls:
        - match:
          - gateways:
            - mesh
            port: 443
            sniHosts:
            - httpbin.org
          route:
          - destination:
              host: istio-egressgateway.istio-egress.svc.cluster.local
              subset: target-egress-gateway-TLS-passthrough
              port:
                number: 443
        - match:
          - gateways:
            - istio-egress/egress-gateway
            port: 443
            sniHosts:
            - httpbin.org
          route:
          - destination:
              host: httpbin.org
              port:
                number: 443
            weight: 100
        exportTo:
        - 'istio-egress'
        - 'team-x'
        - 'team-y'
      EOF
      
    5. Añade una política de autorización que acepte cualquier tipo de tráfico enviado al puerto 443 del servicio de pasarela de salida. El targetPort correspondiente en los pods de la pasarela es 8443.

      cat <<EOF | kubectl apply -f -
      apiVersion: security.istio.io/v1beta1
      kind: AuthorizationPolicy
      metadata:
        name: egress-all-443
        namespace: istio-egress
      spec:
        action: ALLOW
        rules:
          - when:
            - key: destination.port
              values: ["8443"]
      EOF
      
    6. Ejecuta istioctl analyze para comprobar si hay errores de configuración:

      ${ISTIOCTL} analyze -n istio-egress --revision REVISION
      

      Incluyen la siguiente información:

      ✔ No validation issues found when analyzing namespace: istio-egress.
      
    7. Envía una solicitud HTTP simple a example.com desde la aplicación de prueba en el espacio de nombres team-x:

      kubectl -n team-x exec -it $(kubectl -n team-x get pod -l app=test \
          -o jsonpath={.items..metadata.name}) -c test -- curl -I http://example.com
      

      La solicitud se realiza correctamente y se devuelve una respuesta 200 OK.

    8. Ahora, haz varias solicitudes TLS (HTTPS) desde la aplicación de prueba en el espacio de nombres team-x:

      for i in {1..4}
      do
          kubectl -n team-x exec -it $(kubectl -n team-x get pod -l app=test \
              -o jsonpath={.items..metadata.name}) -c test -- curl -s -o /dev/null \
              -w "%{http_code}\n" \
              https://example.com
      done
      

      Ves respuestas 200.

    9. Vuelve a consultar el registro de la pasarela de salida:

      kubectl -n istio-egress logs -f $(kubectl -n istio-egress get pod -l istio=egressgateway \
          -o jsonpath="{.items[0].metadata.name}") istio-proxy
      

      Verá entradas de registro similares a las siguientes:

      [2020-09-24T18:04:38.608Z] "- - -" 0 - "-" "-" 1363 5539 10 - "-" "-" "-" "-" "93.184.216.34:443" outbound|443||example.com 10.1.4.31:51098 10.1.4.31:8443 10.1.1.15:57030 example.com -
      

      La solicitud HTTPS se ha tratado como tráfico TCP y se ha enviado a través de la pasarela al host de destino, por lo que no se incluye información HTTP en el registro.

    Usar NetworkPolicy de Kubernetes como control adicional

    Hay muchos casos en los que una aplicación puede saltarse un proxy sidecar. Puedes usar NetworkPolicy de Kubernetes para especificar qué conexiones pueden establecer las cargas de trabajo. Una vez que se aplica una política de red única, se deniegan todas las conexiones que no se hayan permitido específicamente.

    En este tutorial solo se tienen en cuenta las conexiones de salida y los selectores de salida de las políticas de red. Si controlas el tráfico de entrada con políticas de red en tus propios clústeres, debes crear políticas de entrada que se correspondan con tus políticas de salida. Por ejemplo, si permites el tráfico saliente de las cargas de trabajo del espacio de nombres team-x al espacio de nombres team-y, también debes permitir el tráfico entrante al espacio de nombres team-y desde el espacio de nombres team-x.

    1. Permite que las cargas de trabajo y los proxies implementados en el espacio de nombres team-x se conecten a istiod y a la pasarela de salida:

      cat <<EOF | kubectl apply -f -
      apiVersion: networking.k8s.io/v1
      kind: NetworkPolicy
      metadata:
        name: allow-egress-to-control-plane
        namespace: team-x
      spec:
        podSelector: {}
        policyTypes:
          - Egress
        egress:
        - to:
          - namespaceSelector:
              matchLabels:
                "kubernetes.io/metadata.name": istio-system
            podSelector:
              matchLabels:
                istio: istiod
          - namespaceSelector:
              matchLabels:
                "kubernetes.io/metadata.name": istio-egress
            podSelector:
              matchLabels:
                istio: egressgateway
      EOF
      
    2. Permite que las cargas de trabajo y los proxies consulten el DNS:

      cat <<EOF | kubectl apply -f -
      apiVersion: networking.k8s.io/v1
      kind: NetworkPolicy
      metadata:
        name: allow-egress-to-dns
        namespace: team-x
      spec:
        podSelector: {}
        policyTypes:
          - Egress
        egress:
        - to:
          - namespaceSelector:
              matchLabels:
                "kubernetes.io/metadata.name": kube-system
          ports:
          - port: 53
            protocol: UDP
          - port: 53
            protocol: TCP
      EOF
      
    3. Permite que las cargas de trabajo y los proxies se conecten a las IPs que sirven las APIs y los servicios de Google, incluida la autoridad de certificación de Cloud Service Mesh:

      cat <<EOF | kubectl apply -f -
      apiVersion: networking.k8s.io/v1
      kind: NetworkPolicy
      metadata:
        name: allow-egress-to-google-apis
        namespace: team-x
      spec:
        podSelector: {}
        policyTypes:
          - Egress
        egress:
        - to:
          - ipBlock:
              cidr: 199.36.153.4/30
          - ipBlock:
              cidr: 199.36.153.8/30
      EOF
      
    4. Permite que las cargas de trabajo y los proxies se conecten al servidor de metadatos de GKE:

      cat <<EOF | kubectl apply -f -
      apiVersion: networking.k8s.io/v1
      kind: NetworkPolicy
      metadata:
        name: allow-egress-to-metadata-server
        namespace: team-x
      spec:
        podSelector: {}
        policyTypes:
          - Egress
        egress:
        - to: # For GKE data plane v2
          - ipBlock:
              cidr: 169.254.169.254/32
        - to: # For GKE data plane v1
          - ipBlock:
              cidr: 127.0.0.1/32 # Prior to 1.21.0-gke.1000
          - ipBlock:
              cidr: 169.254.169.252/32 # 1.21.0-gke.1000 and later
          ports:
          - protocol: TCP
            port: 987
          - protocol: TCP
            port: 988
      EOF
      
    5. Opcional: Permite que las cargas de trabajo y los proxies del espacio de nombres team-x se conecten entre sí:

      cat <<EOF | kubectl apply -f -
      apiVersion: networking.k8s.io/v1
      kind: NetworkPolicy
      metadata:
        name: allow-egress-to-same-namespace
        namespace: team-x
      spec:
        podSelector: {}
        ingress:
          - from:
            - podSelector: {}
        egress:
          - to:
            - podSelector: {}
      EOF
      
    6. Opcional: Permite que las cargas de trabajo y los proxies del espacio de nombres team-x se conecten a cargas de trabajo implementadas por otro equipo:

      cat <<EOF | kubectl apply -f -
      apiVersion: networking.k8s.io/v1
      kind: NetworkPolicy
      metadata:
        name: allow-egress-to-team-y
        namespace: team-x
      spec:
        podSelector: {}
        policyTypes:
          - Egress
        egress:
        - to:
          - namespaceSelector:
              matchLabels:
                "kubernetes.io/metadata.name": team-y
      EOF
      
    7. Las conexiones entre los proxies de sidecar persisten. Las conexiones existentes no se cierran cuando aplicas una nueva política de red. Reinicia las cargas de trabajo en el espacio de nombres team-x para asegurarte de que se cierren las conexiones existentes:

      kubectl -n team-x rollout restart deployment
      
    8. Verifica que sigues pudiendo enviar una solicitud HTTP a example.com desde la aplicación de prueba en el espacio de nombres team-x:

      kubectl -n team-x exec -it $(kubectl -n team-x get pod -l app=test \
          -o jsonpath={.items..metadata.name}) -c test -- curl -I http://example.com
      

      La solicitud se realiza correctamente y se devuelve una respuesta 200 OK.

    Acceder directamente a las APIs de Google mediante Acceso privado de Google y permisos de gestión de identidades y accesos

    Las APIs y los servicios de Google se exponen mediante direcciones IP externas. Cuando los pods con direcciones IP de alias nativas de VPC se conectan a las APIs de Google mediante el Acceso privado de Google, el tráfico nunca sale de la red de Google.

    Cuando configuraste la infraestructura para este tutorial, habilitaste el acceso privado a Google para la subred que usan los pods de GKE. Para permitir el acceso a las direcciones IP que usa el acceso privado de Google, has creado una ruta, una regla de cortafuegos de VPC y una zona DNS privada. Esta configuración permite que los pods accedan directamente a las APIs de Google sin enviar tráfico a través de la pasarela de salida. Puedes controlar qué APIs están disponibles para determinadas cuentas de servicio de Kubernetes (y, por lo tanto, para determinados espacios de nombres) mediante Workload Identity Federation para GKE y IAM. La autorización de Istio no tiene efecto porque la puerta de enlace de salida no gestiona las conexiones con las APIs de Google.

    Para que los pods puedan llamar a las APIs de Google, debes usar IAM para conceder permisos. El clúster que vas a usar en este tutorial está configurado para usar la federación de Workload Identity para GKE, que permite que una cuenta de servicio de Kubernetes actúe como cuenta de servicio de Google.

    1. Crea una cuenta de servicio de Google para que la use tu aplicación:

      gcloud iam service-accounts create sa-test-app-team-x
      
    2. Permite que la cuenta de servicio de Kubernetes suplante la identidad de la cuenta de servicio de Google:

      gcloud iam service-accounts add-iam-policy-binding \
        --role roles/iam.workloadIdentityUser \
        --member "serviceAccount:${PROJECT_ID}.svc.id.goog[team-x/test]" \
        sa-test-app-team-x@${PROJECT_ID}.iam.gserviceaccount.com
      
    3. Anota la cuenta de servicio de Kubernetes de la aplicación de prueba en el espacio de nombres team-x con la dirección de correo de la cuenta de servicio de Google:

      cat <<EOF | kubectl apply -f -
      apiVersion: v1
      kind: ServiceAccount
      metadata:
        annotations:
          iam.gke.io/gcp-service-account: sa-test-app-team-x@${PROJECT_ID}.iam.gserviceaccount.com
        name: test
        namespace: team-x
      EOF
      
    4. El pod de la aplicación de prueba debe poder acceder al servidor de metadatos de Google (que se ejecuta como un DaemonSet) para obtener credenciales temporales para llamar a las APIs de Google. Crea una entrada de servicio para el servidor de metadatos de GKE:

      cat <<EOF | kubectl apply -f -
      apiVersion: networking.istio.io/v1beta1
      kind: ServiceEntry
      metadata:
        name: metadata-google-internal
        namespace: istio-egress
        labels:
          # Show this service and its telemetry in the Cloud Service Mesh page of the Google Cloud console
          service.istio.io/canonical-name: metadata.google.internal
      spec:
        hosts:
        - metadata.google.internal
        ports:
        - number: 80
          name: http
          protocol: HTTP
        - number: 443
          name: tls
          protocol: TLS
        resolution: DNS
        location: MESH_EXTERNAL
        exportTo:
        - 'istio-egress'
        - 'team-x'
      EOF
      
    5. Crea también una entrada de servicio para private.googleapis.com y storage.googleapis.com:

      cat <<EOF | kubectl apply -f -
      apiVersion: networking.istio.io/v1beta1
      kind: ServiceEntry
      metadata:
        name: private-googleapis-com
        namespace: istio-egress
        labels:
          # Show this service and its telemetry in the Cloud Service Mesh page of the Google Cloud console
          service.istio.io/canonical-name: googleapis.com
      spec:
        hosts:
        - private.googleapis.com
        - storage.googleapis.com
        ports:
        - number: 80
          name: http
          protocol: HTTP
        - number: 443
          name: tls
          protocol: TLS
        resolution: DNS
        location: MESH_EXTERNAL
        exportTo:
        - 'istio-egress'
        - 'team-x'
      EOF
      
    6. Verifica que la cuenta de servicio de Kubernetes esté configurada correctamente para actuar como cuenta de servicio de Google:

      kubectl -n team-x exec -it $(kubectl -n team-x get pod -l app=test \
          -o jsonpath={.items..metadata.name}) -c test -- gcloud auth list
      

      Verás la cuenta de servicio de Google como la única identidad activa.

    7. Crea un archivo de prueba en un segmento de Cloud Storage:

      echo "Hello, World!" > /tmp/hello
      gcloud storage buckets create gs://${PROJECT_ID}-bucket
      gcloud storage cp /tmp/hello gs://${PROJECT_ID}-bucket/
      
    8. Concede permiso a la cuenta de servicio para enumerar y ver archivos del segmento:

      gcloud storage buckets add-iam-policy-binding gs://${PROJECT_ID}-bucket/ \
          --member=serviceAccount:sa-test-app-team-x@${PROJECT_ID}.iam.gserviceaccount.com \
          --role=roles/storage.objectViewer
      
    9. Verifica que la aplicación de prueba pueda acceder al contenedor de prueba:

      kubectl -n team-x exec -it \
      $(kubectl -n team-x get pod -l app=test -o jsonpath={.items..metadata.name}) \
      -c test \
      -- gcloud storage cat gs://${PROJECT_ID}-bucket/hello
      

      Incluyen la siguiente información:

      Hello, World!
      

    Limpieza

    Para evitar que los recursos utilizados en este tutorial se cobren en tu cuenta de Google Cloud, elimina el proyecto que contiene los recursos o conserva el proyecto y elimina los recursos.

    Para evitar que se apliquen cargos en tu cuenta de Google Cloud por los recursos utilizados en este tutorial, sigue los pasos que se indican en las siguientes secciones:

    Eliminar el proyecto

    La forma más fácil de evitar que te cobren es eliminar el proyecto que has creado para el tutorial.

    1. In the Google Cloud console, go to the Manage resources page.

      Go to Manage resources

    2. In the project list, select the project that you want to delete, and then click Delete.
    3. In the dialog, type the project ID, and then click Shut down to delete the project.

    Siguientes pasos