Saiba como invocar funções autenticadas do Cloud Run

1. Introdução

Visão geral

O Cloud Run functions é uma solução de computação leve para desenvolvedores. Ele cria funções autônomas com uma finalidade única que podem ser acionadas usando HTTPS ou responder a CloudEvents sem a necessidade de gerenciar um servidor ou um ambiente de execução. Saiba mais sobre o Cloud Run functions em nossa postagem do blog.

Há duas abordagens principais para controlar invocações do Cloud Run functions: proteger o acesso com base na identidade e proteger o acesso usando controles de acesso baseados em rede. Este codelab se concentra na primeira abordagem e mostra três cenários para proteger o acesso com base na identidade para invocar uma função:

  1. Use o token de identidade da gcloud para invocar uma função para fins de desenvolvimento e teste locais.
  2. Represente uma conta de serviço ao desenvolver e testar localmente para usar as mesmas credenciais da produção.
  3. Use as bibliotecas de cliente do Google para processar a autenticação nas APIs do Cloud, por exemplo, quando um serviço precisa invocar uma função.

O que você vai aprender

  • Como configurar a autenticação em uma função do Cloud Run e verificar se ela foi configurada corretamente.
  • Invocar uma função autenticada de um ambiente de desenvolvimento local fornecendo o token da sua identidade da gcloud.
  • Como criar uma conta de serviço e conceder a ela o papel adequado para invocar uma função.
  • Como representar um serviço de um ambiente de desenvolvimento local que tenha os papéis adequados para invocar uma função.

2. Configuração e requisitos

Pré-requisitos

Ativar o Cloud Shell

  1. No console do Cloud, clique em Ativar o Cloud Shell d1264ca30785e435.png.

84688aa223b1c3a2.png

Se esta for a primeira vez que você inicia o Cloud Shell, uma tela intermediária será exibida descrevendo o que ele é. Se você recebeu uma tela intermediária, clique em Continuar.

d95252b003979716.png

Leva apenas alguns instantes para provisionar e se conectar ao Cloud Shell.

7833d5e1c5d18f54.png

Essa máquina virtual contém todas as ferramentas de desenvolvimento necessárias. Ela oferece um diretório principal persistente de 5 GB, além de ser executada no Google Cloud. Isso aprimora o desempenho e a autenticação da rede. Neste codelab, quase todo o trabalho pode ser feito simplesmente com um navegador.

Depois de se conectar ao Cloud Shell, você vai ver que sua conta está autenticada e que o projeto está configurado com o ID do seu projeto.

  1. Execute o seguinte comando no Cloud Shell para confirmar se a conta está autenticada:
gcloud auth list

Resposta ao comando

 Credentialed Accounts
ACTIVE  ACCOUNT
*       <my_account>@<my_domain.com>

To set the active account, run:
    $ gcloud config set account `ACCOUNT`
  1. Execute o comando a seguir no Cloud Shell para confirmar se o comando gcloud sabe sobre seu projeto:
gcloud config list project

Resposta ao comando

[core]
project = <PROJECT_ID>

Se o projeto não estiver configurado, faça a configuração usando este comando:

gcloud config set project <PROJECT_ID>

Resposta ao comando

Updated property [core/project].

3. Criar e testar uma função do Cloud Run autenticada

Exigir autenticação significa que o principal que invoca a função precisa ter o papel de invocador do Cloud Run. Caso contrário, a função retornará um erro 403 Forbidden. Este codelab mostra como conceder os papéis de invocador adequados a um principal.

Configurar variáveis de ambiente locais para comandos gcloud simplificados

Primeiro, crie algumas variáveis de ambiente para melhorar a legibilidade dos comandos gcloud usados neste codelab.

REGION=us-central1
PROJECT_ID=$(gcloud config get-value project)

Criar o código-fonte da função

Embora este codelab use o Node.js, você pode usar qualquer ambiente de execução compatível com as bibliotecas de cliente do Google Auth.

Primeiro, crie um diretório e acesse-o.

mkdir auth-function-codelab && cd $_

Em seguida, crie o arquivo package.json.

touch package.json

echo '{
  "dependencies": {
    "@google-cloud/functions-framework": "^3.0.0"
  }
}
' > package.json

Depois, crie o arquivo de origem index.js.

touch index.js

echo 'const functions = require("@google-cloud/functions-framework");

functions.http("helloWorld", (req, res) => {
 res.send(`Hello ${req.query.name || req.body.name || "World"}!`);
});' > index.js

Criar a função autenticada

Confira as etapas para criar uma função autenticada para o ambiente de execução nodejs20. No entanto, você pode usar qualquer ambiente de execução compatível com as bibliotecas de cliente do Google Auth.

FUNCTION_NAME=authenticated-function-codelab
ENTRY_POINT=helloWorld

Para implantar uma função do Cloud Run diretamente no Cloud Run, execute o seguinte comando:

gcloud beta run deploy $FUNCTION_NAME \
      --source . \
      --function helloWorld \
      --region $REGION \
      --no-allow-unauthenticated

Em seguida, salve o URL da função como uma variável de ambiente para usar mais tarde.

FUNCTION_URL="$(gcloud run services describe $FUNCTION_NAME --region $REGION --format 'value(status.url)')"

Se preferir implantar como uma função do Cloud de segunda geração, use o seguinte comando:

gcloud functions deploy nodejs-http-function \
  --gen2 \
  --runtime=nodejs20 \
  --region=$REGION \
  --source=. \
  --entry-point=helloWorld \
  --trigger-http \
  --no-allow-unauthenticated

Em seguida, salve o URL da função como uma variável de ambiente para usar mais tarde.

FUNCTION_URL="$(gcloud functions describe $FUNCTION_NAME --gen2 --region us-central1 --format='get(serviceConfig.uri)')"

Verificar se a função exige autenticação tentando invocar como um autor da chamada anônimo

Você vai invocar a função sem autenticação para verificar se recebe um erro 403 esperado.

Em uma linha de comando, execute o seguinte comando curl:

curl -i $FUNCTION_URL

Você verá o seguinte resultado:

<html><head>
<meta http-equiv="content-type" content="text/html;charset=utf-8">
<title>403 Forbidden</title>
</head>
<body text=#000000 bgcolor=#ffffff>
<h1>Error: Forbidden</h1>
<h2>Your client does not have permission to get URL <code>/</code> from this server.</h2>
<h2></h2>
</body></html>

Agora você está pronto para conferir três cenários em que é possível invocar sua função fornecendo autenticação.

4. Cenário 1: usar o token de identidade da gcloud

Como desenvolvedor, você vai querer uma maneira de testar sua função enquanto a desenvolve localmente. Nesta seção, você vai realizar um teste rápido para verificar se a função está autenticada corretamente usando sua própria identidade.

Verifique se você está autenticado usando gcloud executando o seguinte comando:

gcloud auth list

Um asterisco vai aparecer ao lado da sua identidade ativa, por exemplo:

Credentialed Accounts
ACTIVE  ACCOUNT

*       <my_account>@<my_domain.com>

To set the active account, run:
    $ gcloud config set account `ACCOUNT`

Você pode encontrar mais informações sobre como configurar o gcloud init e o gcloud auth login na documentação.

Em seguida, invoque a função e transmita o token de identidade.

curl $FUNCTION_URL -H "Authorization: bearer $(gcloud auth print-identity-token)"

Agora você verá o resultado:

Hello World!

Solução de problemas

Se você receber um erro 403 Forbidden, verifique se sua identidade tem o papel de invocador do Cloud Run. Você pode usar o console do IAM para verificar os papéis concedidos a um principal.

Embora usar seu próprio token de identidade seja uma maneira rápida de testar sua função durante o desenvolvimento, o autor da chamada da função autenticada precisará dos papéis adequados. Caso contrário, o autor da chamada vai receber um erro 403 Forbidden.

Você vai querer seguir o princípio de privilégio mínimo, limitando o número de identidades e contas de serviço que têm papéis para invocar a função. No próximo cenário, você vai aprender a criar uma conta de serviço e conceder a ela os papéis adequados para invocar a função.

5. Cenário 2: representar uma conta de serviço

Neste cenário, você vai representar (ou seja, assumir as permissões de) uma conta de serviço para invocar uma função ao desenvolver e testar localmente. Ao representar uma conta de serviço, você pode testar sua função com as mesmas credenciais da produção.

Ao fazer isso, você não apenas verifica os papéis, mas também segue o princípio de privilégio mínimo, sem precisar conceder o papel de invocador da função do Cloud a outras identidades apenas para fins de teste local.

Para fins deste codelab, você vai criar uma conta de serviço que tenha apenas papéis para invocar a função criada neste codelab.

Criar uma nova conta de serviço

Primeiro, crie algumas variáveis de ambiente adicionais para representar as contas de serviço usadas nos comandos gcloud.

SERVICE_ACCOUNT_NAME="invoke-functions-codelab"
SERVICE_ACCOUNT_ADDRESS=$SERVICE_ACCOUNT_NAME@$PROJECT_ID.iam.gserviceaccount.com

Em seguida, crie a conta de serviço.

gcloud iam service-accounts create $SERVICE_ACCOUNT_NAME \
  --display-name="Cloud Run function Authentication codelab"

E conceda à conta de serviço o papel de invocador do Cloud Run:

gcloud run services add-iam-policy-binding $FUNCTION_NAME \
  --region=us-central1  \
  --member serviceAccount:$SERVICE_ACCOUNT_ADDRESS \
  --role='roles/run.invoker'

Invocar a função representando a conta de serviço

Para isso, represente a conta de serviço recém-criada recebendo o token de ID.

Adicionar papéis necessários para representação

Para representar uma conta de serviço, sua conta de usuário precisa ter o papel de criador de token da conta de serviço (roles/iam.serviceAccountTokenCreator) para gerar um token de ID para a conta de serviço.

Você pode executar os comandos a seguir para conceder esse papel à sua conta de usuário ativa:

ACCOUNT_EMAIL=$(gcloud auth list --filter=status:ACTIVE --format="value(account)")

gcloud iam service-accounts add-iam-policy-binding $SERVICE_ACCOUNT_ADDRESS  \
  --member user:$ACCOUNT_EMAIL \
  --role='roles/iam.serviceAccountTokenCreator'

Usar o token de ID da conta de serviço

Aguarde alguns minutos para que as permissões sejam propagadas. Agora você pode invocar a função transmitindo o token de ID da conta de serviço.

curl $FUNCTION_URL -H "Authorization: bearer $(gcloud auth print-identity-token --impersonate-service-account $SERVICE_ACCOUNT_ADDRESS)" 

E você verá o seguinte:

WARNING: This command is using service account impersonation. All API calls will be executed as [invoke-functions-codelab@<project-id>.iam.gserviceaccount.com].

Hello World!

6. Cenário 3: usar as bibliotecas de cliente do Google

Para esta última parte do codelab, execute um pequeno serviço localmente para gerar um token de ID para uma conta de serviço e, em seguida, chame a função de maneira programática usando as bibliotecas de cliente do Google Auth e o Application Default Credentials (ADC). Leia mais sobre as bibliotecas de cliente do Google na seção Explicações sobre bibliotecas de cliente da documentação.

O uso do ADC é especialmente importante quando você quer escrever e testar sua função localmente (por exemplo, no laptop, no Cloud Shell etc.) ao interagir com outros recursos do Google Cloud (por exemplo, Cloud Storage, API Vision etc.). Neste exemplo, você vai aprender a fazer com que um serviço invoque outra função que exige autenticação. Para mais informações sobre o ADC e o desenvolvimento local, consulte a postagem do blog Como desenvolver e testar suas funções do Cloud localmente | Blog do Google Cloud (link em inglês).

Executar o comando gcloud para representar uma conta de serviço

O ADC encontra automaticamente as credenciais com base no ambiente do aplicativo e as usa para autenticação nas APIs do Google Cloud. A flag –impersonate-service-account permite representar uma conta de serviço usando a identidade dela para autenticação nas APIs do Cloud.

Para representar uma conta de serviço, execute o seguinte comando:

gcloud auth application-default login --impersonate-service-account=$SERVICE_ACCOUNT_ADDRESS

Agora você está executando comandos gcloud como essa conta de serviço, em vez da sua identidade.

Criar e executar um serviço para invocar uma função autenticada

Cada ambiente de execução tem a própria biblioteca de cliente do Google Auth que pode ser instalada. Este codelab mostra como criar e executar um app Node.js localmente.

Confira as etapas para o Node.js:

  1. Crie um novo diretório
mkdir local-dev && cd $_
  1. Crie um novo app Node.js
npm init -y
  1. Instale a biblioteca de cliente do Google Auth
npm install google-auth-library
  1. Crie um arquivo index.js
  2. Recupere o URL da função do Cloud Run, que você vai adicionar ao código na próxima etapa.
echo $FUNCTION_URL
  1. Adicione o código a seguir a index.js. Mude a variável targetAudience para o URL da função do Cloud Run.

index.js

// Cloud Functions uses your function's url as the `targetAudience` value

const targetAudience = '<YOUR-CLOUD-RUN-FUNCTION-URL>';

// For Cloud Functions, endpoint(`url`) and `targetAudience` should be equal

const url = targetAudience;

const { GoogleAuth } = require('google-auth-library');
const auth = new GoogleAuth();

async function request() {
    console.info(`request ${url} with target audience ${targetAudience}`);

    // this call retrieves the ID token for the impersonated service account
    const client = await auth.getIdTokenClient(targetAudience);

    const res = await client.request({ url });
    console.info(res.data);
}

request().catch(err => {
    console.error(err.message);
    process.exitCode = 1;
});
  1. Executar o app
node index.js

O resultado "Hello World!" vai aparecer.

Solução de problemas

Se você receber um erro Permission ‘iam.serviceAccounts.getOpenIdToken' denied on resource (ou it may not exist)., aguarde alguns minutos para que o papel de criador de token da conta de serviço seja propagado.

Se você recebeu o erro Cannot fetch ID token in this environment, use GCE or set the GOOGLE_APPLICATION_CREDENTIALS variável de ambiente to a service account credentials JSON file, talvez você tenha esquecido de executar o comando

gcloud auth application-default login --impersonate-service-account=$SERVICE_ACCOUNT_ADDRESS

7. Parabéns!

Parabéns por concluir o codelab.

Recomendamos que você revise a documentação sobre como proteger as funções do Cloud Run.

Também recomendamos esta postagem do blog sobre desenvolvimento local com o Cloud Run functions para aprender a desenvolver e testar sua função do Cloud Run no ambiente de desenvolvedor local.

O que vimos

  • Como configurar a autenticação em uma função do Cloud Run e verificar se ela foi configurada corretamente.
  • Invocar uma função autenticada de um ambiente de desenvolvimento local fornecendo o token da sua identidade da gcloud.
  • Como criar uma conta de serviço e conceder a ela o papel adequado para invocar uma função.
  • Como representar um serviço de um ambiente de desenvolvimento local que tenha os papéis adequados para invocar uma função.

8. Liberar espaço

Para evitar cobranças acidentais (por exemplo, se essa função do Cloud for invocada mais vezes do que sua alocação mensal de invocação da função do Cloud Run na camada sem custo financeiro), exclua a função do Cloud ou o projeto criado na etapa 2.

Para parar de representar a conta de serviço, faça login novamente usando sua identidade:

gcloud auth application-default login

Para excluir a função do Cloud Run, acesse o console do Cloud Run functions em https://console.cloud.google.com/functions/. Verifique se o projeto criado na etapa 2 é o projeto selecionado no momento.

Selecione a my-authenticated-function que você implantou anteriormente. Em seguida, clique em Excluir.

Se você optar por excluir todo o projeto, acesse https://console.cloud.google.com/cloud-resource-manager, selecione o projeto criado na etapa 2 e escolha Excluir. Se você excluir o projeto, será necessário mudar os projetos no SDK Cloud. Para conferir a lista de todos os projetos disponíveis, execute gcloud projects list.