Como autenticar desenvolvedores, funções e usuários finais

Por padrão, somente proprietários e editores de projetos podem criar, atualizar ou excluir funções. Para conceder a outros usuários ou grupos a capacidade de executar essas ações, é possível usar o Cloud Identity and Access Management (IAM) para conceder papéis a diferentes membros.

Da mesma forma, é possível conceder ou restringir a capacidade de invocar uma função. Esse comportamento é diferente para funções HTTP e funções em segundo plano:

Três casos de uso comuns para autenticação incluem:

  • Proteger o acesso do desenvolvedor para que apenas usuários específicos possam invocar a função durante o teste.

  • Proteger o acesso de função a função para que apenas funções autorizadas possam invocar sua função.

  • Proteger o acesso do usuário final a um aplicativo de clientes de dispositivos móveis ou da Web.

Desenvolvedores

Além de ações administrativas, como criar, atualizar e excluir funções, os desenvolvedores querem testar as funções de maneira privada antes de liberá-las publicamente.

Ao usar curl ou ferramentas semelhantes, você deve tratá-las como solicitações de usuários finais e fornecer um token OAuth do Google no cabeçalho Authorization da solicitação. 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)"

Para que essa solicitação funcione, o papel atribuído ao desenvolvedor deve conter a permissão cloudfunctions.functions.invoke. Por padrão, os papéis de administrador e de desenvolvedor do Cloud Functions têm essa permissão. Consulte Papéis de IAM do Cloud Functions para obter a lista completa de papéis e as permissões associadas.

Por fim, 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.

Função a função

Ao criar serviços que conectam várias funções, é recomendável garantir que cada função só possa fazer solicitações para determinadas 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.

Primeiro, você precisa configurar a função de recebimento para aceitar solicitações da função de chamada:

  1. Conceda o papel de Invocador do Cloud Functions (roles/cloudfunctions.invoker) à identidade da função de chamada na função de recebimento. Por padrão, essa identidade é PROJECT_ID@appspot.gserviceaccount.com.

Console

  1. Acesse o Google Cloud Console:

    Ir para o Google Cloud Console

  2. Clique na caixa de seleção ao lado da função cujas permissões você quer modificar.

  3. Clique em Mostrar painel de informações no canto superior direito para exibir a guia Permissões, que exibe os papéis atribuídos à função.

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

  5. Selecione o papel Cloud Functions > Invocador do Cloud Functionsno menu suspenso Selecionar um papel.

  6. 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 é a função de recebimento e CALLING_FUNCTION_IDENTITY é a identidade da função de chamada.

Na função de chamada, você precisa:

  1. Criar um token de código OAuth assinado pelo Google com o 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.

Nodejs
// Make sure to `npm install --save request-promise` or add the dependency to your package.json
const request = require('request-promise');

exports.callingFunction = (req, res) => {
  // Make sure to replace variables with appropriate values
  const receivingFunctionURL = 'https://REGION-PROJECT.cloudfunctions.net/RECEIVING_FUNCTION';

  // Set up metadata server request
  // See https://cloud.google.com/compute/docs/instances/verifying-instance-identity#request_signature
  const metadataServerTokenURL = 'http://metadata/computeMetadata/v1/instance/service-accounts/default/identity?audience=';
  const tokenRequestOptions = {
      uri: metadataServerTokenURL + receivingFunctionURL,
      headers: {
          'Metadata-Flavor': 'Google'
      }
  };

  // Fetch the token, then provide the token in the request to the receiving function
  request(tokenRequestOptions)
    .then((token) => {
      return request(receivingFunctionURL).auth(null, null, true, token)
    })
    .then((response) => {
      res.status(200).send(response);
    })
    .catch((error) => {
      res.status(400).send(error);
    });
};
    
Python
# Requests is already installed, no need to add it to requirements.txt
import requests

def calling_function(request):
  # Make sure to replace variables with appropriate values
  receiving_function_url = 'https://REGION-PROJECT.cloudfunctions.net/RECEIVING_FUNCTION'

  # Set up metadata server request
  # See https://cloud.google.com/compute/docs/instances/verifying-instance-identity#request_signature
  metadata_server_token_url = 'http://metadata/computeMetadata/v1/instance/service-accounts/default/identity?audience='

  token_request_url = metadata_server_token_url + receiving_function_url
  token_request_headers = {'Metadata-Flavor': 'Google'}

  # Fetch the token
  token_response = requests.get(token_request_url, headers=token_request_headers)
  jwt = token_response.content.decode("utf-8")

  # Provide the token in the request to the receiving function
  receiving_function_headers = {'Authorization': f'bearer {jwt}'}
  function_response = requests.get(receiving_function_url, headers=receiving_function_headers)

  return function_response.content
    

Serviço a função

Se você invocar uma função de uma instância de computador que não tem acesso a metadados (por exemplo, seu próprio servidor), é necessário gerar manualmente o token adequado:

  1. Autoassine um JWT de conta de serviço com a declaração target_audience definida como a URL da função de recebimento.

  2. Troque o JWT autoassinado por um token de código assinado pelo Google, que deve ter a reivindicação aud definida como a URL acima.

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

Os documentos do Cloud IAP têm códigos de amostra para demonstrar essa função.

Usuários finais

A maioria dos aplicativos processa solicitações de usuários finais. Essa é uma prática recomendada para restringir o acesso apenas a usuários finais permitidos. Para conseguir isso, é possível integrar o Login do Google e conceder aos usuários o papel de IAM roles/cloudfunctions.invoker ou implementar o Firebase Authentication e validar manualmente as credenciais.

Login do Google

Primeiro, ative o Login do Google no seu projeto:

  1. Crie um ID do cliente OAuth 2.0 para seu aplicativo no mesmo projeto da função que você quer proteger:
    1. Acesse a página Credenciais.

      Acesse a página Credenciais

    2. Selecione o projeto com a função que você quer proteger.
    3. Clique em Criar credenciais e selecione ID do cliente OAuth.
      1. Talvez seja solicitado que você configure sua tela de consentimento do OAuth antes de criar um ID de cliente. Se necessário, faça isso para continuar.
    4. Selecione o Tipo de aplicativo para que você quer criar credenciais.
    5. Adicione um Nome e Restrições, se apropriado, e clique em Criar.
  2. Implante novamente a função que você quer proteger. Isso garante que o ID correto do cliente seja definido na função.

Se houver vários IDs de cliente OAuth (por exemplo, um para Android, um para iOS e um para Web), implante novamente as funções depois de adicionar cada um deles para garantir que a função receba a alteração. Da mesma forma, se você excluir um ID de cliente, é preciso implantar de novo as funções para removê-lo e negar solicitações. Todos os IDs de cliente dentro de um projeto serão aceitos.

Na sua Web ou aplicativo para dispositivos móveis, você precisa:

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

O Cloud Functions valida o token de autenticação e permite ou rejeita a solicitação antes que a função seja iniciada. Se uma solicitação for rejeitada, você não será cobrado por ela.

Como acessar informações do perfil do usuário

Se você quer acessar as informações do perfil de usuário, retire o token do cabeçalho Authorization, decodifique o JSON Web Token e extraia o corpo.

O corpo do token de código deve conter as seguintes informações:

{
 // These six fields are included in all Google ID Tokens.
 "iss": "https://accounts.google.com",
 "sub": "110169484474386276334",
 "azp": "1008719970978-hb24n2dstb40o45d4feuo2ukqmcc6381.apps.googleusercontent.com",
 "aud": "1008719970978-hb24n2dstb40o45d4feuo2ukqmcc6381.apps.googleusercontent.com",
 "iat": "1433978353",
 "exp": "1433981953",

 // These seven fields are only included when the user has granted the "profile"
 // and "email" OAuth scopes to the application.
 "email": "testuser@gmail.com",
 "email_verified": "true",
 "name" : "Test User",
 "picture": "https://lh4.googleusercontent.com/-kYgzyAWpZzJ/ABCDEFGHI/AAAJKLMNOP/tIXL9Ir44LE/s99-c/photo.jpg",
 "given_name": "Test",
 "family_name": "User",
 "locale": "en"
}

Não é necessário validar o token, porque ele já foi validado pelo Cloud IAM.

Solução de problemas

Se as solicitações de usuários forem rejeitadas e você acreditar que elas devem ser permitidas, certifique-se de que os usuários tenham recebido o papel roles/cloudfunctions.invoker ou tenham a permissão cloudfunctions.functions.invoke. Saiba mais na referência do Cloud Functions IAM.

Aplicativos da Web, autenticação e CORS

Se você quer criar um aplicativo da Web protegido com o Login do Google e o Cloud Functions IAM, você provavelmente lidará com o CORS (Cross-Origin Resource Sharing). As solicitações de simulação do CORS são enviadas sem um cabeçalho Authorization. Portanto, elas são rejeitadas em todas as funções HTTP não públicas. Como há falha nas solicitações simuladas, a solicitação principal também falhará.

Para contornar esse problema, é possível hospedar seu aplicativo da web e suas funções no mesmo domínio para evitar solicitações simuladas de CORS. Caso contrário, torne suas funções públicas e processe o CORS e a autenticação no código de função.

Como alternativa, é possível implantar um proxy do Cloud Endpoints e ativar o CORS . Se você quiser recursos de autenticação, é possível ativar a validação do token de código do Google , que valida esses mesmos tokens de autenticação.

Firebase Authentication

Se você quiser autenticar usuários usando e-mail/senha, número de telefone, provedores de redes sociais como Facebook ou GitHub ou um mecanismo de autenticação personalizado, use o Firebase Authentication.

Primeiro, você precisa configurar o Firebase Authentication no seu projeto e função:

  1. Configure o Firebase Authentication no Console do Firebase.

    Acessar o Console do Firebase

  2. Importe o SDK Admin do Firebase apropriado e configure-o adequadamente.

  3. Adicione um middleware ao código para verificar os tokens do código do Firebase.

  4. Implante sua função publicamente.

Na Web ou app para dispositivo móvel, você precisa:

  1. Usar a biblioteca de cliente do Firebase Auth apropriada para receber um token do código:
  2. Incluir o token de código em um cabeçalho Authorization: Bearer ID_TOKEN na solicitação para a função.

Como alternativa, é possível implantar um proxy do Cloud Endpoints e ativar a validação do token de código do Firebase , validando esses mesmos tokens de autenticação.

Como acessar informações do perfil do usuário

Se você quiser acessar as informações do perfil do usuário, use o SDK Admin do Firebase para recuperar os dados do usuário.

Chaves de API

As chaves de API identificam o aplicativo cliente e o projeto do GCP chamando sua API, permitindo realizar uma simples autorização, bem como verificações de cota e limitação de taxa.

As chaves de API não são tão seguras quanto os outros métodos de autenticação listados pelos seguintes motivos:

  1. As chaves de API têm longa duração. Isso significa que se uma chave vazar, ela pode ser usada indefinidamente (ou pelo menos até que as chaves sejam giradas, o que exige que todos os clientes a atualizem).
  2. As chaves de API geralmente são armazenadas no lado do cliente, tornando-as vulneráveis à reutilização por partes maliciosas.

Se você optar por usar chaves de API para a cota e a limitação de taxa, recomendamos usá-las com tokens de autenticação.

Para configurar o acesso à chave de API, implante um proxy do Cloud Endpoints e ative configure o securityDefinitions para ativar a validação da chave de API.

Próximas etapas

Saiba como gerenciar o acesso às funções para as quais você está se autenticando.