Vérifier l’identité des instances

Avant d'envoyer des informations sensibles à une instance de machine virtuelle, l'application peut vérifier l'identité de la machine virtuelle à l'aide de jetons d'identité d'instance signés par Google. Chaque instance possède un jeton Web JSON (JWT) unique qui contient des informations sur l'instance ainsi que la signature RS256 de Google. Vos applications peuvent vérifier la signature par rapport aux certificats publics Oauth2 de Google pour confirmer l'identité de l'instance avec laquelle elles ont établi une connexion.

Compute Engine génère des jetons d'instance signés uniquement lorsqu'une instance les demande à partir de métadonnées d'instance. Les instances peuvent accéder à leur propre jeton unique, mais pas aux jetons des autres instances.

Il sera probablement nécessaire de vérifier l'identité de vos instances dans les cas suivants :

  • Lorsque vous démarrez une instance pour la première fois, vos applications peuvent avoir besoin de s'assurer que l'instance à laquelle elles se sont connectées possède une identité valide avant de lui transmettre des informations sensibles.
  • Lorsque vos règles vous obligent à stocker des informations d'identifiants à l'extérieur de l'environnement Compute Engine et que vous envoyez régulièrement ces identifiants à vos instances pour un usage provisoire, vos applications peuvent vérifier l'identité des instances à chaque fois qu'elles doivent transmettre des identifiants.

Les méthodes d'authentification des instances de Google présentent les avantages suivants :

  • Compute Engine crée un jeton unique à chaque fois qu'une instance le demande et chaque jeton expire dans l'heure qui suit. Vous pouvez configurer vos applications pour qu'elles n'acceptent qu'une seule fois le jeton d'identité d'une instance, ce qui réduit le risque de réutilisation du jeton par un système non autorisé.
  • Les clés privées de Google et les certificats publics Oauth2 changent tous les jours pour réduire la surface d'attaque potentielle contre ces signatures.
  • Les jetons de métadonnées signés utilisent le standard ouvert de l'industrie RFC 7519 et la couche d'identité OpenID Connect 1.0, de sorte que les outils et les bibliothèques existants fonctionnent de manière transparente avec les jetons d'identité.

Avant de commencer

Vérifier l'identité d'une instance

Dans certains cas, vos applications doivent vérifier l'identité d'une instance exécutée sur Compute Engine avant de transmettre des données sensibles à cette instance. Voici un exemple typique avec un système exécuté à l'extérieur de Compute Engine appelé "Host1" et une instance de Compute Engine appelée "VM1". VM1 peut se connecter à Host1 et valider l'identité de cette instance en procédant comme suit :

  1. VM1 établit une connexion sécurisée avec Host1 via le protocole de connexion sécurisée de votre choix, tel que HTTPS.

  2. VM1 demande son jeton d'identité unique au serveur de métadonnées et spécifie l'audience du jeton. Dans cet exemple, la valeur de l'audience est l'URI de Host1. La demande adressée au serveur de métadonnées inclut l'URI d'audience afin que Host1 puisse vérifier la valeur lors de l'étape de vérification du jeton.

  3. Google génère un nouveau jeton d'identité d'instance unique au format JWT et le fournit à VM1. La charge utile du jeton contient plusieurs informations sur l'instance et inclut également l'URI d'audience. Consultez la section Contenu du jeton pour une description complète du contenu du jeton.

  4. VM1 envoie le jeton d'identité à Host1 via la connexion sécurisée existante.

  5. Host1 décode le jeton d'identité pour obtenir l'en-tête du jeton et les valeurs de la charge utile.

  6. Host1 s'assure que le jeton est signé par Google en vérifiant la valeur d'audience et la signature du certificat par rapport au certificat Google public.

  7. Si le jeton est valide, Host1 procède à la transmission et ferme la connexion lorsque celle-ci est terminée. Host1 et tous les autres systèmes doivent demander un nouveau jeton pour toute connexion ultérieure à VM1.

Obtenir le jeton d'identité de l'instance

Lorsque votre instance de machine virtuelle reçoit une demande de transmission de son jeton d'identité, l'instance demande ce jeton au serveur de métadonnées en utilisant le processus normal d'obtention des métadonnées d'instance. Vous pouvez, par exemple, utiliser l'une des méthodes suivantes :

cURL

Créez une demande curl et incluez une valeur dans le paramètre audience. Vous pouvez éventuellement inclure le paramètre format pour spécifier si vous souhaitez ou non inclure les détails du projet et de l'instance dans la charge utile. Si vous utilisez le format full, vous pouvez inclure le paramètre licenses pour indiquer si vous souhaitez ou non inclure les codes de licence dans la charge utile.

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

où :

  • [AUDIENCE] correspond à l'URI unique convenu entre l'instance et le système pour vérifier l'identité de l'instance. Par exemple, l'audience pourrait être une URL permettant la connexion entre les deux systèmes.
  • [FORMAT] correspond au paramètre facultatif qui spécifie si les informations du projet et de l'instance sont incluses ou non dans la charge utile. Spécifiez full pour inclure ces informations dans la charge utile ou standard pour omettre les informations de la charge utile. La valeur par défaut est standard. Pour tout savoir sur le format des jetons, consultez la section Format des jetons d'identité.
  • [LICENSES] correspond au paramètre facultatif qui spécifie si les codes de licence pour les images associées à cette instance sont inclus ou non dans la charge utile. Spécifiez TRUE pour inclure ces informations ou FALSE pour omettre les informations de la charge utile. La valeur par défaut est FALSE. Ne fonctionne que si le format est full.

Le serveur de métadonnées répond à cette demande avec un jeton Web JSON signé à l'aide de l'algorithme RS256. Le jeton comprend une signature Google et des informations supplémentaires dans la charge utile. Vous pouvez envoyer ce jeton à d'autres systèmes et applications afin qu'ils puissent vérifier le jeton et l'identité de votre instance.

Python

Vous pouvez soumettre une demande simple de votre instance au serveur de métadonnées en utilisant les méthodes de la bibliothèque requests de Python. Dans l'exemple suivant, le jeton d'identité de l'instance est demandé, puis imprimé. Le jeton est unique à l'instance qui effectue cette demande.

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)

Le serveur de métadonnées répond à cette demande avec un jeton Web JSON signé à l'aide de l'algorithme RS256. Le jeton comprend une signature Google et des informations supplémentaires dans la charge utile. Vous pouvez envoyer ce jeton à d'autres systèmes et applications afin qu'ils puissent vérifier le jeton et l'identité de votre instance.

Vérifier le jeton

Après avoir reçu un jeton d'identité d'instance à partir d'une instance de Compute Engine, votre application peut vérifier le jeton en procédant comme suit.

  1. Recevoir le jeton de l'instance de la machine virtuelle, décoder le jeton à l'aide d'un décodeur JWT RS256 et lire le contenu de l'en-tête pour obtenir la valeur kid.

  2. Vérifier que le jeton est signé en vérifiant le jeton par rapport au certificat Google public. Chaque certificat public a une valeur kid qui correspond à la valeur kid de l'en-tête du jeton.

  3. Si le jeton est valide, comparer le contenu de la charge utile aux valeurs attendues. Si la charge utile du jeton inclut des informations sur l'instance et le projet, votre application peut vérifier les valeurs instance_id, project_id et zone. Ces valeurs sont un tuple unique qui confirme que votre application communique avec la bonne instance dans le projet souhaité.

Vous pouvez décoder et vérifier le jeton à l'aide de n'importe quel outil, mais la méthode la plus courante consiste à utiliser les bibliothèques de la langue de votre choix. Par exemple, vous pouvez utiliser la méthode verify_token de la bibliothèque Google OAuth 2.0 pour Python. La méthode verify_token associe la valeur kid au certificat approprié, vérifie la signature, vérifie la déclaration de l'audience et renvoie le contenu de la charge utile à partir du jeton.

# 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)
…

Après avoir vérifié le jeton et son contenu, votre application peut continuer à communiquer avec cette instance via une connexion sécurisée, puis fermer la connexion une fois l'opération terminée. Pour établir des connexions plus tard, demandez un nouveau jeton à partir de l'instance et vérifiez à nouveau l'identité de l'instance.

Contenu du jeton

Le jeton d'identité de l'instance se compose de trois parties principales :

L'en-tête inclut la valeur kid pour identifier les certificats Oauth2 publics que vous devez utiliser pour vérifier la signature. L'en-tête comprend également la valeur alg pour confirmer que la signature est générée à l'aide de l'algorithme RS256.

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

Charge utile

La charge utile contient la déclaration d'audience aud. Si l'instance spécifie format=full lors de la demande de jeton, la charge utile inclut également des déclarations au sujet de l'instance de la machine virtuelle et de son projet. Lorsque vous demandez un jeton de format complet, le fait de spécifier licenses=TRUE inclut également les revendications relatives aux licences associées à l'instance.

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

où :

  • [TOKEN_ISSUER] correspond à une URL identifiant l'émetteur du jeton. Pour Compute Engine, cette valeur est https://accounts.google.com ;
  • [ISSUED_TIME] est un horodatage unix indiquant le moment d'émission du jeton. Cette valeur est mise à jour à chaque fois que l'instance demande un jeton au serveur de métadonnées ;
  • [EXPIRED_TIME] est un horodatage unix indiquant la date d'expiration du jeton ;
  • [AUDIENCE] correspond à l'URI unique convenu entre l'instance et le système pour vérifier l'identité de l'instance. Par exemple, l'audience pourrait être une URL permettant la connexion entre les deux systèmes.
  • [SUBJECT] correspond à l'objet du jeton, qui est l'ID unique du compte de service que vous avez associé à votre instance ;
  • [AUTHORIZED_PARTY] correspond à la partie à laquelle le jeton d'ID a été émis. Il s'agit de l'ID unique du compte de service que vous avez associé à votre instance ;
  • [PROJECT_ID] correspond à l'ID du projet dans lequel vous avez créé l'instance ;
  • [PROJECT_NUMBER] correspond au numéro unique du projet dans lequel vous avez créé l'instance ;
  • [ZONE] est la zone où se trouve l'instance.
  • [INSTANCE_ID] correspond à l'ID unique de l'instance à laquelle appartient ce jeton. Cet ID est unique et jamais réutilisé ;
  • [INSTANCE_NAME] correspond au nom de l'instance à laquelle appartient ce jeton. Ce nom peut être réutilisé par plusieurs instances dans le temps. Utilisez donc la valeur instance_id pour identifier un ID d'instance unique ;
  • [CREATION_TIMESTAMP] est un horodatage unix indiquant le moment de création de l'instance.
  • [LICENSE_1] à [LICENSE_N] sont les codes de licence des images associées à cette instance.

Votre charge utile peut prendre la forme de l'exemple suivant :

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

Signature

Google génère la signature en encodant en base64url l'en-tête et la charge utile et en combinant les deux valeurs. Vous pouvez comparer cette valeur aux certificats Oauth2 publics pour vérifier le jeton.

Étape suivante

Cette page vous a-t-elle été utile ? Évaluez-la :

Envoyer des commentaires concernant…

Documentation Compute Engine