Como verificar a identidade das instâncias

Antes de enviar informações confidenciais a uma instância de máquina virtual, o aplicativo pode verificar a identidade da máquina usando tokens de identidade da instância assinados pelo Google. Cada instância tem um JSON Web Token (JWT) exclusivo que inclui detalhes sobre ela, bem como a assinatura RS256 do Google. Seus aplicativos podem verificar a assinatura dos certificados OAuth2 públicos do Google para confirmar a identidade da instância com que estabeleceram uma conexão.

O Compute Engine gera tokens assinados somente quando uma instância os solicita a partir dos metadados dela. Uma instância só pode acessar o próprio token exclusivo, e não os de outras instâncias.

Verifique as identidades das suas instâncias nos seguintes cenários:

  • Quando a instância é iniciada pela primeira vez, os aplicativos podem precisar confirmar se a identidade dela é válida antes de transmitirem informações confidenciais para a instância.
  • Quando as políticas exigem o armazenamento das credenciais fora do ambiente do Compute Engine, e você as envia regularmente às instâncias para uso temporário. Os aplicativos podem confirmar a identidade das instâncias sempre que precisarem transmitir credenciais.

Os métodos de autenticação de instâncias do Google têm os seguintes benefícios:

  • O Compute Engine cria um token exclusivo sempre que uma instância o solicita. Cada token expira em até uma hora. É possível configurar seus aplicativos para aceitarem um token de identidade somente uma vez. Isso reduz o risco de que o token seja reutilizado por um sistema não autorizado.
  • As chaves privadas do Google e os certificados OAuth2 públicos são alternados diariamente para reduzir a superfície de ataques contra essas assinaturas.
  • Os tokens de metadados assinados usam o padrão aberto do setor RFC 7519 e a camada de identidade OpenID Connect 1.0 (links em inglês). Assim, as ferramentas e bibliotecas atuais funcionam perfeitamente com os tokens de identidade.

Antes de começar

Como verificar a identidade de uma instância

Em alguns cenários, os aplicativos precisam verificar a identidade de uma instância em execução no Compute Engine antes de transmitir dados confidenciais para ela. Vejamos um exemplo comum, em que há uma instância do Compute Engine chamada "VM1" e um sistema em execução fora dele chamado "Host1". A VM1 pode se conectar ao Host1 e validar a identidade da instância com o seguinte processo:

  1. A VM1 estabelece uma conexão segura com o Host1 por meio do protocolo de conexão protegida que você escolher, como HTTPS.

  2. A VM1 solicita o token de identidade exclusivo do servidor de metadados e especifica o público do token. Nesse exemplo, o valor do público é o URI do Host1. A solicitação ao servidor de metadados inclui o URI do público para que o Host1 possa confirmar o valor mais tarde, durante a etapa de verificação do token.

  3. O Google gera um novo token exclusivo de identidade da instância no formato JWT e o fornece à VM1. O payload do token inclui vários detalhes sobre a instância, além do URI do público. Confira uma descrição completa sobre o Conteúdo do token na seção correspondente.

  4. A VM1 envia o token de identidade ao Host1 por meio da conexão segura atual.

  5. O Host1 decodifica o token de identidade para receber os valores do cabeçalho e payload.

  6. Para verificar se o token é assinado pelo Google, o Host1 compara o valor do público e a assinatura do certificado com o certificado público do Google.

  7. Se o token for válido, o Host1 prossegue com a transmissão e encerra a conexão quando terminar. O Host1 e quaisquer outros sistemas precisam solicitar um novo token para conexões posteriores com a VM1.

Como receber o token de identidade da instância

Quando recebe uma solicitação para fornecer o token de identidade, a instância de máquina virtual o solicita do servidor de metadados. Para isso, ela usa o processo normal de recebimento de metadados da instância. Por exemplo, você pode usar um dos seguintes métodos:

cURL

Crie uma solicitação curl e inclua um valor no parâmetro audience. Também é possível incluir o parâmetro format para especificar se quiser ou não incluir detalhes do projeto e da instância na carga útil. Se estiver usando o formato full, é possível incluir o parâmetro licenses para especificar se quer ou não incluir códigos de licença no payload.

$ curl -H "Metadata-Flavor: Google" \
'http://metadata/computeMetadata/v1/instance/service-accounts/default/identity?audience=[AUDIENCE]&format=[FORMAT]&licenses=[LICENSES]'

em que:

  • [AUDIENCE] é o URI exclusivo aceito pela instância e pelo sistema que verifica a identidade dela. Por exemplo, o público pode ser um URL da conexão entre os dois sistemas;
  • [FORMAT] é o parâmetro opcional que especifica se os detalhes do projeto e da instância estão incluídos ou não no payload. Especifique full para incluir essas informações no payload ou standard para omiti-las. O valor padrão é standard. Leia sobre o formato do token de identidade para saber todos os detalhes;
  • [LICENSES] é um parâmetro opcional que especifica se os códigos de licença para imagens associadas a essa instância são ou não incluídos no payload. Especifique TRUE para incluir essas informações ou FALSE para omiti-las do payload. O valor padrão é FALSE. Não tem efeito a menos que format seja full.

O servidor de metadados usa o algoritmo RS256 (em inglês) para responder a essa solicitação com um token da Web JSON assinado. Ele inclui uma assinatura do Google e informações adicionais no payload. É possível enviar esse token para outros sistemas e aplicativos para que eles possam verificá-lo e confirmar a identidade da instância.

Python

Você pode enviar uma solicitação simples da sua instância ao servidor de metadados usando os métodos na biblioteca Python requests. O exemplo a seguir solicita e imprime um token de identidade da instância. Ele é exclusivo para a instância que faz a solicitação.

import requests

AUDIENCE_URL = 'http://www.example.com'
METADATA_HEADERS = {'Metadata-Flavor': 'Google'}
FORMAT = 'full'
LICENSES = 'TRUE'

# Construct a URL with the audience and format.
url = 'http://metadata.google.internal/computeMetadata/v1/instance/service-accounts/default/identity?audience={}&format={}&licenses={}'
url = url.format(AUDIENCE_URL, FORMAT, LICENSES)

# Request a token from the metadata server.
r = requests.get(url, headers=METADATA_HEADERS)

# Extract the token from the response.
token = r.text

print(token)

O servidor de metadados usa o algoritmo RS256 para responder a essa solicitação com um JSON Web Token assinado. Ele inclui uma assinatura do Google e informações adicionais no payload. É possível enviar esse token para outros sistemas e aplicativos para que eles possam verificá-lo e confirmar a identidade da instância.

Como verificar o token

Depois que seu aplicativo receber um token de identidade de uma instância do Compute Engine, ele poderá verificá-lo usando o processo a seguir.

  1. Receba o token da instância de máquina virtual, faça a decodificação dele usando um decodificador RS256 JWT e leia o conteúdo do cabeçalho para conseguir o valor kid.

  2. Compare o token com o certificado público do Google para verificar se ele está assinado. Cada certificado público tem um valor kid que corresponde ao kid no cabeçalho do token.

  3. Se o token for válido, compare o conteúdo do payload com os valores esperados. Se o payload do token incluir detalhes sobre a instância e o projeto, o aplicativo poderá verificar os valores instance_id, project_id e zone. Eles são uma tupla globalmente exclusiva que confirma se o aplicativo se comunica com a instância correta no projeto esperado.

É possível decodificar e verificar o token usando a ferramenta que você quiser. No entanto, um método comum é usar as bibliotecas do seu idioma. Por exemplo, é possível usar o método verify_token da biblioteca Google OAuth 2.0 (em inglês) para Python. O verify_token combina o valor kid ao certificado apropriado, verifica a assinatura, confere a reivindicação de público e retorna o conteúdo do payload do token.

# Import libraries for token verification
import google.auth.transport.requests
from google.oauth2 import id_token

# Receive token from VM over an SSL connection
token = …
…

# Verify token signature and store the token payload
request = google.auth.transport.requests.Request()
payload = id_token.verify_token(token, request=request, audience=audience)
…

Depois de verificar o token e seu conteúdo, o aplicativo poderá se comunicar com essa instância em uma conexão segura e depois encerrar a conexão quando terminar. Para as conexões posteriores, solicite um novo token da instância e volte a verificar a identidade dela.

Conteúdo do token

O token de identidade da instância contém três partes principais:

O cabeçalho inclui o valor kid para identificar quais certificados OAuth2 públicos são necessários para verificar a assinatura. Ele também inclui o valor alg para confirmar que a assinatura foi gerada usando o algoritmo RS256 (em inglês).

{
  "alg": "RS256",
  "kid": "511a3e85d2452aee960ed557e2666a8c5cedd8ae",
}

Payload

O payload contém a reivindicação de público aud. Se a instância especificou format=full ao solicitar o token, o payload também inclui reivindicações sobre a instância de máquina virtual e o projeto dela. Ao solicitar um token de formato completo, a especificação de licenses=TRUE também incluirá reivindicações sobre as licenças associadas à instância.

{
   "iss": "[TOKEN_ISSUER]",
   "iat": [ISSUED_TIME],
   "exp": [EXPIRED_TIME],
   "aud": "[AUDIENCE]",
   "sub": "[SUBJECT]",
   "azp": "[AUTHORIZED_PARTY]",
   "google": {
    "compute_engine": {
      "project_id": "[PROJECT_ID]",
      "project_number": [PROJECT_NUMBER],
      "zone": "[ZONE]",
      "instance_id": [INSTANCE_ID],
      "instance_name": "[INSTANCE_NAME]",
      "instance_creation_timestamp": [CREATION_TIMESTAMP],
      "license_id": [
        "[LICENSE_1]",
          ...
        "[LICENSE_N]"
      ]
    }
  }
}

em que:

  • [TOKEN_ISSUER] é um URL que identifica o emissor do token. No Compute Engine, esse valor é https://accounts.google.com;
  • [ISSUED_TIME] é um carimbo de data/hora Unix que indica quando o token foi emitido. Esse valor é atualizado sempre que a instância solicita um token do servidor de metadados;
  • [EXPIRED_TIME] é um carimbo de data e hora Unix que indica quando o token expira;
  • [AUDIENCE] é o URI exclusivo aceito pela instância e pelo sistema que verifica a identidade dela. Por exemplo, o público pode ser um URL da conexão entre os dois sistemas;
  • [SUBJECT] é o assunto do token, que é o código exclusivo da conta de serviço associada à instância;
  • [AUTHORIZED_PARTY] é a parte à qual foi emitido o código do token, que é o código exclusivo da conta de serviço associada à instância;
  • [PROJECT_ID] é o código do projeto em que você criou a instância;
  • [PROJECT_NUMBER] é o número exclusivo do projeto em que a instância foi criada;
  • [ZONE] é a zona em que a instância está localizada;
  • [INSTANCE_ID] é o código exclusivo da instância a que esse token pertence. Esse código é único e não pode ser reutilizado;
  • [INSTANCE_NAME] é o nome da instância a que esse token pertence. Ele pode ser reutilizado por várias instâncias ao longo do tempo. Por isso, use o valor instance_id para identificar um código exclusivo da instância;
  • [CREATION_TIMESTAMP] é um carimbo de data/hora Unix que indica quando a instância foi criada;
  • [LICENSE_1] até [LICENSE_N] são os códigos de licença para imagens associadas a essa instância.

Veja o exemplo de payload a seguir:

{
  "iss": "https://accounts.google.com",
  "iat": 1496953245,
  "exp": 1496956845,
  "aud": "https://www.example.com",
  "sub": "107517467455664443765",
  "azp": "107517467455664443765",
  "google": {
    "compute_engine": {
      "project_id": "my-project",
      "project_number": 739419398126,
      "zone": "us-west1-a",
      "instance_id": "152986662232938449",
      "instance_name": "example",
      "instance_creation_timestamp": 1496952205,
      "license_id": [
        "1000204"
      ]
    }
  }
}

Assinatura

O Google gera a assinatura por Base64url, codificando o cabeçalho e o payload, além de concatenar os dois valores. É possível comparar esse valor com os certificados OAuth2 públicos para verificar o token.

A seguir

Esta página foi útil? Conte sua opinião sobre:

Enviar comentários sobre…

Documentação do Compute Engine