VM-Identität überprüfen


Bevor eine Anwendung sensible Informationen an eine VM-Instanz sendet, kann sie mit von Google signierten Instanz-Identitätstokens die Identität der Instanz prüfen. Jede Instanz hat ein eindeutiges JSON Web Token (JWT), das Details über die Instanz sowie die RSA256-Signatur von Google enthält. Die Anwendungen können die Signatur mit den öffentlichen OAuth2-Zertifikaten von Google abgleichen. Auf diese Weise wird die Identität der Instanz überprüft, zu der eine Verbindung hergestellt wurde.

Compute Engine generiert signierte Instanztokens nur, wenn eine Instanz diese von den Instanzmetadaten anfordert. Instanzen können jeweils nur auf ihre eigenen eindeutigen Tokens zugreifen und nicht auf Tokens anderer Instanzen.

In folgenden Fällen ist eventuell eine Überprüfung der Identität der Instanzen erforderlich:

  • Wenn Sie eine Instanz zum ersten Mal starten, muss für Anwendungen möglicherweise erst sichergestellt werden, dass die Instanz, zu der sie eine Verbindung herstellen, eine gültige Identität hat, bevor die Anwendungen sensible Informationen an die Instanz senden.
  • Wenn Ihre Richtlinien verlangen, dass Anmeldedaten außerhalb der Compute Engine-Umgebung gespeichert werden und Sie diese Anmeldedaten regelmäßig zur temporären Nutzung an Ihre Instanzen senden. Ihre Anwendungen können die Identität von Instanzen dann jedes Mal prüfen, wenn sie die Anmeldedaten senden müssen.

Die Methoden zur Authentifizierung von Instanzen von Google bieten folgende Vorteile:

  • Compute Engine erstellt jedes Mal ein eindeutiges Token, wenn eine Instanz es anfordert. Jedes Token läuft nach einer Stunde ab. Sie können Ihre Anwendungen so konfigurieren, dass sie Identitätstokens von Instanzen jeweils nur einmal akzeptieren. Damit verringert sich das Risiko, dass ein Token von einem nicht autorisierten System noch einmal verwendet wird.
  • Signierte Metadatentokens verwenden den offenen Branchenstandard RFC 7519 und die Identitätsschicht OpenID Connect 1.0, sodass vorhandene Tools und Bibliotheken mit den Identitätstokens kompatibel sind.

Hinweise

  • Erfahren Sie, wie Sie Werte von Instanzmetadaten abrufen.
  • Machen Sie sich mit den Grundlagen der JSON Web Tokens vertraut, um zu verstehen, wie Sie diese in Anwendungen nutzen können.
  • Erfahren Sie, wie Sie auf Ihren Instanzen Dienstkonten erstellen und aktivieren. Mit Ihren Instanzen muss ein Dienstkonto verknüpft sein, von dem sie Identitätstokens abrufen können. Das Dienstkonto erfordert keine IAM-Berechtigungen für den Abruf dieser Identitätstokens.
  • Richten Sie die Authentifizierung ein, falls Sie dies noch nicht getan haben. Bei der Authentifizierung wird Ihre Identität für den Zugriff auf Google Cloud-Dienste und APIs überprüft. Zur Ausführung von Code oder Beispielen aus einer lokalen Entwicklungsumgebung können Sie sich bei Compute Engine authentifizieren. Wählen Sie dazu eine der folgenden Optionen aus:

    Wenn Sie die Python Beispiele auf dieser Seite in einer lokalen Entwicklungsumgebung verwenden möchten, installieren und initialisieren Sie die gcloud CLI und richten dann die Standardanmeldedaten für Anwendungen mit Ihren Nutzeranmeldedaten ein.

    1. Install the Google Cloud CLI.
    2. To initialize the gcloud CLI, run the following command:

      gcloud init
    3. If you're using a local shell, then create local authentication credentials for your user account:

      gcloud auth application-default login

      You don't need to do this if you're using Cloud Shell.

    Weitere Informationen unter Set up authentication for a local development environment.

Identität einer Instanz prüfen

In einigen Szenarien müssen Anwendungen die Identität einer Instanz prüfen, bevor sie vertrauliche Daten an diese Instanz übertragen. Ein typisches Beispiel hierfür ist ein System namens "Host1", das außerhalb von Compute Engine ausgeführt wird, und eine Compute Engine-Instanz namens "VM1". VM1 kann eine Verbindung zu Host1 herstellen und mit dem folgenden Vorgang die Identität dieser Instanz überprüfen:

  1. VM1 stellt über ein sicheres Verbindungsprotokoll Ihrer Wahl wie z. B. HTTPS eine sichere Verbindung zu Host1 her.

  2. VM1 ruft ein eindeutiges Identitätstoken vom Metadatenserver ab und legt die Zielgruppe des Tokens fest. In diesem Beispiel ist der Zielgruppenwert der URI für Host1. Die Anfrage an den Metadatenserver enthält den Zielgruppen-URI, damit Host1 den Wert später im Schritt zur Bestätigung des Tokens überprüfen kann.

  3. Google generiert ein neues, eindeutiges Instanzidentitätstoken im JWT-Format und stellt es für VM1 bereit. Die Nutzlast des Tokens umfasst verschiedene Details der Instanz und enthält außerdem den Zielgruppen-URI. Eine vollständige Beschreibung der Inhalte von Tokens finden Sie unter Tokeninhalte.

  4. VM1 sendet das Identitätstoken über die bestehende sichere Verbindung an Host1.

  5. Host1 decodiert das Identitätstoken, um den Header und die Nutzlastwerte des Tokens abzurufen.

  6. Host1 überprüft, ob das Token von Google signiert ist. Hierzu wird der Zielgruppenwert geprüft und die Zertifikatssignatur mit dem öffentlichen Google-Zertifikat verglichen.

  7. Bei einem gültigen Token startet Host1 die Datenübertragung und trennt die Verbindung, wenn die Übertragung beendet ist. Für jede nachfolgende Herstellung einer Verbindung zu VM1 müssen Host1 und alle anderen Systeme ein neues Token anfordern.

Identitätstoken der Instanz abrufen

Wenn Ihre VM-Instanz eine Anfrage erhält, ihr Identitätstoken zu senden, fordert sie dieses Token nach dem Standardverfahren zum Abruf von Instanzmetadaten beim Metadatenserver an. Beispielsweise können Sie eine der folgenden Methoden verwenden:

cURL

Erstellen Sie eine curl-Anfrage und geben Sie für den Parameter audience einen Wert an. Optional können Sie den Parameter format einfügen, um anzugeben, ob Projekt- und Instanzdetails in die Nutzlast eingefügt werden sollen. Wenn Sie das Format full verwenden, können Sie den Parameter licenses einfügen, um anzugeben, ob Sie Lizenzcodes in die Nutzlast aufnehmen möchten.

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

Dabei gilt:

  • AUDIENCE: der eindeutige URI, der von der Instanz und vom System zur Prüfung der Identität der Instanz definiert wurde. Die Zielgruppe kann zum Beispiel eine URL für die Verbindung zwischen den beiden Systemen sein.
  • FORMAT: der optionale Parameter, der festlegt, ob in die Nutzlast Projekt- und Instanzinformationen aufgenommen werden. Geben Sie full an, um diese Informationen in die Nutzlast aufzunehmen, oder standard, um die Informationen aus der Nutzlast wegzulassen. Der Standardwert ist standard. Weitere Informationen finden Sie unter Format von Identitätstokens.
  • LICENSES: ein optionaler Parameter, der angibt, ob Lizenzcodes für die mit dieser Instanz verbundenen Images in die Nutzlast eingeschlossen werden. Geben Sie TRUE an, um diese Informationen einzuschließen, oder FALSE, um diese Informationen aus der Nutzlast auszuschließen. Der Standardwert ist FALSE. Hat keine Auswirkungen, es sei denn, format ist full

Der Metadatenserver antwortet auf die Anfrage mit einem JSON Web Token, das nach dem Algorithmus RS256 signiert wird. Die Nutzlast des Tokens enthält eine Google-Signatur und Zusatzinformationen. Sie können dieses Token an andere Systeme und Anwendungen senden, damit diese das Token prüfen und die Identität Ihrer Instanz bestätigen.

Python

Sie können mithilfe von Methoden in der requests-Bibliothek von Python eine einfache Anfrage von Ihrer Instanz an den Metadatenserver senden. Im nachstehenden Beispiel wird ein Instanz-Identitätstoken angefordert und anschließend gedruckt. Das Token ist eindeutig für die Instanz, von der die Anfrage gesendet wird.

import requests

AUDIENCE_URL = "http://www.example.com"
METADATA_HEADERS = {"Metadata-Flavor": "Google"}
METADATA_VM_IDENTITY_URL = (
    "http://metadata.google.internal/computeMetadata/v1/"
    "instance/service-accounts/default/identity?"
    "audience={audience}&format={format}&licenses={licenses}"
)
FORMAT = "full"
LICENSES = "TRUE"


def acquire_token(
    audience: str = AUDIENCE_URL, format: str = "standard", licenses: bool = True
) -> str:
    """
    Requests identity information from the metadata server.

    Args:
        audience: the unique URI agreed upon by both the instance and the
            system verifying the instance's identity. For example, the audience
            could be a URL for the connection between the two systems.
        format: the optional parameter that specifies whether the project and
            instance details are included in the payload. Specify `full` to
            include this information in the payload or standard to omit the
            information from the payload. The default value is `standard`.
        licenses: an optional parameter that specifies whether license
            codes for images associated with this instance are included in the
            payload. Specify TRUE to include this information or FALSE to omit
            this information from the payload. The default value is FALSE.
            Has no effect unless format is `full`.

    Returns:
        A JSON Web Token signed using the RS256 algorithm. The token includes a
        Google signature and additional information in the payload. You can send
        this token to other systems and applications so that they can verify the
        token and confirm that the identity of your instance.
    """
    # Construct a URL with the audience and format.
    url = METADATA_VM_IDENTITY_URL.format(
        audience=audience, format=format, licenses=licenses
    )

    # Request a token from the metadata server.
    r = requests.get(url, headers=METADATA_HEADERS)
    # Extract and return the token from the response.
    r.raise_for_status()
    return r.text

Der Metadatenserver antwortet auf die Anfrage mit einem JSON Web Token, das nach dem Algorithmus RS256 signiert wird. Die Nutzlast des Tokens enthält eine Google-Signatur und Zusatzinformationen. Sie können dieses Token an andere Systeme und Anwendungen senden, damit diese das Token verifizieren und die Identität Ihrer Instanz bestätigen.

Token verifizieren

Nachdem Ihre Anwendung ein Instanz-Identitätstoken von einer Compute Engine-Instanz empfangen hat, kann sie dieses Token folgendermaßen prüfen:

  1. Sie empfängt das Token von einer VM-Instanz, decodiert es mithilfe eines RS256-JWT-Decodierers und liest den Wert kid aus dem Header.

  2. Sie prüft durch Vergleich mit dem öffentlichen Google Zertifikat, ob das Token signiert ist. Jedes öffentliche Zertifikat hat einen kid-Wert, der dem kid-Wert im Token-Header entspricht.

  3. Ist das Token gültig, prüft die Anwendung den Inhalt der Nutzlast auf die erwarteten Werte. Enthält die Nutzlast des Tokens Informationen über die Instanz und das Projekt, kann die Anwendung die Werte für instance_id, project_id und zone prüfen. Diese Werte sind global eindeutige Tupel, die prüfen, ob die Anwendung mit der korrekten Instanz im gewünschten Projekt kommuniziert.

Sie können das Token mit jedem beliebigen Tool decodieren und prüfen. Die gängigste Methode ist die Verwendung der Bibliotheken der von Ihnen gewählten Sprache. Sie können beispielsweise für Python die Methode verify_token der Google-OAuth 2.0-Bibliothek verwenden. Die Methode verify_token vergleicht den Wert kid mit dem geeigneten Zertifikat, überprüft die Signatur, prüft die Zielgruppenanforderung und gibt die Nutzlastinhalte des Tokens zurück.

import google.auth.transport.requests
from google.oauth2 import id_token



def verify_token(token: str, audience: str) -> dict:
    """
    Verify token signature and return the token payload.

    Args:
        token: the JSON Web Token received from the metadata server to
            be verified.
        audience: the unique URI agreed upon by both the instance and the
            system verifying the instance's identity.

    Returns:
        Dictionary containing the token payload.
    """
    request = google.auth.transport.requests.Request()
    payload = id_token.verify_token(token, request=request, audience=audience)
    return payload

Nachdem die Anwendung das Token und dessen Inhalte geprüft hat, kann sie mit der jeweiligen Instanz über eine sichere Verbindung kommunizieren und nach Abschluss des Vorgangs die Verbindung trennen. Für nachfolgende Verbindungen wird von der Instanz ein neues Token angefordert und deren Identität noch einmal überprüft.

Tokeninhalte

Das Instanz-Identitätstoken hat drei Hauptbestandteile:

Der Header enthält den Wert kid, der festlegt, mit welchen öffentlichen OAuth2-Zertifikaten Sie die Signatur überprüfen müssen. Außerdem enthält der Header den Wert alg, um anzugeben, dass die Signatur mit dem Algorithmus RS256 generiert wurde.

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

Nutzlast

Die Nutzlast enthält die Zielgruppenanforderung aud. Wenn von der Instanz bei der Anforderung des Tokens format=full angegeben wurde, enthält die Nutzlast Informationsanforderungen über die VM-Instanz und deren Projekt. Wenn Sie ein Token im vollständigen Format anfordern, werden durch Angabe von licenses=TRUE auch Anforderungen in Bezug auf die mit der Instanz verknüpften Lizenzen eingeschlossen.

{
   "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],
      "instance_confidentiality": [INSTANCE_CONFIDENTIALITY],
      "license_id": [
        "[LICENSE_1]",
          ...
        "[LICENSE_N]"
      ]
    }
  }
}

Dabei gilt:

  • [TOKEN_ISSUER]: eine URL, die den Aussteller des Tokens identifiziert. Für Compute Engine ist dies https://accounts.google.com.
  • [ISSUED_TIME]: ein UNIX-Zeitstempel, der angibt, wann das Token ausgestellt wurde. Dieser Wert wird jedes Mal aktualisiert, wenn die Instanz ein Token vom Metadatenserver anfordert.
  • [EXPIRED_TIME]: ein UNIX-Zeitstempel, der angibt, wann die Gültigkeit des Tokens abläuft.
  • [AUDIENCE]: der eindeutige URI, der von der Instanz und vom System zur Prüfung der Identität der Instanz definiert wurde. Die Zielgruppe kann zum Beispiel eine URL für die Verbindung zwischen den beiden Systemen sein.
  • [SUBJECT]: der Betreff des Tokens, d. h. die eindeutige ID des Dienstkontos, das Sie mit Ihrer Instanz verknüpft haben.
  • [AUTHORIZED_PARTY]: die Partei, für die das ID-Token ausgestellt wurde, d. h., die eindeutige ID des Dienstkontos, das Sie mit Ihrer Instanz verknüpft haben.
  • [PROJECT_ID]: die ID des Projekts, in dem Sie die Instanz erstellt haben.
  • [PROJECT_NUMBER]: die eindeutige Nummer des Projekts, in dem Sie die Instanz erstellt haben.
  • [ZONE]: die Zone, in der sich die Instanz befindet.
  • [INSTANCE_ID]: die eindeutige ID der Instanz, zu der dieses Token gehört. Diese ID ist innerhalb des Projekts und der Zone eindeutig.
  • [INSTANCE_NAME]: der Name der Instanz, zu der dieses Token gehört. Wenn Ihr Projekt zonales DNS verwendet, kann dieser Name zonenübergreifend wiederverwendet werden. Verwenden Sie daher eine Kombination aus project_id, zone und instance_id, um eine eindeutige Instanz-ID zu identifizieren. Projekte mit aktiviertem globalen DNS haben im gesamten Projekt einen eindeutigen Instanznamen.
  • [CREATION_TIMESTAMP]: ein UNIX-Zeitstempel, der angibt, wann die Instanz erstellt wurde.
  • [INSTANCE_CONFIDENTIALITY]: 1, wenn die Instanz eine vertrauliche VM ist.
  • [LICENSE_1] bis [LICENSE_N]: die Lizenzcodes für Images, die mit dieser Instanz verbunden sind.

Die Nutzlast sieht in etwa wie im folgenden Beispiel aus:

{
  "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,
      "instance_confidentiality": 1,
      "license_id": [
        "1000204"
      ]
    }
  }
}

Signatur

Google generiert die Signatur mit Base64Url, durch Codierung des Headers und der Nutzlast sowie Verkettung der beiden Werte. Sie können diese Werte mit den öffentlichen OAuth2-Zertifikaten vergleichen, um das Token zu prüfen.

Nächste Schritte