Além de autenticar utilizadores, pode ter de permitir que outros serviços interajam com a sua API. Embora as aplicações cliente possam apresentar aos utilizadores um pedido de início de sessão na Web para enviarem as respetivas credenciais, precisa de outra abordagem para a comunicação segura entre serviços. Esta página mostra a abordagem que recomendamos para implementar a autenticação entre serviços e fornece código de exemplo.
Vista geral
Para identificar um serviço que envia pedidos para a sua API, usa uma conta de serviço. O serviço de chamadas usa a chave privada da conta de serviço para assinar um símbolo da Web JSON (JWT) seguro e envia o JWT assinado no pedido para a sua API.
Para implementar a autenticação de serviço para serviço na sua API e serviço de chamadas:
- Crie uma conta de serviço e uma chave para o serviço de chamadas usar.
- Adicione suporte para autenticação no documento OpenAPI do seu serviço Cloud Endpoints.
Adicione código ao serviço de chamadas que:
- Cria um JWT e assina-o com a chave privada da conta de serviço.
- Envia o JWT assinado num pedido à API.
O ESP valida se as reivindicações no JWT correspondem à configuração no seu documento OpenAPI antes de encaminhar o pedido para a sua API. O ESP não verifica as autorizações do Cloud ID que concedeu na conta de serviço.
Pré-requisitos
Esta página pressupõe que já:
Criar uma conta de serviço com uma chave
Precisa de uma conta de serviço com um ficheiro de chave privada que o serviço de chamadas usa para assinar o JWT. Se tiver mais do que um serviço a enviar pedidos para a sua API, pode criar uma conta de serviço para representar todos os serviços de chamadas. Se precisar de distinguir os serviços, por exemplo, se tiverem autorizações diferentes, pode criar uma conta de serviço e uma chave para cada serviço de chamadas.
Esta secção mostra como usar a Google Cloud consola e a ferramenta de linha de comandos gcloud
para criar a conta de serviço e o ficheiro de chave privada, e para
atribuir à conta de serviço a função
Criador de tokens de contas de serviço. Para obter informações sobre como usar uma API para realizar esta tarefa, consulte o artigo
Criar e gerir contas de serviço.
Para criar uma conta de serviço e uma chave:
Google Cloud consola
Crie uma conta de serviço:
Na Google Cloud consola, aceda à página Criar conta de serviço.
Selecione o projeto que quer usar.
No campo Nome da conta de serviço, introduza um nome.
Opcional: no campo Descrição da conta de serviço, introduza uma descrição.
Clique em Criar.
Clique em Concluído.
Não feche a janela do navegador. Vai usá-lo no passo seguinte.
Crie uma chave de conta de serviço:
- Na Google Cloud consola, clique no endereço de email da conta de serviço que criou.
- Clique em Chaves.
- Clique em Adicionar chave e, de seguida, em Criar nova chave.
- Clique em Criar. Um ficheiro JSON que contém a chave privada da conta de serviço é transferido para o seu computador.
- Clique em Fechar.
gcloud
Pode executar os seguintes comandos através da CLI Google Cloud no seu computador local ou no Cloud Shell.
Defina a conta predefinida para
gcloud. Se tiver mais do que uma conta, certifique-se de que escolhe a conta que está no Google Cloud projeto que quer usar.gcloud auth loginApresentar os IDs dos seus Google Cloud projetos.
gcloud projects listDefina o projeto predefinido. Substitua
PROJECT_IDpelo ID do projeto que quer usar. Google Cloudgcloud config set project PROJECT_ID
Crie uma conta de serviço. Substitua
SA_NAMEeSA_DISPLAY_NAMEpelo nome e nome a apresentar que quer usar.gcloud iam service-accounts create SA_NAME \ --display-name "SA_DISPLAY_NAME"
Apresentar o endereço de email da conta de serviço que acabou de criar.
gcloud iam service-accounts listAdicione a função Criador de tokens de contas de serviço. Substitua
SA_EMAIL_ADDRESSpelo endereço de email da conta de serviço.gcloud projects add-iam-policy-binding PROJECT_ID \ --member serviceAccount:SA_EMAIL_ADDRESS \ --role roles/iam.serviceAccountTokenCreator
Crie um ficheiro de chave de conta de serviço no diretório de trabalho atual. Substitua
FILE_NAMEpelo nome que quer usar para o ficheiro de chave. Por predefinição, o comandogcloudcria um ficheiro JSON.gcloud iam service-accounts keys create FILE_NAME.json \ --iam-account SA_EMAIL_ADDRESS
Consulte a
gcloud referência
para mais informações sobre os comandos anteriores.
Para obter informações sobre a salvaguarda da chave privada, consulte as Práticas recomendadas para gerir credenciais.
Configurar a API para suportar a autenticação
Para ativar a autenticação de contas de serviço para serviços que chamam o seu gateway, modifique os objetos de segurança no seu documento OpenAPI para que o ESP valide as reivindicações no JWT assinado. As modificações variam consoante a versão da especificação OpenAPI usada.
OpenAPI 2.0
- Adicione a conta de serviço como emissor na sua 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 identifique esta definição de segurança. Pode querer 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 email da conta de serviço. - Pode definir várias definições de segurança na sua especificação OpenAPI, mas
cada definição tem de ter um
x-google-issuerdiferente. Se tiver criado contas de serviço separadas para cada serviço de chamadas, pode criar uma definição de segurança para cada conta de serviço, 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
- Opcionalmente, adicione
x-google-audiencesà secçãosecurityDefinitions. Se não adicionarx-google-audiences, o ESP requer que a reivindicação"aud"(público-alvo) no JWT esteja no formatohttps://SERVICE_NAME, em que SERVICE_NAME é o nome do seu serviço ESP, que configurou no campohostdo seu documento OpenAPI. - Adicione uma secção
securityno nível superior do ficheiro (não com recuo nem aninhada) para aplicar a toda a API ou no nível do método para aplicar a um método específico. Se usar secçõessecurityao nível da API e ao nível do método, as definições ao nível do método substituem as definições ao nível da API.security: - DEFINITION_NAME: []
- Substitua
DEFINITION_NAMEpelo nome que usou na secçãosecurityDefinitions. - Se tiver mais do que uma definição na secção
securityDefinitions, adicione-as na secçãosecurity, por exemplo:security: - service-1: [] - service-2: []
- Substitua
- Implemente a sua especificação OpenAPI atualizada. Antes de o ESP encaminhar um pedido para a sua API, o ESP
valida:
- A assinatura do JWT através da chave pública, que se encontra no URI especificado no campo
x-google-jwks_urina sua especificação OpenAPI. - Que a reivindicação
"iss"(emissor) no JWT corresponde ao valor especificado no campox-google-issuer. - Que a reivindicação
"aud"(público-alvo) no JWT contém o nome do serviço do ESP ou corresponde a um dos valores que especificou no campox-google-audiences. - Que o token não expirou através da reivindicação
"exp"(tempo de expiração).
- A assinatura do JWT através da chave pública, que se encontra no URI especificado no campo
OpenAPI 3.x
- Adicione a conta de serviço como emissor na sua 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 este esquema de segurança. Recomendamos que o substitua pelo nome da conta de serviço ou por um nome que identifique o serviço de chamadas. - Substitua
SA_EMAIL_ADDRESSpelo endereço de email da conta de serviço. - Pode definir vários esquemas de segurança na sua especificação OpenAPI, mas
cada definição tem de ter um
issuerdiferente. Se tiver criado contas de serviço separadas para cada serviço de chamadas, pode criar uma definição de segurança para cada conta de serviço, 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
- Opcionalmente, adicione
audiencesà secçãosecuritySchemes. Se não adicionaraudiences, o ESP requer que a reivindicação"aud"(público-alvo) no JWT esteja no formatohttps://SERVICE_NAME, em que SERVICE_NAME é o nome do seu serviço ESP, que configurou no campohostdo seu documento OpenAPI. - Adicione uma secção
securityno nível superior do ficheiro (sem indentação nem aninhamento) para aplicar a toda a API ou no nível do método para aplicar a um método específico. Se usar secçõessecurityao nível da API e ao nível do método, as definições ao nível do método substituem as definições ao nível da API.security: - SCHEME_NAME: []
- Substitua SCHEME_NAME pelo nome que usou na secção
securitySchemes. - Se tiver mais do que uma definição na secção
securitySchemes, adicione-as na secçãosecurity, por exemplo:security: - service-1: [] - service-2: []
- Substitua SCHEME_NAME pelo nome que usou na secção
- Implemente a sua especificação OpenAPI atualizada. Antes de o ESP encaminhar um pedido para a sua API, o ESP
valida:
- A assinatura do JWT através da chave pública, que se encontra no URI especificado no campo
jwksUrina sua especificação OpenAPI. - Que a reivindicação
"iss"(emissor) no JWT corresponde ao valor especificado no campoissuer. - Que a reivindicação
"aud"(público-alvo) no JWT contém o nome do serviço do seu ESP ou corresponde a um dos valores que especificou no campoaudiences. - Que o token não expirou através da reivindicação
"exp"(hora de validade).
- A assinatura do JWT através da chave pública, que se encontra no URI especificado no campo
Fazer um pedido autenticado a uma API Google Cloud Endpoints
Para fazer um pedido autenticado, o serviço de chamada envia um JWT assinado pela conta de serviço que especificou no documento OpenAPI. O serviço de chamadas tem de:
- Crie um JWT e assine-o com a chave privada da conta de serviço.
- Envie o JWT assinado num pedido à API.
O seguinte exemplo de código demonstra este processo para determinados idiomas. Para fazer um pedido autenticado noutros idiomas, consulte jwt.io para ver uma lista de bibliotecas suportadas.
-
No serviço de chamadas, adicione a seguinte função e transmita-lhe os seguintes parâmetros:
Java -
saKeyfile: o caminho completo para o ficheiro da chave privada da conta de serviço. -
saEmail: o endereço de email da conta de serviço. -
audience: se adicionou o campox-google-audiencesao seu documento OpenAPI, definaaudiencepara um dos valores que especificou parax-google-audiences. Caso contrário, definaaudiencecomohttps://SERVICE_NAME, ondeSERVICE_NAMEé o nome do serviço Endpoints. -
expiryLength: o tempo de expiração do JWT, em segundos.
Python -
sa_keyfile: o caminho completo para o ficheiro da chave privada da conta de serviço. -
sa_email: o endereço de email da conta de serviço. -
audience: se adicionou o campox-google-audiencesao seu documento OpenAPI, definaaudiencepara um dos valores que especificou parax-google-audiences. Caso contrário, definaaudiencecomohttps://SERVICE_NAME, ondeSERVICE_NAMEé o nome do serviço Endpoints. -
expiry_length: o tempo de expiração do JWT, em segundos.
Ir -
saKeyfile: o caminho completo para o ficheiro da chave privada da conta de serviço. -
saEmail: o endereço de email da conta de serviço. -
audience: se adicionou o campox-google-audiencesao seu documento OpenAPI, definaaudiencepara um dos valores que especificou parax-google-audiences. Caso contrário, definaaudiencecomohttps://SERVICE_NAME, ondeSERVICE_NAMEé o nome do serviço Endpoints. -
expiryLength: o tempo de expiração do JWT, em segundos.
A função cria um JWT, assina-o através do ficheiro de chave privada e devolve o JWT assinado.
Java Python Ir -
-
No serviço de chamadas, adicione a seguinte função para enviar o JWT assinado no cabeçalho
Authorization: Bearerno pedido à API:Java Python Ir
Quando envia um pedido através de um JWT, por motivos de segurança, recomendamos que coloque o token de autenticação no cabeçalho Authorization: Bearer. Por exemplo:
curl --request POST \
--header "Authorization: Bearer ${TOKEN}" \
"${ENDPOINTS_HOST}/echo"
onde ENDPOINTS_HOST e TOKEN são variáveis de ambiente que contêm o nome do anfitrião da API e o token de autenticação, respetivamente.
Receber resultados autenticados na sua API
Normalmente, o ESP encaminha todos os cabeçalhos que recebe. No entanto, 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 gRPC.
O ESP envia o resultado da autenticação no cabeçalho X-Endpoint-API-UserInfo para a API de back-end. Recomendamos que use este cabeçalho em vez do cabeçalho Authorization original. Este cabeçalho é uma string que base64urlcodifica
um objeto JSON. O formato do objeto JSON difere entre o ESPv2 e o ESP.
Para o ESPv2, o objeto JSON é exatamente o payload JWT original. Para o ESP,
o objeto JSON usa nomes de campos diferentes e coloca o payload JWT original no campo claims.
Consulte o artigo Processar JWTs no serviço de back-end
para mais informações sobre o formato.