Além de autenticar usuários, pode ser necessário permitir que outros serviços interajam com a API. Os aplicativos clientes podem fornecer aos usuários um prompt de login da Web para enviar suas credenciais, mas é preciso outra abordagem para uma comunicação segura entre serviços. Nesta página, você verá a abordagem recomendada para implementar autenticação entre serviços, além do código de amostra.
Visão geral
Para identificar um serviço que envia solicitações para a API, use uma conta de serviço. O serviço de chamada usa a chave privada da conta de serviço para assinar um JSON Web Token (JWT) seguro e enviá-lo na solicitação para a API.
Para implementar o serviço de chamada e a autenticação entre serviços na API, faça o seguinte:
- Crie uma conta de serviço e uma chave que será usada pelo serviço de chamada.
- Acrescente compatibilidade para autenticação no documento OpenAPI do serviço Cloud Endpoints.
Adicione o código ao serviço de chamada que:
- cria um JWT e o assina com a chave privada da conta de serviço;
- envia o JWT assinado em uma solicitação à API.
O ESP verifica se as declarações no JWT correspondem à configuração no documento da OpenAPI antes de encaminhar a solicitação à API. No entanto, o ESP não confere as permissões do Cloud Identity concedidas na conta de serviço.
Pré-requisitos
Nesta página, presume-se que você já:
Como criar uma conta de serviço com uma chave
Você precisa de uma conta de serviço com um arquivo de chave privada que o serviço de chamada usa para assinar o JWT. Se você tiver mais de um serviço enviando solicitações para sua API, crie uma conta de serviço para representar todos os serviços de chamada. Caso precise diferenciar os serviços crie uma conta de serviço e uma chave para cada serviço de chamada, eles podem ter permissões diferentes, por exemplo.
Esta seção mostra como usar o console Google Cloud e a ferramenta de linha de comando gcloud para criar a conta de serviço e o arquivo de chave privada, e para atribuir o papel Criador de token de conta de serviço à conta de serviço. Para informações sobre como executar essa tarefa usando uma API, consulte
Como criar e gerenciar contas de serviço.
Para criar uma conta de serviço e uma chave, faça o seguinte:
Console do Google Cloud
Crie uma conta de serviço:
No console Google Cloud , acesse a página Criar conta de serviço.
Selecione o projeto desejado.
No campo Nome da conta de serviço, insira um nome.
Opcional: no campo Descrição da conta de serviço, digite uma descrição.
Clique em Criar.
Clique em Concluído.
Não feche a janela do navegador. Você vai usá-la na próxima etapa.
Crie uma chave de conta de serviço:
- No console do Google Cloud , clique no endereço de e-mail da conta de serviço que você criou.
- Clique em Chaves.
- Clique em Adicionar chave e, depois, em Criar nova chave.
- Clique em Criar. Será feito o download de um arquivo JSON contendo a chave privada da conta de serviço no seu computador.
- Clique em Fechar.
gcloud
É possível executar os comandos a seguir usando a Google Cloud CLI na sua máquina local ou no Cloud Shell.
Defina a conta padrão para
gcloud. Se você tiver mais de uma conta, escolha a que está no projeto Google Cloud que quer usar.gcloud auth loginExiba os IDs dos seus projetos Google Cloud .
gcloud projects listDefina o projeto padrão. Substitua
PROJECT_IDpelo ID do projeto Google Cloud que você quer usar.gcloud config set project PROJECT_ID
Crie uma conta de serviço. Substitua
SA_NAMEeSA_DISPLAY_NAMEpelo nome e o nome de exibição que você quer usar.gcloud iam service-accounts create SA_NAME \ --display-name "SA_DISPLAY_NAME"
Liste o endereço de e-mail da conta de serviço recém-criada.
gcloud iam service-accounts listAdicione o papel de criador do token de conta de serviço. Substitua
SA_EMAIL_ADDRESSpelo endereço de e-mail da conta de serviço.gcloud projects add-iam-policy-binding PROJECT_ID \ --member serviceAccount:SA_EMAIL_ADDRESS \ --role roles/iam.serviceAccountTokenCreator
Crie um arquivo de chave de conta de serviço no diretório de trabalho atual. Substitua
FILE_NAMEpelo nome escolhido para o arquivo de chaves. Por padrão, o comandogcloudcria um arquivo JSON.gcloud iam service-accounts keys create FILE_NAME.json \ --iam-account SA_EMAIL_ADDRESS
Consulte a referência da gcloud para mais informações sobre os comandos anteriores.
Para informações sobre como proteger a chave privada, consulte Práticas recomendadas para gerenciar credenciais.
Como configurar a API para dar suporte à autenticação
Para ativar a autenticação de conta de serviço para serviços chamando seu gateway, modifique os objetos de segurança no documento OpenAPI para que o ESP valide as declarações no JWT assinado. As modificações variam de acordo com a versão da especificação OpenAPI usada.
OpenAPI 2.0
- Adicione a conta de serviço como um emissor na especificação OpenAPI:
securityDefinitions: DEFINITION_NAME: authorizationUrl: "" flow: "implicit" type: "oauth2" x-google-issuer: "SA_EMAIL_ADDRESS" x-google-jwks_uri: "https://www.googleapis.com/robot/v1/metadata/x509/SA_EMAIL_ADDRESS"
- Substitua
DEFINITION_NAMEpor uma string que identifica essa definição de segurança. É possível substituí-lo pelo nome da conta de serviço ou por um nome que identifique o serviço de chamada. - Substitua
SA_EMAIL_ADDRESSpelo endereço de e-mail da conta de serviço. - É possível definir várias definições de segurança na especificação OpenAPI, mas cada uma delas precisa ter um
x-google-issuerdiferente. Caso tenha criado contas de serviço separadas para cada serviço de chamada, crie uma definição de segurança para cada uma delas, por exemplo:securityDefinitions: service-1: authorizationUrl: "" flow: "implicit" type: "oauth2" x-google-issuer: "service-1@example-project-12345.iam.gserviceaccount.com" x-google-jwks_uri: "https://www.googleapis.com/robot/v1/metadata/x509/service-1@example-project-12345.iam.gserviceaccount.com" service-2: authorizationUrl: "" flow: "implicit" type: "oauth2" x-google-issuer: "service-2@example-project-12345.iam.gserviceaccount.com" x-google-jwks_uri: "https://www.googleapis.com/robot/v1/metadata/x509/service-2@example-project-12345.iam.gserviceaccount.com"
- Substitua
- Se quiser, adicione
x-google-audiencesà seçãosecurityDefinitions. Se você não adicionarx-google-audiences, o ESP exigirá que a declaração"aud"(público-alvo) no JWT esteja no formatohttps://SERVICE_NAME, em que SERVICE_NAME é o nome do serviço do ESP, configurado no campohostdo documento da OpenAPI. - Adicione uma seção
securityno nível superior do arquivo (não recuada ou aninhada), a ser aplicada a toda a API, ou no nível dos métodos, a ser aplicada a um método específico. Se você usar seçõessecurityno nível da API e do método, as configurações no nível do método vão substituir as configurações no nível da API.security: - DEFINITION_NAME: []
- Substitua
DEFINITION_NAMEpelo nome usado na seçãosecurityDefinitions. - Se você tiver mais de uma definição na seção
securityDefinitions, adicione-as na seçãosecurity. Por exemplo:security: - service-1: [] - service-2: []
- Substitua
- Implante a especificação OpenAPI atualizada. Antes de o ESP encaminhar uma solicitação à API, ele verifica:
- a assinatura do JWT usando a chave pública, que está localizada no URI especificado no campo
x-google-jwks_urina especificação OpenAPI; - se a declaração
"iss"(emissor) no JWT corresponde ao valor especificado no campox-google-issuer; - se a declaração
"aud"(público-alvo) no JWT contém o nome do seu serviço do ESP ou corresponde a um dos valores especificados no campox-google-audiences; - se o token não expirou, usando a declaração
"exp"(prazo de validade).
- a assinatura do JWT usando a chave pública, que está localizada no URI especificado no campo
OpenAPI 3.x
- Adicione a conta de serviço como um emissor na especificação OpenAPI:
components: securitySchemes: SCHEME_NAME: type: oauth2 flows: implicit: authorizationUrl: "" scopes: {} x-google-auth: issuer: SA_EMAIL_ADDRESS jwksUri: https://www.googleapis.com/robot/v1/metadata/x509/SA_EMAIL_ADDRESS audiences: - 848149964201.apps.googleusercontent.com - 841077041629.apps.googleusercontent.com jwtLocations: - header: Authorization valuePrefix: "Bearer " security: - SCHEME_NAME: []
- Substitua
SCHEME_NAMEpor uma string que identifica esse esquema de segurança. É possível substituí-lo pelo nome da conta de serviço ou por um nome que identifique o serviço de chamada. - Substitua
SA_EMAIL_ADDRESSpelo endereço de e-mail da conta de serviço. - É possível definir vários esquemas de segurança na especificação OpenAPI, mas cada definição precisa ter um
issuerdiferente. Caso tenha criado contas de serviço separadas para cada serviço de chamada, crie uma definição de segurança para cada uma delas, por exemplo:components: securitySchemes: service-1: type: oauth2 flows: implicit: authorizationUrl: "" scopes: {} x-google-auth: issuer: "service-1@example-project-12345.iam.gserviceaccount.com" jwksUri: https://www.googleapis.com/robot/v1/metadata/x509/service-1@example-project-12345.iam.gserviceaccount.com jwtLocations: - header: Authorization valuePrefix: "Bearer " service-2: type: oauth2 flows: implicit: authorizationUrl: "" scopes: {} x-google-auth: issuer: "service-2@example-project-12345.iam.gserviceaccount.com" jwksUri: "https://www.googleapis.com/robot/v1/metadata/x509/service-2@example-project-12345.iam.gserviceaccount.com" jwtLocations: - header: Authorization valuePrefix: "Bearer "
- Substitua
- Se quiser, adicione
audiencesà seçãosecuritySchemes. Se você não adicionaraudiences, o ESP exigirá que a declaração"aud"(público-alvo) no JWT esteja no formatohttps://SERVICE_NAME, em que SERVICE_NAME é o nome do serviço do ESP, configurado no campohostdo documento OpenAPI. - Adicione uma seção
securityno nível superior do arquivo (não recuada ou aninhada), a ser aplicada a toda a API, ou no nível dos métodos, a ser aplicada a um método específico. Se você usar seçõessecurityno nível da API e do método, as configurações no nível do método vão substituir as configurações no nível da API.security: - SCHEME_NAME: []
- Substitua SCHEME_NAME pelo nome usado na seção
securitySchemes. - Se você tiver mais de uma definição na seção
securitySchemes, adicione-as na seçãosecurity. Por exemplo:security: - service-1: [] - service-2: []
- Substitua SCHEME_NAME pelo nome usado na seção
- Implante a especificação OpenAPI atualizada. Antes de o ESP encaminhar uma solicitação à API, ele verifica:
- a assinatura do JWT usando a chave pública, que está localizada no URI especificado no campo
jwksUrina especificação OpenAPI; - se a declaração
"iss"(emissor) no JWT corresponde ao valor especificado no campoissuer; - se a declaração
"aud"(público-alvo) no JWT contém o nome do seu serviço do ESP ou corresponde a um dos valores especificados no campoaudiences; - se o token não expirou, usando a declaração
"exp"(prazo de validade).
- a assinatura do JWT usando a chave pública, que está localizada no URI especificado no campo
Como fazer uma chamada autenticada para uma API do Endpoints
Para fazer uma solicitação autenticada, o serviço de chamada envia um JWT assinado pela conta de serviço especificada no documento OpenAPI. É preciso que o serviço de chamada:
- crie um JWT assinado com a chave privada da conta de serviço;
- envie o JWT assinado em uma solicitação à API.
O código de amostra a seguir demonstra esse processo para algumas linguagens. Para fazer uma solicitação autenticada em outras linguagens, consulte jwt.io para ver uma lista de bibliotecas compatíveis.
- No serviço de chamada, adicione a seguinte função e transmita os seguintes parâmetros:
Java -
saKeyfile: o caminho completo para o arquivo da chave privada da conta de serviço. saEmail: o endereço de e-mail da conta de serviço.-
audience: se você adicionou o campox-google-audiencesao seu documento da OpenAPI, definaaudiencecomo um dos valores especificados parax-google-audiences. Caso contrário, definaaudiencecomohttps://SERVICE_NAME, em queSERVICE_NAMEé o nome do serviço do Google Endpoints. expiryLength: o prazo de validade do JWT, em segundos.
Python -
sa_keyfile: o caminho completo para o arquivo da chave privada da conta de serviço. -
sa_email: o endereço de e-mail da conta de serviço. -
audience: se você adicionou o campox-google-audiencesao documento da OpenAPI, definaaudiencecomo um dos valores especificados parax-google-audiences. Caso contrário, definaaudiencecomohttps://SERVICE_NAME, em queSERVICE_NAMEé o nome do serviço do Google Endpoints. expiry_length: o prazo de validade do JWT, em segundos.
Go -
saKeyfile: o caminho completo para o arquivo da chave privada da conta de serviço. -
saEmail: o endereço de e-mail da conta de serviço. -
audience: se você adicionou o campox-google-audiencesao documento da OpenAPI, definaaudiencecomo um dos valores especificados parax-google-audiences. Caso contrário, definaaudiencecomohttps://SERVICE_NAME, em queSERVICE_NAMEé o nome do serviço do Google Endpoints. expiryLength: o prazo de validade do JWT, em segundos.
A função cria um JWT e o assina usando o arquivo de chave privada. Em seguida, retorna o JWT assinado.
Java Python Go -
- No serviço de chamada, adicione a seguinte função para enviar o JWT assinado no cabeçalho
Authorization: Bearerna solicitação para a API:Java Python Go
Ao enviar uma solicitação usando um JWT, por motivos de segurança, recomenda-se colocar o token de autenticação no cabeçalho Authorization: Bearer. Exemplo:
curl --request POST \
--header "Authorization: Bearer ${TOKEN}" \
"${ENDPOINTS_HOST}/echo"
em que ENDPOINTS_HOST e TOKEN são variáveis de ambiente que contêm o nome do host da API e o token de autenticação, respectivamente.
Como receber resultados autenticados na API
O ESP geralmente encaminha todos os cabeçalhos recebidos. No entanto, ele substitui o cabeçalho Authorization original quando o endereço de back-end é especificado por x-google-backend na especificação OpenAPI ou BackendRule na configuração do serviço de gRPC.
O ESP enviará o resultado da autenticação no X-Endpoint-API-UserInfo para a API de back-end. Recomendamos usar esse cabeçalho em vez do cabeçalho Authorization original. Esse cabeçalho é uma string em que base64url codifica
um objeto JSON. O formato do objeto JSON é diferente entre o ESPv2 e o ESP.
Para o ESPv2, o objeto JSON é exatamente o payload do JWT original. Para o ESP, o objeto JSON usa nomes de campo diferentes e coloca o payload JWT original no campo claims.
Consulte Como lidar com JWTs no serviço de back-end
para mais informações sobre o formato.