Como autenticar no Cloud Platform usando contas de serviço

Neste tutorial, demonstramos como criar uma conta de serviço do Google Cloud, atribuir papéis para autenticação nos serviços do Cloud Platform e usar as credenciais dessa conta em aplicativos em execução no GKE.

Neste exemplo, usaremos o Cloud Pub/Sub, mas as instruções são aplicáveis a qualquer serviço do Cloud Platform. No aplicativo de amostra deste tutorial, uma conta de serviço é usada para fazer autenticação no Cloud Pub/Sub e assinar as mensagens publicadas em um tópico do Pub/Sub de um aplicativo baseado em Python.

Objetivos

Este tutorial inclui as etapas a seguir:

  • Como criar uma conta de serviço.
  • Como atribuir os papéis necessários para a conta de serviço trabalhar com o Cloud Pub/Sub.
  • Como salvar a chave da conta como um secret do Kubernetes (em inglês).
  • Como usar a conta de serviço para configurar e implantar um aplicativo.

No aplicativo de amostra usado neste tutorial, você assina um tópico do Pub/Sub e imprime as mensagens publicadas na saída padrão. Para configurar o aplicativo com as permissões corretas, use o gcloud para publicar as mensagens e inspecione o stream de saída do contêiner para observar se as mensagens são recebidas corretamente.

Como se autenticar com contas de serviço

Há três maneiras de se autenticar nos serviços do Google Cloud usando contas de serviço no GKE:

1. Usar identidade de carga de trabalho

A identidade da carga de trabalho é a maneira recomendada de se autenticar nos serviços do Google Cloud a partir do GKE. A identidade da carga de trabalho permite configurar contas de serviço do Google Cloud usando recursos do Kubernetes. Se esse for seu caso de uso, ele deverá ser sua primeira opção. Este exemplo destina-se a casos de uso em que a identidade da carga de trabalho não é adequada.

2. Usar a conta de serviço padrão do Compute Engine

Cada nó em um cluster do GKE é uma instância do Compute Engine. Portanto, por padrão, os aplicativos executados em um cluster do GKE tentarão autenticar usando a conta de serviço padrão do Compute Engine e herdarem os escopos associados.

Essa conta de serviço padrão pode ou não ter permissões para usar os serviços do Google Cloud necessários. É possível expandir os escopos da conta de serviço padrão, mas isso pode criar riscos de segurança e não é recomendado.

3. Credenciais da conta de serviço gerenciada usando Secrets

A última opção é criar uma conta de serviço para o aplicativo e injetar a chave de autenticação como um Kubernetes secret. Este será o foco deste tutorial.

Por que usar as contas de serviço?

Os benefícios de ter contas de serviço separadas para aplicativos diferentes são:

  • melhor visibilidade e auditoria das solicitações de API feitas no aplicativo;

  • capacidade de revogar chaves para aplicativos específicos, em vez de compartilhar uma conta de serviço e precisar revogar o acesso à API de todos os aplicativos;

  • exposição reduzida, no caso de um possível incidente de segurança em que as credenciais da conta de serviço sejam comprometidas.

Antes de começar

Siga estas etapas para ativar a API do Kubernetes Engine:
  1. Acesse a página do Kubernetes Engine no Console do Google Cloud.
  2. Crie ou selecione um projeto.
  3. Aguarde a ativação da API e dos serviços relacionados. Isso pode levar alguns minutos.
  4. Verifique se a cobrança está ativada para o seu projeto do Google Cloud. Saiba como confirmar se a cobrança está ativada para o seu projeto.

Instale as ferramentas de linha de comando a seguir usadas neste tutorial:

  • gcloud é usado para criar e excluir clusters do Kubernetes Engine. gcloud está incluído no SDK do Google Cloud.
  • O kubectl é usado para gerenciar o Kubernetes, o sistema de orquestração de cluster usado pelo Kubernetes Engine. É possível instalar kubectl usando gcloud:
    gcloud components install kubectl

Definir padrões para a ferramenta de linha de comando gcloud

Para poupar tempo, em vez de digitar o ID do projeto e as opções de zona do Compute Engine na ferramenta de linha de comando gcloud, defina os padrões:
gcloud config set project project-id
gcloud config set compute/zone compute-zone

Ativar APIs

Para este tutorial, você precisa ativar a API Pub/Sub e a API Resource Manager no seu projeto:

gcloud services enable cloudresourcemanager.googleapis.com pubsub.googleapis.com

criar um cluster de contêiner

Crie um cluster de contêiner chamado pubsub-test para implantar o aplicativo de assinante do Pub/Sub:

gcloud container clusters create pubsub-test

Etapa 1: criar um tópico do Pub/Sub

O aplicativo de assinante Pub/Sub que você implantará usa uma assinatura chamada echo-read em um tópico do Pub/Sub chamado echo. Crie estes recursos antes de implantar o aplicativo:

Primeiro, crie um tópico do Pub/Sub:

gcloud

gcloud pubsub topics create echo

Config Connector

Observação: esta etapa requer o Config Connector. Siga estas instruções para instalar o Config Connector no cluster.

apiVersion: pubsub.cnrm.cloud.google.com/v1beta1
kind: PubSubTopic
metadata:
  name: echo
Para implantar esse manifesto, faça o download para sua máquina como topic.yaml e execute:
kubectl apply -f topic.yaml

Em seguida, crie uma inscrição:

gcloud

gcloud pubsub subscriptions create echo-read --topic=echo

Config Connector

apiVersion: pubsub.cnrm.cloud.google.com/v1beta1
kind: PubSubSubscription
metadata:
  name: echo-read
spec:
  topicRef:
    name: echo
Para implantar esse manifesto, faça o download para sua máquina como subscription.yaml e execute:
kubectl apply -f subscription.yaml

Etapa 2: implantar o aplicativo assinante do Pub/Sub

A próxima etapa é implantar o contêiner do aplicativo que recebe as mensagens publicadas para o tópico do Pub/Sub. Esse aplicativo foi escrito em Python com as bibliotecas de cliente do Google Cloud Pub/Sub. Veja o código-fonte no GitHub (em inglês).

No arquivo de manifesto a seguir, você encontra a descrição de uma implantação (em inglês) que execute uma única instância da imagem do Docker desse aplicativo:

# Copyright 2020 Google LLC
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
#     http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

apiVersion: apps/v1
kind: Deployment
metadata:
  name: pubsub
spec:
  selector:
    matchLabels:
      app: pubsub
  template:
    metadata:
      labels:
        app: pubsub
    spec:
      containers:
      - name: subscriber
        image: gcr.io/google-samples/pubsub-sample:v1

Para implantar esse manifesto, faça o download dele para sua máquina como pubsub.yaml e execute:

kubectl apply -f pubsub.yaml

Depois que o aplicativo for implantado, consulte os pods executando:

kubectl get pods -l app=pubsub
Saída:
NAME                      READY     STATUS             RESTARTS   AGE
pubsub-2009462906-1l6bh   0/1       CrashLoopBackOff   1          30s

Observe que o contêiner não está iniciando e entrou em um estado CrashLoopBackOff. Para inspecionar os registros do pod, execute:

kubectl logs -l app=pubsub

Saída:

...
google.gax.errors.RetryError: RetryError(Exception occurred in retry method that
was not classified as transient, caused by <_Rendezvous (StatusCode.PERMISSION_DENIED, scopes.) of RPC that terminated with Request had insufficient authentication>)

O rastreamento de pilha e a mensagem de erro indicam que o aplicativo não tem permissão para consultar o serviço do Cloud Pub/Sub.

Etapa 3: criar credenciais de conta de serviço

Para conceder ao aplicativo em execução no GKE acesso aos serviços do Google Cloud Platform, você precisa usar as contas de serviço. As contas de serviço permitem que você defina um conjunto de permissões de IAM associadas ao aplicativo.

Console

Para criar uma conta de serviço, acesse Contas de serviço no Console do Cloud e clique em Criar conta de serviço:

  1. Especifique o Nome da conta de serviço. Por exemplo, pubsub-app.
  2. Na lista suspensa Papel, selecione "Pub/Sub → Assinante".
  3. Clique em Criar chave e escolha o tipo de chave como JSON.
  4. Clique em Criar.

Depois que a conta de serviço é criada, será feito o download de um arquivo de chave JSON contendo as credenciais da conta de serviço para seu computador. Use esse arquivo de chave para configurar o aplicativo para autenticação na API Cloud Pub/Sub.

Config Connector

Primeiro, faça o download do seguinte recurso como service-account.yaml.

apiVersion: iam.cnrm.cloud.google.com/v1beta1
kind: IAMServiceAccount
metadata:
  name: pubsub-app
spec:
  displayName: Service account for PubSub example

Depois, execute:

kubectl apply -f service-account.yaml

Em seguida, aplique o Papel "Assinante do Pub/Sub" à conta de serviço. Faça o download do recurso a seguir como service-account-policy.yaml. Substitua [PROJECT_ID] pelo ID do seu projeto.

apiVersion: iam.cnrm.cloud.google.com/v1beta1
kind: IAMPolicyMember
metadata:
  name: policy-member-binding
spec:
  member: serviceAccount:pubsub-app@[PROJECT_ID].iam.gserviceaccount.com
  role: roles/pubsub.subscriber
  resourceRef:
    apiVersion: resourcemanager.cnrm.cloud.google.com/v1beta1
    kind: Project
    external: projects/[PROJECT_ID]

Depois, execute:

kubectl apply -f service-account-policy.yaml

Etapa 4: importar credenciais como um secret

Agora que você tem a chave da conta de serviço, você precisa de uma maneira de carregá-la no contêiner. Sua primeira ideia pode ser adicionar uma etapa no Dockerfile, mas as chaves da conta de serviço são arquivos sensíveis à segurança que não devem ser salvos em imagens de contêiner.

Em vez disso, o Kubernetes oferece o tipo de recurso Secret para ativar com segurança arquivos particulares dentro de pods no tempo de execução.

kubectl

Para salvar o arquivo de chave JSON como um Secret chamado pubsub-key, execute o seguinte comando com o caminho para o arquivo de credenciais da conta de serviço baixado:

kubectl create secret generic pubsub-key --from-file=key.json=PATH-TO-KEY-FILE.json

Esse comando cria um Secret chamado pubsub-key que tem um arquivo key.json com o conteúdo da chave privada que você fez o download do Console do GCP. Após criar o secret, remova o arquivo do seu computador.

Config Connector

Faça o download do recurso a seguir como service-account-key.yaml.

apiVersion: iam.cnrm.cloud.google.com/v1beta1
kind: IAMServiceAccountKey
metadata:
  name: pubsub-key
spec:
  publicKeyType: TYPE_X509_PEM_FILE
  keyAlgorithm: KEY_ALG_RSA_2048
  privateKeyType: TYPE_GOOGLE_CREDENTIALS_FILE
  serviceAccountRef:
    name: pubsub-app

Depois, execute:

kubectl apply -f service-account-key.yaml

Etapa 5: configurar o aplicativo com o secret

Para usar o secret pubsub-key no aplicativo, modifique a especificação de implantação para:

  1. Defina um volume com o secret.
  2. Ative o volume do secret para o contêiner de aplicativo.
  3. Defina a variável de ambiente GOOGLE_APPLICATION_CREDENTIALS de modo que ela aponte para o arquivo da chave no volume montado da chave secreta.

O arquivo de manifesto atualizado ficará parecido com este:

# Copyright 2020 Google LLC
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
#     http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

apiVersion: apps/v1
kind: Deployment
metadata:
  name: pubsub
spec:
  selector:
    matchLabels:
      app: pubsub
  template:
    metadata:
      labels:
        app: pubsub
    spec:
      volumes:
      - name: google-cloud-key
        secret:
          secretName: pubsub-key
      containers:
      - name: subscriber
        image: gcr.io/google-samples/pubsub-sample:v1
        volumeMounts:
        - name: google-cloud-key
          mountPath: /var/secrets/google
        env:
        - name: GOOGLE_APPLICATION_CREDENTIALS
          value: /var/secrets/google/key.json

Neste arquivo de manifesto, os seguintes itens estão definidos para que as credenciais fiquem disponíveis para o aplicativo:

  • Um volume chamado google-cloud-key que usa o secret denominado pubsub-key.

  • Um volume montado, que disponibiliza google-cloud-key no diretório /var/secrets/google dentro do contêiner.

  • A variável de ambiente GOOGLE_APPLICATION_CREDENTIALS definida como /var/secrets/google/key.json, que contém o arquivo de credenciais quando o secret é ativado para o contêiner como um volume.

A variável de ambiente GOOGLE_APPLICATION_CREDENTIALS é reconhecida automaticamente pelas bibliotecas de cliente do Google Cloud. Nesse caso, o cliente do Cloud Pub/Sub para Python.

Para implantar esse manifesto, faça o download dele para sua máquina como pubsub-with-secret.yaml e execute:

kubectl apply -f pubsub-with-secret.yaml

Depois de implantado corretamente, o status do pod será listado como Running:

kubectl get pods -l app=pubsub
Saída:
NAME                     READY     STATUS    RESTARTS   AGE
pubsub-652482369-2d6h2   1/1       Running   0          29m

Etapa 6: testar o recebimento das mensagens do Pub/Sub

Agora que você configurou o aplicativo, publique uma mensagem no tópico do Pub/Sub chamado echo:

gcloud pubsub topics publish echo --message="Hello, world!"

Em alguns segundos, uma mensagem é recebida pelo aplicativo e impressa no stream de saída. Para inspecionar os registros do pod implantado, execute:

kubectl logs -l app=pubsub
Saída:
Pulling messages from Pub/Sub subscription...
[2017-06-19 12:31:42.501123] ID=130941112144812 Data=Hello, world!

Você configurou com sucesso a autenticação de um aplicativo no GKE na API do Pub/Sub usando credenciais de conta de serviço.

Como limpar

Para evitar que os recursos usados neste tutorial sejam cobrados na conta do Google Cloud Platform:

  1. Remova a inscrição e o tópico do Pub/Sub:

    gcloud pubsub subscriptions delete echo-read
    gcloud pubsub topics delete echo
  2. Exclua o cluster de contêiner:

    gcloud container clusters delete pubsub-test

A seguir