Del perímetro a la malla: Exposición de aplicaciones de la malla de servicios a través de Ingress de GKE

Last reviewed 2022-09-29 UTC

En este instructivo, se muestra cómo combinar Anthos Service Mesh con Cloud Load Balancing para exponer aplicaciones en una malla de servicios a los clientes de Internet.

Anthos Service Mesh es una malla de servicios administrada, basada en Istio, que proporciona una capa de comunicación estandarizada, observable y más segura para aplicaciones. Ya sea que uses Anthos Service Mesh, Traffic Director o Istio, una malla de servicios proporciona una plataforma de comunicación integral para clientes que se comunican en la malla. Sin embargo, conectar los clientes que están fuera de la malla a las aplicaciones alojadas en ella sigue siendo un desafío.

Puedes exponer una aplicación a los clientes de muchas maneras, según la ubicación en que estos se encuentren. En este instructivo, se muestra cómo exponer una aplicación a los clientes mediante la combinación de Cloud Load Balancing y Anthos Service Mesh para integrar balanceadores de cargas en una malla de servicios. Este instructivo está dirigido a profesionales avanzados que ejecutan Anthos Service Mesh, pero también funciona para Istio en Google Kubernetes Engine.

Puerta de enlace de entrada de la malla

En Istio 0.8, se agregó la puerta de enlace de entrada de la malla, que proporciona un conjunto exclusivo de proxies cuyos puertos están expuestos al tráfico que proviene del exterior de la malla de servicios. Gracias a estos proxies de entrada de la malla, puedes controlar por separado el comportamiento de exposición de L4 y el comportamiento de enrutamiento de la aplicación. Los proxies también te permiten aplicar enrutamiento y políticas al tráfico externo a la malla antes de que llegue a un proxy de sidecar de la aplicación. La entrada de la malla define el tratamiento del tráfico cuando llega a un nodo en la malla, pero los componentes externos deben definir cómo llega el tráfico primero a la malla.

Para administrar este tráfico externo, necesitas un balanceador de cargas externo a la malla. En este instructivo, se usa Google Cloud Load Balancing aprovisionado a través de recursos de Ingress de GKE para automatizar la implementación. El ejemplo canónico de esta configuración es un servicio de balanceo de cargas externo que (en el caso de Google Cloud) implementa un balanceador de cargas de TCP/UDP público. Ese balanceador de cargas apunta a los NodePorts de un clúster de GKE. Estos NodePorts exponen los Pods de puerta de enlace de entrada de Istio, que enrutan el tráfico a los proxies de sidecar de la malla descendente. En el siguiente diagrama, se ilustra esta topología. El balanceo de cargas para el tráfico privado interno se parece a esta arquitectura, excepto que implementas un balanceador de cargas de TCP/UDP interno en su lugar.

Un balanceador de cargas externo enruta los clientes externos a la malla a través de proxies de puerta de enlace de entrada.

El uso del balanceo de cargas transparente de L4 con una puerta de enlace de entrada de la malla ofrece las siguientes ventajas:

  • Esta configuración simplifica la implementación del balanceador de cargas.
  • El balanceador de cargas proporciona una IP virtual estable (VIP), verificación de estado y distribución de tráfico confiable cuando se producen cambios en el clúster, interrupciones del nodo o interrupciones de procesos.
  • Todas las reglas de enrutamiento, la terminación de TLS y la política de tráfico se manejan en una sola ubicación en la puerta de enlace de entrada de la malla.

Ingress y servicios de GKE

Puedes proporcionar acceso a las aplicaciones a los clientes que se encuentran fuera del clúster de muchas maneras. En la siguiente tabla, se enumeran los componentes fundamentales de Kubernetes disponibles para implementar balanceadores de cargas en Google Cloud. El tipo de balanceador de cargas que usas para exponer las aplicaciones a los clientes depende en gran medida de si los clientes son externos o internos, qué tipo de asistencia de protocolo se requiere y si la malla de servicios abarca varios clústeres de GKE o si está en un solo clúster.

Todos los tipos de balanceadores de cargas de la siguiente tabla pueden exponer las aplicaciones alojadas en la malla, según el caso de uso.

Recurso de GKE Balanceador de cargas basado en la nube Características
Ingress para balanceadores de cargas HTTP(S) externos Balanceador de cargas HTTP(S) externo

Proxies de L7 en puntos de presencia perimetrales (PoP) de Google

VIP pública

Con alcance mundial

Un solo clúster

Ingress para balanceadores de cargas HTTP(S) internos Balanceador de cargas HTTP(S) interno

Proxies de L7 dentro de la red de nube privada virtual (VPC)

VIP privada

Con alcance regional

Un solo clúster

Servicio de LoadBalancer externo Balanceador de cargas de red

Transferencia de L4 en los PoP perimetrales de Google

VIP pública

Con alcance regional

Un solo clúster

Service de LoadBalancer interno Balanceadores de cargas de TCP/UDP internos

Transferencia de L4 en la red de enrutamiento de VPC

VIP privada

Con alcance regional

Un solo clúster

Ingress de varios clústeres (ingress externa de varios clústeres) Balanceador de cargas HTTP(S) externo

Proxies de L7 en los PoP perimetrales de Google

VIP pública

Con alcance mundial

Varios clústeres

Aunque el balanceador de cargas predeterminado para Anthos Service Mesh es el balanceador de cargas de TCP/UDP externo, en este instructivo, nos enfocamos en el balanceador de cargas de HTTP(S) externo. El balanceador de cargas de HTTP(S) externo proporciona integración en servicios perimetrales como Identity-Aware Proxy (IAP), Google Cloud Armor y Cloud CDN, así como una red distribuida global de proxies perimetrales. En la siguiente sección, se describe la arquitectura y las ventajas de usar dos capas de balanceo de cargas de HTTP.

Entrada de la nube y entrada de la malla

La implementación del balanceo de cargas de L7 externo fuera de la malla, junto con una capa de entrada de la malla, ofrece ventajas significativas, en especial para el tráfico de Internet. Aunque las puertas de enlace de entrada de Anthos Service Mesh y de Istio proporcionan enrutamiento avanzado y administración del tráfico en la malla, algunas funciones se entregan mejor en el perímetro de la red. Aprovechar las herramientas de redes del perímetro de Internet a través del balanceador de cargas de HTTP(S) externo de Google Cloud puede proporcionar importantes beneficios de rendimiento, confiabilidad o seguridad en la entrada basada en la malla. Los beneficios son los siguientes:

Esta capa externa de balanceo de cargas de L7 se denomina entrada de la nube porque se compila en balanceadores de cargas administrados en la nube, y no en los proxies autoadministrados que usa la entrada de la malla. En la combinación de la entrada de la nube y de la malla, se usan funciones complementarias de la infraestructura de Google Cloud y la malla. En el siguiente diagrama, se muestra cómo puedes combinar la entrada de la nube y la entrada de la malla a fin de que funcionen como dos capas de balanceo de cargas para el tráfico de Internet.

La entrada de la nube actúa como puerta de enlace para el tráfico externo que ingresa a la malla a través de la red de VPC.

En esta topología, la capa de entrada de la nube origina el tráfico desde el exterior de la malla de servicios y lo dirige a la capa de entrada de la malla. Luego, la capa de entrada de la malla dirige el tráfico a los backends de aplicaciones alojadas en la malla.

Topología de la entrada de la nube y de la malla

En esta sección, se describen las funciones complementarias que cada capa de entrada cumple cuando se usan juntas. Estas funciones no son reglas concretas, sino lineamientos en los que se usan las ventajas de cada capa. Es probable que haya variaciones de este patrón, según tu caso de uso.

  • Entrada de la nube. Cuando se combina con la entrada de la malla, es más conveniente usar la capa de entrada de la nube para la seguridad perimetral y el balanceo de cargas global. Debido a que la capa de entrada de la nube está integrada en la protección contra DSD, los firewalls en la nube, la autenticación y los productos de encriptación en el perímetro, esta capa tiene un gran rendimiento en la ejecución de estos servicios fuera de la malla. La lógica de enrutamiento suele ser sencilla en esta capa, pero la lógica puede ser más compleja para entornos de varios clústeres y multirregionales. Debido a la función crítica de los balanceadores de cargas orientados a Internet, es probable que la capa de entrada de la nube se administre mediante un equipo de infraestructura que tenga un control exclusivo sobre cómo se exponen y protegen las aplicaciones en Internet. Este control también hace que esta capa sea menos flexible y dinámica que una infraestructura controlada por desarrolladores, una consideración que puede afectar a quién y cómo se proporciona acceso administrativo a esta capa.
  • Entrada de la malla. Cuando se combina con la entrada de la nube, la capa de entrada de la malla proporciona enrutamiento flexible cerca de la aplicación. Debido a esta flexibilidad, la entrada de la malla es mejor que la de la nube para una lógica de enrutamiento compleja y la visibilidad a nivel de la aplicación. La separación entre las capas de entrada también facilita a los propietarios de la aplicación el control directo de esta capa sin afectar a otros equipos. Cuando expones aplicaciones de la malla de servicios a través de un balanceador de cargas de L4 en lugar de un balanceador de cargas de L7, debes finalizar la TLS del cliente en la capa de entrada de la malla dentro de la malla para proteger las aplicaciones.

Verificaciones de estado

Una dificultad del uso de dos capas de balanceo de cargas de L7 es la verificación de estado. Debes configurar cada balanceador de cargas para verificar el estado de la siguiente capa a fin de garantizar que pueda recibir tráfico. En la topología del siguiente diagrama, se muestra cómo la entrada de la nube verifica el estado de los proxies de entrada de la malla, y la malla, a su vez, verifica el estado de los backends de la aplicación.

La entrada de la nube verifica el estado de la entrada de la malla, y la entrada de la malla verifica el estado de los backends de la aplicación.

Esta topología tiene las siguientes consideraciones:

  • Entrada de la nube. En este instructivo, debes configurar el balanceador de cargas de Google Cloud a través de la entrada para verificar el estado de los proxies de entrada de la malla en sus puertos de verificación de estado expuestos. Si un proxy de la malla no funciona o si el clúster, la malla o la región no están disponibles, el balanceador de cargas de Google Cloud detecta esta condición y no envía tráfico al proxy de la malla.
  • Entrada de la malla. En la aplicación de la malla, debes realizar verificaciones de estado directamente en los backends, de modo que puedas ejecutar el balanceo de cargas y la administración de tráfico de forma local.

Seguridad

En la topología anterior, se incluyen varios elementos de seguridad. Uno de los elementos más importantes es la forma en que configuras la encriptación y la implementación de certificados. Ingress para balanceadores de cargas de HTTP(S) externos tiene una integración profunda en certificados administrados por Google. Esta integración aprovisiona de forma automática los certificados públicos, los adjunta a un balanceador de cargas y los renueva y los rota a través de la interfaz declarativa de Ingress de GKE. Los clientes de Internet se autentican con los certificados públicos y se conectan al balanceador de cargas externo como el primer salto en la nube privada virtual (VPC).

El siguiente salto, que está entre Google Front End (GFE) y el proxy de entrada de la malla, está encriptado de forma predeterminada. La encriptación a nivel de la red entre GFE y sus backends se aplica de forma automática. Sin embargo, si tus requisitos de seguridad determinan que el propietario de la plataforma retiene la propiedad de las claves de encriptación, puedes habilitar HTTP/2 con encriptación TLS entre la entrada del clúster (GFE) y la entrada de la malla (la instancia del proxy de Envoy). Cuando habilitas HTTP/2 con encriptación TLS para esta ruta, puedes usar un certificado autofirmado o público a fin de encriptar el tráfico, ya que GFE no se autentica con él. Esta capa adicional de encriptación se demuestra en esta guía. A fin de evitar el manejo inadecuado de certificados, no uses el certificado público para el balanceador de cargas público en otro lugar. En cambio, te recomendamos que uses otros certificados en la malla de servicios.

Si la malla de servicios exige TLS, todo el tráfico se encripta entre proxies de sidecar y la entrada de la malla. En el siguiente diagrama, se ilustra la encriptación HTTPS del cliente al balanceador de cargas de Google Cloud, del balanceador de cargas al proxy de entrada de la malla y del proxy de entrada al proxy de sidecar.

La seguridad se implementa mediante certificados administrados ubicados fuera de la malla y certificados internos dentro de la malla.

Objetivos

  • Implementar un clúster de Google Kubernetes Engine (GKE) en Google Cloud
  • Implementar Anthos Service Mesh basada en Istio en el clúster de GKE
  • Configurar Ingress de GKE para finalizar el tráfico de HTTPS público y dirigir ese tráfico a las aplicaciones alojadas en la malla de servicios
  • Implementar la aplicación Online Boutique en el clúster de GKE que expones a los clientes en Internet

Costos

En este documento, usarás los siguientes componentes facturables de Google Cloud:

Para generar una estimación de costos en función del uso previsto, usa la calculadora de precios. Es posible que los usuarios nuevos de Google Cloud califiquen para obtener una prueba gratuita.

Cuando finalices las tareas que se describen en este documento, puedes borrar los recursos que creaste para evitar que continúe la facturación. Para obtener más información, consulta Cómo realizar una limpieza.

Antes de comenzar

  1. En la página del selector de proyectos de la consola de Google Cloud, selecciona o crea un proyecto de Google Cloud.

    Ir al selector de proyectos

  2. Asegúrate de que la facturación esté habilitada para tu proyecto de Google Cloud.

  3. En la consola de Google Cloud, activa Cloud Shell.

    Activar Cloud Shell

    Ejecuta todos los comandos de terminal de este instructivo desde Cloud Shell.

  4. Actualiza a la versión más reciente de Google Cloud CLI:

    gcloud components update
    
  5. Configura un proyecto predeterminado de Google Cloud:

    export PROJECT=PROJECT
    export PROJECT_NUMBER=$(gcloud projects describe ${PROJECT} --format="value(projectNumber)")
    gcloud config set project ${PROJECT}
    

    Reemplaza PROJECT por el ID del proyecto que deseas usar para este instructivo.

  6. Cree un directorio de trabajo:

    mkdir -p ${HOME}/edge-to-mesh
    cd ${HOME}/edge-to-mesh
    export WORKDIR=`pwd`
    

    Cuando termines el instructivo, puedes borrar el directorio de trabajo.

Crea clústeres de GKE

Las funciones que se describen en este instructivo requieren una versión 1.16 o posterior del clúster de GKE.

  1. En Cloud Shell, crea un archivo kubeconfig nuevo. Con este paso te aseguras de no causar un conflicto con el archivo kubeconfig (predeterminado) existente.

    touch edge2mesh_kubeconfig
    export KUBECONFIG=${WORKDIR}/edge2mesh_kubeconfig
    
  2. Define las variables de entorno para el clúster de GKE:

    export CLUSTER_NAME=edge-to-mesh
    export CLUSTER_LOCATION=us-west1-a
    
  3. Habilita la API de Google Kubernetes Engine.

    gcloud

    gcloud services enable container.googleapis.com
    

    Config Connector

    En este instructivo, se incluyen recursos de Config Connector. Puedes usar estos recursos para completar las mismas tareas que completas en la pestaña gcloud. Para usar estos recursos, instala Config Connector y aplica los recursos de la manera que mejor se adapte a tu entorno.

    Usa el siguiente manifiesto Services:

    apiVersion: serviceusage.cnrm.cloud.google.com/v1beta1
    kind: Service
    metadata:
      annotations:
        cnrm.cloud.google.com/deletion-policy: "abandon"
        cnrm.cloud.google.com/disable-dependent-services: "false"
      name: container.googleapis.com
    spec:
      resourceID: container.googleapis.com
      projectRef:
        external: PROJECT
    
  4. Crear un clúster de GKE

    gcloud

    gcloud container clusters create ${CLUSTER_NAME} \
        --machine-type=e2-standard-4 \
        --num-nodes=4 \
        --zone ${CLUSTER_LOCATION} \
        --enable-ip-alias \
        --workload-pool=${PROJECT}.svc.id.goog \
        --release-channel rapid \
        --addons HttpLoadBalancing \
        --labels mesh_id=proj-${PROJECT_NUMBER}
    

    Config Connector

    Usa los siguientes manifiestos ContainerCluster y ContainerNodePool:

    apiVersion: container.cnrm.cloud.google.com/v1beta1
    kind: ContainerNodePool
    metadata:
      annotations:
        cnrm.cloud.google.com/project-id: PROJECT
      name: edge-to-mesh
    spec:
      clusterRef:
        name: edge-to-mesh
      location: us-west1-a
      nodeConfig:
        machineType: e2-standard-4
      nodeCount: 4
    ---
    apiVersion: container.cnrm.cloud.google.com/v1beta1
    kind: ContainerCluster
    metadata:
      annotations:
        cnrm.cloud.google.com/project-id: PROJECT
        cnrm.cloud.google.com/remove-default-node-pool: "true"
      labels:
        mesh_id: proj-PROJECT_NUMBER
      name: edge-to-mesh
    spec:
      addonsConfig:
        httpLoadBalancing:
          disabled: false
      location: us-west1-a
      initialNodeCount: 1
      releaseChannel:
        channel: RAPID
      workloadIdentityConfig:
        workloadPool: PROJECT.svc.id.goog
    

    Reemplaza PROJECT_NUMBER por el valor de la variable de entorno PROJECT_NUMBER que recuperaste antes.

    Para usar una entrada de la nube, debes tener habilitado el complemento de balanceo de cargas de HTTP. Los clústeres de GKE tienen habilitado el balanceo de cargas de HTTP de forma predeterminada; no debes inhabilitarlo.

    Para usar Anthos Service Mesh administrado, debes aplicar la etiqueta mesh_id en el clúster.

  5. Asegúrate de que el clúster esté en ejecución:

    gcloud container clusters list
    

    El resultado es similar a este:

    NAME          LOCATION    MASTER_VERSION    MASTER_IP      MACHINE_TYPE   NODE_VERSION      NUM_NODES  STATUS
    edge-to-mesh  us-west1-a  v1.22.6-gke.300   35.233.195.59  e2-standard-4  v1.22.6-gke.300   4          RUNNING
    
  6. Conéctese al clúster:

    gcloud container clusters get-credentials ${CLUSTER_NAME} \
        --zone ${CLUSTER_LOCATION} \
        --project ${PROJECT}
    

Instala una malla de servicios

En esta sección, debes configurar Anthos Service Mesh administrado con la API de Fleet.

  1. Habilite las API necesarias:

    gcloud

    gcloud services enable mesh.googleapis.com
    

    Config Connector

    Usa el siguiente manifiesto Services:

    apiVersion: serviceusage.cnrm.cloud.google.com/v1beta1
    kind: Service
    metadata:
      annotations:
        cnrm.cloud.google.com/deletion-policy: "abandon"
        cnrm.cloud.google.com/disable-dependent-services: "false"
      name: mesh.googleapis.com
    spec:
      resourceID: mesh.googleapis.com
      projectRef:
        external: PROJECT
    
  2. Habilita Anthos Service Mesh en la flota:

    gcloud

    gcloud container fleet mesh enable
    

    Config Connector

    Usa el siguiente manifiesto GKEHubFeature:

    apiVersion: gkehub.cnrm.cloud.google.com/v1beta1
    kind: GKEHubFeature
    metadata:
      name: servicemesh
    spec:
      projectRef:
        external: PROJECT
      location: global
      resourceID: servicemesh
    
  3. Registra el clúster en la flota:

    gcloud

    gcloud container fleet memberships register ${CLUSTER_NAME} \
        --gke-cluster ${CLUSTER_LOCATION}/${CLUSTER_NAME} \
        --enable-workload-identity
    

    Config Connector

    Usa el siguiente manifiesto GKEHubMembership:

    apiVersion: gkehub.cnrm.cloud.google.com/v1beta1
    kind: GKEHubMembership
    metadata:
      annotations:
        cnrm.cloud.google.com/project-id: PROJECT
      name: edge-to-mesh
    spec:
      location: global
      authority:
        issuer: https://container.googleapis.com/v1/projects/PROJECT/locations/us-west1-a/clusters/edge-to-mesh
      endpoint:
        gkeCluster:
          resourceRef:
            name: edge-to-mesh
    
  4. Habilita la administración automática del plano de control y el plano de datos administrados:

    gcloud

    gcloud container fleet mesh update \
        --management automatic \
        --memberships ${CLUSTER_NAME}
    

    Config Connector

    Usa el siguiente manifiesto GKEHubFeatureMembership:

    apiVersion: gkehub.cnrm.cloud.google.com/v1beta1
    kind: GKEHubFeatureMembership
    metadata:
      name: servicemesh-membership
    spec:
      projectRef:
        external: PROJECT_ID
      location: global
      membershipRef:
        name: edge-to-mesh
      featureRef:
        name: servicemesh
      mesh:
        management: MANAGEMENT_AUTOMATIC
    
  5. Después de unos minutos, verifica que el estado del plano de control sea ACTIVE:

    gcloud container fleet mesh describe
    

    El resultado es similar a este:

    ...
    membershipSpecs:
      projects/841956571429/locations/global/memberships/edge-to-mesh:
        mesh:
          management: MANAGEMENT_AUTOMATIC
    membershipStates:
      projects/841956571429/locations/global/memberships/edge-to-mesh:
        servicemesh:
          controlPlaneManagement:
            details:
            - code: REVISION_READY
              details: 'Ready: asm-managed-rapid'
            state: ACTIVE
          dataPlaneManagement:
            details:
            - code: OK
              details: Service is running.
            state: ACTIVE
        state:
          code: OK
          description: 'Revision(s) ready for use: asm-managed-rapid.'
          updateTime: '2022-09-29T05:30:28.320896186Z'
    name: projects/your-project/locations/global/features/servicemesh
    resourceState:
      state: ACTIVE
    ...
    

Implementa Ingress de GKE

En los siguientes pasos, debes implementar el balanceador de cargas de HTTP(S) externo a través del controlador de Ingress de GKE. El recurso Ingress automatiza el aprovisionamiento del balanceador de cargas, sus certificados TLS y la verificación de estado del backend. Además, debes usar Cloud Endpoints a fin de aprovisionar de forma automática un nombre de DNS público para la aplicación.

Instala una puerta de enlace de entrada

Como práctica recomendada de seguridad, te recomendamos que implementes la puerta de enlace de entrada en un espacio de nombres diferente en el plano de control.

  1. En Cloud Shell, crea un espacio de nombres asm-ingress dedicado:

    kubectl create namespace asm-ingress
    
  2. Agrega una etiqueta de espacio de nombres al espacio de nombres asm-ingress:

    kubectl label namespace asm-ingress istio-injection=enabled
    

    El resultado es similar a este:

    namespace/asm-ingress labeled
    

    Si etiquetas el espacio de nombres asm-ingress con istio-injection=enabled, se indica a Anthos Service Mesh que inserte de manera automática proxies de sidecar de Envoy cuando se implementa una aplicación.

  3. Ejecuta el siguiente comando para crear el manifiesto Deployment como ingress-deployment.yaml:

    cat <<EOF > ingress-deployment.yaml
    apiVersion: apps/v1
    kind: Deployment
    metadata:
      name: asm-ingressgateway
      namespace: asm-ingress
    spec:
      selector:
        matchLabels:
          asm: ingressgateway
      template:
        metadata:
          annotations:
            # This is required to tell Anthos Service Mesh to inject the gateway with the
            # required configuration.
            inject.istio.io/templates: gateway
          labels:
            asm: ingressgateway
        spec:
          securityContext:
            fsGroup: 1337
            runAsGroup: 1337
            runAsNonRoot: true
            runAsUser: 1337
          containers:
          - name: istio-proxy
            securityContext:
              allowPrivilegeEscalation: false
              capabilities:
                drop:
                - all
              privileged: false
              readOnlyRootFilesystem: true
            image: auto # The image will automatically update each time the pod starts.
            resources:
              limits:
                cpu: 2000m
                memory: 1024Mi
              requests:
                cpu: 100m
                memory: 128Mi
          serviceAccountName: asm-ingressgateway
    ---
    apiVersion: autoscaling/v2
    kind: HorizontalPodAutoscaler
    metadata:
      name: asm-ingressgateway
      namespace: asm-ingress
    spec:
      maxReplicas: 5
      minReplicas: 3
      metrics:
      - type: Resource
        resource:
          name: cpu
          target:
            type: Utilization
            averageUtilization: 50
      scaleTargetRef:
        apiVersion: apps/v1
        kind: Deployment
        name: asm-ingressgateway
    ---
    apiVersion: rbac.authorization.k8s.io/v1
    kind: Role
    metadata:
      name: asm-ingressgateway
      namespace: asm-ingress
    rules:
    - apiGroups: [""]
      resources: ["secrets"]
      verbs: ["get", "watch", "list"]
    ---
    apiVersion: rbac.authorization.k8s.io/v1
    kind: RoleBinding
    metadata:
      name: asm-ingressgateway
      namespace: asm-ingress
    roleRef:
      apiGroup: rbac.authorization.k8s.io
      kind: Role
      name: asm-ingressgateway
    subjects:
      - kind: ServiceAccount
        name: asm-ingressgateway
    ---
    apiVersion: v1
    kind: ServiceAccount
    metadata:
      name: asm-ingressgateway
      namespace: asm-ingress
    EOF
    

    Este Deployment tiene su propio ServiceAccount con Role y RoleBinding asociados, lo que permite que la puerta de enlace acceda a los certificados.

  4. Implementa ingress-deployment.yaml en el clúster para crear el recurso Deployment:

    kubectl apply -f ingress-deployment.yaml
    

    El resultado es similar a este:

    deployment.apps/asm-ingressgateway configured
    role.rbac.authorization.k8s.io/asm-ingressgateway configured
    rolebinding.rbac.authorization.k8s.io/asm-ingressgateway configured
    serviceaccount/asm-ingressgateway created
    

    Asegúrate de que todas las implementaciones estén en funcionamiento:

    kubectl wait --for=condition=available --timeout=600s deployment --all -n asm-ingress
    

    El resultado es similar a este:

    deployment.apps/asm-ingressgateway condition met
    
  5. Ejecuta el siguiente comando para crear el manifiesto Service como ingress-service.yaml:

    cat <<EOF > ingress-service.yaml
    apiVersion: v1
    kind: Service
    metadata:
      name: asm-ingressgateway
      namespace: asm-ingress
      annotations:
        cloud.google.com/neg: '{"ingress": true}'
        cloud.google.com/backend-config: '{"default": "ingress-backendconfig"}'
        cloud.google.com/app-protocols: '{"https":"HTTP2"}' # HTTP/2 with TLS encryption
      labels:
        asm: ingressgateway
    spec:
      ports:
      # status-port exposes a /healthz/ready endpoint that can be used with GKE Ingress health checks
      - name: status-port
        port: 15021
        protocol: TCP
        targetPort: 15021
      # Any ports exposed in Gateway resources should be exposed here.
      - name: http2
        port: 80
        targetPort: 8080
      - name: https
        port: 443
        targetPort: 8443
      selector:
        asm: ingressgateway
      type: ClusterIP
    EOF
    

    Este Service incluye las siguientes anotaciones que establecen parámetros para el balanceador de cargas de Ingress cuando se implementa:

    • cloud.google.com/backend-config hace referencia al nombre de un recurso personalizado llamado BackendConfig. El controlador de Ingress usa BackendConfig para configurar parámetros en el recurso BackendService de Google Cloud. Usa este recurso en el próximo paso para definir los parámetros personalizados de la verificación de estado de Google Cloud.
    • cloud.google.com/neg: '{"ingress": true}' habilita los backends de Ingress (en este caso, los proxies de entrada de la malla) para el balanceo de cargas nativo del contenedor. Para obtener un balanceo de cargas más eficiente y estable, estos backends usan grupos de extremos de red (NEG) en lugar de grupos de instancias.
    • cloud.google.com/app-protocols: '{"https":"HTTP2"}' indica a GFE que se conecte a la puerta de enlace de entrada de la malla de servicios mediante HTTP2 con TLS, como se describe en Ingress para balanceo de cargas de HTTP(S) externo y Descripción general del balanceo de cargas de HTTP(S) externo para obtener una capa adicional de encriptación.
  6. Implementa ingress-service.yaml en el clúster para crear el recurso Service:

    kubectl apply -f ingress-service.yaml
    

    El resultado es similar a este:

    service/asm-ingressgateway created
    

Aplica la configuración del Service de backend

  1. En Cloud Shell, ejecuta el siguiente comando para crear el manifiesto BackendConfig como ingress-backendconfig.yaml:

    cat <<EOF > ingress-backendconfig.yaml
    apiVersion: cloud.google.com/v1
    kind: BackendConfig
    metadata:
      name: ingress-backendconfig
      namespace: asm-ingress
    spec:
      healthCheck:
        requestPath: /healthz/ready
        port: 15021
        type: HTTP
      securityPolicy:
        name: edge-fw-policy
    EOF
    

    BackendConfig es una definición de recurso personalizado (CRD) que define parámetros de backend para el balanceo de cargas de Ingress. Para obtener una lista completa de los parámetros de backend y frontend que puedes configurar a través de Ingress de GKE, consulta Características de Ingress.

    En este instructivo, se especifican verificaciones de estado personalizadas para los proxies de entrada de la malla en el manifiesto BackendConfig. Istio y Anthos Service Mesh exponen sus verificaciones de estado del proxy de sidecar en el puerto 15021 de la ruta /healthz/ready. Los parámetros de verificación de estado personalizados son obligatorios porque el puerto de entrega (443) de los proxies de entrada de la malla es diferente del puerto de verificación de estado (15021). Ingress de GKE usa los siguientes parámetros de verificación de estado en BackendConfig para configurar las verificaciones de estado del balanceador de cargas de Google Cloud. También se hace referencia a una política de seguridad que ayuda a proteger el tráfico de balanceo de cargas de diferentes tipos de ataques de red.

    • healthCheck.port define el puerto que recibe una verificación de estado según el balanceador de cargas de Google Cloud en la dirección IP de cada Pod.
    • healthCheck.requestPath define la ruta de acceso HTTP que recibe una verificación de estado en el puerto especificado.
    • type define el protocolo de la verificación de estado (en este caso, HTTP).
    • securityPolicy.name hace referencia al nombre de una política de seguridad de Cloud Armor.
  2. Implementa ingress-backendconfig.yaml en el clúster para crear el recurso BackendConfig:

    kubectl apply -f ingress-backendconfig.yaml
    

    El resultado es similar a este:

    backendconfig.cloud.google.com/ingress-backendconfig created
    

    Los parámetros BackendConfig y las anotaciones del Service asm-ingressgateway no se aplican a un balanceador de cargas de Google Cloud hasta que se implementa el recurso Ingress. La implementación de Ingress vincula todos estos recursos.

Define políticas de seguridad

Google Cloud Armor proporciona defensa contra DSD y políticas de seguridad personalizables que puedes adjuntar a un balanceador de cargas a través de los recursos de Ingress. En los siguientes pasos, crearás una política de seguridad que usa reglas preconfiguradas para bloquear ataques de secuencias de comandos entre sitios (XSS). Esta regla ayuda a bloquear el tráfico que coincide con las firmas de ataques conocidas, pero permite el resto del tráfico. En tu entorno se pueden usar reglas diferentes; esto depende de tu carga de trabajo.

gcloud

  1. En Cloud Shell, crea una política de seguridad llamada edge-fw-policy:

    gcloud compute security-policies create edge-fw-policy \
        --description "Block XSS attacks"
    
  2. Crea una regla de política de seguridad que use los filtros de XSS preconfigurados:

    gcloud compute security-policies rules create 1000 \
        --security-policy edge-fw-policy \
        --expression "evaluatePreconfiguredExpr('xss-stable')" \
        --action "deny-403" \
        --description "XSS attack filtering"
    

Config Connector

Usa el siguiente manifiesto ComputeSecurityPolicy:

apiVersion: compute.cnrm.cloud.google.com/v1beta1
kind: ComputeSecurityPolicy
metadata:
  annotations:
    cnrm.cloud.google.com/project-id: PROJECT_ID
  name: edge-fw-policy
spec:
  rule:
  - action: allow
    description: "Default rule"
    match:
      versionedExpr: SRC_IPS_V1
      config:
        srcIpRanges:
        - "*"
    priority: 2147483647
  - action: deny-403
    description: "XSS attack filtering"
    match:
      expr:
        expression: "evaluatePreconfiguredExpr('xss-stable')"
    priority: 1000

ingress-backendconfig hace referencia a edge-fw-policy en la sección anterior. Cuando se implementa el recurso Ingress, este vincula esta política de seguridad con el balanceador de cargas para ayudar a proteger cualquier backend del Service asm-ingressgateway.

Configura direcciones IP y DNS

  1. En Cloud Shell, crea una IP estática global para el balanceador de cargas de Google Cloud:

    gcloud

    gcloud compute addresses create ingress-ip --global
    

    Config Connector

    Usa el siguiente manifiesto ComputeAddress:

    apiVersion: compute.cnrm.cloud.google.com/v1beta1
    kind: ComputeAddress
    metadata:
      annotations:
        cnrm.cloud.google.com/project-id: PROJECT_ID
      name: ingress-ip
    spec:
      location: global
    

    El recurso Ingress usa esta IP estática, que permite que la IP continúe siendo la misma, incluso si el balanceador de cargas externo cambia.

  2. Obtén la dirección IP estática:

    export GCLB_IP=$(gcloud compute addresses describe ingress-ip --global --format "value(address)")
    echo ${GCLB_IP}
    

    A fin de crear una asignación estable y fácil de usar para la IP de Ingress, debes tener un registro DNS público. Puedes usar el proveedor de DNS y la automatización que desees. En este instructivo, se usa Endpoints en lugar de crear una zona de DNS administrada. Endpoints proporciona un registro DNS administrado por Google gratuito para una IP pública.

  3. Ejecuta el siguiente comando para crear el archivo de especificación YAML llamado dns-spec.yaml:

    cat <<EOF > dns-spec.yaml
    swagger: "2.0"
    info:
      description: "Cloud Endpoints DNS"
      title: "Cloud Endpoints DNS"
      version: "1.0.0"
    paths: {}
    host: "frontend.endpoints.${PROJECT}.cloud.goog"
    x-google-endpoints:
    - name: "frontend.endpoints.${PROJECT}.cloud.goog"
      target: "${GCLB_IP}"
    EOF
    

    La especificación YAML define el registro DNS público en el formato frontend.endpoints.${PROJECT}.cloud.goog, en el que ${PROJECT} es tu número de proyecto único.

  4. Implementa el archivo dns-spec.yaml en tu proyecto de Google Cloud:

    gcloud endpoints services deploy dns-spec.yaml
    

    El resultado es similar a este:

    Operation finished successfully. The following command can describe the Operation details:
     gcloud endpoints operations describe operations/rollouts.frontend.endpoints.edge2mesh.cloud.goog:442b2b38-4aee-4c60-b9fc-28731657ee08
    
    Service Configuration [2021-11-14r0] uploaded for service [frontend.endpoints.edge2mesh.cloud.goog]
    

    Ahora que la IP y el DNS están configurados, puedes generar un certificado público para proteger el frontend de Ingress. Ingress de GKE admite certificados administrados por Google como recursos de Kubernetes, lo que te permite aprovisionarlos a través de medios declarativos.

Aprovisiona un certificado TLS

  1. En Cloud Shell, ejecuta el siguiente comando para crear el manifiesto ManagedCertificate como managed-cert.yaml:

    cat <<EOF > managed-cert.yaml
    apiVersion: networking.gke.io/v1
    kind: ManagedCertificate
    metadata:
      name: gke-ingress-cert
      namespace: asm-ingress
    spec:
      domains:
        - "frontend.endpoints.${PROJECT}.cloud.goog"
    EOF
    

    En este archivo YAML, se especifica que el nombre de DNS creado a través de Endpoints se usa para aprovisionar un certificado público. Como Google administra completamente el ciclo de vida de estos certificados públicos, estos se generan y se rotan de forma automática con regularidad, sin intervención directa del usuario.

  2. Implementa el archivo managed-cert.yaml en el clúster de GKE:

    kubectl apply -f managed-cert.yaml
    

    El resultado es similar a este:

    managedcertificate.networking.gke.io/gke-ingress-cert created
    
  3. Inspecciona el recurso ManagedCertificate para verificar el progreso de la generación del certificado:

    kubectl describe managedcertificate gke-ingress-cert -n asm-ingress
    

    El resultado es similar a este:

    Name:         gke-ingress-cert
    Namespace:    asm-ingress
    Labels:       <none>
    Annotations:  kubectl.kubernetes.io/last-applied-configuration:
                    {"apiVersion":"networking.gke.io/v1","kind":"ManagedCertificate","metadata":{"annotations":{},"name":"gke-ingress-cert","namespace":"...
    API Version:  networking.gke.io/v1
    Kind:         ManagedCertificate
    Metadata:
      Creation Timestamp:  2020-08-05T20:44:49Z
      Generation:          2
      Resource Version:    1389781
      Self Link:           /apis/networking.gke.io/v1/namespaces/asm-ingress/managedcertificates/gke-ingress-cert
      UID:                 d74ec346-ced9-47a8-988a-6e6e9ddc4019
    Spec:
      Domains:
        frontend.endpoints.edge2mesh.cloud.goog
    Status:
      Certificate Name:    mcrt-306c779e-8439-408a-9634-163664ca6ced
      Certificate Status:  Provisioning
      Domain Status:
        Domain:  frontend.endpoints.edge2mesh.cloud.goog
        Status:  Provisioning
    Events:
      Type    Reason  Age   From                            Message
      ----    ------  ----  ----                            -------
      Normal  Create  44s   managed-certificate-controller  Create SslCertificate mcrt-306c779e-8439-408a-9634-163664ca6ced
    

    Cuando el certificado está listo, el Certificate Status aparece como Active.

Implementa el recurso Ingress

  1. En Cloud Shell, ejecuta el siguiente comando para crear el manifiesto Ingress como ingress.yaml:

    cat <<EOF > ingress.yaml
    apiVersion: networking.k8s.io/v1
    kind: Ingress
    metadata:
      name: gke-ingress
      namespace: asm-ingress
      annotations:
        kubernetes.io/ingress.allow-http: "false"
        kubernetes.io/ingress.global-static-ip-name: "ingress-ip"
        networking.gke.io/managed-certificates: "gke-ingress-cert"
        kubernetes.io/ingress.class: "gce"
    spec:
      defaultBackend:
        service:
          name: asm-ingressgateway
          port:
            number: 443
      rules:
      - http:
          paths:
          - path: /*
            pathType: ImplementationSpecific
            backend:
              service:
                name: asm-ingressgateway
                port:
                  number: 443
    EOF
    

    En este manifiesto, se define un recurso Ingress que vincula todos los recursos anteriores. En el manifiesto, se especifican los siguientes campos:

    • kubernetes.io/ingress.allow-http: "false" inhabilita el tráfico de HTTP en el puerto 80 del balanceador de cargas de Google Cloud. Esto evita que los clientes se conecten con tráfico no encriptado, porque el puerto 443 solo escucha HTTPS y el puerto 80 está inhabilitado.
    • kubernetes.io/ingress.global-static-ip-name: "ingress-ip" vincula la dirección IP creada antes con el balanceador de cargas. Este vínculo permite que la dirección IP y el balanceador de cargas se creen por separado, de modo que la IP pueda reutilizarse de manera independiente del ciclo de vida del balanceador de cargas.
    • networking.gke.io/managed-certificates: "gke-ingress-cert" vincula este balanceador de cargas con el recurso de certificado SSL administrado por Google creado antes.
  2. Implementa ingress.yaml en el clúster:

    kubectl apply -f ingress.yaml
    
  3. Inspecciona el recurso Ingress para verificar el progreso de la implementación del balanceador de cargas:

    kubectl describe ingress gke-ingress -n asm-ingress
    

    El resultado es similar a este:

    ...
    Annotations:
      ingress.kubernetes.io/https-forwarding-rule:       k8s2-fs-fq3ng2uk-asm-ingress-gke-ingress-qm3qqdor
      ingress.kubernetes.io/ssl-cert:                    mcrt-306c779e-8439-408a-9634-163664ca6ced
      networking.gke.io/managed-certificates:            gke-ingress-cert
      kubernetes.io/ingress.global-static-ip-name:  ingress-ip
      ingress.gcp.kubernetes.io/pre-shared-cert:    mcrt-306c779e-8439-408a-9634-163664ca6ced
      ingress.kubernetes.io/backends:               {"k8s-be-31610--07bdde06b914144a":"HEALTHY","k8s1-07bdde06-asm-ingress-asm-ingressgateway-443-228c1881":"HEALTHY"}
      ingress.kubernetes.io/forwarding-rule:        k8s2-fr-fq3ng2uk-asm-ingress-gke-ingress-qm3qqdor
      ingress.kubernetes.io/https-target-proxy:     k8s2-ts-fq3ng2uk-asm-ingress-gke-ingress-qm3qqdor
      ingress.kubernetes.io/target-proxy:           k8s2-tp-fq3ng2uk-asm-ingress-gke-ingress-qm3qqdor
      ingress.kubernetes.io/url-map:                k8s2-um-fq3ng2uk-asm-ingress-gke-ingress-qm3qqdor
    ...
    

    El recurso Ingress está listo cuando las anotaciones ingress.kubernetes.io/backends indican que los backends tienen el estado HEALTHY. En las anotaciones, también se muestran los nombres de distintos recursos de Google Cloud que se aprovisionan, incluidos los servicios de backend, los certificados SSL y los proxies de destino HTTPS.

Instala el certificado de puerta de enlace de entrada autofirmado

En los siguientes pasos, generarás e instalarás un certificado (como un recurso secret de Kubernetes) que permite que el GFE establezca una conexión TLS con la puerta de enlace de entrada de la malla de servicios. Para obtener más detalles sobre los requisitos del certificado de puerta de enlace de entrada, consulta la guía de consideraciones del protocolo de backend seguro.

  1. En Cloud Shell, crea la clave privada y el certificado con openssl:

    openssl req -new -newkey rsa:4096 -days 365 -nodes -x509 \
     -subj "/CN=frontend.endpoints.${PROJECT}.cloud.goog/O=Edge2Mesh Inc" \
     -keyout frontend.endpoints.${PROJECT}.cloud.goog.key \
     -out frontend.endpoints.${PROJECT}.cloud.goog.crt
    
  2. Crea el Secret en el espacio de nombres asm-ingress:

    kubectl -n asm-ingress create secret tls edge2mesh-credential \
     --key=frontend.endpoints.${PROJECT}.cloud.goog.key \
     --cert=frontend.endpoints.${PROJECT}.cloud.goog.crt
    

Configura la puerta de enlace de entrada para el balanceo de cargas externo

En los siguientes pasos, crearás un recurso Gateway compartido en el espacio de nombres asm-ingress. Por lo general, las puertas de enlace son propiedad de los administradores de la plataforma o el equipo de administradores de red. Por lo tanto, el recurso Gateway se crea en el espacio de nombres asm-ingress que pertenece al administrador de la plataforma y se puede usar en otros espacios de nombres a través de sus propias entradas VirtualService.

  1. En Cloud Shell, ejecuta el siguiente comando para crear el manifiesto Gateway como ingress-gateway.yaml:

    cat <<EOF > ingress-gateway.yaml
    apiVersion: networking.istio.io/v1alpha3
    kind: Gateway
    metadata:
        name: asm-ingressgateway
        namespace: asm-ingress
    spec:
      selector:
        asm: ingressgateway
      servers:
      - port:
          number: 443
          name: https
          protocol: HTTPS
        hosts:
        - "*" # IMPORTANT: Must use wildcard here when using SSL, see note below
        tls:
          mode: SIMPLE
          credentialName: edge2mesh-credential
    EOF
    

    Ten en cuenta que debes usar la entrada comodín * en el campo hosts en Gateway. GCLB no usa la extensión SNI en los backends. El uso de la entrada comodín envía el paquete encriptado (de GCLB) a la puerta de enlace de entrada de ASM. La puerta de enlace de Ingress de ASM desencripta el paquete y usa el encabezado del host HTTP (en el paquete desencriptado) para tomar decisiones de enrutamiento (basadas en entradas VirtualService).

  2. Implementa ingress-gateway.yaml en el clúster:

    kubectl apply -f ingress-gateway.yaml
    

    El resultado es similar a este:

    gateway.networking.istio.io/asm-ingressgateway created
    

Instala la app de muestra Online Boutique

  1. En Cloud Shell, crea un espacio de nombres onlineboutique dedicado:

    kubectl create namespace onlineboutique
    
  2. Agrega una etiqueta de espacio de nombres al espacio de nombres onlineboutique:

    kubectl label namespace onlineboutique istio-injection=enabled
    

    El resultado es similar a este:

    namespace/onlineboutique labeled
    

    Si etiquetas el espacio de nombres onlineboutique con istio-injection=enabled, se indica a Anthos Service Mesh que inserte de manera automática proxies de sidecar de Envoy cuando se implementa una aplicación.

  3. Descarga los archivos YAML de Kubernetes para la app de muestra Online Boutique:

    curl -LO \
        https://raw.githubusercontent.com/GoogleCloudPlatform/microservices-demo/main/release/kubernetes-manifests.yaml
    
  4. Implementa la app Online Boutique:

    kubectl apply -f kubernetes-manifests.yaml -n onlineboutique
    

    El resultado es similar a este:

    deployment.apps/frontend created
    service/frontend created
    service/frontend-external created
    ...
    
  5. Asegúrate de que todas las implementaciones estén en funcionamiento:

    kubectl get pods -n onlineboutique
    

    El resultado es similar a este:

    NAME                                     READY   STATUS    RESTARTS   AGE
    adservice-d854d8786-fjb7q                2/2     Running   0          3m
    cartservice-85b5d5b4ff-8qn7g             2/2     Running   0          2m59s
    checkoutservice-5f9bf659b8-sxhsq         2/2     Running   0          3m1s
    ...
    
  6. Ejecuta el siguiente comando para crear el manifiesto VirtualService como frontend-virtualservice.yaml:

    cat <<EOF > frontend-virtualservice.yaml
    apiVersion: networking.istio.io/v1alpha3
    kind: VirtualService
    metadata:
      name: frontend-ingress
      namespace: onlineboutique
    spec:
      hosts:
      - "frontend.endpoints.${PROJECT}.cloud.goog"
      gateways:
      - asm-ingress/asm-ingressgateway
      http:
      - route:
        - destination:
            host: frontend
            port:
              number: 80
    EOF
    

    Ten en cuenta que VirtualService se crea en el espacio de nombres de la aplicación (onlineboutique). Por lo general, el propietario de la aplicación decide y configura cómo y qué tráfico se enruta a la aplicación frontend para que el propietario de la app implemente VirtualService.

  7. Implementa frontend-virtualservice.yaml en el clúster:

    kubectl apply -f frontend-virtualservice.yaml
    

    El resultado es similar a este:

    virtualservice.networking.istio.io/frontend-virtualservice created
    
  8. Accede al siguiente vínculo:

    echo "https://frontend.endpoints.${PROJECT}.cloud.goog"
    

    Se mostrará el frontend de Online Boutique.

    Productos que se muestran en la página principal de Online Boutique.

  9. Para ver los detalles del certificado, haz clic en Consulta la información del sitio en la barra de direcciones del navegador y, luego, haz clic en Certificado (Válido).

    En el visualizador de certificados, se muestran los detalles del certificado administrado, incluida la fecha de vencimiento y quién emitió el certificado.

Ahora tienes un balanceador de cargas de HTTPS global que funciona como frontend en tu aplicación alojada en la malla de servicios.

Limpia

Una vez que hayas terminado el instructivo, puedes limpiar los recursos que creaste en Google Cloud para que no se te cobre por ellos en el futuro. Puedes borrar el proyecto por completo o borrar los recursos del clúster y, luego, borrar el clúster.

Borra el proyecto

  1. En la consola de Google Cloud, ve a la página Administrar recursos.

    Ir a Administrar recursos

  2. En la lista de proyectos, elige el proyecto que quieres borrar y haz clic en Borrar.
  3. En el diálogo, escribe el ID del proyecto y, luego, haz clic en Cerrar para borrar el proyecto.

Borra los recursos individuales

Si deseas conservar el proyecto de Google Cloud que usaste en este instructivo, borra los recursos individuales:

  1. Borra el recurso Ingress:

    kubectl delete -f ingress.yaml
    
  2. Borra el certificado administrado:

    kubectl delete -f managed-cert.yaml
    
  3. Borra la entrada de DNS de Endpoints:

    gcloud endpoints services delete "frontend.endpoints.${PROJECT}.cloud.goog"
    

    El resultado es similar a este:

    Are you sure? This will set the service configuration to be deleted, along
    with all of the associated consumer information. Note: This does not
    immediately delete the service configuration or data and can be undone using
    the undelete command for 30 days. Only after 30 days will the service be
    purged from the system.
    
  4. Cuando se te solicite continuar, ingresa Y.

    El resultado es similar a este:

    Waiting for async operation operations/services.frontend.endpoints.edge2mesh.cloud.goog-5 to complete...
    Operation finished successfully. The following command can describe the Operation details:
     gcloud endpoints operations describe operations/services.frontend.endpoints.edge2mesh.cloud.goog-5
    
  5. Borra la dirección IP estática:

    gcloud compute addresses delete ingress-ip --global
    

    El resultado es similar a este:

    The following global addresses will be deleted:
    
     - [ingress-ip]
    
  6. Cuando se te solicite continuar, ingresa Y.

    El resultado es similar a este:

    Deleted
    [https://www.googleapis.com/compute/v1/projects/edge2mesh/global/addresses/ingress-ip].
    
  7. Borra el clúster de GKE:

    gcloud container clusters delete $CLUSTER_NAME --zone $CLUSTER_LOCATION
    

¿Qué sigue?