Neben der Authentifizierung von Nutzern müssen Sie möglicherweise anderen Diensten gestatten, mit Ihrer API zu interagieren. Für die sichere Kommunikation zwischen Diensten benötigen Sie einen anderen Ansatz als für Clientanwendungen, die Nutzern eine webbasierte Anmeldeaufforderung zum Senden ihrer Anmeldedaten bereitstellen können. Auf dieser Seite wird die Methode gezeigt, die wir zum Implementieren der zwischendienstlichen Authentifizierung empfehlen, begleitet von Beispielcode.
Übersicht
Zur Identifizierung eines Dienstes, der Anfragen an die API sendet, wird ein Dienstkonto verwendet. Mit dem privaten Schlüssel des Dienstkontos signiert der aufrufende Dienst ein sicheres JSON Web Token (JWT) und sendet es in der Anfrage an die API.
So implementieren Sie die Authentifizierung zwischen Diensten in der API und im aufrufenden Dienst:
- Erstellen Sie ein Dienstkonto und einen Schlüssel für den aufrufenden Dienst.
- Konfigurieren Sie die Authentifizierung im OpenAPI-Dokument für Ihren Cloud Endpoints-Dienst.
Ergänzen Sie den Code des aufrufenden Dienstes so, dass:
- ein JWT erstellt und mit dem privaten Schlüssel des Dienstkontos signiert wird und
- das signierte JWT in einer Anfrage an die API gesendet wird.
Der ESP überprüft, ob die Anforderungen im JWT mit der Konfiguration im OpenAPI-Dokument übereinstimmen, bevor er die Anfrage an die API weiterleitet. Der ESP prüft nicht die Cloud Identity-Berechtigungen, die Sie für das Dienstkonto gewährt haben.
Vorbereitung
Folgende Voraussetzungen sollten erfüllt sein:
Dienstkonto mit einem Schlüssel erstellen
Sie benötigen ein Dienstkonto mit einer privaten Schlüsseldatei, die der aufrufende Dienst zum Signieren des JWT verwendet. Wenn mehrere Dienste Anfragen an Ihre API senden, können Sie ein einziges Dienstkonto für alle aufrufenden Dienste erstellen. Falls Sie zwischen den Diensten unterscheiden müssen, weil diese beispielsweise unterschiedliche Berechtigungen haben, können Sie pro aufrufendem Dienst ein Dienstkonto und einen Schlüssel erstellen.
In diesem Abschnitt wird gezeigt, wie Sie mit der Google Cloud Console und dem gcloud-Befehlszeilentool das Dienstkonto und die Datei mit dem privaten Schlüssel erstellen und dem Dienstkonto die Rolle Ersteller von Dienstkonto-Tokens zuweisen. Wie Sie diese Schritte mithilfe einer API ausführen, erfahren Sie unter Dienstkonten erstellen und verwalten.
So erstellen Sie ein Dienstkonto und eine Schlüsseldatei:
Google Cloud Console
Erstellen Sie ein Dienstkonto:
Wechseln Sie in der Google Cloud Console zur Seite Dienstkonto erstellen.
Wählen Sie das Projekt aus, das Sie verwenden möchten.
Geben Sie im Feld Dienstkontoname einen Namen ein.
Optional: Geben Sie im Feld Dienstkontobeschreibung eine Beschreibung ein.
Klicken Sie auf Erstellen.
Klicken Sie auf Fertig.
Schließen Sie das Browserfenster nicht. Sie verwenden es in der nächsten Aufgabe.
Erstellen Sie einen Dienstkontoschlüssel:
- Klicken Sie in der Google Cloud Console auf die E-Mail-Adresse des von Ihnen erstellten Dienstkontos.
- Klicken Sie auf Schlüssel.
- Klicken Sie auf Schlüssel hinzufügen > Neuen Schlüssel erstellen.
- Klicken Sie auf Erstellen. Eine JSON-Datei mit dem privaten Schlüssel des Dienstkontos wird auf Ihren Computer heruntergeladen.
- Klicken Sie auf Schließen.
gcloud
Die folgenden Befehle können Sie mit dem Google Cloud CLI auf Ihrem lokalen Computer oder in Cloud Shell ausführen.
Legen Sie das Standardkonto für
gcloudfest. Wenn Sie mehrere Konten haben, müssen Sie das Konto auswählen, das sich im zu verwendenden Google Cloud -Projekt befindet:gcloud auth loginRufen Sie die Projekt-IDs für Ihre Google Cloud -Projekte ab.
gcloud projects listLegen Sie das Standardprojekt fest. Ersetzen Sie
PROJECT_IDdurch die Google Cloud Projekt-ID, die Sie verwenden möchten.gcloud config set project PROJECT_ID
Erstellen Sie ein Dienstkonto. Ersetzen Sie
SA_NAMEundSA_DISPLAY_NAMEdurch den zu verwendenden Namen bzw. Anzeigenamen:gcloud iam service-accounts create SA_NAME \ --display-name "SA_DISPLAY_NAME"
Rufen Sie die E-Mail-Adresse des gerade erstellten Dienstkontos ab:
gcloud iam service-accounts listFügen Sie die Rolle Ersteller von Dienstkonto-Tokens hinzu. Ersetzen Sie
SA_EMAIL_ADDRESSdurch die E-Mail-Adresse des Dienstkontos.gcloud projects add-iam-policy-binding PROJECT_ID \ --member serviceAccount:SA_EMAIL_ADDRESS \ --role roles/iam.serviceAccountTokenCreator
Erstellen Sie im aktuellen Arbeitsverzeichnis eine Schlüsseldatei für das Dienstkonto. Ersetzen Sie dabei
FILE_NAMEdurch den Namen, den Sie für die Schlüsseldatei verwenden möchten. Mit dem Befehlgcloudwird standardmäßig eine JSON-Datei erstellt.gcloud iam service-accounts keys create FILE_NAME.json \ --iam-account SA_EMAIL_ADDRESS
Weitere Informationen zu den vorherigen Befehlen finden Sie in der Referenz zu gcloud.
Informationen zum Schutz des privaten Schlüssels finden Sie unter Best Practices für die Verwaltung von Anmeldedaten.
API für die Authentifizierung konfigurieren
Um die Authentifizierung von Dienstkonten für Dienste, die Ihr Gateway aufrufen, zu aktivieren, ändern Sie die Sicherheitsobjekte in Ihrem OpenAPI-Dokument, damit der ESP die Anforderungen im signierten JWT validieren kann. Die Änderungen variieren je nach verwendeter OpenAPI-Spezifikationsversion.
OpenAPI 2.0
- Fügen Sie das Dienstkonto als Aussteller in Ihre OpenAPI-Spezifikation ein:
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"
- Ersetzen Sie
DEFINITION_NAMEdurch einen String, der diese Sicherheitsdefinition bezeichnet. Sie könnten dazu den Namen des Dienstkontos verwenden oder einen Namen, der den anrufenden Dienst identifiziert. - Ersetzen Sie
SA_EMAIL_ADDRESSdurch die E-Mail-Adresse des Dienstkontos. - Sie können mehrere Sicherheitsdefinitionen in Ihrer OpenAPI-Spezifikation definieren, allerdings muss jede Definition einen anderen
x-google-issuerhaben. Wenn Sie separate Dienstkonten für jeden aufrufenden Dienst erstellt haben, können Sie für jedes Dienstkonto eine Sicherheitsdefinition erstellen, z. B.: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"
- Ersetzen Sie
- Fügen Sie optional
x-google-audiencesin den AbschnittsecurityDefinitionsein. Wenn Siex-google-audiencesnicht hinzufügen, erfordert der ESP, dass der Anspruch"aud"(Zielgruppe) im JWT das Formathttps://SERVICE_NAMEhat, wobei SERVICE_NAME der Name Ihres ESP-Dienstes ist, den Sie im FeldhostIhres OpenAPI-Dokuments konfiguriert haben. - Fügen Sie den Abschnitt
securityentweder auf der obersten Ebene der Datei (nicht eingerückt oder verschachtelt) ein, um ihn auf die gesamte API anzuwenden, oder auf der Methodenebene, um ihn auf eine bestimmte Methode zu beschränken. Wenn Sie den Abschnittsecuritysowohl auf der API-Ebene als auch auf der Methodenebene verwenden, werden die Einstellungen auf der API-Ebene durch die Einstellungen auf der Methodenebene überschrieben.security: - DEFINITION_NAME: []
- Ersetzen Sie
DEFINITION_NAMEdurch den Namen, den Sie im AbschnittsecurityDefinitionsverwendet haben. - Wenn Sie mehrere Definitionen im Abschnitt
securityDefinitionshaben, fügen Sie sie im Abschnittsecurityhinzu. Beispiel:security: - service-1: [] - service-2: []
- Ersetzen Sie
- Stellen Sie die aktualisierte OpenAPI-Spezifikation bereit. Bevor der ESP eine Anfrage an die API weiterleitet, überprüft er:
- Die Signatur des JWT mithilfe des öffentlichen Schlüssels, der sich im URI befindet und im Feld
x-google-jwks_urider OpenAPI-Spezifikation angegeben wurde. - Ob die Anforderung
"iss"(issuer) im JWT mit dem im Feldx-google-issuerangegebenen Wert übereinstimmt. - Ob die Anforderung
"aud"(audience) im JWT den Namen des ESP-Dienstes enthält oder mit einem der Werte übereinstimmt, die Sie im Feldx-google-audiencesangegeben haben. - Ob das Token abgelaufen ist. Das erfolgt mithilfe der Anforderung
"exp"(expiration time).
- Die Signatur des JWT mithilfe des öffentlichen Schlüssels, der sich im URI befindet und im Feld
OpenAPI 3.x
- Fügen Sie das Dienstkonto als Aussteller in Ihre OpenAPI-Spezifikation ein:
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: []
- Ersetzen Sie
SCHEME_NAMEdurch einen String, der dieses Sicherheitsschema identifiziert. Sie könnten dazu den Namen des Dienstkontos verwenden oder einen Namen, der den anrufenden Dienst identifiziert. - Ersetzen Sie
SA_EMAIL_ADDRESSdurch die E-Mail-Adresse des Dienstkontos. - Sie können in Ihrer OpenAPI-Spezifikation mehrere Sicherheitsschemas definieren, allerdings muss jede Definition einen anderen
issuerhaben. Wenn Sie separate Dienstkonten für jeden aufrufenden Dienst erstellt haben, können Sie für jedes Dienstkonto eine Sicherheitsdefinition erstellen, z. B.: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 "
- Ersetzen Sie
- Fügen Sie optional
audiencesin den AbschnittsecuritySchemesein. Wenn Sieaudiencesnicht hinzufügen, erfordert der ESP, dass der Anspruch"aud"(Zielgruppe) im JWT das Formathttps://SERVICE_NAMEhat, wobei SERVICE_NAME der Name Ihres ESP-Dienstes ist, den Sie im FeldhostIhres OpenAPI-Dokuments konfiguriert haben. - Fügen Sie den Abschnitt
securityentweder auf der obersten Ebene der Datei (nicht eingerückt oder verschachtelt) ein, um ihn auf die gesamte API anzuwenden, oder auf der Methodenebene, um ihn auf eine bestimmte Methode zu beschränken. Wenn Sie den Abschnittsecuritysowohl auf der API-Ebene als auch auf der Methodenebene verwenden, werden die Einstellungen auf der API-Ebene durch die Einstellungen auf der Methodenebene überschrieben.security: - SCHEME_NAME: []
- Ersetzen Sie SCHEME_NAME durch den Namen, den Sie im Abschnitt
securitySchemesverwendet haben. - Wenn Sie mehrere Definitionen im Abschnitt
securitySchemeshaben, fügen Sie sie im Abschnittsecurityhinzu. Beispiel:security: - service-1: [] - service-2: []
- Ersetzen Sie SCHEME_NAME durch den Namen, den Sie im Abschnitt
- Stellen Sie die aktualisierte OpenAPI-Spezifikation bereit. Bevor der ESP eine Anfrage an die API weiterleitet, überprüft er:
- Die Signatur des JWT mithilfe des öffentlichen Schlüssels, der sich im URI befindet und im Feld
jwksUrider OpenAPI-Spezifikation angegeben wurde. - Ob die Anforderung
"iss"(issuer) im JWT mit dem im Feldissuerangegebenen Wert übereinstimmt. - Ob die Anforderung
"aud"(audience) im JWT den Namen des ESP-Dienstes enthält oder mit einem der Werte übereinstimmt, die Sie im Feldaudiencesangegeben haben. - Ob das Token abgelaufen ist. Das erfolgt mithilfe der Anforderung
"exp"(expiration time).
- Die Signatur des JWT mithilfe des öffentlichen Schlüssels, der sich im URI befindet und im Feld
Authentifizierte Anfrage an eine Endpoints API senden
Bei einer authentifizierten Anfrage sendet der aufrufende Dienst ein JWT, das vom Dienstkonto signiert wurde, das Sie im OpenAPI-Dokument angegeben haben. Der anrufende Dienst muss folgende Schritte ausführen:
- Ein JWT erstellen und mit dem privaten Schlüssel des Dienstkontos signieren.
- Das signierte JWT in einer Anfrage an die API senden.
Der folgende Beispielcode veranschaulicht diesen Prozess für ausgewählte Sprachen. Um eine authentifizierte Anfrage in anderen Sprachen zu stellen, jwt.io.
- Fügen Sie im aufrufenden Dienst die folgende Funktion hinzu und übergeben Sie ihr folgende Parameter:
Java saKeyfile: Der vollständige Pfad zum privaten Schlüssel des Dienstkontos.-
saEmail: Die E-Mail-Adresse des Dienstkontos. -
audience: Wenn Sie das Feldx-google-audiencesin das OpenAPI-Dokument eingefügt haben, legen Sieaudienceauf einen der Werte fest, die Sie fürx-google-audiencesangegeben haben. Setzen Sie andernfallsaudienceaufhttps://SERVICE_NAME, wobeiSERVICE_NAMEder Name des Endpoints-Dienstes ist. expiryLength: Die Ablaufzeit des JWT in Sekunden.
Python -
sa_keyfile: Der vollständige Pfad zum privaten Schlüssel des Dienstkontos. -
sa_email: Die E-Mail-Adresse des Dienstkontos. -
audience: Wenn Sie das Feldx-google-audiencesin das OpenAPI-Dokument eingefügt haben, legen Sieaudienceauf einen der Werte fest, die Sie fürx-google-audiencesangegeben haben. Setzen Sie andernfallsaudienceaufhttps://SERVICE_NAME, wobeiSERVICE_NAMEder Name des Endpoints-Dienstes ist. expiry_length: Die Ablaufzeit des JWT in Sekunden.
Go saKeyfile: Der vollständige Pfad zum privaten Schlüssel des Dienstkontos.-
saEmail: Die E-Mail-Adresse des Dienstkontos. -
audience: Wenn Sie das Feldx-google-audiencesin das OpenAPI-Dokument eingefügt haben, legen Sieaudienceauf einen der Werte fest, die Sie fürx-google-audiencesangegeben haben. Setzen Sie andernfallsaudienceaufhttps://SERVICE_NAME, wobeiSERVICE_NAMEder Name des Endpoints-Dienstes ist. expiryLength: Die Ablaufzeit des JWT in Sekunden.
Die Funktion erstellt ein JWT, signiert es mithilfe der privaten Schlüsseldatei und gibt das signierte JWT zurück.
Java Python Go - Fügen Sie im aufrufenden Dienst die folgende Funktion hinzu, um das signierte JWT im Header
Authorization: Bearerder Anfrage an die API zu senden:Java Python Go
Wenn Sie eine Anfrage mit einem JWT senden, empfehlen wir aus Sicherheitsgründen, das Authentifizierungstoken in den Header Authorization: Bearer einzufügen. Beispiel:
curl --request POST \
--header "Authorization: Bearer ${TOKEN}" \
"${ENDPOINTS_HOST}/echo"
Dabei sind ENDPOINTS_HOST und TOKEN Umgebungsvariablen, die den Hostnamen der API bzw. das Authentifizierungstoken enthalten.
Authentifizierte Ergebnisse in Ihrer API empfangen
Der ESP leitet in der Regel alle empfangenen Header weiter. Der ESP überschreibt aber möglicherweise den ursprünglichen Authorization-Header, wenn die Back-End-Adresse in der OpenAPI-Spezifikation durch x-google-backend oder in der gRPC-Dienstkonfiguration mit BackendRule angegeben wird.
Der ESP sendet das Authentifizierungsergebnis in X-Endpoint-API-UserInfo an die Back-End-API. Wir empfehlen, diesen Header anstelle des ursprünglichen Authorization-Headers zu verwenden. Dieser Header ist ein String, in den base64url ein JSON-Objekt codiert. Das JSON-Objektformat unterscheidet sich zwischen ESPv2 und ESP.
Bei ESPv2 ist das JSON-Objekt genau die ursprüngliche JWT-Nutzlast. Für ESP verwendet das JSON-Objekt andere Feldnamen und die ursprüngliche JWT-Nutzlast wird im Feld claims platziert.
Weitere Informationen zum Format finden Sie unter JWTs im Back-End-Dienst verarbeiten.