Como autenticar para invocação

Para criar, atualizar ou executar outras ações administrativas em uma função, você precisa ter uma conta que seja um member que tenha um papel apropriado. Para mais informações, consulte Como autorizar o acesso por meio do IAM.

Porém, invocar uma função pode ser um evento mais complexo. As funções orientadas por eventos só podem ser invocadas pela fonte do evento no qual elas estão inscritas, mas as funções HTTP podem ser chamadas por diferentes tipos de identidades. , originários de lugares diferentes. O invocador pode ser um desenvolvedor que está testando a função ou outra função ou serviço que quer usar a função. Por padrão, essas identidades precisam se autenticar (fornecer provas da identidade) e ter as permissões apropriadas. O acesso não autenticado é possível, mas precisa estar ativado. Consulte Como gerenciar o acesso por meio do IAM para mais informações.

Como autenticar testes de desenvolvedor

Como desenvolvedor, você precisa de acesso para criar, atualizar e excluir funções. Isso é concedido usando o processo normal (IAM).

No entanto, como desenvolvedor, você provavelmente precisará invocar suas funções para fins de teste. Para invocar uma função usando curl ou ferramentas semelhantes, é preciso:

  • A conta que você está usando para acessar o Cloud Functions tem um papel que contém a permissão cloudfunctions.functions.invoke. Por padrão, os papéis de administrador e desenvolvedor do Cloud Functions têm essa permissão. Consulte Papéis de IAM do Cloud Functions para ver a lista completa de papéis e as permissões associadas.

  • Se você estiver trabalhando na sua máquina local, configure o acesso da linha de comando ao inicializar o SDK do Google Cloud. Certifique-se de fazer o download da chave da conta de serviço e definir sua variável de ambiente GOOGLE_APPLICATION_CREDENTIALS.

  • Forneça as credenciais de autenticação na solicitação como um token de ID gerado pelo Google armazenado em um cabeçalho Authorization. Por exemplo, é possível obter um token via gcloud da seguinte maneira:

    curl https://REGION-PROJECT_ID.cloudfunctions.net/FUNCTION_NAME \
      -H "Authorization: bearer $(gcloud auth print-identity-token)"
    

Como sempre, recomendamos que você aloque o conjunto mínimo de permissões necessárias para desenvolver e usar suas funções. Certifique-se de que as políticas do IAM nas suas funções estão limitadas ao número mínimo de usuários e contas de serviço.

Como autenticar uma função para chamadas de função

Ao criar serviços que conectam várias funções, é recomendável garantir que cada função envie solicitações somente a um subconjunto específico de outras funções. Por exemplo, se você tiver uma função login, ela deve ser capaz de acessar a função user profiles, mas não a função search.

Para configurar a função de recebimento para aceitar solicitações de uma função de chamada específica, você precisa adicionar a conta de serviço da função de chamada como membro na função de recebimento e conceder a esse membro o papel de Invocador do Cloud Functions (roles/cloudfunctions.invoker). O processo é o mesmo para adicionar qualquer outro membro à função.

Console

  1. Acesse o Console do Google Cloud:

    Ir para o Google Cloud Console

  2. Clique na caixa de seleção ao lado da função de recebimento.

  3. Clique em Permissões na parte superior da tela. O painel Permissões é aberto.

  4. Clique em Adicionar membro.

  5. No campo Novos membros, insira a identidade da função de chamada. Ela deve ser um e-mail da conta de serviço.

  6. Selecione o papel Cloud Functions > Chamador do Cloud Functions no menu suspenso Selecionar papel.

  7. Clique em Salvar.

GCloud

Use o comando gcloud functions add-iam-policy-binding:

gcloud functions add-iam-policy-binding RECEIVING_FUNCTION \
  --member='serviceAccount:CALLING_FUNCTION_IDENTITY' \
  --role='roles/cloudfunctions.invoker'

em que RECEIVING_FUNCTION é o nome da função de recebimento e CALLING_FUNCTION_IDENTITY é a identidade da função de chamada, um e-mail de conta de serviço.

Como ela invoca a função de recebimento, a função de chamada também precisa fornecer um token de código assinado pelo Google para autenticação. Esse processo é realizado em duas etapas:

  1. Criar um token de ID assinado pelo Google com o campo de público-alvo (aud) definido como a URL da função de recebimento.

  2. Incluir o token de código em um cabeçalho Authorization: Bearer ID_TOKEN na solicitação para a função.

A maneira mais fácil e confiável de gerenciar esse processo é usar as bibliotecas de autenticação, conforme mostrado abaixo, para gerar e empregar esse token.

Como gerar tokens de maneira programática

É possível usar o seguinte código para gerar um token de ID. Esse código funciona em qualquer ambiente em que as bibliotecas possam receber credenciais de autenticação, incluindo ambientes compatíveis com o Application Default Credentials local.

Node.js

/**
 * TODO(developer): Uncomment these variables before running the sample.
 */
// const url = 'https://TARGET_URL';
// let targetAudience = null;
const {GoogleAuth} = require('google-auth-library');
const auth = new GoogleAuth();

async function request() {
  if (!targetAudience) {
    // Use the request URL hostname as the target audience for requests.
    const {URL} = require('url');
    targetAudience = new URL(url);
  }
  console.info(`request ${url} with target audience ${targetAudience}`);
  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;
});

Python

import urllib

import google.auth.transport.requests
import google.oauth2.id_token

def make_authorized_get_request(service_url):
    """
    make_authorized_get_request makes a GET request to the specified HTTP endpoint
    in service_url (must be a complete URL) by authenticating with the
    ID token obtained from the google-auth client library.
    """

    req = urllib.request.Request(service_url)

    auth_req = google.auth.transport.requests.Request()
    id_token = google.oauth2.id_token.fetch_id_token(auth_req, service_url)

    req.add_header("Authorization", f"Bearer {id_token}")
    response = urllib.request.urlopen(req)

    return response.read()

Go


import (
	"context"
	"fmt"
	"io"

	"google.golang.org/api/idtoken"
)

// makeGetRequest makes a request to the provided targetURL with an authenticated client.
func makeGetRequest(w io.Writer, targetURL string) error {
	// functionURL := "https://TARGET_URL"
	ctx := context.Background()

	// client is a http.Client that automatically adds an "Authorization" header
	// to any requests made.
	client, err := idtoken.NewClient(ctx, targetURL)
	if err != nil {
		return fmt.Errorf("idtoken.NewClient: %v", err)
	}

	resp, err := client.Get(targetURL)
	if err != nil {
		return fmt.Errorf("client.Get: %v", err)
	}
	defer resp.Body.Close()
	if _, err := io.Copy(w, resp.Body); err != nil {
		return fmt.Errorf("io.Copy: %v", err)
	}

	return nil
}

Java

import com.google.api.client.http.GenericUrl;
import com.google.api.client.http.HttpRequest;
import com.google.api.client.http.HttpResponse;
import com.google.api.client.http.HttpTransport;
import com.google.api.client.http.javanet.NetHttpTransport;
import com.google.auth.http.HttpCredentialsAdapter;
import com.google.auth.oauth2.GoogleCredentials;
import com.google.auth.oauth2.IdTokenCredentials;
import com.google.auth.oauth2.IdTokenProvider;
import java.io.IOException;

public class Authentication {

  // makeGetRequest makes a GET request to the specified Cloud Run or
  // Cloud Functions endpoint, serviceUrl (must be a complete URL), by
  // authenticating with an Id token retrieved from Application Default Credentials.
  public static HttpResponse makeGetRequest(String serviceUrl) throws IOException {
    GoogleCredentials credentials = GoogleCredentials.getApplicationDefault();
    if (!(credentials instanceof IdTokenProvider)) {
      throw new IllegalArgumentException("Credentials are not an instance of IdTokenProvider.");
    }
    IdTokenCredentials tokenCredential =
        IdTokenCredentials.newBuilder()
            .setIdTokenProvider((IdTokenProvider) credentials)
            .setTargetAudience(serviceUrl)
            .build();

    GenericUrl genericUrl = new GenericUrl(serviceUrl);
    HttpCredentialsAdapter adapter = new HttpCredentialsAdapter(tokenCredential);
    HttpTransport transport = new NetHttpTransport();
    HttpRequest request = transport.createRequestFactory(adapter).buildGetRequest(genericUrl);
    return request.execute();
  }
}

Como gerar tokens manualmente

Se você estiver invocando uma função e, por algum motivo, não for possível usar as bibliotecas de autenticação, há duas maneiras de receber o token de código manualmente:Servidor de metadados do Compute ou criando um JWT autoassinado e o troca por um token de código assinado pelo Google.

Como usar o servidor de metadados

Use o servidor de metadados do Compute para buscar tokens de código com um público-alvo específico da seguinte maneira:

curl "http://metadata.google.internal/computeMetadata/v1/instance/service-accounts/default/identity?audience=[AUDIENCE]" \
     -H "Metadata-Flavor: Google"

Em que AUDIENCE é o URL da função que você está invocando, como https://GCP_REGION-PROJECT_ID.cloudfunctions.net/my-function.

Como trocar um JWT autoassinado por um token de ID assinado pelo Google

  1. Atribua o papel de Chamador do Cloud Functions (roles/cloudfunctions.invoker) à conta de serviço da função de chamada.

  2. Adicione essa conta de serviço como um membro à função de recebimento

  3. Crie uma conta de serviço e uma chave e faça o download do arquivo com a chave privada (no formato JSON) para o host de onde a função ou serviço de chamada faz as solicitações

  4. Crie um JWT com o cabeçalho definido como {"alg":"RS256","typ":"JWT"}. O payload precisa incluir uma declaração target_audience definida para o URL da função de recebimento e as declarações iss e sub definidas para o endereço de e-mail da conta de serviço usada acima Também deve incluir exp e iat declarações A declaração aud precisa ser definida como https://www.googleapis.com/oauth2/v4/token

  5. Use a chave privada, cujo download foi feito, acima

  6. Usando este JWT, envie uma solicitação POST para https://www.googleapis.com/oauth2/v4/token Os dados de autenticação precisam ser incluídos no cabeçalho e no corpo da solicitação.

    No cabeçalho:

    Authorization: Bearer $JWT - where $JWT is the JWT you just created
    Content-Type: application/x-www-form-urlencoded
    

    No corpo:

    grant_type=urn:ietf:params:oauth:grant-type:jwt-bearer&assertion=$JWT
    

    Substitua $JWT pelo JWT que você acabou de criar.

    Isso retorna outro JWT, que inclui um id_token assinado pelo Google.

Envie sua solicitação GET/POST para a função de recebimento. Inclua o token de ID assinado pelo Google em um cabeçalho Authorization: Bearer ID_TOKEN_JWT na solicitação.