Configura la seguridad del servicio con gRPC sin proxy

En esta guía, se muestra cómo configurar un servicio de seguridad para una malla de servicios de gRPC sin proxy.

Requisitos

Antes de configurar la seguridad del servicio para la malla de servicios sin proxy de gRPC, asegúrate de cumplir con los siguientes requisitos.

Configura la administración de identidades y accesos

Debes tener los permisos necesarios para usar Google Kubernetes Engine. Como mínimo, debes tener las siguientes funciones:

  • Función roles/container.clusterAdmin de GKE
  • roles/compute.instanceAdmin función de Compute Engine
  • La función roles/iam.serviceAccountUser

A fin de crear los recursos necesarios para la configuración, debes tener la función compute.NetworkAdmin. Esta función contiene todos los permisos necesarios para crear, actualizar, borrar, enumerar y usar (es decir, hacer referencia a esto en otros recursos) los recursos necesarios. Si eres propietario o editor de tu proyecto, automáticamente tienes esta función.

Ten en cuenta que networksecurity.googleapis.com.clientTlsPolicies.use y networksecurity.googleapis.com.serverTlsPolicies.use no se aplican cuando haces referencia a estos recursos en el recurso del servicio de backend.

Si esto se aplica en el futuro y usas la función compute.NetworkAdmin, no notarás ningún problema cuando se aplique esta verificación.

Si usas funciones personalizadas y esta verificación se aplica en el futuro, debes asegurarte de incluir el permiso .use correspondiente. De lo contrario, en el futuro, es posible que tu función personalizada no tenga los permisos necesarios para hacer referencia a clientTlsPolicy o serverTlsPolicy desde el servicio de backend.

Prepárate para la configuración

La seguridad de la malla de servicios sin proxy (PSM) agrega seguridad a una malla de servicios configurada para el balanceo de cargas según la documentación de servicios de gRPC sin proxy. En una malla de servicios sin proxy, un cliente de gRPC usa el esquema xds: en el URI para acceder al servicio, lo que habilita las funciones de balanceo de cargas de PSM y descubrimiento de extremos.

Actualiza los clientes y servidores de gRPC a la versión correcta

Compila o vuelve a compilar tus aplicaciones con la versión mínima de gRPC compatible con tu lenguaje.

Actualiza el archivo de arranque

Las aplicaciones de gRPC usan un solo archivo de arranque, el cual debe tener todos los campos que requiere el código del cliente y el servidor de gRPC. Un generador de arranque genera de forma automática el archivo de arranque para incluir las marcas y los valores que necesita la seguridad de PSM. Para obtener más información, consulta la sección Archivo de arranque, que incluye un archivo de arranque de muestra.

Descripción general de la configuración

Este proceso de configuración es una extensión de la configuración de Cloud Service Mesh con GKE y servicios de gRPC sin proxy. Se hace referencia a los pasos existentes sin modificar de ese procedimiento de configuración cada vez que se aplican.

Las principales mejoras en la configuración de Cloud Service Mesh con GKE son las siguientes:

  1. Configura el servicio de CA, en el que creas grupos de CA privados y las autoridades certificadoras obligatorias.
  2. Crea un clúster de GKE con Workload Identity Federation for GKE y las funciones de certificados de malla, y la integración del servicio de AC.
  3. Configurar la emisión de certificados de malla en el clúster
  4. Crear las cuentas de servicio de cliente y servidor
  5. Configurar el servidor de ejemplo que usa las APIs de xDS y las credenciales del servidor de xDS para obtener la configuración de seguridad de Cloud Service Mesh
  6. Configurar el cliente de ejemplo que usa credenciales de xDS
  7. Actualizar la configuración de Cloud Service Mesh para incluir la configuración de seguridad

Puedes ver ejemplos de códigos para usar credenciales de xDS en las siguientes ubicaciones:

Actualiza la CLI de Google Cloud

Para actualizar la CLI de Google Cloud, ejecuta el siguiente comando:

gcloud components update

Configura variables de entorno

En esta guía, usas los comandos de Cloud Shell, y la información repetida en los comandos se representa con múltiples variables de entorno. Establece tus valores específicos según las siguientes variables de entorno en el entorno de shell antes de ejecutar los comandos. Cada línea de comentario indica el significado de la variable de entorno asociada.

# Your project ID
PROJECT_ID=PROJECT_ID

# GKE cluster name and zone for this example.
CLUSTER_NAME=CLUSTER_NAME
ZONE=ZONE
gcloud config set compute/zone $ZONE

# GKE cluster URL derived from the above
GKE_CLUSTER_URL="https://container.googleapis.com/v1/projects/${PROJECT_ID}/locations/${ZONE}/clusters/${CLUSTER_NAME}"

# Workload pool to be used with the GKE cluster
WORKLOAD_POOL="${PROJECT_ID}.svc.id.goog"

# Kubernetes namespace to run client and server demo.
K8S_NAMESPACE='default'
DEMO_BACKEND_SERVICE_NAME='grpc-gke-helloworld-service'

# Compute other values
# Project number for your project
PROJNUM=$(gcloud projects describe ${PROJECT_ID} --format="value(projectNumber)")

# VERSION is the GKE cluster version. Install and use the most recent version
# from the rapid release channel and substitute its version for
# CLUSTER_VERSION, for example:
# VERSION=latest available version
# Note that the minimum required cluster version is 1.21.4-gke.1801.
VERSION="CLUSTER_VERSION"
SA_GKE=service-${PROJNUM}@container-engine-robot.iam.gserviceaccount.com

Habilita el acceso a las API requeridas

En esta sección, se explica cómo habilitar el acceso a las API necesarias.

  1. Ejecuta el siguiente comando para habilitar Cloud Service Mesh y otras APIs necesarias para la seguridad de la malla de servicios de gRPC sin proxy.

    gcloud services enable \
        container.googleapis.com \
        cloudresourcemanager.googleapis.com \
        compute.googleapis.com \
        trafficdirector.googleapis.com \
        networkservices.googleapis.com \
        networksecurity.googleapis.com \
        privateca.googleapis.com \
        gkehub.googleapis.com
    
  2. Ejecuta el siguiente comando para permitir que la cuenta de servicio predeterminada acceda a la API de seguridad de Cloud Service Mesh.

    GSA_EMAIL=$(gcloud iam service-accounts list --format='value(email)' \
        --filter='displayName:Compute Engine default service account')
    
    gcloud projects add-iam-policy-binding ${PROJECT_ID} \
      --member serviceAccount:${GSA_EMAIL} \
       --role roles/trafficdirector.client
    

Crea o actualiza un clúster de GKE

La seguridad del servicio de Cloud Service Mesh depende de la integración del servicio de AC con GKE. El clúster de GKE debe cumplir con los siguientes requisitos además de los requisitos para la configuración:

  • Usa una versión de clúster mínima de 1.21.4-gke.1801. Si necesitas funciones que se encuentran en una versión posterior, puedes obtenerla del canal de versiones rápido.
  • El clúster de GKE debe estar habilitado y configurado con certificados de malla de trabajo, como se describe en Crea autoridades certificadoras para emitir certificados.
  1. Crea un clúster nuevo que use la federación de identidades para cargas de trabajo para GKE. Si actualizas un clúster existente, avanza al siguiente paso. El valor que proporciones para --tags debe coincidir con el nombre que se pasó a la marca --target-tags del comando firewall-rules create en la sección Configura Cloud Service Mesh con componentes de Cloud Load Balancing.

    # Create a GKE cluster with GKE managed mesh certificates.
    gcloud container clusters create CLUSTER_NAME \
      --release-channel=rapid \
      --scopes=cloud-platform \
      --image-type=cos_containerd \
      --machine-type=e2-standard-2 \
      --zone=ZONE \
      --workload-pool=PROJECT_ID.svc.id.goog \
      --enable-mesh-certificates \
      --cluster-version=CLUSTER_VERSION \
      --enable-ip-alias \
      --tags=allow-health-checks \
      --workload-metadata=GKE_METADATA
    

    La creación del clúster puede tomar varios minutos en completarse.

  2. Si usas un clúster existente, activa la federación de identidades para cargas de trabajo para GKE y los certificados de malla de GKE. Asegúrate de que el clúster se haya creado con la marca --enable-ip-alias, que no se puede usar con el comando update.

    gcloud container clusters update CLUSTER_NAME \
      --enable-mesh-certificates
    
  3. Ejecuta el siguiente comando a fin de cambiar al clúster nuevo como el clúster predeterminado para los comandos de kubectl:

    gcloud container clusters get-credentials CLUSTER_NAME \
      --zone ZONE
    

Registra clústeres con una flota

Registra el clúster que creaste o actualizaste en Crea un clúster de GKE con una flota. El registro del clúster facilita la configuración de clústeres en varios proyectos.

Ten en cuenta que estos pasos pueden demorar hasta diez minutos en completarse.

  1. Registra tu clúster en la flota:

    gcloud container fleet memberships register CLUSTER_NAME \
      --gke-cluster=ZONE/CLUSTER_NAME \
      --enable-workload-identity --install-connect-agent \
      --manifest-output-file=MANIFEST-FILE_NAME
    

    de la siguiente manera:

    • CLUSTER_NAME: Es el nombre del clúster.
    • ZONE: La zona del clúster.
    • MANIFEST-FILE_NAME: Es la ruta de acceso en la que estos comandos generan el manifiesto para el registro.

    Cuando el proceso de registro se realice de forma correcta, verás un mensaje como el siguiente:

    Finished registering the cluster CLUSTER_NAME with the fleet.
  2. Aplica el archivo de manifiesto generado a tu clúster:

    kubectl apply -f MANIFEST-FILE_NAME
    

    Cuando el proceso de la aplicación se realice de forma correcta, verás mensajes como los siguientes:

    namespace/gke-connect created
    serviceaccount/connect-agent-sa created
    podsecuritypolicy.policy/gkeconnect-psp created
    role.rbac.authorization.k8s.io/gkeconnect-psp:role created
    rolebinding.rbac.authorization.k8s.io/gkeconnect-psp:rolebinding created
    role.rbac.authorization.k8s.io/agent-updater created
    rolebinding.rbac.authorization.k8s.io/agent-updater created
    role.rbac.authorization.k8s.io/gke-connect-agent-20210416-01-00 created
    clusterrole.rbac.authorization.k8s.io/gke-connect-impersonation-20210416-01-00 created
    clusterrolebinding.rbac.authorization.k8s.io/gke-connect-impersonation-20210416-01-00 created
    clusterrolebinding.rbac.authorization.k8s.io/gke-connect-feature-authorizer-20210416-01-00 created
    rolebinding.rbac.authorization.k8s.io/gke-connect-agent-20210416-01-00 created
    role.rbac.authorization.k8s.io/gke-connect-namespace-getter created
    rolebinding.rbac.authorization.k8s.io/gke-connect-namespace-getter created
    secret/http-proxy created
    deployment.apps/gke-connect-agent-20210416-01-00 created
    service/gke-connect-monitoring created
    secret/creds-gcp create
    
  3. Obtén el recurso de la membresía del clúster:

    kubectl get memberships membership -o yaml
    

    El resultado debe incluir el grupo de Workload Identity que asigna la flota, en el que PROJECT_ID es el ID de tu proyecto:

    workload_identity_pool: PROJECT_ID.svc.id.goog
    

    Esto significa que el clúster se registró correctamente.

Crea autoridades certificadoras para emitir certificados

Para emitir certificados a tus pods, crea un grupo de servicios de CA y las siguientes autoridades certificadoras (CA):

  • CA raíz. Esta es la raíz de confianza de todos los certificados de malla emitidos. Puedes usar una CA raíz existente si tienes una. Crea la CA raíz en el nivel enterprise, que está destinado a la emisión de certificados de larga duración y bajo volumen.
  • CA subordinada. Esta CA emite certificados para cargas de trabajo. Crea la CA subordinada en la región en la que se implementa el clúster. Crea la CA subordinada en el nivel devops, que está destinado a la emisión de certificados de corta duración y gran volumen.

Crear una CA subordinada es opcional, pero te recomendamos crear una en lugar de usar tu CA raíz para emitir certificados de malla de GKE. Si decides usar la CA raíz para emitir certificados de malla, asegúrate de que se mantenga el modo de emisión basado en configuración predeterminado.

La CA subordinada puede estar en una región diferente de tu clúster, pero recomendamos crearla en la misma región que tu clúster para optimizar el rendimiento. Sin embargo, puedes crear las CA subordinadas y raíz en regiones diferentes sin ningún impacto en el rendimiento o la disponibilidad.

Estas regiones son compatibles con el servicio de CA:

Nombre de la región Descripción de la región
asia-east1 Taiwán
asia-east2 Hong Kong
asia-northeast1 Tokio
asia-northeast2 Osaka
asia-northeast3 Seúl
asia-south1 Bombay
asia-south2 Delhi
asia-southeast1 Singapur
asia-southeast2 Yakarta
australia-southeast1 Sídney
australia-southeast2 Melbourne
europe-central2 Varsovia
europe-north1 Finlandia
europe-southwest1 Madrid
europe-west1 Bélgica
europe-west2 Londres
europe-west3 Fráncfort
europe-west4 Países Bajos
europe-west6 Zúrich
europe-west8 Milán
europe-west9 París
europe-west10 Berlín
europe-west12 Turín
me-central1 Doha
me-central2 Dammam
me-west1 Tel Aviv
northamerica-northeast1 Montreal
northamerica-northeast2 Toronto
southamerica-east1 São Paulo
southamerica-west1 Santiago
us-central1 Iowa
us-east1 Carolina del Sur
us-east4 Virginia del Norte
us-east5 Columbus
us-south1 Dallas
us-west1 Oregón
us-west2 Los Ángeles
us-west3 Salt Lake City
us-west4 Las Vegas

La lista de ubicaciones compatibles también se puede verificar ejecutando el siguiente comando:

gcloud privateca locations list
  1. Otorga la roles/privateca.caManager de IAM a las personas que crean un grupo de CA y una CA. Ten en cuenta que, para MEMBER, el formato correcto es user:userid@example.com. Si esa persona es el usuario actual, puedes obtener el ID del usuario actual con el comando de shell $(gcloud auth list --filter=status:ACTIVE --format="value(account)").

    gcloud projects add-iam-policy-binding PROJECT_ID \
      --member=MEMBER \
      --role=roles/privateca.caManager
    
  2. Otorga el rol role/privateca.admin en el servicio de AC a las personas que necesiten modificar las políticas de IAM. En este caso, MEMBER es una persona que necesita este acceso, en particular, cualquier persona que realice los siguientes pasos que otorgan los roles privateca.auditor y privateca.certificateManager:

    gcloud projects add-iam-policy-binding PROJECT_ID \
      --member=MEMBER \
      --role=roles/privateca.admin
    
  3. Crea el grupo de servicios de CA raíz.

    gcloud privateca pools create ROOT_CA_POOL_NAME \
      --location ROOT_CA_POOL_LOCATION \
      --tier enterprise
    
  4. Crea una CA raíz.

    gcloud privateca roots create ROOT_CA_NAME --pool ROOT_CA_POOL_NAME \
      --subject "CN=ROOT_CA_NAME, O=ROOT_CA_ORGANIZATION" \
      --key-algorithm="ec-p256-sha256" \
      --max-chain-length=1 \
      --location ROOT_CA_POOL_LOCATION
    

    En esta configuración de demostración, usa los siguientes valores para las variables:

    • ROOT_CA_POOL_NAME=td_sec_pool
    • ROOT_CA_NAME=pkcs2-ca
    • ROOT_CA_POOL_LOCATION=us-east1
    • ROOT_CA_ORGANIZATION="TestCorpLLC"
  5. Crea el grupo subordinado y la CA subordinada. Asegúrate de que el modo de emisión basado en la configuración predeterminado permanezca permitido.

    gcloud privateca pools create SUBORDINATE_CA_POOL_NAME \
      --location SUBORDINATE_CA_POOL_LOCATION \
      --tier devops
    
    gcloud privateca subordinates create SUBORDINATE_CA_NAME \
      --pool SUBORDINATE_CA_POOL_NAME \
      --location SUBORDINATE_CA_POOL_LOCATION \
      --issuer-pool ROOT_CA_POOL_NAME \
      --issuer-location ROOT_CA_POOL_LOCATION \
      --subject "CN=SUBORDINATE_CA_NAME, O=SUBORDINATE_CA_ORGANIZATION" \
      --key-algorithm "ec-p256-sha256" \
      --use-preset-profile subordinate_mtls_pathlen_0
    

    En esta configuración de demostración, usa los siguientes valores para las variables:

    • SUBORDINATE_CA_POOL_NAME="td-ca-pool"
    • SUBORDINATE_CA_POOL_LOCATION=us-east1
    • SUBORDINATE_CA_NAME="td-ca"
    • SUBORDINATE_CA_ORGANIZATION="TestCorpLLC"
    • ROOT_CA_POOL_NAME=td_sec_pool
    • ROOT_CA_POOL_LOCATION=us-east1
  6. Otorga la función privateca.auditor de IAM al grupo de CA raíz para permitir el acceso desde la cuenta de servicio de GKE:

    gcloud privateca pools add-iam-policy-binding ROOT_CA_POOL_NAME \
     --location ROOT_CA_POOL_LOCATION \
     --role roles/privateca.auditor \
     --member="serviceAccount:service-PROJNUM@container-engine-robot.iam.gserviceaccount.com"
    
  7. Otorga la función privateca.certificateManager de IAM para que el grupo CA subordinado permita el acceso desde la cuenta de servicio de GKE:

    gcloud privateca pools add-iam-policy-binding SUBORDINATE_CA_POOL_NAME \
      --location SUBORDINATE_CA_POOL_LOCATION \
      --role roles/privateca.certificateManager \
      --member="serviceAccount:service-PROJNUM@container-engine-robot.iam.gserviceaccount.com"
    
  8. Guarda la siguiente configuración de YAML WorkloadCertificateConfig para indicarle a tu clúster cómo emitir certificados de malla:

    apiVersion: security.cloud.google.com/v1
    kind: WorkloadCertificateConfig
    metadata:
      name: default
    spec:
      # Required. The CA service that issues your certificates.
      certificateAuthorityConfig:
        certificateAuthorityServiceConfig:
          endpointURI: ISSUING_CA_POOL_URI
    
      # Required. The key algorithm to use. Choice of RSA or ECDSA.
      #
      # To maximize compatibility with various TLS stacks, your workloads
      # should use keys of the same family as your root and subordinate CAs.
      #
      # To use RSA, specify configuration such as:
      #   keyAlgorithm:
      #     rsa:
      #       modulusSize: 4096
      #
      # Currently, the only supported ECDSA curves are "P256" and "P384", and the only
      # supported RSA modulus sizes are 2048, 3072 and 4096.
      keyAlgorithm:
        rsa:
          modulusSize: 4096
    
      # Optional. Validity duration of issued certificates, in seconds.
      #
      # Defaults to 86400 (1 day) if not specified.
      validityDurationSeconds: 86400
    
      # Optional. Try to start rotating the certificate once this
      # percentage of validityDurationSeconds is remaining.
      #
      # Defaults to 50 if not specified.
      rotationWindowPercentage: 50
    
    

    Reemplaza lo siguiente:

    • El ID del proyecto del proyecto en el que se ejecuta tu clúster.
      PROJECT_ID
    • El URI completamente calificado de la CA que emite los certificados de malla (ISSUING_CA_POOL_URI). Puede ser tu CA subordinada (recomendada) o la CA raíz. El formato es:
      //privateca.googleapis.com/projects/PROJECT_ID/locations/SUBORDINATE_CA_POOL_LOCATION/caPools/SUBORDINATE_CA_POOL_NAME
  9. Guarda la siguiente configuración de YAML TrustConfig para indicarle a tu clúster cómo confiar en los certificados emitidos:

    apiVersion: security.cloud.google.com/v1
    kind: TrustConfig
    metadata:
      name: default
    spec:
      # You must include a trustStores entry for the trust domain that
      # your cluster is enrolled in.
      trustStores:
      - trustDomain: PROJECT_ID.svc.id.goog
        # Trust identities in this trustDomain if they appear in a certificate
        # that chains up to this root CA.
        trustAnchors:
        - certificateAuthorityServiceURI: ROOT_CA_POOL_URI
    

    Reemplaza lo siguiente:

    • El ID del proyecto del proyecto en el que se ejecuta tu clúster.
      PROJECT_ID
    • El URI completamente calificado del grupo de CA raíz (ROOT_CA_POOL_URI). El formato es:
      //privateca.googleapis.com/projects/PROJECT_ID/locations/ROOT_CA_POOL_LOCATION/caPools/ROOT_CA_POOL_NAME
  10. Aplica las configuraciones a tu clúster.

    kubectl apply -f WorkloadCertificateConfig.yaml
    kubectl apply -f TrustConfig.yaml
    

Crea un servicio de gRPC sin proxy con NEG

Para la seguridad de PSM, necesitas un servidor gRPC sin proxy capaz de usar xDS para adquirir la configuración de seguridad de la malla de servicios de Cloud. Este paso es similar al de Configura servicios de GKE con NEG de la guía de configuración del balanceo de cargas de PSM, pero debes usar el servidor helloworld con xDS habilitado del ejemplo de xDS en el repositorio grpc-java en lugar de la imagen de java-example-hostname.

Debes compilar y ejecutar este servidor en un contenedor compilado a partir de una imagen de openjdk:8-jdk. También usarás la función de NEG con nombre, que te permite especificar un nombre para el NEG. Esto simplifica los pasos posteriores porque la implementación conoce el nombre del NEG sin tener que buscarlo.

El siguiente es un ejemplo completo de la especificación de Kubernetes del servidor de gRPC. Ten en cuenta lo siguiente:

  • La especificación crea una cuenta de servicio de Kubernetes, example-grpc-server, que usa el Pod del servidor de gRPC.
  • En la especificación, se usa el campo name en la anotación cloud.google.com/neg del servicio para especificar el nombre de NEG example-grpc-server.
  • La variable ${PROJNUM} representa el número de tu proyecto.
  • En la especificación, se usa la sección initContainers para ejecutar un generador de arranque a fin de propagar el archivo de arranque que necesita la biblioteca de gRPC sin proxy. Este archivo de arranque reside en /tmp/grpc-xds/td-grpc-bootstrap.json en el contenedor del servidor de gRPC llamado example-grpc-server.

Agrega la siguiente anotación a las especificaciones del Pod:

 annotations:
   security.cloud.google.com/use-workload-certificates: ""

Puedes ver la ubicación correcta en la especificación completa que sigue.

Cuando se crea, cada Pod obtiene un volumen en /var/run/secrets/workload-spiffe-credentials. Este volumen contiene lo siguiente:

  • private_key.pem es una clave privada generada de forma automática.
  • certificates.pem es un conjunto de certificados con formato PEM que se puede presentar en otro Pod como la cadena de certificados de cliente o usarse como una cadena de certificados de servidor.
  • ca_certificates.pem es un conjunto de certificados con formato PEM que se usa como anclajes de confianza cuando se valida la cadena de certificados de cliente que presenta otro Pod o la cadena de certificados de servidor que se recibe cuando se conecta a otro Pod.

Ten en cuenta que ca_certificates.pem contiene certificados para el dominio de confianza local de las cargas de trabajo, que es el grupo de cargas de trabajo del clúster.

El certificado de hoja en certificates.pem contiene la siguiente aserción de identidad de SPIFFE de texto sin formato:

spiffe://WORKLOAD_POOL/ns/NAMESPACE/sa/KUBERNETES_SERVICE_ACCOUNT

En esta aserción, sucede lo siguiente:

  • WORKLOAD_POOL es el nombre del grupo de cargas de trabajo del clúster.
  • NAMESPACE es el espacio de nombres de tu cuenta de servicio de Kubernetes.
  • KUBERNETES_SERVICE_ACCOUNT es el nombre de tu cuenta de servicio de Kubernetes.

Las siguientes instrucciones para tu lenguaje crean la especificación que se usará en este ejemplo.

Java

  1. Ejecuta el siguiente comando para asegurarte de que el número de proyecto esté configurado de forma correcta:

    if [ -z "$PROJNUM" ] ; then export PROJNUM=$(gcloud projects describe $(gcloud info --format='value(config.project)') --format="value(projectNumber)") ; fi ; echo $PROJNUM
    
  2. Crea la especificación:

    cat << EOF > example-grpc-server.yaml
    apiVersion: v1
    kind: ServiceAccount
    metadata:
     name: example-grpc-server
     namespace: default
     annotations:
       iam.gke.io/gcp-service-account: ${PROJNUM}-compute@developer.gserviceaccount.com
    ---
    apiVersion: v1
    kind: Service
    metadata:
     name: example-grpc-server
     namespace: default
     labels:
       k8s-app: example-grpc-server
     annotations:
       cloud.google.com/neg: '{"exposed_ports":{"8080":{"name": "example-grpc-server"}}}'
    spec:
     ports:
     - name: helloworld
       port: 8080
       protocol: TCP
       targetPort: 50051
     selector:
       k8s-app: example-grpc-server
     type: ClusterIP
    ---
    apiVersion: apps/v1
    kind: Deployment
    metadata:
     name: example-grpc-server
     namespace: default
     labels:
       k8s-app: example-grpc-server
    spec:
     replicas: 1
     selector:
       matchLabels:
         k8s-app: example-grpc-server
     strategy: {}
     template:
       metadata:
         annotations:
            security.cloud.google.com/use-workload-certificates: ""
         labels:
           k8s-app: example-grpc-server
       spec:
         containers:
         - image: openjdk:8-jdk
           imagePullPolicy: IfNotPresent
           name: example-grpc-server
           command:
           - /bin/sleep
           - inf
           env:
           - name: GRPC_XDS_BOOTSTRAP
             value: "/tmp/grpc-xds/td-grpc-bootstrap.json"
           ports:
           - protocol: TCP
             containerPort: 50051
           resources:
             limits:
               cpu: 800m
               memory: 512Mi
             requests:
               cpu: 100m
               memory: 512Mi
           volumeMounts:
           - name: grpc-td-conf
             mountPath: /tmp/grpc-xds/
         initContainers:
         - name: grpc-td-init
           image: gcr.io/trafficdirector-prod/td-grpc-bootstrap:0.16.0
           imagePullPolicy: Always
           args:
           - --config-mesh-experimental
           - "grpc-mesh"
           - --output
           - "/tmp/bootstrap/td-grpc-bootstrap.json"
           - --node-metadata=app=helloworld
           resources:
             limits:
               cpu: 100m
               memory: 100Mi
             requests:
               cpu: 10m
               memory: 100Mi
           volumeMounts:
           - name: grpc-td-conf
             mountPath: /tmp/bootstrap/
         serviceAccountName: example-grpc-server
         volumes:
         - name: grpc-td-conf
           emptyDir:
             medium: Memory
    EOF
    

C++

  1. Ejecuta el siguiente comando para asegurarte de que el número de proyecto esté configurado de forma correcta:

    if [ -z "$PROJNUM" ] ; then export PROJNUM=$(gcloud projects describe $(gcloud info --format='value(config.project)') --format="value(projectNumber)") ; fi ; echo $PROJNUM
    
  2. Crea la especificación:

    cat << EOF > example-grpc-server.yaml
    apiVersion: v1
    kind: ServiceAccount
    metadata:
     name: example-grpc-server
     namespace: default
     annotations:
       iam.gke.io/gcp-service-account: ${PROJNUM}-compute@developer.gserviceaccount.com
    ---
    apiVersion: v1
    kind: Service
    metadata:
     name: example-grpc-server
     namespace: default
     labels:
       k8s-app: example-grpc-server
     annotations:
       cloud.google.com/neg: '{"exposed_ports":{"8080":{"name": "example-grpc-server"}}}'
    spec:
     ports:
     - name: helloworld
       port: 8080
       protocol: TCP
       targetPort: 50051
     selector:
       k8s-app: example-grpc-server
     type: ClusterIP
    ---
    apiVersion: apps/v1
    kind: Deployment
    metadata:
     name: example-grpc-server
     namespace: default
     labels:
       k8s-app: example-grpc-server
    spec:
     replicas: 1
     selector:
       matchLabels:
         k8s-app: example-grpc-server
     strategy: {}
     template:
       metadata:
         annotations:
            security.cloud.google.com/use-workload-certificates: ""
         labels:
           k8s-app: example-grpc-server
       spec:
         containers:
         - image: phusion/baseimage:18.04-1.0.0
           imagePullPolicy: IfNotPresent
           name: example-grpc-server
           command:
           - /bin/sleep
           - inf
           env:
           - name: GRPC_XDS_BOOTSTRAP
             value: "/tmp/grpc-xds/td-grpc-bootstrap.json"
           ports:
           - protocol: TCP
             containerPort: 50051
           resources:
             limits:
               cpu: 8
               memory: 8Gi
             requests:
               cpu: 300m
               memory: 512Mi
           volumeMounts:
           - name: grpc-td-conf
             mountPath: /tmp/grpc-xds/
         initContainers:
         - name: grpc-td-init
           image: gcr.io/trafficdirector-prod/td-grpc-bootstrap:0.16.0
           imagePullPolicy: Always
           args:
           - --config-mesh-experimental
           - "grpc-mesh"
           - --output
           - "/tmp/bootstrap/td-grpc-bootstrap.json"
           - --node-metadata=app=helloworld
           resources:
             limits:
               cpu: 100m
               memory: 100Mi
             requests:
               cpu: 10m
               memory: 100Mi
           volumeMounts:
           - name: grpc-td-conf
             mountPath: /tmp/bootstrap/
         serviceAccountName: example-grpc-server
         volumes:
         - name: grpc-td-conf
           emptyDir:
             medium: Memory
    EOF
    

Python

  1. Ejecuta el siguiente comando para asegurarte de que el número de proyecto esté configurado de forma correcta:

    if [ -z "$PROJNUM" ] ; then export PROJNUM=$(gcloud projects describe $(gcloud info --format='value(config.project)') --format="value(projectNumber)") ; fi ; echo $PROJNUM
    
  2. Crea la especificación:

    cat << EOF > example-grpc-server.yaml
    apiVersion: v1
    kind: ServiceAccount
    metadata:
     name: example-grpc-server
     namespace: default
     annotations:
       iam.gke.io/gcp-service-account: ${PROJNUM}-compute@developer.gserviceaccount.com
    ---
    apiVersion: v1
    kind: Service
    metadata:
     name: example-grpc-server
     namespace: default
     labels:
       k8s-app: example-grpc-server
     annotations:
       cloud.google.com/neg: '{"exposed_ports":{"8080":{"name": "example-grpc-server"}}}'
    spec:
     ports:
     - name: helloworld
       port: 8080
       protocol: TCP
       targetPort: 50051
     selector:
       k8s-app: example-grpc-server
     type: ClusterIP
    ---
    apiVersion: apps/v1
    kind: Deployment
    metadata:
     name: example-grpc-server
     namespace: default
     labels:
       k8s-app: example-grpc-server
    spec:
     replicas: 1
     selector:
       matchLabels:
         k8s-app: example-grpc-server
     strategy: {}
     template:
       metadata:
         annotations:
            security.cloud.google.com/use-workload-certificates: ""
         labels:
           k8s-app: example-grpc-server
       spec:
         containers:
         - image: phusion/baseimage:18.04-1.0.0
           imagePullPolicy: IfNotPresent
           name: example-grpc-server
           command:
           - /bin/sleep
           - inf
           env:
           - name: GRPC_XDS_BOOTSTRAP
             value: "/tmp/grpc-xds/td-grpc-bootstrap.json"
           ports:
           - protocol: TCP
             containerPort: 50051
           resources:
             limits:
               cpu: 8
               memory: 8Gi
             requests:
               cpu: 300m
               memory: 512Mi
           volumeMounts:
           - name: grpc-td-conf
             mountPath: /tmp/grpc-xds/
         initContainers:
         - name: grpc-td-init
           image: gcr.io/trafficdirector-prod/td-grpc-bootstrap:0.16.0
           imagePullPolicy: Always
           args:
           - --config-mesh-experimental
           - "grpc-mesh"
           - --output
           - "/tmp/bootstrap/td-grpc-bootstrap.json"
           - --node-metadata=app=helloworld
           resources:
             limits:
               cpu: 100m
               memory: 100Mi
             requests:
               cpu: 10m
               memory: 100Mi
           volumeMounts:
           - name: grpc-td-conf
             mountPath: /tmp/bootstrap/
         serviceAccountName: example-grpc-server
         volumes:
         - name: grpc-td-conf
           emptyDir:
             medium: Memory
    EOF
    

Go

  1. Ejecuta el siguiente comando para asegurarte de que el número de proyecto esté configurado de forma correcta:

    if [ -z "$PROJNUM" ] ; then export PROJNUM=$(gcloud projects describe $(gcloud info --format='value(config.project)') --format="value(projectNumber)") ; fi ; echo $PROJNUM
    
  2. Crea la especificación:

    cat << EOF > example-grpc-server.yaml
    apiVersion: v1
    kind: ServiceAccount
    metadata:
     name: example-grpc-server
     namespace: default
     annotations:
       iam.gke.io/gcp-service-account: ${PROJNUM}-compute@developer.gserviceaccount.com
    ---
    apiVersion: v1
    kind: Service
    metadata:
     name: example-grpc-server
     namespace: default
     labels:
       k8s-app: example-grpc-server
     annotations:
       cloud.google.com/neg: '{"exposed_ports":{"8080":{"name": "example-grpc-server"}}}'
    spec:
     ports:
     - name: helloworld
       port: 8080
       protocol: TCP
       targetPort: 50051
     selector:
       k8s-app: example-grpc-server
     type: ClusterIP
    ---
    apiVersion: apps/v1
    kind: Deployment
    metadata:
     name: example-grpc-server
     namespace: default
     labels:
       k8s-app: example-grpc-server
    spec:
     replicas: 1
     selector:
       matchLabels:
         k8s-app: example-grpc-server
     strategy: {}
     template:
       metadata:
         annotations:
            security.cloud.google.com/use-workload-certificates: ""
         labels:
           k8s-app: example-grpc-server
       spec:
         containers:
         - image: golang:1.16-alpine
           imagePullPolicy: IfNotPresent
           name: example-grpc-server
           command:
           - /bin/sleep
           - inf
           env:
           - name: GRPC_XDS_BOOTSTRAP
             value: "/tmp/grpc-xds/td-grpc-bootstrap.json"
           ports:
           - protocol: TCP
             containerPort: 50051
           resources:
             limits:
               cpu: 8
               memory: 8Gi
             requests:
               cpu: 300m
               memory: 512Mi
           volumeMounts:
           - name: grpc-td-conf
             mountPath: /tmp/grpc-xds/
         initContainers:
         - name: grpc-td-init
           image: gcr.io/trafficdirector-prod/td-grpc-bootstrap:0.16.0
           imagePullPolicy: Always
           args:
           - --config-mesh-experimental
           - "grpc-mesh"
           - --output
           - "/tmp/bootstrap/td-grpc-bootstrap.json"
           - --node-metadata=app=helloworld
           resources:
             limits:
               cpu: 100m
               memory: 100Mi
             requests:
               cpu: 10m
               memory: 100Mi
           volumeMounts:
           - name: grpc-td-conf
             mountPath: /tmp/bootstrap/
         serviceAccountName: example-grpc-server
         volumes:
         - name: grpc-td-conf
           emptyDir:
             medium: Memory
    EOF
    

    Completa el proceso de la siguiente manera.

  1. Aplica la especificación:

    kubectl apply -f example-grpc-server.yaml
    
  2. Otorga las funciones necesarias a la cuenta de servicio:

    gcloud iam service-accounts add-iam-policy-binding \
      --role roles/iam.workloadIdentityUser \
      --member "serviceAccount:${PROJECT_ID}.svc.id.goog[default/example-grpc-server]" \
      ${PROJNUM}-compute@developer.gserviceaccount.com
    
    gcloud projects add-iam-policy-binding ${PROJECT_ID} \
      --member "serviceAccount:${PROJECT_ID}.svc.id.goog[default/example-grpc-server]" \
      --role roles/trafficdirector.client
    
  3. Ejecuta estos comandos para verificar que el servicio y el Pod se creen correctamente:

    kubectl get deploy/example-grpc-server
    kubectl get svc/example-grpc-server
    
  4. Verifica que el nombre de NEG sea correcto:

    gcloud compute network-endpoint-groups list \
        --filter "name=example-grpc-server" --format "value(name)"
    

    El comando debería mostrar el nombre de NEG example-grpc-server.

Configura Cloud Service Mesh con componentes del balanceo de cargas de Google Cloud

Los pasos de esta sección son similares a los de Configura Cloud Service Mesh con componentes de balanceo de cargas, pero hay algunos cambios, como se describe en las siguientes secciones.

Crea la verificación de estado, la regla de firewall y el servicio de backend

Cuando el servidor de gRPC está configurado para usar mTLS, las verificaciones de estado de gRPC no funcionan porque el cliente de verificación de estado no puede presentar un certificado de cliente válido a los servidores. Para abordar esto, puedes usar uno de dos métodos.

En el primer método, el servidor debe crear un puerto de entrega adicional que se designe como puerto de verificación de estado. Esto se conecta a un servicio de verificación de estado especial, como texto sin formato o TLS para ese puerto.

El servidor de ejemplo helloworld de xDS usa PORT_NUMBER + 1 como el puerto de verificación de estado de texto simple. En el ejemplo, se usa 50052 como puerto de verificación de estado porque 50051 es el puerto del servidor de aplicaciones de gRPC.

En el segundo método, debes configurar la verificación de estado para comprobar solo la conectividad TCP con el puerto de entrega de la aplicación. Esto solo verifica la conectividad y genera tráfico innecesario al servidor cuando hay protocolos de enlace TLS fallidos. Por este motivo, te recomendamos que uses el primer método.

  1. Crea la verificación de estado. Ten en cuenta que la verificación de estado no comenzará hasta que crees y, también, inicies el servidor.

    • Si creas un puerto de entrega designado para la verificación de estado, que es el enfoque que recomendamos, usa este comando:

      gcloud compute health-checks create grpc grpc-gke-helloworld-hc \
       --enable-logging --port 50052
      
    • Si creas una verificación de estado de TCP, la cual no recomendamos, usa este comando:

      gcloud compute health-checks create tcp grpc-gke-helloworld-hc \
      --use-serving-port
      
  2. Crea el firewall. Asegúrate de que el valor de --target-tags coincida con el valor que proporcionaste para --tags en la sección Crea o actualiza un clúster de GKE.

    gcloud compute firewall-rules create grpc-gke-allow-health-checks \
      --network default --action allow --direction INGRESS \
      --source-ranges 35.191.0.0/16,130.211.0.0/22 \
      --target-tags allow-health-checks \
      --rules tcp:50051-50052
    
  3. Crea el servicio de backend:

    gcloud compute backend-services create grpc-gke-helloworld-service \
       --global \
       --load-balancing-scheme=INTERNAL_SELF_MANAGED \
       --protocol=GRPC \
       --health-checks grpc-gke-helloworld-hc
    
  4. Vincula el NEG al servicio de backend:

    gcloud compute backend-services add-backend grpc-gke-helloworld-service \
       --global \
       --network-endpoint-group example-grpc-server \
       --network-endpoint-group-zone ${ZONE} \
       --balancing-mode RATE \
       --max-rate-per-endpoint 5
    

Crea los recursos Mesh y GRPCRoute

Esto es similar a la forma en que configuras los recursos Mesh y GRPCRoute en Configura servicios de gRPC sin proxy.

  1. Crea la especificación Mesh y guárdala en un archivo llamado mesh.yaml.

    name: grpc-mesh
    
  2. Importa el recurso Mesh desde la especificación.

    gcloud network-services meshes import grpc-mesh \
      --source=mesh.yaml \
      --location=global
    
  3. Crea la especificación GRPCRoute y guárdala en un archivo llamado grpc_route.yaml.

    name: helloworld-grpc-route
    hostnames:
    - helloworld-gke:8000
    meshes:
    - projects/PROJECT_NUMBER/locations/global/meshes/grpc-mesh
    rules:
    - action:
        destinations:
        - serviceName: projects/PROJECT_NUMBER/locations/global/backendServices/grpc-gke-helloworld-service
    
  4. Importa el recurso GRPCRoute desde la especificación grpc_route.yaml.

    gcloud network-services grpc-routes import helloworld-grpc-route \
      --source=grpc_route.yaml \
      --location=global
    

Configura Cloud Service Mesh con seguridad de gRPC sin proxy

En este ejemplo, se muestra cómo configurar mTLS en el lado del cliente y del servidor.

Formato de las referencias de políticas

Ten en cuenta el siguiente formato obligatorio para hacer referencia a las políticas de TLS del servidor y de cliente:

projects/PROJECT_ID/locations/global/[serverTlsPolicies|clientTlsPolicies]/[server-tls-policy|client-mtls-policy]

Por ejemplo:

projects/PROJECT_ID/locations/global/serverTlsPolicies/server-tls-policy
projects/PROJECT_ID/locations/global/clientTlsPolicies/client-mtls-policy

Configura mTLS en el servidor

Primero, crea una política de TLS para el servidor. La política solicita al gRPC del lado del servidor que use la configuración del complemento certificateProvicerInstance identificada por el nombre google_cloud_private_spiffe para el certificado de identidad, que es parte de serverCertificate. En la sección mtlsPolicy, se indica la seguridad mTLS y se usa el mismo google_cloud_private_spiffe que la configuración del complemento para clientValidationCa, que es la especificación del certificado raíz (validación).

A continuación, crea una política de extremos. Esto especifica que un backend, por ejemplo, un servidor de gRPC, que usa el puerto 50051 con cualquier etiqueta de metadatos o ninguna etiqueta, recibe la política de TLS del servidor adjunta llamada server-mtls-policy. Debes especificar etiquetas de metadatos con MATCH_ALL o un valor admitido. Las etiquetas de metadatos admitidas se pueden encontrar en el campo endpointMatcher.metadataLabelMatcher.metadataLabelMatchCriteria del documento NetworkServicesEndpointPolicy. Crea la política de extremos con un archivo temporal ep-mtls-psms.yaml que contenga los valores del recurso de la política de extremos con la política que ya definiste.

  1. Crea un archivo temporal server-mtls-policy.yaml en el directorio actual con los valores del recurso de la política de TLS del servidor:

    name: "projects/PROJECT_ID/locations/global/serverTlsPolicies/server-mtls-policy"
    serverCertificate:
      certificateProviderInstance:
        pluginInstance: google_cloud_private_spiffe
    mtlsPolicy:
      clientValidationCa:
      - certificateProviderInstance:
          pluginInstance: google_cloud_private_spiffe
    
  2. Crea un recurso de política de TLS de servidor llamado server-mtls-policy mediante la importación del archivo temporal server-mtls-policy.yaml:

    gcloud network-security server-tls-policies import server-mtls-policy \
      --source=server-mtls-policy.yaml --location=global
    
  3. Crea la política de extremos mediante el archivo temporal ep-mtls-psms.yaml:

    name: "ep-mtls-psms"
    type: "GRPC_SERVER"
    serverTlsPolicy: "projects/PROJECT_ID/locations/global/serverTlsPolicies/server-mtls-policy"
    trafficPortSelector:
      ports:
      - "50051"
    endpointMatcher:
      metadataLabelMatcher:
        metadataLabelMatchCriteria: "MATCH_ALL"
        metadataLabels:
        - labelName: app
          labelValue: helloworld
    
  4. Importa el archivo ep-mtls-psms.yaml para crear el recurso de política de extremo:

    gcloud beta network-services endpoint-policies import ep-mtls-psms \
      --source=ep-mtls-psms.yaml --location=global
    

Configura mTLS en el cliente

La política de seguridad del cliente está vinculada con el servicio de backend. Cuando un cliente accede a un backend (el servidor de gRPC) a través del servicio de backend, la política de seguridad adjunta del cliente se envía al cliente.

  1. Crea el contenido de los recursos de la política de TLS del cliente en un archivo temporal llamado client-mtls-policy.yaml en el directorio actual:

    name: "client-mtls-policy"
    clientCertificate:
      certificateProviderInstance:
        pluginInstance: google_cloud_private_spiffe
    serverValidationCa:
    - certificateProviderInstance:
        pluginInstance: google_cloud_private_spiffe
    
  2. Crea el recurso de política de TLS de cliente llamado client-mtls-policy mediante la importación del archivo temporal client-mtls-policy.yaml:

    gcloud network-security client-tls-policies import client-mtls-policy \
      --source=client-mtls-policy.yaml --location=global
    
  3. Crea un fragmento en un archivo temporal para hacer referencia a esta política y agrega detalles de subjectAltNames en el mensaje SecuritySettings, como en el siguiente ejemplo. Reemplaza ${PROJECT_ID} por el valor de ID de tu proyecto, que es el valor de la variable de entorno ${PROJECT_ID} que se describió antes. Ten en cuenta que example-grpc-server en subjectAltNames es el nombre de la cuenta de servicio de Kubernetes que se usa para el Pod del servidor de gRPC en la especificación de implementación.

    if [ -z "$PROJECT_ID" ] ; then echo Please make sure PROJECT_ID is set. ; fi
    cat << EOF > client-security-settings.yaml
    securitySettings:
      clientTlsPolicy: projects/${PROJECT_ID}/locations/global/clientTlsPolicies/client-mtls-policy
      subjectAltNames:
        - "spiffe://${PROJECT_ID}.svc.id.goog/ns/default/sa/example-grpc-server"
    EOF
    
  4. Agrega el mensaje securitySettings al servicio de backend que ya creaste. Con estos pasos se exporta el contenido del servicio de backend actual, se agrega el mensaje de securitySetting del cliente y se vuelve a importar el contenido nuevo para actualizar el servicio de backend.

    gcloud compute backend-services export grpc-gke-helloworld-service --global \
      --destination=/tmp/grpc-gke-helloworld-service.yaml
    
    cat /tmp/grpc-gke-helloworld-service.yaml client-security-settings.yaml \
      >/tmp/grpc-gke-helloworld-service1.yaml
    
    gcloud compute backend-services import grpc-gke-helloworld-service --global \
      --source=/tmp/grpc-gke-helloworld-service1.yaml -q
    

Verifica la configuración

Se completó la configuración de Cloud Service Mesh, incluida la seguridad del servidor y del cliente. A continuación, prepara y ejecuta las cargas de trabajo del servidor y del cliente. Esto completa el ejemplo.

Crea un cliente de gRPC sin proxy

Este paso es similar al paso anterior Crea un servicio de gRPC sin proxy. Usa el cliente helloworld habilitado para xDS desde el directorio de ejemplo de xDS en el repositorio grpc-java. Compila y ejecuta el cliente en un contenedor compilado a partir de una imagen openjdk:8-jdk. La especificación de Kubernetes para el cliente de gRPC hace lo siguiente.

  • Crea una cuenta de servicio de Kubernetes example-grpc-client que usa el Pod de cliente de gRPC.
  • ${PROJNUM} representa el número de proyecto y se debe reemplazar por el número real.

Agrega la siguiente anotación a las especificaciones del Pod:

  annotations:
    security.cloud.google.com/use-workload-certificates: ""

Cuando se crea, cada Pod obtiene un volumen en /var/run/secrets/workload-spiffe-credentials. Este volumen contiene lo siguiente:

  • private_key.pem es una clave privada generada de forma automática.
  • certificates.pem es un conjunto de certificados con formato PEM que se puede presentar en otro Pod como la cadena de certificados de cliente o usarse como una cadena de certificados de servidor.
  • ca_certificates.pem es un conjunto de certificados con formato PEM que se usa como anclajes de confianza cuando se valida la cadena de certificados de cliente que presenta otro Pod o la cadena de certificados de servidor que se recibe cuando se conecta a otro Pod.

Ten en cuenta que ca_certificates.pem contiene los certificados raíz del dominio de confianza local para las cargas de trabajo, que es el grupo de cargas de trabajo del clúster.

El certificado de hoja en certificates.pem contiene la siguiente aserción de identidad de SPIFFE de texto sin formato:

spiffe://WORKLOAD_POOL/ns/NAMESPACE/sa/KUBERNETES_SERVICE_ACCOUNT

En esta aserción, sucede lo siguiente:

  • WORKLOAD_POOL es el nombre del grupo de cargas de trabajo del clúster.
  • NAMESPACE es el nombre de tu cuenta de servicio de Kubernetes.
  • KUBERNETES_SERVICE_ACCOUNT es el espacio de nombres de tu cuenta de servicio de Kubernetes.

Las siguientes instrucciones para tu lenguaje crean la especificación que se usará en este ejemplo.

Java

  1. Ejecuta el siguiente comando para asegurarte de que el número de proyecto esté configurado de forma correcta:

    if [ -z "$PROJNUM" ] ; then export PROJNUM=$(gcloud projects describe $(gcloud info --format='value(config.project)') --format="value(projectNumber)") ; fi ; echo $PROJNUM
    
  2. Crea la siguiente especificación:

    cat << EOF > example-grpc-client.yaml
    apiVersion: v1
    kind: ServiceAccount
    metadata:
      name: example-grpc-client
      namespace: default
      annotations:
        iam.gke.io/gcp-service-account: ${PROJNUM}-compute@developer.gserviceaccount.com
    ---
    apiVersion: apps/v1
    kind: Deployment
    metadata:
      name: example-grpc-client
      namespace: default
      labels:
        k8s-app: example-grpc-client
    spec:
      replicas: 1
      selector:
        matchLabels:
          k8s-app: example-grpc-client
      strategy: {}
      template:
        metadata:
          annotations:
            security.cloud.google.com/use-workload-certificates: ""
          labels:
            k8s-app: example-grpc-client
        spec:
          containers:
          - image: openjdk:8-jdk
            imagePullPolicy: IfNotPresent
            name: example-grpc-client
            command:
            - /bin/sleep
            - inf
            env:
            - name: GRPC_XDS_BOOTSTRAP
              value: "/tmp/grpc-xds/td-grpc-bootstrap.json"
            resources:
              limits:
                cpu: 800m
                memory: 512Mi
              requests:
                cpu: 100m
                memory: 512Mi
            volumeMounts:
            - name: grpc-td-conf
              mountPath: /tmp/grpc-xds/
          initContainers:
          - name: grpc-td-init
            image: gcr.io/trafficdirector-prod/td-grpc-bootstrap:0.16.0
            imagePullPolicy: Always
            args:
            - --config-mesh-experimental
            - "grpc-mesh"
            - --output
            - --config-mesh-experimental
            - "grpc-mesh"
            - "/tmp/bootstrap/td-grpc-bootstrap.json"
            resources:
              limits:
                cpu: 100m
                memory: 100Mi
              requests:
                cpu: 10m
                memory: 100Mi
            volumeMounts:
            - name: grpc-td-conf
              mountPath: /tmp/bootstrap/
          serviceAccountName: example-grpc-client
          volumes:
          - name: grpc-td-conf
            emptyDir:
              medium: Memory
    EOF
    

C++

  1. Ejecuta el siguiente comando para asegurarte de que el número de proyecto esté configurado de forma correcta:

    if [ -z "$PROJNUM" ] ; then export PROJNUM=$(gcloud projects describe $(gcloud info --format='value(config.project)') --format="value(projectNumber)") ; fi ; echo $PROJNUM
    
  2. Crea la siguiente especificación:

    cat << EOF > example-grpc-client.yaml
    apiVersion: v1
    kind: ServiceAccount
    metadata:
      name: example-grpc-client
      namespace: default
      annotations:
        iam.gke.io/gcp-service-account: ${PROJNUM}-compute@developer.gserviceaccount.com
    ---
    apiVersion: apps/v1
    kind: Deployment
    metadata:
      name: example-grpc-client
      namespace: default
      labels:
        k8s-app: example-grpc-client
    spec:
      replicas: 1
      selector:
        matchLabels:
          k8s-app: example-grpc-client
      strategy: {}
      template:
        metadata:
          annotations:
            security.cloud.google.com/use-workload-certificates: ""
          labels:
            k8s-app: example-grpc-client
        spec:
          containers:
          - image: phusion/baseimage:18.04-1.0.0
            imagePullPolicy: IfNotPresent
            name: example-grpc-client
            command:
            - /bin/sleep
            - inf
            env:
            - name: GRPC_XDS_BOOTSTRAP
              value: "/tmp/grpc-xds/td-grpc-bootstrap.json"
            resources:
              limits:
                cpu: 8
                memory: 8Gi
              requests:
                cpu: 300m
                memory: 512Mi
            volumeMounts:
            - name: grpc-td-conf
              mountPath: /tmp/grpc-xds/
          initContainers:
          - name: grpc-td-init
            image: gcr.io/trafficdirector-prod/td-grpc-bootstrap:0.16.0
            imagePullPolicy: Always
            args:
            - --config-mesh-experimental
            - "grpc-mesh"
            - --output
            - "/tmp/bootstrap/td-grpc-bootstrap.json"
            resources:
              limits:
                cpu: 100m
                memory: 100Mi
              requests:
                cpu: 10m
                memory: 100Mi
            volumeMounts:
            - name: grpc-td-conf
              mountPath: /tmp/bootstrap/
          serviceAccountName: example-grpc-client
          volumes:
          - name: grpc-td-conf
            emptyDir:
              medium: Memory
    EOF
    

Python

  1. Ejecuta el siguiente comando para asegurarte de que el número de proyecto esté configurado de forma correcta:

    if [ -z "$PROJNUM" ] ; then export PROJNUM=$(gcloud projects describe $(gcloud info --format='value(config.project)') --format="value(projectNumber)") ; fi ; echo $PROJNUM
    
  2. Crea la siguiente especificación:

    cat << EOF > example-grpc-client.yaml
    apiVersion: v1
    kind: ServiceAccount
    metadata:
      name: example-grpc-client
      namespace: default
      annotations:
        iam.gke.io/gcp-service-account: ${PROJNUM}-compute@developer.gserviceaccount.com
    ---
    apiVersion: apps/v1
    kind: Deployment
    metadata:
      name: example-grpc-client
      namespace: default
      labels:
        k8s-app: example-grpc-client
    spec:
      replicas: 1
      selector:
        matchLabels:
          k8s-app: example-grpc-client
      strategy: {}
      template:
        metadata:
          annotations:
            security.cloud.google.com/use-workload-certificates: ""
          labels:
            k8s-app: example-grpc-client
        spec:
          containers:
          - image: phusion/baseimage:18.04-1.0.0
            imagePullPolicy: IfNotPresent
            name: example-grpc-client
            command:
            - /bin/sleep
            - inf
            env:
            - name: GRPC_XDS_BOOTSTRAP
              value: "/tmp/grpc-xds/td-grpc-bootstrap.json"
            resources:
              limits:
                cpu: 8
                memory: 8Gi
              requests:
                cpu: 300m
                memory: 512Mi
            volumeMounts:
            - name: grpc-td-conf
              mountPath: /tmp/grpc-xds/
          initContainers:
          - name: grpc-td-init
            image: gcr.io/trafficdirector-prod/td-grpc-bootstrap:0.16.0
            imagePullPolicy: Always
            args:
            - --config-mesh-experimental
            - "grpc-mesh"
            - --output
            - "/tmp/bootstrap/td-grpc-bootstrap.json"
            resources:
              limits:
                cpu: 100m
                memory: 100Mi
              requests:
                cpu: 10m
                memory: 100Mi
            volumeMounts:
            - name: grpc-td-conf
              mountPath: /tmp/bootstrap/
          serviceAccountName: example-grpc-client
          volumes:
          - name: grpc-td-conf
            emptyDir:
              medium: Memory
    EOF
    

Go

  1. Ejecuta el siguiente comando para asegurarte de que el número de proyecto esté configurado de forma correcta:

    if [ -z "$PROJNUM" ] ; then export PROJNUM=$(gcloud projects describe $(gcloud info --format='value(config.project)') --format="value(projectNumber)") ; fi ; echo $PROJNUM
    
  2. Crea la siguiente especificación:

    cat << EOF > example-grpc-client.yaml
    apiVersion: v1
    kind: ServiceAccount
    metadata:
      name: example-grpc-client
      namespace: default
      annotations:
        iam.gke.io/gcp-service-account: ${PROJNUM}-compute@developer.gserviceaccount.com
    ---
    apiVersion: apps/v1
    kind: Deployment
    metadata:
      name: example-grpc-client
      namespace: default
      labels:
        k8s-app: example-grpc-client
    spec:
      replicas: 1
      selector:
        matchLabels:
          k8s-app: example-grpc-client
      strategy: {}
      template:
        metadata:
          annotations:
            security.cloud.google.com/use-workload-certificates: ""
          labels:
            k8s-app: example-grpc-client
        spec:
          containers:
          - image: golang:1.16-alpine
            imagePullPolicy: IfNotPresent
            name: example-grpc-client
            command:
            - /bin/sleep
            - inf
            env:
            - name: GRPC_XDS_BOOTSTRAP
              value: "/tmp/grpc-xds/td-grpc-bootstrap.json"
            resources:
              limits:
                cpu: 8
                memory: 8Gi
              requests:
                cpu: 300m
                memory: 512Mi
            volumeMounts:
            - name: grpc-td-conf
              mountPath: /tmp/grpc-xds/
          initContainers:
          - name: grpc-td-init
            image: gcr.io/trafficdirector-prod/td-grpc-bootstrap:0.16.0
            imagePullPolicy: Always
            args:
            - --config-mesh-experimental
            - "grpc-mesh"
            - --output
            - "/tmp/bootstrap/td-grpc-bootstrap.json"
            resources:
              limits:
                cpu: 100m
                memory: 100Mi
              requests:
                cpu: 10m
                memory: 100Mi
            volumeMounts:
            - name: grpc-td-conf
              mountPath: /tmp/bootstrap/
          serviceAccountName: example-grpc-client
          volumes:
          - name: grpc-td-conf
            emptyDir:
              medium: Memory
    EOF
    

Completa el proceso de la siguiente manera.

  1. Aplica la especificación:

    kubectl apply -f example-grpc-client.yaml
    
  2. Otorga las funciones necesarias a la cuenta de servicio:

    gcloud iam service-accounts add-iam-policy-binding \
      --role roles/iam.workloadIdentityUser \
      --member "serviceAccount:${PROJECT_ID}.svc.id.goog[default/example-grpc-client]" \
      ${PROJNUM}-compute@developer.gserviceaccount.com
    
    gcloud projects add-iam-policy-binding ${PROJECT_ID} \
      --member "serviceAccount:${PROJECT_ID}.svc.id.goog[default/example-grpc-client]" \
      --role roles/trafficdirector.client
    
  3. Verifica que el Pod se esté ejecutando.

    kubectl get pods
    

    El comando muestra información similar a la siguiente:

    NAMESPACE   NAME                                    READY   STATUS    RESTARTS   AGE
    default     example-grpc-client-7c969bb997-9fzjv    1/1     Running   0          104s
    [..skip..]
    

Ejecuta el servidor

Compila y ejecuta el servidor helloworld con xDS habilitado en el Pod del servidor que creaste antes.

Java

  1. Obtén el nombre del Pod creado para el servicio example-grpc-server:

    kubectl get pods | grep example-grpc-server
    

    Verás comentarios como los siguientes:

    default    example-grpc-server-77548868d-l9hmf     1/1    Running   0     105s
    
  2. Abre una shell al pod servidor:

    kubectl exec -it example-grpc-server-77548868d-l9hmf -- /bin/bash
    
  3. En la shell, verifica que el archivo de arranque en /tmp/grpc-xds/td-grpc-bootstrap.json coincida con el esquema descrito en la sección Archivo de arranque.

  4. Descarga la versión 1.42.1 de gRPC para Java y compila la aplicación del servidor xds-hello-world.

    curl -L https://github.com/grpc/grpc-java/archive/v1.42.1.tar.gz | tar -xz
    
    cd grpc-java-1.42.1/examples/example-xds
    
    ../gradlew --no-daemon installDist
    
  5. Ejecuta el servidor con la marca --xds-creds para indicar la seguridad habilitada para xDS, con 50051 como el puerto de escucha y xds-server como el nombre de identificación del servidor:

    ./build/install/example-xds/bin/xds-hello-world-server --xds-creds 50051 xds-server
    
  6. Después de que el servidor obtenga la configuración necesaria de Cloud Service Mesh, verás el siguiente resultado:

    Listening on port 50051
    plain text health service listening on port 50052
    

C++

  1. Obtén el nombre del Pod creado para el servicio example-grpc-server:

    kubectl get pods | grep example-grpc-server
    

    Verás comentarios como los siguientes:

    default    example-grpc-server-77548868d-l9hmf     1/1    Running   0     105s
    
  2. Abre una shell al pod servidor:

    kubectl exec -it example-grpc-server-77548868d-l9hmf -- /bin/bash
    
  3. En la shell, verifica que el archivo de arranque en /tmp/grpc-xds/td-grpc-bootstrap.json coincida con el esquema descrito en la sección Archivo de arranque.

  4. Descarga gRPC para C++ y compila la aplicación del servidor xds-hello-world.

    apt-get update -y && \
            apt-get install -y \
                build-essential \
                clang \
                python3 \
                python3-dev
    
    curl -L https://github.com/grpc/grpc/archive/master.tar.gz | tar -xz
    
    cd grpc-master
    
    tools/bazel build examples/cpp/helloworld:xds_greeter_server
    
  5. Ejecuta el servidor mediante 50051 como el puerto de escucha y xds_greeter_server como el nombre de identificación del servidor:

    bazel-bin/examples/cpp/helloworld/xds_greeter_server --port=50051 --maintenance_port=50052 --secure
    

    Para ejecutar el servidor sin credenciales, puedes especificar lo siguiente:

    bazel-bin/examples/cpp/helloworld/xds_greeter_server --nosecure
    
  6. Después de que el servidor obtenga la configuración necesaria de Cloud Service Mesh, verás el siguiente resultado:

    Listening on port 50051
    plain text health service listening on port 50052
    

Python

  1. Obtén el nombre del Pod creado para el servicio example-grpc-server:

    kubectl get pods | grep example-grpc-server
    

    Verás comentarios como los siguientes:

    default    example-grpc-server-77548868d-l9hmf     1/1    Running   0     105s
    
  2. Abre una shell al pod servidor:

    kubectl exec -it example-grpc-server-77548868d-l9hmf -- /bin/bash
    
  3. En la shell, verifica que el archivo de arranque en /tmp/grpc-xds/td-grpc-bootstrap.json coincida con el esquema descrito en la sección Archivo de arranque.

  4. Descarga la versión 1.41.0 de gRPC para Python y compila la aplicación de ejemplo.

    apt-get update -y
    
    apt-get install -y python3 python3-pip
    
    curl -L https://github.com/grpc/grpc/archive/v1.41.x.tar.gz | tar -xz
    
    cd grpc-1.41.x/examples/python/xds/
    
    python3 -m virtualenv venv
    
    source venv/bin/activate
    
    python3 -m pip install -r requirements.txt
    

  5. Ejecuta el servidor con la marca --xds-creds para indicar la seguridad habilitada para xDS, con 50051 como el puerto de escucha.

    python3 server.py 50051 --xds-creds
    
  6. Después de que el servidor obtenga la configuración necesaria de Cloud Service Mesh, verás el siguiente resultado:

    2021-05-06 16:10:34,042: INFO     Running with xDS Server credentials
    2021-05-06 16:10:34,043: INFO     Greeter server listening on port 50051
    2021-05-06 16:10:34,046: INFO     Maintenance server listening on port 50052
    

Go

  1. Obtén el nombre del Pod creado para el servicio example-grpc-server:

    kubectl get pods | grep example-grpc-server
    

    Verás comentarios como los siguientes:

    default    example-grpc-server-77548868d-l9hmf     1/1    Running   0     105s
    
  2. Abre una shell al pod servidor:

    kubectl exec -it example-grpc-server-77548868d-l9hmf -- /bin/sh
    
  3. En la shell, verifica que el archivo de arranque en /tmp/grpc-xds/td-grpc-bootstrap.json coincida con el esquema descrito en la sección Archivo de arranque.

  4. Descarga la versión 1.41.0 de gRPC para Go y navega al directorio que contiene la aplicación del servidor xds-hello-world.

    apk add curl
    
    curl -L https://github.com/grpc/grpc-go/archive/v1.42.0.tar.gz | tar -xz
    
    cd grpc-go-1.42.0/examples/features/xds/server
    
    
  5. Compila y ejecuta el servidor con la marca --xds_creds para indicar la seguridad habilitada para xDS, con 50051 como el puerto de escucha:

    GRPC_GO_LOG_VERBOSITY_LEVEL=2 GRPC_GO_LOG_SEVERITY_LEVEL="info" \
      go run main.go \
      -xds_creds \
      -port 50051
    
  6. Después de que el servidor obtenga la configuración necesaria de Cloud Service Mesh, verás el siguiente resultado:

    Using xDS credentials...
    Serving GreeterService on 0.0.0.0:50051 and HealthService on 0.0.0.0:50052
    

El proceso de verificación de estado toma entre 3 y 5 minutos para mostrar que el servicio está en buen estado después de iniciarse.

Ejecuta el cliente y verifica la configuración

Compila y ejecuta el cliente helloworld habilitado para xDS en el Pod de cliente que creaste antes.

Java

  1. Obtén el nombre del pod cliente:

    kubectl get pods | grep example-grpc-client
    

    Verás comentarios como los siguientes:

    default    example-grpc-client-7c969bb997-9fzjv     1/1    Running   0     105s
    
  2. Abre una shell al pod de cliente:

    kubectl exec -it example-grpc-client-7c969bb997-9fzjv -- /bin/bash
    
  3. En la shell de comandos, descarga la versión 1.42.1 de gRPC para Java y compila la aplicación cliente xds-hello-world.

    curl -L https://github.com/grpc/grpc-java/archive/v1.42.1.tar.gz | tar -xz
    
    cd grpc-java-1.42.1/examples/example-xds
    
    ../gradlew --no-daemon installDist
    
  4. Ejecuta el cliente con la marca --xds-creds para indicar la seguridad habilitada para xDS, el nombre del cliente y la string de conexión de destino:

    ./build/install/example-xds/bin/xds-hello-world-client --xds-creds xds-client \
          xds:///helloworld-gke:8000
    

    Deberías ver un resultado similar a este:

    Greeting: Hello xds-client, from xds-server
    

C++

  1. Obtén el nombre del pod cliente:

    kubectl get pods | grep example-grpc-client
    

    Verás comentarios como los siguientes:

    default    example-grpc-client-7c969bb997-9fzjv     1/1    Running   0     105s
    
  2. Abre una shell al pod de cliente:

    kubectl exec -it example-grpc-client-7c969bb997-9fzjv -- /bin/bash
    
  3. Una vez que estés dentro de la shell, descarga gRPC para C++ y compila la aplicación cliente xds-hello-world.

    apt-get update -y && \
            apt-get install -y \
                build-essential \
                clang \
                python3 \
                python3-dev
    
    curl -L https://github.com/grpc/grpc/archive/master.tar.gz | tar -xz
    
    cd grpc-master
    
    tools/bazel build examples/cpp/helloworld:xds_greeter_client
    
  4. Ejecuta el cliente con la marca --xds-creds para indicar la seguridad habilitada para xDS, el nombre del cliente y la string de conexión de destino:

    bazel-bin/examples/cpp/helloworld/xds_greeter_client --target=xds:///helloworld-gke:8000
    

    Para ejecutar el cliente sin credenciales, usa lo siguiente:

    bazel-bin/examples/cpp/helloworld/xds_greeter_client --target=xds:///helloworld-gke:8000 --nosecure
    

    Deberías ver un resultado similar a este:

    Greeter received: Hello world
    

Python

  1. Obtén el nombre del pod cliente:

    kubectl get pods | grep example-grpc-client
    

    Verás comentarios como los siguientes:

    default    example-grpc-client-7c969bb997-9fzjv     1/1    Running   0     105s
    
  2. Abre una shell al pod de cliente:

    kubectl exec -it example-grpc-client-7c969bb997-9fzjv -- /bin/bash
    
  3. Una vez que estés dentro de la shell, descarga la versión 1.41.0 de gRPC para Python y compila la aplicación cliente de ejemplo.

    apt-get update -y
    apt-get install -y python3 python3-pip
    python3 -m pip install virtualenv
    curl -L https://github.com/grpc/grpc/archive/v1.41.x.tar.gz | tar -xz
    cd grpc-1.41.x/examples/python/xds/
    python3 -m virtualenv venv
    source venv/bin/activate
    python3 -m pip install -r requirements.txt
    
  4. Ejecuta el cliente con la marca --xds-creds para indicar la seguridad habilitada para xDS, el nombre del cliente y la string de conexión de destino:

    python3 client.py xds:///helloworld-gke:8000 --xds-creds
    

    Deberías ver un resultado similar a este:

    Greeter client received: Hello you from example-host!
    

Go

  1. Obtén el nombre del pod cliente:

    kubectl get pods | grep example-grpc-client
    

    Verás comentarios como los siguientes:

    default    example-grpc-client-7c969bb997-9fzjv     1/1    Running   0     105s
    
  2. Abre una shell al pod de cliente:

    kubectl exec -it example-grpc-client-7c969bb997-9fzjv -- /bin/sh
    
  3. Una vez que estés dentro de la shell, descarga la versión 1.42.0 de gRPC para Go y navega al directorio que contiene la aplicación cliente xds-hello-world.

    apk add curl
    
    curl -L https://github.com/grpc/grpc-go/archive/v1.42.0.tar.gz | tar -xz
    
    cd grpc-go-1.42.0/examples/features/xds/client
    
  4. Compila y ejecuta el cliente con la marca --xds_creds para indicar la seguridad habilitada para xDS, el nombre del cliente y la cadena de conexión de destino:

    GRPC_GO_LOG_VERBOSITY_LEVEL=2 GRPC_GO_LOG_SEVERITY_LEVEL="info" \
      go run main.go \
      -xds_creds \
      -name xds-client \
      -target xds:///helloworld-gke:8000
    

    Deberías ver un resultado similar a este:

    Greeting: Hello xds-client, from example-grpc-server-77548868d-l9hmf
    

Configura el acceso a nivel de servicio con una política de autorización

Se requiere compatibilidad con gRFC A41 para la compatibilidad con políticas de autorización. Puedes encontrar las versiones de lenguaje necesarias en GitHub.

Usa estas instrucciones para configurar el acceso a nivel de servicio con políticas de autorización. Antes de crear políticas de autorización, lee la precaución en Restringir el acceso con autorización.

Para facilitar la verificación de la configuración, crea un nombre de host adicional que el cliente pueda usar para referirse al servicio helloworld-gke.

  1. Actualiza la especificación GRPCRoute que se almacenó anteriormente en grpc_route.yaml

    name: helloworld-grpc-route
    hostnames:
    - helloworld-gke:8000
    - helloworld-gke-noaccess:8000
    meshes:
    - projects/PROJECT_NUMBER/locations/global/meshes/grpc-mesh
    rules:
    - action:
        destinations:
        - serviceName: projects/PROJECT_NUMBER/locations/global/backendServices/grpc-gke-helloworld-service
    
  2. Vuelve a importar el recurso GRPCRoute desde la especificación grpc_route.yaml.

    gcloud network-services grpc-routes import helloworld-grpc-route \
      --source=grpc_route.yaml \
      --location=global
    

Con las siguientes instrucciones, se crea una política de autorización que permite solicitudes que envía la cuenta example-grpc-client en la que el nombre de host es helloworld-gke:8000 y el puerto es 50051.

gcloud

  1. Para crear una política de autorización, crea un archivo llamado helloworld-gke-authz-policy.yaml.

    action: ALLOW
    name: helloworld-gke-authz-policy
    rules:
    - sources:
      - principals:
        - spiffe://PROJECT_ID.svc.id.goog/ns/default/sa/example-grpc-client
      destinations:
      - hosts:
        - helloworld-gke:8000
        ports:
        - 50051
    
  2. Importa la política.

    gcloud network-security authorization-policies import \
      helloworld-gke-authz-policy \
      --source=helloworld-gke-authz-policy.yaml \
      --location=global
    
  3. Actualiza la política de extremos para hacer referencia a la política de autorización nueva. Para ello, agrega lo siguiente al archivo ep-mtls-psms.yaml.

    authorizationPolicy: projects/${PROJECT_ID}/locations/global/authorizationPolicies/helloworld-gke-authz-policy
    

    La política de extremo ahora especifica que mTLS y la política de autorización se deben aplicar en las solicitudes entrantes a los Pods cuyos archivos de arranque de gRPC contienen la etiqueta app:helloworld.

  4. Importa la política:

    gcloud network-services endpoint-policies import ep-mtls-psms \
      --source=ep-mtls-psms.yaml --location=global
    

Valida la política de autorización

Usa estas instrucciones para confirmar que la política de autorización funciona de forma correcta.

Java

  1. Abre una shell al Pod de cliente que usaste antes.

    kubectl exec -it example-grpc-client-7c969bb997-9fzjv -- /bin/bash
    
  2. En la shell de comandos, ejecuta los siguientes comandos para validar la configuración.

    cd grpc-java-1.42.1/examples/example-xds
    ./build/install/example-xds/bin/xds-hello-world-client --xds-creds xds-client \
          xds:///helloworld-gke:8000
    

    Deberías ver un resultado similar a este:

    Greeting: Hello xds-client, from xds-server
    
  3. Vuelve a ejecutar el cliente con el nombre del servidor alternativo. Ten en cuenta que este es un caso de error. La solicitud no es válida porque la política de autorización solo permite el acceso al nombre de host helloworld-gke:8000.

    ./build/install/example-xds/bin/xds-hello-world-client --xds-creds xds-client \
          xds:///helloworld-gke-noaccess:8000
    

    Deberías ver un resultado similar a este:

    WARNING: RPC failed: Status{code=PERMISSION_DENIED}
    

    Si no ves este resultado, es posible que la política de autorización aún no esté en uso. Espera unos minutos y vuelve a probar todo el proceso de verificación.

Go

  1. Abre una shell al Pod de cliente que usaste antes.

    kubectl exec -it example-grpc-client-7c969bb997-9fzjv -- /bin/bash
    
  2. En la shell de comandos, ejecuta los siguientes comandos para validar la configuración.

    cd grpc-go-1.42.0/examples/features/xds/client
    GRPC_GO_LOG_VERBOSITY_LEVEL=2 GRPC_GO_LOG_SEVERITY_LEVEL="info" \
      go run main.go \
      -xds_creds \
      -name xds-client \
      -target xds:///helloworld-gke:8000
    

    Deberías ver un resultado similar a este:

    Greeting: Hello xds-client, from example-grpc-server-77548868d-l9hmf
    
  3. Vuelve a ejecutar el cliente con el nombre del servidor alternativo. Ten en cuenta que este es un caso de error. La solicitud no es válida porque la política de autorización solo permite el acceso al nombre de host helloworld-gke:8000.

    GRPC_GO_LOG_VERBOSITY_LEVEL=2 GRPC_GO_LOG_SEVERITY_LEVEL="info" \
      go run main.go \
      -xds_creds \
      -name xds-client \
      -target xds:///helloworld-gke-noaccess:8000
    

    Deberías ver un resultado similar a este:

    could not greet: rpc error: code = PermissionDenied desc = Incoming RPC is not allowed: rpc error: code = PermissionDenied desc = incoming RPC did not match an allow policy
    exit status 1
    

    Si no ves este resultado, es posible que la política de autorización aún no esté en uso. Espera unos minutos y vuelve a probar todo el proceso de verificación.

Usa TLS en lugar de mTLS

En este ejemplo, el uso de TLS solo requiere un pequeño cambio.

  1. En ServerTlsPolicy, descarta el mtlsPolicy:

    cat << EOF > server-tls-policy.yaml
    name: "server-tls-policy"
    serverCertificate:
      certificateProviderInstance:
        pluginInstance: google_cloud_private_spiffe
    EOF
    
  2. En su lugar, usa esta política en EndpointPolicy:

    cat << EOF > ep-tls-psms.yaml
    name: "ep-mtls-psms"
    type: "GRPC_SERVER"
    serverTlsPolicy: "projects/${PROJECT_ID}/locations/global/serverTlsPolicies/server-tls-policy"
    trafficPortSelector:
      ports:
      - "50051"
    endpointMatcher:
      metadataLabelMatcher:
        metadataLabelMatchCriteria: "MATCH_ALL"
        metadataLabels: []
    EOF
    
  3. ClientTlsPolicy para mTLS también funciona en el caso de TLS, pero la sección clientCertificate de la política se puede descartar, ya que no es necesaria para TLS:

    cat << EOF > client-tls-policy.yaml
    name: "client-tls-policy"
    serverValidationCa:
    - certificateProviderInstance:
        pluginInstance: google_cloud_private_spiffe
    EOF
    

Usa la seguridad del servicio con el ejemplo de Wallet

En esta sección, se proporciona una descripción general de alto nivel sobre cómo habilitar el ejemplo de Vault con seguridad de servicios para Java, C++ y Go.

Java

Puedes encontrar el código fuente de ejemplo para Java en github. El código ya usa las credenciales XdsChannel y XdsServer cuando configuras la seguridad sin proxy.

En estas instrucciones, se describe la configuración del ejemplo de Vault con Go. El proceso es similar para Java En las instrucciones se usa una imagen de Docker preexistente que se obtuvo del repositorio de contenedores de Google Cloud.

Para crear el ejemplo, sigue estas instrucciones:

  1. Clona el repositorio y obtén los archivos en el directorio Ejemplos de gRPC.
  2. Edita el archivo 00-common-env.sh. Marca como comentario la línea existente que establece el valor de WALLET_DOCKER_IMAGE en la imagen de Docker de Go y quita los comentarios de la línea que establece el valor de WALLET_DOCKER_IMAGE en la imagen de Docker de Java.
  3. Crea y configura instancias de Cloud Router con las instrucciones que aparecen en Crea y configura instancias de Cloud Router o con la función create_cloud_router_instances en la secuencia de comandos 10.apis.sh.
  4. Crea un clúster mediante las instrucciones para el ejemplo hello world o la función create_cluster en la secuencia de comandos 20-cluster.sh.
  5. Crea autoridades certificadoras privadas con las instrucciones para el servicio de CA o con la secuencia de comandos 30-private-ca-setup.sh.
  6. Crea recursos de Kubernetes, incluidas las cuentas de servicio, los espacios de nombres, los servicios de Kubernetes, los NEG y la implementación en el lado del servidor para todos los servicios: account, stats, stats_premium, wallet_v1 y wallet_v2, con la secuencia de comandos 40-k8s-resources.sh.
  7. Para cada uno de los servicios que creaste, crea una verificación de estado y un servicio de backend mediante create_health_check y create_backend_service en la secuencia de comandos 50-td-components.sh.
  8. Crea los componentes de enrutamiento de Cloud Service Mesh con create_routing_components en la secuencia de comandos 60-routing-components.sh.
  9. Crea los componentes de seguridad de Cloud Service Mesh para cada servicio de backend con create_security_components en la secuencia de comandos 70-security-components.sh.
  10. Crea la implementación de cliente de Marketplace mediante create_client_deployment en la secuencia de comandos 75-client-deployment.sh.
  11. Para verificar la configuración, inicia el cliente como se describe en Verifica con los clientes de grpc-wallet.

C++

Puedes encontrar el código fuente de ejemplo para C++ en github. El código ya usa las credenciales XdsChannel y XdsServer cuando configuras la seguridad sin proxy.

En estas instrucciones, se describe la configuración del ejemplo de Vault con Go. El proceso es similar para C++ En las instrucciones se usa una imagen de Docker preexistente que se obtuvo del repositorio de contenedores de Google Cloud.

Para crear el ejemplo, sigue estas instrucciones:

  1. Clona el repositorio y obtén los archivos en el directorio Ejemplos de gRPC.
  2. Edita el archivo 00-common-env.sh. Comenta la línea existente que establece el valor de WALLET_DOCKER_IMAGE en la imagen de Docker de Go y quita el comentario de la línea que establece el valor de WALLET_DOCKER_IMAGE en la imagen de Docker de C++.
  3. Crea y configura instancias de Cloud Router con las instrucciones que aparecen en Crea y configura instancias de Cloud Router o con la función create_cloud_router_instances en la secuencia de comandos 10.apis.sh.
  4. Crea un clúster mediante las instrucciones para el ejemplo hello world o la función create_cluster en la secuencia de comandos 20-cluster.sh.
  5. Crea autoridades certificadoras privadas con las instrucciones para el servicio de AC o con la secuencia de comandos 30-private-ca-setup.sh.
  6. Crea recursos de Kubernetes, incluidas las cuentas de servicio, los espacios de nombres, los servicios de Kubernetes, los NEG y la implementación en el lado del servidor para todos los servicios: account, stats, stats_premium, wallet_v1 y wallet_v2, con la secuencia de comandos 40-k8s-resources.sh.
  7. Para cada uno de los servicios que creaste, crea una verificación de estado y un servicio de backend mediante create_health_check y create_backend_service en la secuencia de comandos 50-td-components.sh.
  8. Crea los componentes de enrutamiento de Cloud Service Mesh con create_routing_components en la secuencia de comandos 60-routing-components.sh.
  9. Crea los componentes de seguridad de Cloud Service Mesh para cada servicio de backend con create_security_components en la secuencia de comandos 70-security-components.sh.
  10. Crea la implementación de cliente de Marketplace mediante create_client_deployment en la secuencia de comandos 75-client-deployment.sh.
  11. Para verificar la configuración, inicia el cliente como se describe en Verifica con los clientes de grpc-wallet.

Go

Puedes encontrar código fuente de ejemplo para Go en GitHub. El código ya usa las credenciales XdsChannel y XdsServer cuando configuras la seguridad sin proxy.

En las instrucciones se usa una imagen de Docker preexistente que se obtuvo del repositorio de contenedores de Google Cloud.

Para crear el ejemplo, sigue estas instrucciones:

  1. Clona el repositorio y obtén los archivos en el directorio Ejemplos de gRPC.
  2. Edita el archivo 00-common-env.sh a fin de establecer los valores correctos para las variables de entorno.
  3. Crea y configura instancias de Cloud Router con las instrucciones que aparecen en Crea y configura instancias de Cloud Router o con la función create_cloud_router_instances en la secuencia de comandos 10.apis.sh.
  4. Crea un clúster mediante las instrucciones para el ejemplo hello world o la función create_cluster en la secuencia de comandos 20-cluster.sh.
  5. Crea autoridades certificadoras privadas con las instrucciones para el servicio de CA o con la secuencia de comandos 30-private-ca-setup.sh.
  6. Crea recursos de Kubernetes, incluidas las cuentas de servicio, los espacios de nombres, los servicios de Kubernetes, los NEG y la implementación en el lado del servidor para todos los servicios: account, stats, stats_premium, wallet_v1 y wallet_v2, con la secuencia de comandos 40-k8s-resources.sh.
  7. Para cada uno de los servicios que creaste, crea una verificación de estado y un servicio de backend mediante create_health_check y create_backend_service en la secuencia de comandos 50-td-components.sh.
  8. Crea los componentes de enrutamiento de Cloud Service Mesh con create_routing_components en la secuencia de comandos 60-routing-components.sh.
  9. Crea los componentes de seguridad de Cloud Service Mesh para cada servicio de backend con create_security_components en la secuencia de comandos 70-security-components.sh.
  10. Crea la implementación de cliente de Marketplace mediante create_client_deployment en la secuencia de comandos 75-client-deployment.sh.
  11. Para verificar la configuración, inicia el cliente como se describe en Verifica con los clientes de grpc-wallet.

Archivo de arranque

En el proceso de configuración de esta guía, se usa un generador de arranque para crear el archivo de arranque requerido. En esta sección, se proporciona información de referencia sobre el archivo de arranque.

El archivo de arranque contiene información de configuración que requiere el código de gRPC sin proxy, incluida la información de conexión para el servidor xDS. El archivo de arranque contiene la configuración de seguridad que requiere la función de seguridad de gRPC sin proxy. El servidor de gRPC requiere un campo adicional. Un archivo de arranque de muestra se ve de la siguiente manera:

{
  "xds_servers": [
    {
      "server_uri": "trafficdirector.googleapis.com:443",
      "channel_creds": [
        {
          "type": "google_default"
        }
      ],
      "server_features": [
        "xds_v3"
      ]
    }
  ],
  "authorities": {
    "traffic-director-c2p.xds.googleapis.com": {
      "xds_servers": [
        {
          "server_uri": "dns:///directpath-pa.googleapis.com",
          "channel_creds": [
            {
              "type": "google_default"
            }
          ],
          "server_features": [
            "xds_v3",
            "ignore_resource_deletion"
          ]
        }
      ],
      "client_listener_resource_name_template": "xdstp://traffic-director-c2p.xds.googleapis.com/envoy.config.listener.v3.Listener/%s"
    }
  },
  "node": {
    "id": "projects/9876012345/networks/mesh:grpc-mesh/nodes/b59f49cc-d95a-4462-9126-112f794d5dd3",
    "cluster": "cluster",
    "metadata": {
      "INSTANCE_IP": "10.28.2.8",
      "TRAFFICDIRECTOR_DIRECTPATH_C2P_IPV6_CAPABLE": true,
      "TRAFFICDIRECTOR_GCP_PROJECT_NUMBER": "223606568246",
      "TRAFFICDIRECTOR_NETWORK_NAME": "default",
      "app": "helloworld"
    },
    "locality": {
      "zone": "us-central1-c"
    }
  },
  "certificate_providers": {
    "google_cloud_private_spiffe": {
      "plugin_name": "file_watcher",
      "config": {
        "certificate_file": "/var/run/secrets/workload-spiffe-credentials/certificates.pem",
        "private_key_file": "/var/run/secrets/workload-spiffe-credentials/private_key.pem",
        "ca_certificate_file": "/var/run/secrets/workload-spiffe-credentials/ca_certificates.pem",
        "refresh_interval": "600s"
      }
    }
  },
  "server_listener_resource_name_template": "grpc/server?xds.resource.listening_address=%s"
}

Actualizaciones del archivo de arranque para el servicio de seguridad

Los siguientes campos reflejan las modificaciones relacionadas con la seguridad y el uso de xDS v3:

El campo id dentro de node proporciona una identidad única al cliente de gRPC para Cloud Service Mesh. Debes proporcionar el número del proyecto de Google Cloud y el nombre de red con el ID del nodo en este formato:

projects/{project number}/networks/{network name}/nodes/[UNIQUE_ID]

El siguiente es un ejemplo para el proyecto 1234 y la red predeterminada:

projects/1234/networks/default/nodes/client1

El campo INSTANCE_IP es la dirección IP del pod o 0.0.0.0 para indicar INADDR_ANY. El servidor de gRPC usa este campo para recuperar el recurso de objeto de escucha desde Cloud Service Mesh para la seguridad del servidor.

Campos de configuración de seguridad en el archivo de arranque

Clave JSON Tipo Valor Notas
server_listener_resource_name_template String grpc/server?xds.resource.listening_address=%s Obligatorio para los servidores gRPC. gRPC usa este valor para redactar el nombre del recurso para recuperar el recurso "Listener" de Cloud Service Mesh para la seguridad del servidor y otras opciones de configuración. gRPC usa esto para formar la cadena del nombre del recurso.
certificate_providers Struct de JSON google_cloud_private_spiffe Obligatorio. El valor es un struct de JSON que representa una asignación de nombres para instancias de proveedor de certificados. Se usa una instancia de proveedor de certificados para recuperar identidades y certificados raíz. El archivo de arranque de ejemplo contiene un nombre, google_cloud_private_spiffe, con el struct de JSON de la instancia del proveedor del certificado como valor. Cada struct de JSON de instancia del proveedor de certificados tiene dos campos:
  • plugin_name: valor obligatorio que identifica el complemento del proveedor de certificados que se usará según lo requiera la arquitectura de complementos de gRPC para proveedores de certificados. gRPC tiene compatibilidad integrada con el complemento de observación de archivos que se usa en esta configuración. El plugin_name es file_watcher.
  • config: valor obligatorio que identifica el blog de configuración JSON para el complemento file_watcher. El esquema y el contenido dependen del complemento.

El contenido de la estructura JSON config para el complemento file_watcher es el siguiente:

  • certificate_file: string obligatoria. Este valor es la ubicación del certificado de identidad.
  • private_key_file: string obligatoria. El valor es la ubicación del archivo de clave privada, que debe coincidir con el certificado de identidad.
  • ca_certificate_file: string obligatoria. El valor es la ubicación del certificado raíz, que también se conoce como el paquete de confianza.
  • refresh_interval: string opcional. El valor indica el intervalo de actualización, especificado con la representación de string de una asignación JSON de Duration. El valor predeterminado es “600s”, una duración de 10 minutos.

Generador de arranque

La imagen del contenedor del generador de arranque está disponible en gcr.io/trafficdirector-prod/td-grpc-bootstrap:0.16.0. Su código fuente está disponible en https://github.com/GoogleCloudPlatform/traffic-director-grpc-bootstrap. Las opciones de línea de comandos más usadas son las siguientes:

  • --output: Usa esta opción para especificar dónde se escribe el archivo de arranque de salida, por ejemplo, el comando de arranque --output /tmp/bootstrap/td-grpc-bootstrap.json genera el archivo de arranque en /tmp/bootstrap/td-grpc-bootstrap.json en el sistema de archivos del pod.
  • --config-mesh-experimental: Usa esta opción para especificar el nombre de la malla, que debe coincidir con el recurso Mesh.
  • --node-metadata: Usa esta marca para propagar los metadatos del nodo en el archivo de arranque. Esto es obligatorio cuando usas comparadores de etiquetas de metadatos en EndpointPolicy, en los que Cloud Service Mesh usa los datos de etiquetas proporcionados en la sección de metadatos de nodo del archivo de arranque. El argumento se proporciona en el formato clave=valor, por ejemplo: --node-metadata version=prod --node-metadata type=grpc.

Con la información anterior, se agrega lo siguiente en la sección de metadatos de nodo del archivo de arranque:

{
  "node": {
...
    "metadata": {
      "version": "prod",
      "type": "grpc",
...
    },
...
  },
...
}

Borrar la implementación

También puedes ejecutar estos comandos para borrar la implementación que creaste con esta guía.

Para borrar el clúster, ejecuta este comando:

gcloud container clusters delete CLUSTER_NAME --zone ZONE --quiet

Para borrar los recursos que creaste, ejecuta estos comandos:

gcloud compute backend-services delete grpc-gke-helloworld-service --global --quiet
gcloud compute network-endpoint-groups delete example-grpc-server --zone ZONE --quiet
gcloud compute firewall-rules delete grpc-gke-allow-health-checks --quiet
gcloud compute health-checks delete grpc-gke-helloworld-hc --quiet
gcloud network-services endpoint-policies delete ep-mtls-psms \
    --location=global --quiet
gcloud network-security authorization-policies delete helloworld-gke-authz-policy \
   --location=global --quiet
gcloud network-security client-tls-policies delete client-mtls-policy \
    --location=global --quiet
gcloud network-security server-tls-policies delete server-tls-policy \
    --location=global --quiet
gcloud network-security server-tls-policies delete server-mtls-policy \
    --location=global --quiet

Soluciona problemas

Usa estas instrucciones para resolver problemas con la implementación de seguridad.

Las cargas de trabajo no pueden obtener una configuración de Cloud Service Mesh

Podría aparecer un error similar a este:

PERMISSION_DENIED: Request had insufficient authentication scopes.

Asegúrate de que se den las siguientes condiciones:

  • Creaste tu clúster de GKE con el argumento --scopes=cloud-platform.
  • Asignaste el roles/trafficdirector.client a tus cuentas de servicio de Kubernetes.
  • Asignaste roles/trafficdirector.client a tu cuenta de servicio de Google Cloud predeterminada (la cuenta ${GSA_EMAIL} anterior).
  • Habilitaste el servicio trafficdirector.googleapis.com (API).

Tu servidor de gRPC no usa TLS/mTLS incluso con la configuración correcta de Cloud Service Mesh

Asegúrate de especificar GRPC_SERVER en la configuración de las políticas de extremos. Si especificaste SIDECAR_PROXY, gRPC ignora la configuración.

No puedes crear el clúster de GKE con la versión de clúster solicitada

El comando de creación del clúster de GKE podría fallar con un error similar al siguiente:

Node version "1.20.5-gke.2000" is unsupported.

Asegúrate de usar el argumento --release-channel rapid en el comando de creación de clústeres. Debes usar el canal de versiones rápido para obtener la versión correcta de esta.

Si aparece el error No usable endpoint

Si un cliente no puede comunicarse con el servidor debido a un error No usable endpoint, es posible que el verificador de estado haya marcado los backends del servidor como en mal estado. Para verificar el estado de los backends, ejecuta este comando gcloud:

gcloud compute backend-services get-health grpc-gke-helloworld-service --global

Si el comando muestra que el backend está en mal estado, puede deberse a uno de estos motivos:

  • El firewall no se creó o no contiene el rango de IP de origen correcto.
  • Las etiquetas de destino de tu firewall no coinciden con las etiquetas del clúster que creaste.

Las cargas de trabajo no pueden comunicarse en la configuración de seguridad

Si las cargas de trabajo no pueden comunicarse después de configurar la seguridad de la malla de servicios sin proxy, sigue estas instrucciones para determinar la causa.

  1. Inhabilita la seguridad sin proxy y elimina los problemas en los casos de uso de balanceo de cargas de la malla de servicios sin proxy. Para inhabilitar la seguridad en la malla, realiza una de las siguientes acciones:
    1. Usa credenciales de texto sin formato en el cliente y el servidor O
    2. No configures la seguridad para el servicio de backend ni la política de extremos en la configuración de Cloud Service Mesh.

Sigue los pasos que se indican en Solución de problemas de implementaciones de Cloud Service Mesh sin proxy, ya que no hay una configuración de seguridad en la implementación.

  1. Modifica las cargas de trabajo para usar credenciales de xDS con texto simple o credenciales no seguras como credenciales de resguardo. Mantén la configuración de Cloud Service Mesh con la seguridad inhabilitada, como se mencionó anteriormente. En este caso, aunque gRPC permite que Cloud Service Mesh configure la seguridad, Cloud Service Mesh no envía información de seguridad, en cuyo caso gRPC debe recurrir a credenciales de texto simple (o no seguras) que deberían funcionar de manera similar al primer caso anterior. Si este caso no funciona, haz lo siguiente:

    1. Aumenta el nivel de registro en el cliente y el servidor para que puedas ver los mensajes xDS intercambiados entre gRPC y Cloud Service Mesh.
    2. Asegúrate de que Cloud Service Mesh no tenga habilitada la seguridad en las respuestas de CDS y LDS que se envían a las cargas de trabajo.
    3. Asegúrate de que las cargas de trabajo no usen los modos TLS o mTLS en sus canales. Si ves mensajes de registro relacionados con los protocolos de enlace TLS, verifica el código fuente de tu aplicación y asegúrate de usar texto no seguro o simple como credenciales de resguardo. Si el código fuente de la aplicación es correcto, es posible que sea un error en la biblioteca de gRPC.
  2. Verifica que la integración del servicio de CA con GKE funcione de forma correcta para tu clúster de GKE mediante los pasos para solucionar problemas de esa guía del usuario. Asegúrate de que los certificados y claves que proporciona esa característica estén disponibles en el directorio especificado, /var/run/secrets/workload-spiffe-credentials/.

  3. Habilita TLS (en lugar de mTLS) en la malla, como se describió antes, y reinicia las cargas de trabajo del cliente y del servidor.

    1. Aumenta el nivel de registro en el cliente y el servidor para poder ver los mensajes xDS intercambiados entre gRPC y Cloud Service Mesh.
    2. Asegúrate de que Cloud Service Mesh tenga habilitada la seguridad en las respuestas de CDS y LDS que se envían a las cargas de trabajo.

El cliente falla con un CertificateException y un mensaje Peer certificate SAN check failed

Esto indica un problema con los valores de subjectAltNames en el mensaje SecuritySettings. Ten en cuenta que estos valores se basan en los servicios de Kubernetes que creaste para tu servicio de backend. Para cada servicio de Kubernetes que creaste, hay un ID de SPIFFE asociado, en este formato:

spiffe://${WORKLOAD_POOL}/ns/${K8S_NAMESPACE}/sa/${SERVICE_ACCOUNT}

Estos valores son los siguientes:

  • WORKLOAD_POOL: el grupo de cargas de trabajo del clúster, que es ${PROJECT_ID}.svc.id.goog
  • K8S_NAMESPACE: el espacio de nombres de Kubernetes que usaste en la implementación del servicio
  • SERVICE_ACCOUNT: la cuenta de servicio de Kubernetes que usaste en la implementación del servicio

Para cada servicio de Kubernetes que adjuntaste al servicio de backend como un grupo de extremos de red, asegúrate de haber calculado de forma correcta el ID de SPIFFE y haber agregado ese ID de SPIFFE al campo subjectAltNames en el mensaje SecuritySettings.

Las aplicaciones no pueden usar los certificados mTLS con tu biblioteca de gRPC

Si tus aplicaciones no pueden usar los certificados mTLS con tu biblioteca de gRPC, haz lo siguiente:

  1. Verifica que la especificación del pod contenga la anotación security.cloud.google.com/use-workload-certificates que se describe en Crea un servicio de gRPC sin proxy con NEG.

  2. Verifica que se pueda acceder a los archivos que contienen la cadena de certificados junto con el certificado de hoja, la clave privada y los certificados de CA de confianza en las siguientes rutas desde el pod:

    1. Cadena de certificados junto con certificado de hoja: "/var/run/secrets/workload-spiffe-credentials/certificates.pem"
    2. Clave privada: “/var/run/secrets/workload-spiffe-credentials/private_key.pem”
    3. Paquete de CA: "/var/run/secrets/workload-spiffe-credentials/ca_certificates.pem"
  3. Si los certificados del paso anterior no están disponibles, haz lo siguiente:

      gcloud privateca subordinates describe SUBORDINATE_CA_POOL_NAME 
    --location=LOCATION

    1. Verifica que el plano de control de GKE tenga la vinculación de función de IAM correcta y otórgale acceso al servicio de CA:

      # Get the IAM policy for the CA
      gcloud privateca roots get-iam-policy ROOT_CA_POOL_NAME
      
      # Verify that there is an IAM binding granting access in the following format
      - members:
      - serviceAccount:service-projnumber@container-engine-robot.iam.gserviceaccount.com
      role: roles/privateca.certificateManager
      
      # Where projnumber is the project number (e.g. 2915810291) for the GKE cluster.
      
    2. Verifica que el certificado no haya vencido. Esta es la cadena de certificados y el certificado de hoja en /var/run/secrets/workload-spiffe-credentials/certificates.pem. Como comprobación, ejecuta este comando:

      cat /var/run/secrets/workload-spiffe-credentials/certificates.pem | openssl x509 -text -noout | grep "Not After"
      

    3. Ejecuta el siguiente comando para verificar que el tipo de clave sea compatible con tu aplicación:

      cat /var/run/secrets/workload-spiffe-credentials/certificates.pem | openssl x509 -text -noout | grep "Public Key Algorithm" -A 3
      

    4. Verifica que tu aplicación de Java para gRPC tenga el siguiente keyAlgorithm en el archivo YAML WorkloadCertificateConfig:

      keyAlgorithm:
        rsa:
          modulusSize: 4096
    
  4. Verifica que la CA use la misma familia de claves que la clave del certificado.

El cliente, el servidor o el par rechazaron el certificado de una aplicación

  1. Verifica que la aplicación par use el mismo paquete de confianza para verificar el certificado.
  2. Verifica que el certificado en uso no esté vencido (cadena de certificados junto con certificado de hoja: “/var/run/secrets/workload-spiffe-credentials/certificates.pem”).

Los pods permanecen en un estado pendiente

Si los Pods permanecen en estado pendiente durante el proceso de configuración, aumenta los recursos de CPU y memoria para los pods en tu especificación de implementación.

No se pudo crear el clúster con la marca --enable-mesh-certificates

Asegúrate de ejecutar la versión más reciente de la CLI de gcloud:

gcloud components update

Ten en cuenta que la marca --enable-mesh-certificates solo funciona con gcloud beta.

Los pods no se inician

Es posible que los pods que usan certificados de malla de GKE no se inicien si falla el aprovisionamiento de certificados. Esto puede suceder en situaciones como las siguientes:

  • WorkloadCertificateConfig o TrustConfig no están bien configurados o no se encuentran.
  • No se aprueban las CSR.

Para verificar si el aprovisionamiento de certificados falla, revisa los eventos del pod.

  1. Verifica el estado del Pod:

    kubectl get pod -n POD_NAMESPACE POD_NAME
    

    Reemplaza lo siguiente:

    • POD_NAMESPACE: es el espacio de nombres del Pod.
    • POD_NAME: es el nombre del Pod.
  2. Revisa los eventos recientes de tu pod:

    kubectl describe pod -n POD_NAMESPACE POD_NAME
    
  3. Si falla el aprovisionamiento de certificados, verás un evento con Type=Warning, Reason=FailedMount, From=kubelet y un campo Message que comienza con MountVolume.SetUp failed for volume "gke-workload-certificates". El campo Message contiene información para solucionar problemas.

    Events:
      Type     Reason       Age                From       Message
      ----     ------       ----               ----       -------
      Warning  FailedMount  13s (x7 over 46s)  kubelet    MountVolume.SetUp failed for volume "gke-workload-certificates" : rpc error: code = Internal desc = unable to mount volume: store.CreateVolume, err: unable to create volume "csi-4d540ed59ef937fbb41a9bf5380a5a534edb3eedf037fe64be36bab0abf45c9c": caPEM is nil (check active WorkloadCertificateConfig)
    
  4. Consulta los siguientes pasos de solución de problemas si el motivo por el que tus pods no se inician es porque hay objetos mal configurados o CSR rechazadas.

La configuración de WorkloadCertificateConfig o TrustConfig es incorrecta

Asegúrate de haber creado los objetos WorkloadCertificateConfig y TrustConfig de forma correcta. Puedes diagnosticar una configuración incorrecta en cualquiera de estos objetos mediante kubectl.

  1. Recupera el estado actual.

    Para WorkloadCertificateConfig:

    kubectl get WorkloadCertificateConfig default -o yaml
    

    Para TrustConfig:

    kubectl get TrustConfig default -o yaml
    
  2. Inspecciona el resultado del estado. Un objeto válido tendrá una condición con type: Ready y status: "True".

    status:
      conditions:
      - lastTransitionTime: "2021-03-04T22:24:11Z"
        message: WorkloadCertificateConfig is ready
        observedGeneration: 1
        reason: ConfigReady
        status: "True"
        type: Ready
    

    En el caso de los objetos no válidos, aparece status: "False" en su lugar. Los campos reason y message contienen detalles adicionales sobre la solución de problemas.

Las CSR no están aprobadas.

Si algo sale mal durante el proceso de aprobación de la CSR, puedes verificar los detalles del error en las condiciones de type: Approved y type: Issued de la CSR.

  1. Enumera las CSR relevantes mediante kubectl:

    kubectl get csr \
      --field-selector='spec.signerName=spiffe.gke.io/spiffe-leaf-signer'
    
  2. Elige una CSR que tenga el estado Approved y no Issued, o que no tenga el estado Approved.

  3. Obtén detalles de la CSR seleccionada con kubectl:

    kubectl get csr CSR_NAME -o yaml
    

    Reemplaza CSR_NAME por el nombre de la CSR que elegiste.

Una CSR válida tiene una condición con type: Approved y status: "True", y un certificado válido en el campo status.certificate:

status:
  certificate: <base64-encoded data>
  conditions:
  - lastTransitionTime: "2021-03-04T21:58:46Z"
    lastUpdateTime: "2021-03-04T21:58:46Z"
    message: Approved CSR because it is a valid SPIFFE SVID for the correct identity.
    reason: AutoApproved
    status: "True"
    type: Approved

La información de solución de problemas para CSR no válidas aparece en los campos message y reason.

Faltan certificados en los pods

  1. Obtén las especificaciones de pod para tu pod:

    kubectl get pod -n POD_NAMESPACE POD_NAME -o yaml
    

    Reemplaza lo siguiente:

    • POD_NAMESPACE: es el espacio de nombres del Pod.
    • POD_NAME: es el nombre del Pod.
  2. Verifica que las especificaciones del pod contengan la anotación security.cloud.google.com/use-workload-certificates que se describe en Configura pods para recibir credenciales de mTLS.

  3. Verifica que el controlador de admisión de certificados de malla de GKE inserte de forma correcta un volumen de controlador CSI de tipo workloadcertificates.security.cloud.google.com en tu especificación de pods:

    volumes:
    ...
    -csi:
      driver: workloadcertificates.security.cloud.google.com
      name: gke-workload-certificates
    ...
    
  4. Comprueba la presencia de una activación de volumen en cada uno de los contenedores:

    containers:
    - name: ...
      ...
      volumeMounts:
      - mountPath: /var/run/secrets/workload-spiffe-credentials
        name: gke-workload-certificates
        readOnly: true
      ...
    
  5. Verifica que los siguientes paquetes de certificados y la clave privada estén disponibles en las siguientes ubicaciones del Pod:

    • Paquete de cadena de certificados: /var/run/secrets/workload-spiffe-credentials/certificates.pem
    • Clave privada: /var/run/secrets/workload-spiffe-credentials/private_key.pem
    • Paquete de ancla de confianza de CA: /var/run/secrets/workload-spiffe-credentials/ca_certificates.pem
  6. Si los archivos no están disponibles, realiza los siguientes pasos:

    1. Recupera la instancia del servicio de CA (vista previa) del clúster:

      kubectl get workloadcertificateconfigs default -o jsonpath '{.spec.certificateAuthorityConfig.certificateAuthorityServiceConfig.endpointURI}'
      
    2. Recupera el estado de la instancia del servicio de CA (vista previa):

      gcloud privateca ISSUING_CA_TYPE describe ISSUING_CA_NAME \
        --location ISSUING_CA_LOCATION
      

      Reemplaza lo siguiente:

      • ISSUING_CA_TYPE: el tipo de CA de la emisión, que debe ser subordinates o roots.
      • ISSUING_CA_NAME: el nombre de la CA emisora.
      • ISSUING_CA_LOCATION: la región de la CA emisora.
    3. Obtén la política de IAM para la CA raíz:

      gcloud privateca roots get-iam-policy ROOT_CA_NAME
      

      Reemplaza ROOT_CA_NAME por el nombre de tu CA raíz.

    4. En la política de IAM, verifica que exista la vinculación de la política privateca.auditor:

      ...
      - members:
        - serviceAccount:service-PROJECT_NUMBER@container-engine-robot.iam.gserviceaccount.com
        role: roles/privateca.auditor
      ...
      

      En este ejemplo, PROJECT_NUMBER es el número del proyecto de tu clúster.

    5. Obtén la política de IAM para la CA subordinada:

      gcloud privateca subordinates get-iam-policy SUBORDINATE_CA_NAME
      

      Reemplaza SUBORDINATE_CA_NAME por el nombre de la CA subordinada.

    6. En la política de IAM, verifica que exista la vinculación de la política privateca.certificateManager:

      ...
      - members:
        - serviceAccount: service-PROJECT_NUMBER@container-engine-robot.iam.gserviceaccount.com
        role: roles/privateca.certificateManager
      ...
      

      En este ejemplo, PROJECT_NUMBER es el número del proyecto de tu clúster.

Las aplicaciones no pueden usar las credenciales de mTLS emitidas

  1. Verifica que el certificado no haya vencido:

    cat /var/run/secrets/workload-spiffe-credentials/certificates.pem | openssl x509 -text -noout | grep "Not After"
    
  2. Comprueba que tu aplicación admita el tipo de clave que usaste.

    cat /var/run/secrets/workload-spiffe-credentials/certificates.pem | openssl x509 -text -noout | grep "Public Key Algorithm" -A 3
    
  3. Comprueba que la CA emisora use la misma familia de claves que la clave del certificado.

    1. Obtén el estado de la instancia del servicio de CA (vista previa):

      gcloud privateca ISSUING_CA_TYPE describe ISSUING_CA_NAME \
        --location ISSUING_CA_LOCATION
      

      Reemplaza lo siguiente:

      • ISSUING_CA_TYPE: el tipo de CA de la emisión, que debe ser subordinates o roots.
      • ISSUING_CA_NAME: el nombre de la CA emisora.
      • ISSUING_CA_LOCATION: la región de la CA emisora.
    2. Comprueba que el keySpec.algorithm en el resultado sea el mismo algoritmo de clave que definiste en el manifiesto de YAML WorkloadCertificateConfig. El resultado se verá así:

      config:
        ...
        subjectConfig:
          commonName: td-sub-ca
          subject:
            organization: TestOrgLLC
          subjectAltName: {}
      createTime: '2021-05-04T05:37:58.329293525Z'
      issuingOptions:
        includeCaCertUrl: true
      keySpec:
        algorithm: RSA_PKCS1_2048_SHA256
       ...
      

Los certificados se rechazan

  1. Verifica que la aplicación par use el mismo paquete de confianza para verificar el certificado.
  2. Verifica que el certificado no haya vencido:

    cat /var/run/secrets/workload-spiffe-credentials/certificates.pem | openssl x509 -text -noout | grep "Not After"
    
  3. Verifica que el código de cliente, si no usas la API de recarga de credenciales de gRPC para Go, actualice las credenciales del sistema de archivos de forma periódica.

  4. Verifica que las cargas de trabajo estén en el mismo dominio de confianza que la CA. Los certificados de malla de GKE admiten la comunicación entre cargas de trabajo en un solo dominio de confianza.

Limitaciones

La seguridad del servicio de Cloud Service Mesh solo es compatible con GKE. No puedes implementar la seguridad del servicio con Compute Engine.

Cloud Service Mesh no es compatible con situaciones en las que hay dos o más recursos de políticas de extremos que coinciden de manera equitativa con un extremo, por ejemplo, dos políticas con las mismas etiquetas y puertos, o dos o más políticas con diferentes etiquetas que coinciden de manera equitativa con las etiquetas de un extremo. Si deseas obtener más información sobre cómo las políticas de extremos coinciden con las etiquetas de un extremo, consulta las APIs para EndpointPolicy.EndpointMatcher.MetadataLabelMatcher. En tales casos, Cloud Service Mesh no genera una configuración de seguridad a partir de ninguna de las políticas en conflicto.