Verifica la identidad de las instancias

Antes de que una aplicación envíe información sensible a una instancia de máquina virtual, la aplicación puede verificar la identidad de la máquina virtual mediante tokens de identidad de instancia que firma Google. Cada instancia tiene un JSON Web Token (JWT) único que incluye detalles sobre la instancia y la firma RS256 de Google. Tus aplicaciones pueden verificar la firma con los certificados públicos de Oauth2 de Google para confirmar la identidad de la instancia con la que establecieron una conexión.

Compute Engine genera tokens de instancia firmados solo cuando una instancia los solicita a los metadatos de la instancia. Las instancias solo pueden acceder a su propio token único y no a los tokens para ninguna otra instancia.

Es posible que desees verificar las identidades de tus instancias en las siguientes situaciones:

  • Cuando inicias una instancia por primera vez, es posible que tus aplicaciones necesiten asegurarse de que la instancia a la que se conectaron tenga una identidad válida antes de transmitir información sensible a la instancia.
  • Cuando tus políticas requieren que almacenes credenciales fuera del entorno de Compute Engine y envías esas credenciales regularmente a tus instancias para uso temporal. Tus aplicaciones pueden confirmar las identidades de las instancias cada vez que necesitan transmitir credenciales.

Los métodos de autenticación de instancias de Google tienen los siguientes beneficios:

  • Compute Engine crea un token único cada vez que una instancia lo solicita, y cada token vence en una hora. Puedes configurar tus aplicaciones para que acepten el token de identidad de una instancia solo una vez, lo que reduce el riesgo de que el token pueda ser reutilizado por un sistema no autorizado.
  • Las claves privadas de Google y los certificados públicos de Oauth2 rotan diariamente para reducir la superficie de posibles ataques contra estas firmas.
  • Los tokens de metadatos firmados utilizan el estándar abierto de la industria RFC 7519 y la capa de identidad OpenID Connect 1.0, por lo que las herramientas y bibliotecas existentes funcionarán a la perfección con los tokens de identidad.

Antes de comenzar

Verifica la identidad de una instancia

En algunas situaciones, tus aplicaciones deben verificar la identidad de una instancia que se ejecuta en Compute Engine antes de transmitir datos sensibles a esa instancia. En un ejemplo común, hay un sistema que se ejecuta fuera de Compute Engine denominado “Host1” y una instancia de Compute Engine denominada “VM1”. VM1 puede conectarse a Host1 y validar la identidad de esa instancia con el siguiente proceso:

  1. VM1 establece una conexión segura con Host1 a través de un protocolo de conexión segura de tu elección, como HTTPS.

  2. VM1 solicita el token único de identidad al servidor de metadatos y especifica el público del token. En este ejemplo, el valor del público es el URI para Host1. La solicitud al servidor de metadatos incluye el URI del público para que Host1 pueda verificar el valor más adelante durante el paso de verificación del token.

  3. Google genera un nuevo token único de identidad de instancia en formato JWT y se lo proporciona a VM1. La carga útil del token incluye varios detalles sobre la instancia y también incluye el URI del público. Consulta el contenido del token para obtener una descripción completa de ese contenido.

  4. VM1 envía el token de identidad a Host1 a través de la conexión segura existente.

  5. Host1 decodifica el token de identidad para obtener el encabezado del token y los valores de carga útil.

  6. Host1 verifica que Google haya firmado el token mediante la revisión del valor de la audiencia y la verificación de la firma del certificado con el certificado público de Google.

  7. Si el token es válido, Host1 continúa con la transmisión y finaliza la conexión cuando haya terminado. Host1 y cualquier otro sistema deben solicitar un token nuevo para cualquier conexión posterior a VM1.

Obtén el token de identidad de instancia

Cuando tu instancia de máquina virtual recibe una solicitud para proporcionar su token de identidad, la instancia solicita ese token al servidor de metadatos mediante el proceso normal para obtener metadatos de instancia. Por ejemplo, puedes usar uno de los siguientes métodos:

cURL

Crea una solicitud curl que incluya un valor en el parámetro audience. De manera opcional, puedes incluir el parámetro format para especificar si deseas incluir detalles del proyecto y la instancia en la carga útil. Si usas el formato full, puedes incluir el parámetro licenses para especificar si deseas incluir códigos de licencia en la carga útil.

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

Donde:

  • [AUDIENCE] es el URI único acordado tanto por la instancia como por el sistema que verifica la identidad de la instancia. Por ejemplo, el público podría ser una URL para la conexión entre los dos sistemas.
  • [FORMAT] es el parámetro opcional que especifica si los detalles del proyecto y la instancia se incluyen en la carga útil. Especifica full con el fin de incluir esta información en la carga útil o standard para omitirla. El valor predeterminado es standard. Consulta el formato de token de identidad para conocer los detalles completos del formato de token.
  • [LICENSES] es un parámetro opcional que especifica si los códigos de licencia de las imágenes asociadas con esta instancia se incluyen en la carga útil. Especifica TRUE con el fin de incluir esta información en la carga útil o FALSE para omitirla. El valor predeterminado es FALSE. No tiene efecto, a menos que el valor de format sea full.

El servidor de metadatos responde a esta solicitud con un JSON Web Token firmado con el algoritmo RS256. El token incluye una firma de Google y, también, información adicional en la carga útil. Puedes enviar este token a otros sistemas y aplicaciones para que puedan verificar el token y confirmar la identidad de tu instancia.

Python

Puedes enviar una solicitud simple desde tu instancia al servidor de metadatos mediante los métodos en la biblioteca requests de Python. El siguiente ejemplo solicita y, luego, imprime un token de identidad de instancia. El token es exclusivo de la instancia que realiza esta solicitud.

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)

El servidor de metadatos responde a esta solicitud con un JSON Web Token firmado con el algoritmo RS256. El token incluye una firma de Google y, también, información adicional en la carga útil. Puedes enviar este token a otros sistemas y aplicaciones para que puedan verificar el token y confirmar la identidad de tu instancia.

Verifica el token

Una vez que tu aplicación reciba un token de identidad de instancia de una instancia de Compute Engine, puedes verificar el token mediante el siguiente proceso:

  1. Recibe el token de la instancia de la máquina virtual, decodifica el token con un decodificador RS256 JWT y lee el contenido del encabezado para obtener el valor kid.

  2. Verifica que el token esté firmado mediante la comparación del token con el certificado público de Google. Cada certificado público tiene un valor kid que corresponde al valor kid en el encabezado del token.

  3. Si el token es válido, compara el contenido de la carga útil con los valores esperados. Si la carga útil del token incluye detalles sobre la instancia y el proyecto, tu aplicación puede verificar los valores de instance_id, project_id y zone. Esos valores son una tupla global única que confirma que tu aplicación se está comunicando con la instancia correcta en el proyecto deseado.

Puedes decodificar y verificar el token con cualquier herramienta que desees, pero un método común es utilizar las bibliotecas para el lenguaje que elijas. Por ejemplo, puedes usar el método verify_token de la biblioteca Google OAuth 2.0 para Python. El método verify_token hace que el valor kid coincida con el certificado correspondiente, verifica la firma, comprueba la reclamación del público y muestra el contenido de la carga útil del 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)
…

Después de que tu aplicación verifica el token y su contenido, puede comunicarse con esa instancia a través de una conexión segura y, luego, finalizar la conexión cuando haya terminado. Para conexiones posteriores, solicita un nuevo token a la instancia y vuelve a verificar su identidad.

Contenido del token

El token de identidad de instancia contiene tres partes principales:

El encabezado incluye el valor kid para identificar qué certificados públicos de OAuth2 debes utilizar con el fin de verificar la firma. También incluye el valor alg para confirmar que la firma se genera con el algoritmo RS256.

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

Carga útil

La carga útil contiene la reclamación del público de aud. Si la instancia especificó format=full cuando solicitó el token, la carga útil también incluye reclamaciones sobre la instancia de máquina virtual y su proyecto. Si se solicita un token de formato completo, la especificación de licenses=TRUE también incluirá reclamaciones sobre las licencias asociadas con la instancia.

{
   "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]"
      ]
    }
  }
}

Donde:

  • [TOKEN_ISSUER] es una URL que identifica quién emitió el token. Para Compute Engine, este valor es https://accounts.google.com.
  • [ISSUED_TIME] es una marca de tiempo de UNIX que indica cuándo se emitió el token. Este valor se actualiza cada vez que la instancia solicita un token al servidor de metadatos.
  • [EXPIRED_TIME] es una marca de tiempo de UNIX que indica cuándo vence el token.
  • [AUDIENCE] es el URI único acordado tanto por la instancia como por el sistema que verifica la identidad de la instancia. Por ejemplo, el público podría ser una URL para la conexión entre los dos sistemas.
  • [SUBJECT] es el asunto del token, que es el ID único de la cuenta de servicio que asociaste con tu instancia.
  • [AUTHORIZED_PARTY] es la parte a la que se emitió el token de ID, que es el ID único para la cuenta de servicio que asociaste con tu instancia.
  • [PROJECT_ID] es el ID del proyecto donde creaste la instancia.
  • [PROJECT_NUMBER] es el número único del proyecto en el que creaste la instancia.
  • [ZONE] es la zona donde se encuentra la instancia.
  • [INSTANCE_ID] es el ID único para la instancia a la que pertenece este token. Este ID es único y nunca se reutiliza.
  • [INSTANCE_NAME] es el nombre de la instancia a la que pertenece este token. Varias instancias pueden reutilizar este nombre a lo largo del tiempo, por lo tanto, usa el valor instance_id para identificar un ID de instancia único.
  • [CREATION_TIMESTAMP] es una marca de tiempo de UNIX que indica cuándo creaste la instancia.
  • [LICENSE_1] a [LICENSE_N] son los códigos de licencia para las imágenes asociadas con esta instancia.

Tu carga útil puede ser similar al siguiente ejemplo:

{
  "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"
      ]
    }
  }
}

Firma

Google genera la firma mediante base64url, lo que codifica el encabezado y la carga útil, y concatena los dos valores. Puedes verificar este valor con los certificados públicos de Oauth2 para comprobar el token.

Pasos siguientes

¿Te ha resultado útil esta página? Enviar comentarios:

Enviar comentarios sobre...

Documentación de Compute Engine