Configurar a segurança do serviço com gRPC sem proxy

Neste guia, você verá como configurar um serviço de segurança para a malha de serviço gRPC sem proxy.

Requisitos

Antes de configurar a segurança do serviço para a malha de serviço gRPC sem proxy, verifique se você atende aos requisitos a seguir.

Configurar o gerenciamento de identidade e acesso

Você precisa ter as permissões necessárias para usar o Google Kubernetes Engine. Você precisa ter pelo menos os seguintes papéis:

  • Papel GKE roles/container.clusterAdmin
  • Papel Compute Engine roles/compute.instanceAdmin
  • Papel roles/iam.serviceAccountUser

Para criar os recursos necessários à configuração, você precisa ter o papel compute.NetworkAdmin. Esse papel contém todas as permissões necessárias para criar, atualizar, excluir, listar e usar (ou seja, mencionar isso em outros recursos) os recursos necessários. Se você for o editor-proprietário do projeto, terá esse papel automaticamente.

networksecurity.googleapis.com.clientTlsPolicies.use e networksecurity.googleapis.com.serverTlsPolicies.use não são aplicados quando você faz referência a esses recursos no recurso de serviço de back-end.

Se isso for aplicado no futuro e você estiver usando o compute.NetworkAdmin papel, você não notará nenhum problema quando essa verificação for aplicada.

Se você estiver usando papéis personalizados e essa verificação for aplicada no futuro, certifique-se de incluir a respectiva permissão .use. Caso contrário, no futuro, você verá que o papel personalizado não tem as permissões necessárias para se referir a clientTlsPolicy ou serverTlsPolicy pelo serviço de back-end.

Preparar para a configuração

A segurança da malha de serviço sem proxy (PSM, na sigla em inglês) adiciona segurança a uma malha de serviço configurada para balanceamento de carga de acordo com a documentação dos serviços gRPC sem proxy. Em uma malha de serviço sem proxy, um cliente gRPC usa o esquema xds: no URI para acessar o serviço, o que permite os recursos de balanceamento de carga PSM e descoberta de endpoints.

Atualizar clientes e servidores gRPC para a versão correta

Crie ou recrie seus aplicativos usando a versão mínima do gRPC compatível com sua linguagem.

Atualizar o arquivo de inicialização

Os aplicativos gRPC usam um único arquivo de inicialização, que precisa ter todos os campos exigidos pelo código do cliente e do servidor gRPC. Um gerador de inicialização gera automaticamente o arquivo de inicialização para incluir sinalizações e valores necessários para a segurança do PSM. Para mais informações, consulte a seção Arquivo de inicialização, que inclui um arquivo de inicialização de amostra.

Visão geral da configuração

Esse processo de configuração é uma extensão Configuração do Cloud Service Mesh com o GKE e serviços gRPC sem proxy. As etapas não modificadas dessa configuração são referenciadas sempre que se aplicarem.

As principais melhorias na configuração do Cloud Service Mesh com o GKE são os seguintes:

  1. Configurar o serviço de CA, em que você cria pools de CAs particulares e as autoridades certificadoras necessárias.
  2. Criar um cluster do GKE com a federação de identidade da carga de trabalho do GKE para recursos de certificados de malha e integração do serviço de CA.
  3. Configuração da emissão de certificados de malha no cluster.
  4. Criação das contas de serviço do cliente e do servidor.
  5. Configuração do servidor de exemplo que usa APIs xDS e credenciais do servidor xDS para adquirir a configuração de segurança do Cloud Service Mesh.
  6. Como configurar o cliente de exemplo que usa credenciais xDS.
  7. Atualização da configuração do Cloud Service Mesh para incluir a configuração de segurança.

Você pode ver exemplos de código para usar credenciais xDS nos seguintes locais:

Atualizar a CLI do Google Cloud

Para atualizar a CLI do Google Cloud, execute o comando a seguir:

gcloud components update

Configurar variáveis de ambiente

Neste guia, você usa comandos do Cloud Shell, e a repetição de informações nos comandos é representada por várias variáveis de ambiente. Defina os valores específicos para as seguintes variáveis de ambiente no ambiente shell antes de executar os comandos. Cada linha de comentário indica o significado da variável de ambiente associada.

# 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

Ativar o acesso às APIs necessárias

Esta seção mostra como ativar o acesso às APIs necessárias.

  1. Execute o comando a seguir para ativar o Cloud Service Mesh e outras APIs necessárias para a segurança da malha de serviço gRPC sem 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. Execute o comando a seguir para permitir que a conta de serviço padrão acesse o API 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
    

Criar ou atualizar um cluster do GKE

A segurança do serviço do Cloud Service Mesh depende da integração do serviço de CA com o GKE. O cluster do GKE precisa atender aos seguintes requisitos, além dos requisitos de configuração:

  • Use uma versão de cluster mínima de 1.21.4-gke.1801. Se você precisar de recursos que estejam em uma versão posterior, poderá encontrá-la no canal de lançamento rápido.
  • O cluster do GKE precisa ser ativado e configurado com certificados de malha, conforme descrito em Como criar autoridades certificadoras para emitir certificados.
  1. Crie um cluster que use a federação de identidade da carga de trabalho para o GKE. Se você estiver atualizando um cluster existente, pule para a próxima etapa. O valor fornecido para --tags precisa corresponder ao nome transmitido à sinalização --target-tags para o comando firewall-rules create na seção Como configurar o Cloud Service Mesh com componentes do 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
    

    A criação do cluster pode levar vários minutos para ser concluída.

  2. Se você estiver usando um cluster atual, ative a federação de identidade da carga de trabalho para o GKE e Certificados de malha do GKE. Verifique se o cluster foi criado com a sinalização --enable-ip-alias, que não pode ser usada com o comando update.

    gcloud container clusters update CLUSTER_NAME \
      --enable-mesh-certificates
    
  3. Execute o comando a seguir para alternar para o novo cluster como o cluster padrão para os comandos kubectl:

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

Registrar clusters com uma frota

Registre o cluster que você criou ou atualizou em Como criar um cluster do GKE com uma frota. Registrar o cluster facilita a configuração de clusters em vários projetos.

Essas etapas podem levar até dez minutos para serem concluídas.

  1. Registre seu cluster na frota:

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

    Substitua as variáveis da seguinte maneira:

    • CLUSTER_NAME: o nome do cluster.
    • ZONE: a zona do cluster.
    • MANIFEST-FILE_NAME: o caminho em que esses comandos gerar o manifesto para registro.

    Quando o processo de registro for bem-sucedido, você verá uma mensagem como a seguinte:

    Finished registering the cluster CLUSTER_NAME with the fleet.
  2. Aplique o arquivo de manifesto gerado ao cluster:

    kubectl apply -f MANIFEST-FILE_NAME
    

    Quando o processo do aplicativo for bem-sucedido, você verá mensagens como estas:

    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. Consiga o recurso de assinatura do cluster:

    kubectl get memberships membership -o yaml
    

    A saída precisa incluir o pool de identidade do Workoad atribuído pela frota, em que PROJECT_ID é o ID do projeto:

    workload_identity_pool: PROJECT_ID.svc.id.goog
    

    Isso significa que o cluster foi registrado com sucesso.

Criar autoridades certificadoras para emitir certificados

Para emitir certificados para os pods, crie um pool de serviço de CA e as seguintes autoridades certificadoras (CAs):

  • CA raiz. Essa é a raiz da confiança de todos os certificados de malha emitidos. Use uma CA raiz atual, se tiver uma. Crie a CA raiz no nível enterprise, que é destinado à emissão de certificados de longa duração e de baixo volume.
  • CA subordinada. Essa CA emite certificados para cargas de trabalho. Crie a CA subordinada na região em que o cluster está implantado. Crie a CA subordinada no nível devops, que se destina à emissão de certificados de curta duração e de grande volume.

Criar uma CA subordinada é opcional, mas é altamente recomendável criá-la em vez de usar a CA raiz para emitir certificados de malha do GKE. Se você decidir usar a CA raiz para emitir certificados de malha, verifique se o modo de emissão baseado em configuração padrão permanece permitido.

A CA subordinada pode estar em uma região diferente do cluster, mas é altamente recomendável criá-la na mesma região do cluster para otimizar o desempenho. No entanto, é possível criar as CAs raiz e subordinadas em diferentes regiões sem qualquer impacto no desempenho ou na disponibilidade.

Estas regiões são compatíveis com o serviço de CA:

Nome da região Descrição da região
asia-east1 Taiwan
asia-east2 Hong Kong
asia-northeast1 Tóquio
asia-northeast2 Osaka
asia-northeast3 Seul
asia-south1 Mumbai
asia-south2 Délhi
asia-southeast1 Singapura
asia-southeast2 Jacarta
australia-southeast1 Sydney
australia-southeast2 Melbourne
europe-central2 Varsóvia
europe-north1 Finlândia
europe-southwest1 Madri
europe-west1 Bélgica
europe-west2 Londres
europe-west3 Frankfurt
europe-west4 Países Baixos
europe-west6 Zurique
europe-west8 Milão
europe-west9 Paris
europe-west10 Berlim
europe-west12 Turim
me-central1 Doha
me-central2 Damã
me-west1 Tel Aviv
northamerica-northeast1 Montreal
northamerica-northeast2 Toronto
southamerica-east1 São Paulo
southamerica-west1 Santiago
us-central1 Iowa
us-east1 Carolina do Sul
us-east4 Norte da Virgínia
us-east5 Columbus
us-south1 Dallas
us-west1 Oregon
us-west2 Los Angeles
us-west3 Salt Lake City
us-west4 Las Vegas

A lista de locais compatíveis também pode ser verificada executando o seguinte comando:

gcloud privateca locations list
  1. Conceda o roles/privateca.caManager do IAM a indivíduos que criam um pool de CAs e uma CA. Para MEMBER, o formato correto é user:userid@example.com. Se essa pessoa for o usuário atual, é possível conseguir o ID do usuário atual com o comando 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. Conceder o papel role/privateca.admin para serviços de AC a indivíduos que precisam modificar as políticas do IAM, em que MEMBER é um individual que precisa desse acesso, especificamente, qualquer pessoa que realize as etapas a seguir que concedem privateca.auditor e Papéis privateca.certificateManager:

    gcloud projects add-iam-policy-binding PROJECT_ID \
      --member=MEMBER \
      --role=roles/privateca.admin
    
  3. Crie o pool de serviço de CA raiz.

    gcloud privateca pools create ROOT_CA_POOL_NAME \
      --location ROOT_CA_POOL_LOCATION \
      --tier enterprise
    
  4. Crie uma CA raiz.

    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
    

    Para essa configuração de demonstração, use os seguintes valores para as variáveis:

    • ROOT_CA_POOL_NAME=td_sec_pool
    • ROOT_CA_NAME=pkcs2-ca
    • ROOT_CA_POOL_LOCATION=us-east1
    • ROOT_CA_ORGANIZATION="TestCorpLLC"
  5. Crie o pool subordinado e a CA subordinada. Verifique se o modo de emissão baseado em configuração padrão permanece 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
    

    Para essa configuração de demonstração, use os seguintes valores para as variáveis:

    • 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. Conceda o papel privateca.auditor do IAM para a CA raiz para permitir o acesso da conta de serviço do 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. Conceda o papel privateca.certificateManager do IAM para o pool da CA subordinado para permitir o acesso pela conta de serviço do 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. Salve a seguinte configuração YAML WorkloadCertificateConfig para informar ao cluster como emitir certificados de malha:

    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
    
    

    Substitua:

    • O ID do projeto em que o cluster é executado:
      PROJECT_ID
    • O URI totalmente qualificado da CA que emite os certificados de malha (ISSUING_CA_POOL_URI). Pode ser a CA subordinada (recomendado) ou a CA raiz. O formato é:
      //privateca.googleapis.com/projects/PROJECT_ID/locations/SUBORDINATE_CA_POOL_LOCATION/caPools/SUBORDINATE_CA_POOL_NAME
  9. Salve a seguinte configuração YAML TrustConfig para informar ao cluster como confiar nos 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
    

    Substitua:

    • O ID do projeto em que o cluster é executado:
      PROJECT_ID
    • O URI totalmente qualificado do pool de CA raiz (ROOT_CA_POOL_URI). O formato é:
      //privateca.googleapis.com/projects/PROJECT_ID/locations/ROOT_CA_POOL_LOCATION/caPools/ROOT_CA_POOL_NAME
  10. Aplique as configurações ao cluster:

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

Criar um serviço gRPC sem proxy com NEGs

Para segurança do PSM, você precisa de um servidor gRPC sem proxy capaz de usar xDS para adquirir a configuração de segurança do Cloud Service Mesh. Esta etapa é semelhante a Como configurar serviços do GKE com NEGs no guia de configuração do balanceamento de carga do PSM, com a diferença de que você usa o servidor helloworld com xDS ativado no exemplo do xDS no repositório grpc-java em vez da imagem java-example-hostname.

Crie e execute esse servidor em um contêiner criado a partir de uma imagem openjdk:8-jdk. Use também o recurso NEG nomeado, que permite especificar um nome para o NEG. Isso simplificará etapas posteriores porque a implantação sabe o nome do NEG sem precisar procurá-lo.

Veja a seguir um exemplo completo da especificação Kubernetes do servidor gRPC. Observe o seguinte:

  • A especificação cria uma conta de serviço do Kubernetes example-grpc-server que é usada pelo pod de servidor gRPC.
  • A especificação usa o campo name na anotação cloud.google.com/neg do serviço para especificar o nome do NEG example-grpc-server.
  • A variável ${PROJNUM} representa o número do seu projeto.
  • A especificação usa a seção initContainers para executar um gerador de inicialização para preencher o arquivo de inicialização de que a biblioteca gRPC sem proxy precisa. Esse arquivo de inicialização reside em /tmp/grpc-xds/td-grpc-bootstrap.json no contêiner do servidor gRPC chamado example-grpc-server.

Adicione a seguinte anotação à especificação do pod:

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

Você pode ver a posição correta na especificação completa a seguir.

Na criação, cada pod recebe um volume em /var/run/secrets/workload-spiffe-credentials. Este volume contém o seguinte:

  • private_key.pem, uma chave privada gerada automaticamente.
  • certificates.pem, um pacote de certificados formatados em PEM que pode ser apresentado a outro pod como a cadeia de certificados do cliente ou usado como uma cadeia de certificados de servidor.
  • ca_certificates.pem, um pacote de certificados formatados em PEM para usar como âncoras de confiança ao validar a cadeia de certificados do cliente apresentado por outro pod ou a cadeia de certificados de servidor recebida ao se conectar a outro pod.

Observe que ca_certificates.pem contém certificados para o domínio de confiança local das cargas de trabalho, que é o pool de cargas de trabalho do cluster.

O certificado de folha em certificates.pem contém a seguinte declaração de identidade SPIFFE de texto simples:

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

Nesta declaração:

  • WORKLOAD_POOL é o nome do pool de carga de trabalho do cluster.
  • NAMESPACE é o namespace da conta de serviço do Kubernetes.
  • KUBERNETES_SERVICE_ACCOUNT é o nome da conta de serviço do Kubernetes.

As instruções a seguir para sua linguagem criam a especificação a ser usada neste exemplo.

Java

  1. Execute o seguinte comando para garantir que o número do projeto esteja definido corretamente:

    if [ -z "$PROJNUM" ] ; then export PROJNUM=$(gcloud projects describe $(gcloud info --format='value(config.project)') --format="value(projectNumber)") ; fi ; echo $PROJNUM
    
  2. Crie a especificação:

    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. Execute o seguinte comando para garantir que o número do projeto esteja definido corretamente:

    if [ -z "$PROJNUM" ] ; then export PROJNUM=$(gcloud projects describe $(gcloud info --format='value(config.project)') --format="value(projectNumber)") ; fi ; echo $PROJNUM
    
  2. Crie a especificação:

    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. Execute o seguinte comando para garantir que o número do projeto esteja definido corretamente:

    if [ -z "$PROJNUM" ] ; then export PROJNUM=$(gcloud projects describe $(gcloud info --format='value(config.project)') --format="value(projectNumber)") ; fi ; echo $PROJNUM
    
  2. Crie a especificação:

    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. Execute o seguinte comando para garantir que o número do projeto esteja definido corretamente:

    if [ -z "$PROJNUM" ] ; then export PROJNUM=$(gcloud projects describe $(gcloud info --format='value(config.project)') --format="value(projectNumber)") ; fi ; echo $PROJNUM
    
  2. Crie a especificação:

    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
    

    Conclua o processo da maneira a seguir.

  1. Aplique a especificação:

    kubectl apply -f example-grpc-server.yaml
    
  2. Conceda os papéis necessários à conta de serviço:

    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. Execute estes comandos para verificar se o serviço e o pod foram criados corretamente:

    kubectl get deploy/example-grpc-server
    kubectl get svc/example-grpc-server
    
  4. Verifique se o nome do NEG está correto:

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

    O comando retornará o nome do NEG example-grpc-server.

Configurar o Cloud Service Mesh com componentes de balanceamento de carga do Google Cloud

As etapas desta seção são semelhantes às de Como configurar o Cloud Service Mesh com componentes de balanceamento de carga, mas há algumas mudanças, conforme descrito nas seções a seguir.

Criar a verificação de integridade, a regra de firewall e o serviço de back-end

Quando o servidor gRPC é configurado para usar mTLS, as verificações de integridade do gRPC não funcionam porque o cliente de verificação de integridade não pode apresentar um certificado de cliente válido para os servidores. Você pode resolver isso de duas maneiras:

Na primeira abordagem, o servidor cria uma porta de exibição adicional designada como a porta de verificação de integridade. Ela está anexada a um serviço de verificação de integridade especial, como texto simples ou TLS para essa porta.

O servidor de exemplo helloworld do xDS usa PORT_NUMBER + 1 como a porta de verificação de integridade de texto simples. O exemplo usa 50052 como a porta de verificação de integridade porque 50051 é a porta do servidor de aplicativos gRPC.

Na segunda abordagem, você configura a verificação de integridade para verificar apenas a conectividade TCP com a porta de exibição do aplicativo. Isso verifica apenas a conectividade e também gera tráfego desnecessário para o servidor quando não há handshakes TLS mal-sucedidos. Por esse motivo, recomendamos que você use a primeira abordagem.

  1. Crie a verificação de integridade. A verificação de integridade não é iniciada até que você crie e inicie o servidor.

    • Se você estiver criando uma porta de exibição designada para verificação de integridade, que é a abordagem recomendada, use este comando:

      gcloud compute health-checks create grpc grpc-gke-helloworld-hc \
       --enable-logging --port 50052
      
    • Se você estiver criando uma verificação de integridade TCP, que não recomendamos, use este comando:

      gcloud compute health-checks create tcp grpc-gke-helloworld-hc \
      --use-serving-port
      
  2. Criar o firewall. Verifique se o valor de --target-tags corresponde ao valor que você forneceu para --tags na seção Criar ou atualizar um cluster do 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. Crie o serviço de back-end:

    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. Anexe o NEG ao serviço de back-end:

    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
    

Criar os recursos Mesh e GRPCRoute

Isso é semelhante à maneira como você configura os recursos Mesh e GRPCRoute em Configurar serviços gRPC sem proxy.

  1. Crie a especificação Mesh e salve-a em um arquivo chamado mesh.yaml.

    name: grpc-mesh
    
  2. Importe o recurso Mesh da especificação.

    gcloud network-services meshes import grpc-mesh \
      --source=mesh.yaml \
      --location=global
    
  3. Crie a especificação GRPCRoute e salve-a em um arquivo chamado 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. Importe o recurso GRPCRoute da especificação grpc_route.yaml.

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

Configurar o Cloud Service Mesh com segurança gRPC sem proxy

Este exemplo demonstra como configurar o mTLS no lado do cliente e do servidor.

Formato para referências de políticas

Observe o seguinte formato obrigatório para se referir às políticas de TLS do servidor e TLS do cliente:

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

Exemplo:

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

Configurar o mTLS no lado do servidor

Primeiro, crie uma política de TLS para o servidor. A política solicita que o servidor do gRPC use a configuração do plug-in certificateProvicerInstance identificada pelo nome google_cloud_private_spiffe do certificado de identidade, que faz parte do serverCertificate. A seção mtlsPolicy indica a segurança mTLS e usa o mesmo google_cloud_private_spiffe que a configuração do plug-in para clientValidationCa, que é a especificação de certificado raiz (validação).

Em seguida, crie uma política de endpoint. Isso especifica que um back-end, por exemplo, um servidor gRPC usando a porta 50051 com algum ou nenhum rótulo de metadados, receberá a política de TLS do servidor anexada chamada server-mtls-policy. Você especifica os metadados rótulos usando MATCH_ALL ou um valor compatível. Os rótulos de metadados compatíveis podem ser encontrados no campo endpointMatcher.metadataLabelMatcher.metadataLabelMatchCriteria no documento NetworkServicesEndpointPolicy. Crie a política de endpoint com um arquivo temporário ep-mtls-psms.yaml que contém os valores do recurso de política de endpoint usando a política já definida.

  1. Crie um arquivo temporário server-mtls-policy.yaml no diretório atual com os valores do recurso de política de TLS do 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. Crie um recurso de política de TLS do servidor chamado server-mtls-policy importando o arquivo temporário server-mtls-policy.yaml:

    gcloud network-security server-tls-policies import server-mtls-policy \
      --source=server-mtls-policy.yaml --location=global
    
  3. Crie a política de endpoint criando o arquivo temporário 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. Crie o recurso de política de endpoint importando o arquivo ep-mtls-psms.yaml:

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

Configurar o mTLS no lado do cliente

A política de segurança do lado do cliente está anexada ao serviço de back-end. Quando um cliente acessa um back-end (o servidor gRPC) pelo serviço de back-end, a política de segurança do lado do cliente anexada é enviada ao cliente.

  1. Crie o conteúdo do recurso de política de TLS do cliente em um arquivo temporário chamado client-mtls-policy.yaml no diretório atual:

    name: "client-mtls-policy"
    clientCertificate:
      certificateProviderInstance:
        pluginInstance: google_cloud_private_spiffe
    serverValidationCa:
    - certificateProviderInstance:
        pluginInstance: google_cloud_private_spiffe
    
  2. Crie o recurso de política de TLS do cliente chamado client-mtls-policy importando o arquivo temporário client-mtls-policy.yaml:

    gcloud network-security client-tls-policies import client-mtls-policy \
      --source=client-mtls-policy.yaml --location=global
    
  3. Crie um snippet em um arquivo temporário para referenciar essa política e adicione detalhes para subjectAltNames na mensagem SecuritySettings, como no exemplo a seguir. Substitua ${PROJECT_ID} pelo valor do ID do projeto, que é o valor da variável de ambiente ${PROJECT_ID} descrita anteriormente. Observe que example-grpc-server em subjectAltNames é o nome da conta de serviço do Kubernetes usado para o pod do servidor gRPC na especificação de implantação.

    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. Adicione a mensagem securitySettings ao serviço de back-end que você já criou. Estas tapas exportam o conteúdo do serviço de back-end atual, adicionam a mensagem securitySetting do cliente e reimportam o novo conteúdo para atualizar o serviço de back-end.

    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
    

Verificar a configuração

A configuração do Cloud Service Mesh foi concluída, incluindo servidores e a segurança do lado do cliente. Em seguida, você irá preparar e executar as cargas de trabalho do servidor e do cliente. Isso conclui o exemplo.

Criar um cliente gRPC sem proxy

Esta etapa é semelhante à etapa anterior Como criar um serviço gRPC sem proxy. Você usa o cliente helloworld ativado por xDS no diretório de exemplo xDS no repositório grpc-java. Crie e execute o cliente em um contêiner criado a partir de uma imagem openjdk:8-jdk. A especificação do Kubernetes do cliente gRPC faz o seguinte.

  • Ele cria uma conta de serviço example-grpc-client do Kubernetes que é usada pelo pod do cliente gRPC.
  • ${PROJNUM} representa o número do seu projeto e precisa ser substituído pelo número real.

Adicione a seguinte anotação à especificação do pod:

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

Na criação, cada pod recebe um volume em /var/run/secrets/workload-spiffe-credentials. Este volume contém o seguinte:

  • private_key.pem, uma chave privada gerada automaticamente.
  • certificates.pem, um pacote de certificados formatados em PEM que pode ser apresentado a outro pod como a cadeia de certificados do cliente ou usado como uma cadeia de certificados de servidor.
  • ca_certificates.pem, um pacote de certificados formatados em PEM para usar como âncoras de confiança ao validar a cadeia de certificados do cliente apresentado por outro pod ou a cadeia de certificados de servidor recebida ao se conectar a outro pod.

ca_certificates.pem contém os certificados raiz do domínio de confiança local para as cargas de trabalho, que é o pool de carga de trabalho do cluster.

O certificado de folha em certificates.pem contém a seguinte declaração de identidade SPIFFE de texto simples:

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

Nesta declaração:

  • WORKLOAD_POOL é o nome do pool de carga de trabalho do cluster.
  • NAMESPACE é o nome da conta de serviço do Kubernetes.
  • KUBERNETES_SERVICE_ACCOUNT é o namespace da conta de serviço do Kubernetes.

As instruções a seguir para sua linguagem criam a especificação a ser usada neste exemplo.

Java

  1. Execute o seguinte comando para garantir que o número do projeto esteja definido corretamente:

    if [ -z "$PROJNUM" ] ; then export PROJNUM=$(gcloud projects describe $(gcloud info --format='value(config.project)') --format="value(projectNumber)") ; fi ; echo $PROJNUM
    
  2. Crie a seguinte especificação:

    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. Execute o seguinte comando para garantir que o número do projeto esteja definido corretamente:

    if [ -z "$PROJNUM" ] ; then export PROJNUM=$(gcloud projects describe $(gcloud info --format='value(config.project)') --format="value(projectNumber)") ; fi ; echo $PROJNUM
    
  2. Crie a seguinte especificação:

    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. Execute o seguinte comando para garantir que o número do projeto esteja definido corretamente:

    if [ -z "$PROJNUM" ] ; then export PROJNUM=$(gcloud projects describe $(gcloud info --format='value(config.project)') --format="value(projectNumber)") ; fi ; echo $PROJNUM
    
  2. Crie a seguinte especificação:

    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. Execute o seguinte comando para garantir que o número do projeto esteja definido corretamente:

    if [ -z "$PROJNUM" ] ; then export PROJNUM=$(gcloud projects describe $(gcloud info --format='value(config.project)') --format="value(projectNumber)") ; fi ; echo $PROJNUM
    
  2. Crie a seguinte especificação:

    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
    

Conclua o processo da maneira a seguir.

  1. Aplique a especificação:

    kubectl apply -f example-grpc-client.yaml
    
  2. Conceda os papéis necessários à conta de serviço:

    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. Verifique se o pod do cliente está em execução:

    kubectl get pods
    

    O comando retorna informações semelhantes às seguintes:

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

Executar o servidor

Crie e execute o servidor helloworld ativado por xDS no pod de servidor que você criou anteriormente.

Java

  1. Consiga o nome do pod criado para o serviço example-grpc-server:

    kubectl get pods | grep example-grpc-server
    

    Você verá comentários como estes:

    default    example-grpc-server-77548868d-l9hmf     1/1    Running   0     105s
    
  2. Abra um shell para o pod do servidor:

    kubectl exec -it example-grpc-server-77548868d-l9hmf -- /bin/bash
    
  3. No shell, verifique se o arquivo de inicialização em /tmp/grpc-xds/td-grpc-bootstrap.json corresponde ao esquema descrito na seção Arquivo de inicialização.

  4. Faça o download do gRPC em Java versão 1.42.1 e crie o aplicativo do 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. Execute o servidor com a sinalização --xds-creds para indicar a segurança ativada por xDS, usando 50051 como a porta de detecção e xds-server como o nome de identificação do servidor:

    ./build/install/example-xds/bin/xds-hello-world-server --xds-creds 50051 xds-server
    
  6. Depois que o servidor receber a configuração necessária do Cloud Service Mesh, você verá a seguinte saída:

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

C++

  1. Consiga o nome do pod criado para o serviço example-grpc-server:

    kubectl get pods | grep example-grpc-server
    

    Você verá comentários como estes:

    default    example-grpc-server-77548868d-l9hmf     1/1    Running   0     105s
    
  2. Abra um shell para o pod do servidor:

    kubectl exec -it example-grpc-server-77548868d-l9hmf -- /bin/bash
    
  3. No shell, verifique se o arquivo de inicialização em /tmp/grpc-xds/td-grpc-bootstrap.json corresponde ao esquema descrito na seção Arquivo de inicialização.

  4. Faça o download do gRPC em C++ e crie o aplicativo 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. Execute o servidor usando 50051 como a porta de detecção e xds_greeter_server como o nome de identificação do servidor:

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

    Para executar o servidor sem credenciais, especifique o seguinte:

    bazel-bin/examples/cpp/helloworld/xds_greeter_server --nosecure
    
  6. Depois que o servidor receber a configuração necessária do Cloud Service Mesh, você verá a seguinte saída:

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

Python

  1. Consiga o nome do pod criado para o serviço example-grpc-server:

    kubectl get pods | grep example-grpc-server
    

    Você verá comentários como estes:

    default    example-grpc-server-77548868d-l9hmf     1/1    Running   0     105s
    
  2. Abra um shell para o pod do servidor:

    kubectl exec -it example-grpc-server-77548868d-l9hmf -- /bin/bash
    
  3. No shell, verifique se o arquivo de inicialização em /tmp/grpc-xds/td-grpc-bootstrap.json corresponde ao esquema descrito na seção Arquivo de inicialização.

  4. Faça o download do gRPC em Python 1.41.0 e crie o aplicativo de exemplo.

    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. Execute o servidor com a sinalização --xds-creds para indicar a segurança ativada por xDS, usando 50051 como porta de detecção.

    python3 server.py 50051 --xds-creds
    
  6. Depois que o servidor receber a configuração necessária do Cloud Service Mesh, você verá a seguinte saída:

    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. Consiga o nome do pod criado para o serviço example-grpc-server:

    kubectl get pods | grep example-grpc-server
    

    Você verá comentários como estes:

    default    example-grpc-server-77548868d-l9hmf     1/1    Running   0     105s
    
  2. Abra um shell para o pod do servidor:

    kubectl exec -it example-grpc-server-77548868d-l9hmf -- /bin/sh
    
  3. No shell, verifique se o arquivo de inicialização em /tmp/grpc-xds/td-grpc-bootstrap.json corresponde ao esquema descrito na seção Arquivo de inicialização.

  4. Faça o download do gRPC Go versão 1.41.0 e navegue até o diretório que contém o aplicativo do 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. Crie e execute o servidor com a sinalização --xds_creds para indicar a segurança ativada para xDS, usando 50051 como a porta de detecção:

    GRPC_GO_LOG_VERBOSITY_LEVEL=2 GRPC_GO_LOG_SEVERITY_LEVEL="info" \
      go run main.go \
      -xds_creds \
      -port 50051
    
  6. Depois que o servidor receber a configuração necessária do Cloud Service Mesh, você verá a seguinte saída:

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

O processo de verificação de integridade leva de três a cinco minutos para mostrar que o serviço está íntegro depois que o servidor é iniciado.

Execute o cliente e verifique a configuração

Crie e execute o cliente helloworld ativado para xDS no pod cliente criado anteriormente.

Java

  1. Encontre o nome do pod do cliente:

    kubectl get pods | grep example-grpc-client
    

    Você verá comentários como este:

    default    example-grpc-client-7c969bb997-9fzjv     1/1    Running   0     105s
    
  2. Abra um shell para o pod do cliente:

    kubectl exec -it example-grpc-client-7c969bb997-9fzjv -- /bin/bash
    
  3. No shell de comando, faça o download do gRPC em Java versão 1.42.0 e crie o aplicativo 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. Execute o cliente com a sinalização --xds-creds para indicar a segurança ativada por xDS, o nome do cliente e a string de conexão de destino:

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

    A resposta será parecida com esta:

    Greeting: Hello xds-client, from xds-server
    

C++

  1. Encontre o nome do pod do cliente:

    kubectl get pods | grep example-grpc-client
    

    Você verá comentários como este:

    default    example-grpc-client-7c969bb997-9fzjv     1/1    Running   0     105s
    
  2. Abra um shell para o pod do cliente:

    kubectl exec -it example-grpc-client-7c969bb997-9fzjv -- /bin/bash
    
  3. Dentro do shell, faça o download do gRPC em C++ e crie o aplicativo 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. Execute o cliente com a sinalização --xds-creds para indicar a segurança ativada por xDS, o nome do cliente e a string de conexão de destino:

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

    Para executar o cliente sem credenciais, use o seguinte:

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

    A resposta será parecida com esta:

    Greeter received: Hello world
    

Python

  1. Encontre o nome do pod do cliente:

    kubectl get pods | grep example-grpc-client
    

    Você verá comentários como este:

    default    example-grpc-client-7c969bb997-9fzjv     1/1    Running   0     105s
    
  2. Abra um shell para o pod do cliente:

    kubectl exec -it example-grpc-client-7c969bb997-9fzjv -- /bin/bash
    
  3. Dentro do shell, faça o download do gRPC em Python versão 1.41.0 e crie o aplicativo cliente de exemplo.

    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. Execute o cliente com a sinalização --xds-creds para indicar a segurança ativada por xDS, o nome do cliente e a string de conexão de destino:

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

    A resposta será parecida com esta:

    Greeter client received: Hello you from example-host!
    

Go

  1. Encontre o nome do pod do cliente:

    kubectl get pods | grep example-grpc-client
    

    Você verá comentários como este:

    default    example-grpc-client-7c969bb997-9fzjv     1/1    Running   0     105s
    
  2. Abra um shell para o pod do cliente:

    kubectl exec -it example-grpc-client-7c969bb997-9fzjv -- /bin/sh
    
  3. Depois de entrar no shell, faça o download do gRPC em Go versão 1.42.0 e navegue até o diretório que contém o aplicativo 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. Crie e execute o cliente com a flag --xds_creds para indicar a segurança ativada pelo xDS, o nome do cliente e a string de conexão 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
    

    A resposta será parecida com esta:

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

Configurar o acesso no nível do serviço com uma política de autorização

O suporte para gRFC A41 é necessário para o suporte à política de autorização. Você pode encontrar as versões de linguagem necessárias no github (em inglês)

Use estas instruções para configurar o acesso no nível do serviço com políticas de autorização. Antes de criar políticas de autorização, leia com cuidado em Restringir o acesso usando autorização.

Para facilitar a verificação da configuração, crie outro nome de host que o cliente possa usar para se referir ao serviço helloworld-gke.

  1. Atualize a especificação GRPCRoute armazenada anteriormente em 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. Importe o recurso GRPCRoute novamente da especificação grpc_route.yaml.

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

Nas instruções a seguir, criamos uma política de autorização que permite solicitações enviadas pela conta example-grpc-client em que o nome do host é helloworld-gke:8000 e a porta é 50051.

gcloud

  1. Crie uma política de autorização criando um arquivo chamado 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. Importe a política.

    gcloud network-security authorization-policies import \
      helloworld-gke-authz-policy \
      --source=helloworld-gke-authz-policy.yaml \
      --location=global
    
  3. Atualize a política do endpoint para fazer referência à nova política de autorização anexando o seguinte ao arquivo ep-mtls-psms.yaml.

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

    A política de endpoints agora especifica que o mTLS e a política de autorização precisam ser aplicados às solicitações de entrada para pods com arquivos de inicialização gRPC que contenham o rótulo app:helloworld.

  4. Importe a política:

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

Validar a política de autorização

Use estas instruções para confirmar se a política de autorização está funcionando corretamente.

Java

  1. Abra um shell para o pod do cliente usado anteriormente.

    kubectl exec -it example-grpc-client-7c969bb997-9fzjv -- /bin/bash
    
  2. No shell de comando, execute os seguintes comandos para validar a configuração.

    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
    

    A resposta será parecida com esta:

    Greeting: Hello xds-client, from xds-server
    
  3. Execute o cliente novamente com o nome do servidor alternativo. Este é um caso de falha. A solicitação é inválida porque a política de autorização permite apenas acesso ao nome do host helloworld-gke:8000.

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

    A resposta será parecida com esta:

    WARNING: RPC failed: Status{code=PERMISSION_DENIED}
    

    Se você não vir essa saída, é possível que a política de autorização não esteja no ainda usam. Aguarde alguns minutos e tente todo o processo de verificação novamente.

Go

  1. Abra um shell para o pod do cliente usado anteriormente.

    kubectl exec -it example-grpc-client-7c969bb997-9fzjv -- /bin/bash
    
  2. No shell de comando, execute os seguintes comandos para validar a configuração.

    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
    

    A resposta será parecida com esta:

    Greeting: Hello xds-client, from example-grpc-server-77548868d-l9hmf
    
  3. Execute o cliente novamente com o nome do servidor alternativo. Este é um caso de falha. A solicitação é inválida porque a política de autorização permite apenas acesso ao nome do 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
    

    A resposta será parecida com esta:

    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
    

    Se essa saída não aparecer, talvez a política de autorização ainda não esteja em uso. Aguarde alguns minutos e tente todo o processo de verificação novamente.

Usar TLS em vez de mTLS

O uso de TLS neste exemplo requer apenas uma pequena mudança.

  1. Na ServerTlsPolicy, descarte a mtlsPolicy:

    cat << EOF > server-tls-policy.yaml
    name: "server-tls-policy"
    serverCertificate:
      certificateProviderInstance:
        pluginInstance: google_cloud_private_spiffe
    EOF
    
  2. Na EndpointPolicy, use esta política:

    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. A ClientTlsPolicy para mTLS também funciona no caso TLS, mas a seção clientCertificate da política pode ser descartada porque não é necessária para TLS:

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

Usar a segurança do serviço com o exemplo da Google Wallet

Esta seção fornece uma visão geral de alto nível sobre como ativar o exemplo da Wallet com segurança de serviço para Java, C++ e Go.

Java

Você encontra o exemplo de código-fonte para Java no github (link em inglês). O código já usa as credenciais XdsChannel e XdsServer quando você configura a segurança sem proxy.

Estas instruções descrevem a configuração do exemplo da Wallet com o Go. O processo é semelhante para Java. Nas instruções, são usadas uma imagem Docker existente do repositório de contêineres do Google Cloud.

Para criar o exemplo, siga estas instruções:

  1. Clone o repositório e receba os arquivos no diretório Exemplos de gRPC.
  2. Edite o arquivo 00-common-env.sh. Comente a linha atual que define o valor de WALLET_DOCKER_IMAGE para a imagem do Go Docker e remova a marca de comentário da linha que define o valor de WALLET_DOCKER_IMAGE como a imagem Java Docker.
  3. Crie e configure instâncias do Cloud Router com as instruções nesta página ou usando a função create_cloud_router_instances no script 10.apis.sh.
  4. Crie um cluster usando as instruções para o exemplo hello world ou a função create_cluster no script 20-cluster.sh.
  5. Crie autoridades certificadoras particulares usando as instruções para o serviço de CA ou usando o script 30-private-ca-setup.sh.
  6. Crie recursos do Kubernetes, incluindo contas de serviço, namespaces, serviços do Kubernetes, NEGs e implantação do lado do servidor para todos os serviços: account, stats, stats_premium, wallet_v1: wallet_v2, usando o script 40-k8s-resources.sh.
  7. Para cada serviço criado, crie uma verificação de integridade e um serviço de back-end usando create_health_check e create_backend_service no script 50-td-components.sh.
  8. Crie os componentes de roteamento do Cloud Service Mesh usando create_routing_components no script 60-routing-components.sh.
  9. Criar os componentes de segurança do Cloud Service Mesh para cada serviço de back-end usando create_security_components no script 70-security-components.sh.
  10. Crie a implantação do cliente da Google Wallet usando create_client_deployment no script 75-client-deployment.sh.
  11. Verifique a configuração iniciando seu cliente conforme descrito em Verificar com clientes grpc-wallet.

C++

Você encontra o exemplo de código-fonte para C++ no github (link em inglês). O código já usa as credenciais XdsChannel e XdsServer ao configurar a segurança sem proxy.

Estas instruções descrevem a configuração do exemplo da Wallet com o Go. O processo é semelhante para C++. Nas instruções, são usadas uma imagem Docker existente do repositório de contêineres do Google Cloud.

Para criar o exemplo, siga estas instruções:

  1. Clone o repositório e receba os arquivos no diretório Exemplos de gRPC.
  2. Edite o arquivo 00-common-env.sh. Transforme em comentário a linha atual que define o valor de WALLET_DOCKER_IMAGE como a imagem do Go Docker e remova a marca de comentário da linha que define o valor de WALLET_DOCKER_IMAGE como a imagem do Docker C++.
  3. Crie e configure instâncias do Cloud Router com as instruções nesta página ou usando a função create_cloud_router_instances no script 10.apis.sh.
  4. Crie um cluster usando as instruções para o exemplo hello world ou a função create_cluster no script 20-cluster.sh.
  5. Crie autoridades certificadoras particulares usando as instruções para o serviço de AC ou o script 30-private-ca-setup.sh.
  6. Crie recursos do Kubernetes, incluindo contas de serviço, namespaces, serviços do Kubernetes, NEGs e implantação do lado do servidor para todos os serviços: account, stats, stats_premium, wallet_v1: wallet_v2, usando o script 40-k8s-resources.sh.
  7. Para cada serviço criado, crie uma verificação de integridade e um serviço de back-end usando create_health_check e create_backend_service no script 50-td-components.sh.
  8. Crie os componentes de roteamento do Cloud Service Mesh usando create_routing_components no script 60-routing-components.sh.
  9. Criar os componentes de segurança do Cloud Service Mesh para cada serviço de back-end usando create_security_components no script 70-security-components.sh.
  10. Crie a implantação do cliente da Google Wallet usando create_client_deployment no script 75-client-deployment.sh.
  11. Verifique a configuração iniciando seu cliente conforme descrito em Verificar com clientes grpc-wallet.

Go

Você pode encontrar um código-fonte de exemplo para Go no github. O código já usa as credenciais XdsChannel e XdsServer ao configurar a segurança sem proxy.

Nas instruções, são usadas uma imagem Docker existente do repositório de contêineres do Google Cloud.

Para criar o exemplo, siga estas instruções:

  1. Clone o repositório e receba os arquivos no diretório Exemplos de gRPC.
  2. Edite o arquivo 00-common-env.sh para definir os valores corretos para as variáveis de ambiente.
  3. Crie e configure instâncias do Cloud Router com as instruções nesta página ou usando a função create_cloud_router_instances no script 10.apis.sh.
  4. Crie um cluster usando as instruções para o exemplo hello world ou a função create_cluster no script 20-cluster.sh.
  5. Crie autoridades certificadoras particulares usando as instruções para o serviço de CA ou usando o script 30-private-ca-setup.sh.
  6. Crie recursos do Kubernetes, incluindo contas de serviço, namespaces, serviços do Kubernetes, NEGs e implantação do lado do servidor para todos os serviços: account, stats, stats_premium, wallet_v1: wallet_v2, usando o script 40-k8s-resources.sh.
  7. Para cada serviço criado, crie uma verificação de integridade e um serviço de back-end usando create_health_check e create_backend_service no script 50-td-components.sh.
  8. Crie os componentes de roteamento do Cloud Service Mesh usando create_routing_components no script 60-routing-components.sh.
  9. Criar os componentes de segurança do Cloud Service Mesh para cada serviço de back-end usando create_security_components no script 70-security-components.sh.
  10. Crie a implantação do cliente da Google Wallet usando create_client_deployment no script 75-client-deployment.sh.
  11. Verifique a configuração iniciando seu cliente conforme descrito em Verificar com clientes grpc-wallet.

Arquivo de inicialização

O processo de configuração neste guia usa um gerador de inicialização para criar o arquivo de inicialização necessário. Nesta seção, fornecemos informações de referência sobre o próprio arquivo de inicialização.

O arquivo de inicialização contém informações de configuração exigidas pelo código gRPC sem proxy, incluindo informações de conexão do servidor xDS. O arquivo de inicialização contém a configuração de segurança exigida pelo recurso de segurança gRPC sem proxy. O servidor gRPC requer um campo adicional. Esta é uma amostra de arquivo de inicialização:

{
  "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"
}

Atualizações no arquivo de inicialização do serviço de segurança

Os campos a seguir refletem as modificações relacionadas à segurança e ao uso do xDS v3:

O campo id dentro do node fornece uma identidade exclusiva do cliente gRPC para o Cloud Service Mesh. É necessário fornecer o número do projeto do Google Cloud e o nome da rede usando o ID do nó neste formato:

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

Este é um exemplo do projeto número 1234 e da rede padrão:

projects/1234/networks/default/nodes/client1

O campo INSTANCE_IP é o endereço IP do pod ou 0.0.0.0 para indicar INADDR_ANY. Esse campo é usado pelo servidor gRPC para buscar o recurso Listener do Cloud Service Mesh para segurança no lado do servidor.

Campos de configuração de segurança no arquivo de inicialização

Chave JSON Tipo Valor Observações
server_listener_resource_name_template String grpc/server?xds.resource.listening_address=%s Obrigatório para servidores gRPC. O gRPC usa esse valor para compor o nome do recurso para buscar o recurso "Listener" do Cloud Service Mesh para segurança do servidor e outras configurações. O gRPC o usa para formar a string do nome do recurso
certificate_providers Estrutura JSON google_cloud_private_spiffe Obrigatório. O valor é uma estrutura JSON que representa um mapa de nomes para instâncias de provedor de certificado. Uma instância de provedor de certificado é usada para buscar certificados raiz e identidade. O exemplo do arquivo de inicialização contém um nome: google_cloud_private_spiffe com a estrutura JSON da instância do provedor de certificados como o valor. Cada estrutura JSON de instância do provedor de certificado tem dois campos:
  • plugin_name. Valor obrigatório que identifica o plug-in do provedor de certificado a ser usado, conforme exigido pela arquitetura de plug-ins do gRPC para provedores de certificado. O gRPC tem compatibilidade integrada com o plug-in inspetor de arquivos usado nessa configuração. O plugin_name é file_watcher.
  • config. Valor obrigatório que identifica o blog de configuração JSON para o plug-in file_watcher. O esquema e o conteúdo dependem do plug-in.

O conteúdo da estrutura JSON config para o plug-in file_watcher é:

  • certificate_file: string obrigatória. Esse valor é o local do certificado de identidade.
  • private_key_file: string obrigatória. O valor é o local do arquivo de chave privada, que deve corresponder ao certificado de identidade.
  • ca_certificate_file: string obrigatória. O valor é o local do certificado raiz, também conhecido como o pacote de confiança.
  • refresh_interval: string opcional. O valor indica o intervalo de atualização, especificado usando a representação de string do mapeamento JSON de uma duração. O valor padrão é "600s", uma duração de 10 minutos.

Gerador de inicialização

A imagem de contêiner do gerador de inicialização está disponível em gcr.io/trafficdirector-prod/td-grpc-bootstrap:0.16.0. O código-fonte está disponível em https://github.com/GoogleCloudPlatform/traffic-director-grpc-bootstrap. As opções de linha de comando mais usadas são estas:

  • --output: use esta opção para especificar o local de gravação do arquivo de inicialização de saída. Por exemplo, o comando --output /tmp/bootstrap/td-grpc-bootstrap.json gera o arquivo de inicialização para /tmp/bootstrap/td-grpc-bootstrap.json no sistema de arquivo do pod.
  • --config-mesh-experimental: use essa opção para especificar o nome da malha correspondente ao recurso Mesh.
  • --node-metadata: use esta sinalização para preencher os metadados do nó no arquivo de inicialização. Isso é necessário quando você usa correspondentes de rótulo de metadados no EndpointPolicy, em que o Cloud Service Mesh usa os dados de rótulo fornecidos na seção de metadados do nó do arquivo de inicialização. O argumento é fornecido no formato key=value, por exemplo: --node-metadata version=prod --node-metadata type=grpc

As informações anteriores adicionam o seguinte à seção de metadados do nó do arquivo de inicialização:

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

Excluir a implantação

Como opção, é possível executar esses comandos para excluir a implantação criada usando este guia.

Para excluir o cluster, execute este comando:

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

Para excluir os recursos criados, execute estes 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

Solução de problemas

Use estas instruções para ajudar você a resolver problemas com a implantação da segurança.

As cargas de trabalho não conseguem receber a configuração do Cloud Service Mesh

Se você vir um erro semelhante a este:

PERMISSION_DENIED: Request had insufficient authentication scopes.

Certifique-se disto:

  • Ter criado o cluster do GKE com o argumento --scopes=cloud-platform.
  • Ter atribuído roles/trafficdirector.client às contas de serviço do Kubernetes.
  • Você atribuiu o roles/trafficdirector.client à sua conta de serviço padrão do Google Cloud (${GSA_EMAIL} acima).
  • Ter ativado o serviço trafficdirector.googleapis.com (API).

Seu servidor gRPC não usa TLS/mTLS mesmo com a configuração correta do Cloud Service Mesh

Especifique GRPC_SERVER na configuração das políticas de endpoint. Se você especificou SIDECAR_PROXY, o gRPC ignorará a configuração.

Não é possível criar o cluster do GKE com a versão solicitada

O comando de criação do cluster do GKE pode falhar e apresentar um erro como este:

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

Verifique se você está usando o argumento --release-channel rapid no comando de criação do cluster. Você precisa usar o canal de lançamento rápido para conseguir a versão correta para este lançamento.

Você verá um erro No usable endpoint

Se um cliente não conseguir se comunicar com o servidor devido a um erro No usable endpoint, talvez o verificador de integridade tenha marcado os back-ends do servidor como não íntegros. Para verificar a integridade dos back-ends, execute este comando gcloud:

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

Se o comando retornar o status de back-end não íntegro, pode ser por um destes motivos:

  • O firewall não foi criado ou não contém o intervalo de IP de origem correto.
  • As tags de destino no firewall não correspondem às tags no cluster que você criou.

As cargas de trabalho não conseguem se comunicar na configuração de segurança

Se as cargas de trabalho não conseguirem se comunicar depois que você configurar a segurança da malha de serviço sem proxy, siga estas instruções para determinar a causa.

  1. Desative a segurança sem proxy e elimine problemas nos casos de uso do balanceamento de carga da malha de serviço sem proxy. Para desativar a segurança na malha, siga um destes procedimentos:
    1. Use credenciais de texto simples no lado do cliente e do servidor OU
    2. não configurar a segurança do serviço de back-end e da política de endpoint a configuração do Cloud Service Mesh.

Siga as etapas em Como solucionar problemas de implantações sem proxy do Cloud Service Mesh, porque não há configuração de segurança na sua implantação.

  1. Modifique suas cargas de trabalho para usar credenciais xDS com texto simples ou sem segurança como credenciais substitutas. Manter o Cloud Service Mesh com a segurança desativada, como discutido anteriormente. Nesse caso, embora o gRPC permita que o Cloud Service Mesh configure a segurança, o Cloud Service Mesh não envia informações de segurança. Nesse caso, o gRPC precisa retornar a credenciais de texto simples (ou não seguras) que funcionarão como no primeiro caso acima. Se isso não funcionar, faça o seguinte:

    1. Aumente o nível de geração de registros no lado do cliente e do servidor para que você podem acessar as mensagens xDS trocadas entre o gRPC e o Cloud Service Mesh.
    2. Verifique se o Cloud Service Mesh não está com a segurança ativada no CDS e as respostas LDS que são enviadas às cargas de trabalho.
    3. Verifique se as cargas de trabalho não estão usando os modos TLS ou mTLS nos canais. Se você notar mensagens de registro relacionadas a handshakes de TLS, verifique o código-fonte do aplicativo e confirme se você está usando texto simples ou não seguro como credenciais de fallback. Se o código-fonte do aplicativo estiver correto, talvez seja um bug na biblioteca do gRPC
  2. Verifique se a integração do serviço de CA com o GKE está funcionando corretamente para o cluster do GKE seguindo as etapas de solução de problemas desse guia do usuário. Verifique se os certificados e chaves fornecidos por esse recurso estão disponíveis no diretório especificado, /var/run/secrets/workload-spiffe-credentials/.

  3. Ative o TLS (em vez do mTLS) na malha, conforme descrito anteriormente, e reinicie as cargas de trabalho de cliente e do servidor.

    1. Aumente o nível de geração de registros no cliente e no servidor para ver as mensagens xDS trocadas entre o gRPC e o Cloud Service Mesh.
    2. Verifique se o Cloud Service Mesh ativou a segurança no CDS e no LDS que são enviadas às cargas de trabalho.

O cliente falha com uma CertificateException e uma mensagem Peer certificate SAN check failed

Isso indica um problema com os valores subjectAltNames na mensagem SecuritySettings. Observe que esses valores são baseados nos serviços do Kubernetes criados para seu serviço de back-end. Para cada serviço do Kubernetes criado por você, há um ID de SPIFFE associado neste formato:

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

Esses valores são:

  • WORKLOAD_POOL: o pool da carga de trabalho do cluster, que é ${PROJECT_ID}.svc.id.goog
  • K8S_NAMESPACE: o namespace do Kubernetes usado na implantação do serviço
  • SERVICE_ACCOUNT: a conta de serviço do Kubernetes usada na implantação do serviço

Verifique se você calculou corretamente o ID do SPIFFE e o adicionou ao campo subjectAltNames na mensagem SecuritySettings para todos os serviços do Kubernetes anexados ao serviço de back-end como um grupo de endpoints de rede.

Os aplicativos não podem usar os certificados mTLS com a biblioteca gRPC

Se os aplicativos não puderem usar os certificados mTLS com a biblioteca do gRPC, faça o seguinte:

  1. Verifique se a especificação do pod contém a anotação security.cloud.google.com/use-workload-certificates descrita em Como criar um serviço gRPC sem proxy com NEGs.

  2. Verifique se os arquivos que contêm a cadeia de certificados e o certificado de folha, a chave privada e os certificados de CA confiáveis são acessíveis nos seguintes caminhos de dentro pod:

    1. Cadeia de certificados e certificado de folha: "/var/run/secrets/workload-spiffe-credentials/certificates.pem"
    2. Chave privada: "/var/run/secrets/workload-spiffe-credentials/private_key.pem"
    3. Pacote de CA: "/var/run/secrets/workload-spiffe-credentials/ca_certificates.pem"
  3. Se os certificados da etapa anterior não estiverem disponíveis, faça o seguinte:

      gcloud privateca subordinates describe SUBORDINATE_CA_POOL_NAME 
    --location=LOCATION

    1. Verifique se o plano de controle do GKE tem a vinculação correta de papel do IAM, concedendo acesso ao 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. Verifique se o certificado não expirou. Esta é a cadeia de certificados e o certificado de folha em /var/run/secrets/workload-spiffe-credentials/certificates.pem. Para verificar, execute este comando:

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

    3. Execute este comando para verificar se o tipo de chave é compatível com o aplicativo:

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

    4. Verifique se o aplicativo gRPC em Java tem o seguinte keyAlgorithm no arquivo YAML WorkloadCertificateConfig:

      keyAlgorithm:
        rsa:
          modulusSize: 4096
    
  4. Verifique se a CA usa a mesma família de chaves que a chave de certificado.

O certificado de um aplicativo é rejeitado pelo cliente, servidor ou peering

  1. Verifique se o aplicativo de peering usa o mesmo pacote de confiança para verificar o certificado.
  2. Verifique se o certificado sendo usado não expirou (cadeia de certificados com o certificado de folha: "/var/run/secrets/workload-spiffe-credentials/certificates.pem").

Os pods permanecem em estado pendente

Se os pods permanecerem em estado pendente durante o processo de configuração, aumente os recursos de CPU e memória para os pods na especificação de implantação.

Não foi possível criar um cluster com a sinalização --enable-mesh-certificates

Verifique se você está executando a versão mais recente da CLI gcloud:

gcloud components update

A sinalização --enable-mesh-certificates funciona apenas com gcloud beta.

Os pods não são iniciados

Os pods que usam certificados de malha do GKE poderão falhar ao iniciar se o provisionamento de certificados estiver falhando. Isso pode acontecer quando:

  • A WorkloadCertificateConfig ou TrustConfig estiver configurada incorretamente ou ausente.
  • As CSRs não forem aprovadas.

Verifique se o provisionamento de certificados está falhando verificando os eventos do pod.

  1. Verifique o status do pod:

    kubectl get pod -n POD_NAMESPACE POD_NAME
    

    Substitua:

    • POD_NAMESPACE: o namespace do pod.
    • POD_NAME: o nome do pod.
  2. Verifique os eventos recentes do pod:

    kubectl describe pod -n POD_NAMESPACE POD_NAME
    
  3. Se o provisionamento de certificados estiver falhando, você verá um evento com Type=Warning, Reason=FailedMount, From=kubelet e um campo Message que começa com MountVolume.SetUp failed for volume "gke-workload-certificates". O campo Message contém informações de solução de 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. Veja as etapas de solução de problemas a seguir se o pod não iniciar por causa de objetos configurados incorretamente ou devido a CSRs recusadas.

WorkloadCertificateConfig ou TrustConfig está configurada incorretamente

Verifique se você criou os objetos WorkloadCertificateConfig e TrustConfig corretamente. É possível diagnosticar configurações incorretas em um desses objetos usando kubectl.

  1. Recupere o status atual.

    Para obter WorkloadCertificateConfig:

    kubectl get WorkloadCertificateConfig default -o yaml
    

    Para obter TrustConfig:

    kubectl get TrustConfig default -o yaml
    
  2. Inspecione a saída do status. Um objeto válido terá uma condição com type: Ready e status: "True".

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

    Para objetos inválidos, status: "False" será exibido. Os campos reason e message apresentam mais detalhes sobre a solução de problemas.

As CSRs não foram aprovadas

Se algo der errado durante o processo de aprovação da CSR, verifique os detalhes do erro nas condições type: Approved e type: Issued da CSR.

  1. Liste CSRs relevantes usando kubectl:

    kubectl get csr \
      --field-selector='spec.signerName=spiffe.gke.io/spiffe-leaf-signer'
    
  2. Escolha uma CSR que seja Approved e não Issued ou que não seja Approved.

  3. Veja detalhes sobre a CSR selecionada usando o kubectl:

    kubectl get csr CSR_NAME -o yaml
    

    Substitua CSR_NAME pelo nome da CSR escolhida.

Uma CSR válida tem uma condição com type: Approved e status: "True" e um certificado válido no 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

As informações sobre solução de problemas para CSRs inválidos aparecem nos campos message e reason.

Os pods estão sem certificado

  1. Veja a especificação do pod:

    kubectl get pod -n POD_NAMESPACE POD_NAME -o yaml
    

    Substitua:

    • POD_NAMESPACE: o namespace do pod.
    • POD_NAME: o nome do pod.
  2. Verifique se a especificação do pod contém a anotação security.cloud.google.com/use-workload-certificates descrita em Configurar pods para receber credenciais mTLS.

  3. Verifique se o controlador de admissão de certificados de malha do GKE injetou com sucesso um volume de driver CSI do tipo workloadcertificates.security.cloud.google.com na especificação do pod:

    volumes:
    ...
    -csi:
      driver: workloadcertificates.security.cloud.google.com
      name: gke-workload-certificates
    ...
    
  4. Verifique se todos os contêineres apresentam uma ativação de volume.

    containers:
    - name: ...
      ...
      volumeMounts:
      - mountPath: /var/run/secrets/workload-spiffe-credentials
        name: gke-workload-certificates
        readOnly: true
      ...
    
  5. Verifique se os seguintes pacotes de certificados e a chave privada estão disponíveis nos seguintes locais no pod:

    • Pacote da cadeia de certificados: /var/run/secrets/workload-spiffe-credentials/certificates.pem
    • Chave privada: /var/run/secrets/workload-spiffe-credentials/private_key.pem
    • Pacote de âncoras de confiança da CA: /var/run/secrets/workload-spiffe-credentials/ca_certificates.pem
  6. Se os arquivos não estiverem disponíveis, siga estas etapas:

    1. Recupere a instância do serviço da CA (Visualização) para o cluster:

      kubectl get workloadcertificateconfigs default -o jsonpath '{.spec.certificateAuthorityConfig.certificateAuthorityServiceConfig.endpointURI}'
      
    2. Recupere o status da instância do serviço da CA (Visualização):

      gcloud privateca ISSUING_CA_TYPE describe ISSUING_CA_NAME \
        --location ISSUING_CA_LOCATION
      

      Substitua:

      • ISSUING_CA_TYPE: o tipo de CA emissora, que precisa ser subordinates ou roots.
      • ISSUING_CA_NAME: o nome da CA emissora.
      • ISSUING_CA_LOCATION: a região da CA emissora.
    3. Consiga a política do IAM para a CA raiz:

      gcloud privateca roots get-iam-policy ROOT_CA_NAME
      

      Substitua ROOT_CA_NAME pelo nome da CA raiz.

    4. Na política do IAM, verifique se a vinculação de política privateca.auditor existe:

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

      Neste exemplo, PROJECT_NUMBER é o número do projeto do cluster.

    5. Consiga a política do IAM para a CA subordinada:

      gcloud privateca subordinates get-iam-policy SUBORDINATE_CA_NAME
      

      Substitua SUBORDINATE_CA_NAME pelo nome da CA subordinada.

    6. Na política do IAM, verifique se a vinculação de política privateca.certificateManager existe:

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

      Neste exemplo, PROJECT_NUMBER é o número do projeto do cluster.

Os aplicativos não podem usar as credenciais mTLS emitidas

  1. Verifique se o certificado expirou:

    cat /var/run/secrets/workload-spiffe-credentials/certificates.pem | openssl x509 -text -noout | grep "Not After"
    
  2. Verifique se o tipo de chave que você usou é compatível com o aplicativo.

    cat /var/run/secrets/workload-spiffe-credentials/certificates.pem | openssl x509 -text -noout | grep "Public Key Algorithm" -A 3
    
  3. Verifique se a CA emissora usa a mesma família de chaves que a chave de certificado.

    1. Veja o status da instância do serviço de CA (Visualização):

      gcloud privateca ISSUING_CA_TYPE describe ISSUING_CA_NAME \
        --location ISSUING_CA_LOCATION
      

      Substitua:

      • ISSUING_CA_TYPE: o tipo de CA emissora, que precisa ser subordinates ou roots.
      • ISSUING_CA_NAME: o nome da CA emissora.
      • ISSUING_CA_LOCATION: a região da CA emissora.
    2. Verifique se o keySpec.algorithm na saída é o mesmo algoritmo de chave definido no manifesto YAML WorkloadCertificateConfig. A saída é assim:

      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
       ...
      

Os certificados são recusados

  1. Verifique se o aplicativo de peering usa o mesmo pacote de confiança para verificar o certificado.
  2. Verifique se o certificado expirou:

    cat /var/run/secrets/workload-spiffe-credentials/certificates.pem | openssl x509 -text -noout | grep "Not After"
    
  3. Verifique se o código do cliente, se não estiver usando a API Reload Credentials do gRPC Go, atualiza periodicamente as credenciais do sistema de arquivos.

  4. Verifique se as cargas de trabalho estão no mesmo domínio de confiança que a CA. Os certificados de malha do GKE suportam a comunicação entre as cargas de trabalho em um único domínio de confiança.

Limitações

A segurança do serviço do Cloud Service Mesh é compatível apenas com o GKE. Não é possível implantar a segurança do serviço com o Compute Engine.

O Cloud Service Mesh não oferece suporte a cenários em que há dois ou mais endpoints recursos de política que tenham correspondência igual a um endpoint, por exemplo, dois com os mesmos identificadores e portas ou duas ou mais políticas com diferentes rótulos que correspondem igualmente aos rótulos de um endpoint. Para mais informações sobre como políticas de endpoint forem correspondidas aos identificadores de um endpoint, consulte as APIs para EndpointPolicy.EndpointMatcher.MetadataLabelMatcher. Nessas situações, o Cloud Service Mesh não gera configurações de segurança de qualquer política conflitante.