Zum Aufrufen authentifizieren (1. Generation)

Damit eine authentifizierte Cloud Run Function aufgerufen werden kann, muss das zugrunde liegende Hauptkonto die folgenden Anforderungen erfüllen:

  • Es ist berechtigt, die Funktion aufzurufen.
  • Es muss ein ID-Token angeben, wenn die Funktion aufgerufen wird.

Was ist ein Hauptkonto? Wie im Hilfeartikel Cloud Run Functions schützen beschrieben, unterstützen Cloud Run Functions zwei verschiedene Arten von Identitäten, die auch Hauptkonten genannt werden:

  • Dienstkonten: Dies sind spezielle Konten, die als Identität einer Nicht-Identität verwendet werden, beispielsweise eine Funktion, eine Anwendung oder eine VM. Sie bieten Ihnen die Möglichkeit, diese Nicht-Personen zu authentifizieren.
  • Nutzerkonten: Diese Konten stellen Personen dar, entweder als einzelne Google-Kontoinhaber oder als Teil einer von Google kontrollierten Entität wie einer Google-Gruppe.

Weitere Informationen zu den grundlegenden IAM-Konzepten finden Sie in der IAM-Übersicht.

Zum Aufrufen von authentifizierten Cloud Run Functions muss das Hauptkonto die IAM-Berechtigung für Aufrufer haben:

  • cloudfunctions.functions.invoke. Dies geschieht normalerweise über die Rolle Aufrufer.

Verwenden Sie zum Erteilen dieser Berechtigungen den Befehl add-invoker-policy-binding, wie unter Feature für Funktionsaufrufe authentifizieren beschrieben.

Zum Erstellen, Aktualisieren oder Ausführen anderer administrativer Aktionen für eine Funktion muss das Hauptkonto eine entsprechende Rolle haben. Rollen enthalten Berechtigungen, die die Aktionen definieren, die das Hauptkonto ausführen darf. Weitere Informationen finden Sie unter IAM zum Autorisieren von Zugriff verwenden.

Das Aufrufen einer Funktion kann zusätzliche Komplexitäten haben. Ereignisgesteuerte Funktionen können nur von der Ereignisquelle aufgerufen werden, für die sie abonniert sind. HTTP-Funktionen können jedoch von unterschiedlichen Identitäten aufgerufen werden. Der Aufrufer ist zum Beispiel ein Entwickler, der die Funktion oder eine andere Funktion oder einen anderen Dienst testet, der bzw. die die Funktion verwenden möchte. Standardmäßig müssen diese Identitäten ein ID-Token mit der Anfrage zur eigenen Authentifizierung bereitstellen. Darüber hinaus müssen dem verwendeten Konto auch die entsprechenden Berechtigungen erteilt worden sein.

ID-Tokens generieren und verwenden.

Authentifizierungsbeispiele

In diesem Abschnitt finden Sie verschiedene Beispiele für die Aufruf-Authentifizierung.

Beispiel 1: Entwicklertests authentifizieren

Als Entwickler benötigen Sie Zugriff auf das Erstellen, Aktualisieren und Löschen von Funktionen und dies wird mithilfe des normalen IAM-Prozesses gewährt.

Als Entwickler müssen Sie jedoch möglicherweise zu Testzwecken auch Funktionen aufrufen. Beachten Sie Folgendes, wenn Sie eine Funktion mit curl oder ähnlichen Tools aufrufen:

  • Weisen Sie Ihrem Cloud Run Functions-Nutzerkonto eine Rolle mit der Berechtigung „invoke“ zu.

    • cloudfunctions.functions.invoke. Dies geschieht normalerweise über die Rolle Aufrufer. Standardmäßig haben die Rollen Cloud Run Functions-Administrator und Cloud Run Functions-Entwickler diese Berechtigung. Unter Cloud Run Functions-IAM-Rollen finden Sie die vollständige Liste der Rollen und der zugehörigen Berechtigungen.
  • Wenn Sie von Ihrem lokalen Computer aus arbeiten, richten Sie den Befehlszeilenzugriff ein, indem Sie die Google Cloud CLI initialisieren.

  • Geben Sie Ihre Anfrage mit Authentifizierungsanmeldedaten als von Google generiertes ID-Token an, das in einem Authorization-Header gespeichert ist. So rufen Sie beispielsweise ein ID-Token mit gcloud ab:

    curl  -H "Authorization: Bearer $(gcloud auth print-identity-token)" \
      https://FUNCTION_URL

    Dabei ist FUNCTION_URL die URL Ihrer Funktion. Rufen Sie diese URL auf der Seite „Cloud Run Functions“ der Google Cloud Console oder durch Ausführen des Befehls gcloud functions describe ab, wie im ersten Schritt des Beispiel für einen Google-Cloud CLI-Bereitstellungsbefehl

Sie können von gcloud erstellte Tokens verwenden, um HTTP-Funktionen in einem beliebigen Projekt aufzurufen, solange Ihr Konto die cloudfunctions.functions.invoke-Berechtigung für die aufgerufene Funktion hat. Verwenden Sie zu Entwicklungszwecken von gcloud generierte ID-Tokens. Beachten Sie dabei, dass solche Tokens keine Zielgruppenanforderung haben, was sie für Relay-Angriffe anfällig macht. In Produktionsumgebungen verwenden Sie ID-Tokens, die für ein Dienstkonto ausgestellt wurden und für die die angemessene Zielgruppe angegeben wurde. Dieser Ansatz verbessert die Sicherheit, da die Tokennutzung auf den gewünschten Dienst beschränkt wird.

Wie immer empfehlen wir, dass Sie die minimalen Berechtigungen zuweisen, die zum Entwickeln und Verwenden von Funktionen erforderlich sind. Achten Sie dabei darauf, dass die IAM-Richtlinien für die Funktionen auf die Mindestanzahl von Nutzern und Dienstkonten beschränkt sind.

Beispiel 2: Funktion für Funktionsaufrufe authentifizieren

Wenn Sie Dienste erstellen, die mehrere Funktionen miteinander verbinden, sollten Sie dafür sorgen, dass jede Funktion nur Anfragen an eine bestimmte Teilmenge der anderen Funktionen senden kann. Eine login-Funktion sollte zwar beispielsweise auf die user profiles-Funktion zugreifen können, aber keinen Zugriff auf die search-Funktion haben.

Wenn Sie die empfangende Funktion so konfigurieren möchten, dass Anfragen von einer bestimmten Aufruffunktion akzeptiert werden, müssen Sie dem Dienstkonto der aufrufenden Funktion in der empfangenden Funktion die entsprechende Aufruferrolle zuweisen. Die Rolle „Aufrufer“ ist „Cloud Run Functions-Aufrufer“ (roles/cloudfunctions.invoker):

Console

Cloud Run Functions-Aufrufer verwenden:

  1. Öffnen Sie die Google Cloud Console:

    Zur Google Cloud Console

  2. Klicken Sie auf das Kästchen neben der empfangenden Funktion. (Klicken Sie nicht auf die Funktion selbst.)

  3. Klicken Sie oben auf dem Bildschirm auf Berechtigungen. Der Bereich Berechtigungen wird geöffnet.

  4. Klicken Sie auf Hauptkonto hinzufügen.

  5. Geben Sie im Feld Neue Hauptkonten die Identität der aufrufenden Funktion ein. Dies muss die E-Mail-Adresse eines Dienstkontos sein.

  6. Wählen Sie die Rolle Cloud Functions > Cloud Functions-Invoker aus dem Drop-down-Menü Rolle auswählen aus.

  7. Klicken Sie auf Speichern.

gcloud

Führen Sie den Befehl gcloud functions add-invoker-policy-binding aus:

gcloud functions add-invoker-policy-binding RECEIVING_FUNCTION \
  --member='serviceAccount:CALLING_FUNCTION_IDENTITY'

Mit dem Befehl add-invoker-policy-binding wird eine IAM-Richtlinienbindung für die Rolle „Aufrufer“ hinzugefügt, die es dem angegebenen Mitglied (Hauptkonto) ermöglicht, die angegebene Funktion aufzurufen. Die Google Cloud CLI erkennt die Funktion automatisch und fügt die richtige Rolle „Aufrufer“ hinzu (cloudfunctions.invoker für die 1. Generation).

Ersetzen Sie Folgendes:

  • RECEIVING_FUNCTION: Der Name der empfangenden Funktion.
  • CALLING_FUNCTION_IDENTITY: Die Identität der aufrufenden Funktion, eine E-Mail-Adresse des Dienstkontos.

Da sie die empfangende Funktion aufrufen, muss die aufrufende Funktion auch ein von Google signiertes ID-Token zur Authentifizierung bereitstellen. Hierzu sind zwei Schritte notwendig:

  1. Erstellen Sie ein von Google signiertes ID-Token, in dem das Zielgruppenfeld (aud) auf die URL der empfangenden Funktion eingestellt ist.

  2. Geben Sie das ID-Token in der Anfrage an die Funktion in einem Authorization: Bearer ID_TOKEN-Header an.

Die bei Weitem einfachste und zuverlässigste Methode für die Verwaltung dieses Prozesses ist die Verwendung der unten aufgeführten Authentifizierungsbibliotheken, um dieses Token zu generieren und anzuwenden.

ID-Tokens generieren

In diesem Abschnitt werden verschiedene Möglichkeiten beschrieben, wie Sie das ID-Token generieren können, das Hauptkonten benötigen, um Funktionen aufzurufen.

Nicht authentifizierter Zugriff ohne ein ID-Token ist möglich, muss aber aktiviert werden. Weitere Informationen finden Sie unter IAM zum Autorisieren von Zugriff verwenden.

Tokens programmatisch generieren

Nachdem der folgende Code ein ID-Token generiert hat, ruft er Ihre Cloud Run Function mit diesem Token in Ihrem Namen auf. Dieser Code funktioniert in jeder Umgebung, in der die Bibliotheken Anmeldedaten zur Authentifizierung abrufen können, einschließlich Umgebungen, die lokale Standardanmeldedaten für Anwendungen unterstützen.

Node.js

/**
 * TODO(developer): Uncomment these variables before running the sample.
 */

// Cloud Functions uses your function's url as the `targetAudience` value
// const targetAudience = 'https://project-region-projectid.cloudfunctions.net/myFunction';
// For Cloud Functions, endpoint (`url`) and `targetAudience` should be equal
// const url = targetAudience;


const {GoogleAuth} = require('google-auth-library');
const auth = new GoogleAuth();

async function request() {
  console.info(`request ${url} with target audience ${targetAudience}`);
  const client = await auth.getIdTokenClient(targetAudience);

  // Alternatively, one can use `client.idTokenProvider.fetchIdToken`
  // to return the ID Token.
  const res = await client.request({url});
  console.info(res.data);
}

request().catch(err => {
  console.error(err.message);
  process.exitCode = 1;
});

Python

import urllib

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


def make_authorized_get_request(endpoint, audience):
    """
    make_authorized_get_request makes a GET request to the specified HTTP endpoint
    by authenticating with the ID token obtained from the google-auth client library
    using the specified audience value.
    """

    # Cloud Functions uses your function's URL as the `audience` value
    # audience = https://project-region-projectid.cloudfunctions.net/myFunction
    # For Cloud Functions, `endpoint` and `audience` should be equal

    req = urllib.request.Request(endpoint)

    auth_req = google.auth.transport.requests.Request()
    id_token = google.oauth2.id_token.fetch_id_token(auth_req, audience)

    req.add_header("Authorization", f"Bearer {id_token}")
    response = urllib.request.urlopen(req)

    return response.read()

Go


import (
	"context"
	"fmt"
	"io"

	"google.golang.org/api/idtoken"
)

// `makeGetRequest` makes a request to the provided `targetURL`
// with an authenticated client using audience `audience`.
func makeGetRequest(w io.Writer, targetURL string, audience string) error {
	// For Cloud Functions, endpoint (`serviceUrl`) and `audience` are the same.
	// Example `audience` value (Cloud Functions): https://<PROJECT>-<REGION>-<PROJECT_ID>.cloudfunctions.net/myFunction
	// (`targetURL` and `audience` will differ for GET parameters)
	ctx := context.Background()

	// client is a http.Client that automatically adds an "Authorization" header
	// to any requests made.
	client, err := idtoken.NewClient(ctx, audience)
	if err != nil {
		return fmt.Errorf("idtoken.NewClient: %w", err)
	}

	resp, err := client.Get(targetURL)
	if err != nil {
		return fmt.Errorf("client.Get: %w", err)
	}
	defer resp.Body.Close()
	if _, err := io.Copy(w, resp.Body); err != nil {
		return fmt.Errorf("io.Copy: %w", err)
	}

	return nil
}

Java

import com.google.api.client.http.GenericUrl;
import com.google.api.client.http.HttpRequest;
import com.google.api.client.http.HttpResponse;
import com.google.api.client.http.HttpTransport;
import com.google.api.client.http.javanet.NetHttpTransport;
import com.google.auth.http.HttpCredentialsAdapter;
import com.google.auth.oauth2.GoogleCredentials;
import com.google.auth.oauth2.IdTokenCredentials;
import com.google.auth.oauth2.IdTokenProvider;
import java.io.IOException;

public class Authentication {

  // makeGetRequest makes a GET request to the specified Cloud Run or
  // Cloud Functions endpoint `serviceUrl` (must be a complete URL), by
  // authenticating with an ID token retrieved from Application Default
  // Credentials using the specified `audience`.
  //
  // For Cloud Functions, endpoint (`serviceUrl`) and `audience` are the same.
  // Example `audience` value (Cloud Functions): https://project-region-projectid.cloudfunctions.net/myFunction
  public static HttpResponse makeGetRequest(String serviceUrl, String audience) throws IOException {
    GoogleCredentials credentials = GoogleCredentials.getApplicationDefault();
    if (!(credentials instanceof IdTokenProvider)) {
      throw new IllegalArgumentException("Credentials are not an instance of IdTokenProvider.");
    }
    IdTokenCredentials tokenCredential =
        IdTokenCredentials.newBuilder()
            .setIdTokenProvider((IdTokenProvider) credentials)
            .setTargetAudience(audience)
            .build();

    GenericUrl genericUrl = new GenericUrl(serviceUrl);
    HttpCredentialsAdapter adapter = new HttpCredentialsAdapter(tokenCredential);
    HttpTransport transport = new NetHttpTransport();
    HttpRequest request = transport.createRequestFactory(adapter).buildGetRequest(genericUrl);
    return request.execute();
  }
}

Tokens manuell generieren

Wenn Sie eine Funktion aufrufen und aus irgendeinem Grund die Authentifizierungsbibliotheken nicht verwenden können, gibt es zwei Möglichkeiten, das ID-Token manuell abzurufen, entweder über den Compute-Metadatenserver oder indem du ein selbstsigniertes JWT erstellst und es gegen ein von Google signiertes ID-Token austauscht.

Metadatenserver verwenden

Sie können den Compute-Metadatenserver verwenden, um ID-Tokens mit einer bestimmten Zielgruppe so abzurufen:

curl "http://metadata.google.internal/computeMetadata/v1/instance/service-accounts/default/identity?audience=AUDIENCE" \
     -H "Metadata-Flavor: Google"

Ersetzen Sie AUDIENCE durch die URL der aufgerufenen Funktion. Sie können diese URL wie oben im Abschnitt Entwicklertests authentifizieren beschrieben abrufen.

Ein selbst signiertes JWT für ein von Google signiertes ID-Token austauschen

  1. Gewähren Sie dem Dienstkonto der aufrufenden Funktion für die empfangende Funktion die Rolle „Aufrufer“ (roles/cloudfunctions.invoker).

  2. Erstellen Sie ein Dienstkonto und einen Schlüssel und laden Sie die Datei mit dem privaten Schlüssel im JSON-Format auf den Host herunter, von dem aus die aufrufende Funktion oder der Dienst Anfragen stellt.

  3. Erstellen Sie ein JWT, bei dem der Header auf {"alg":"RS256","typ":"JWT"} gesetzt ist. Die Nutzlast sollte eine target_audience-Anforderung enthalten, die auf die URL der empfangenden Funktion festgelegt ist, und die iss- und sub-Anforderungen, die auf die E-Mail-Adresse des oben verwendeten Dienstkontos festgelegt sind. Außerdem sollten die Anforderungen exp und iat enthalten sein. Für die Anforderung aud muss https://www.googleapis.com/oauth2/v4/token festgelegt sein.

  4. Verwenden Sie den oben heruntergeladenen privaten Schlüssel, um das JWT zu signieren.

  5. Senden Sie mithilfe dieses JWT eine POST-Anfrage an https://www.googleapis.com/oauth2/v4/token. Authentifizierungsdaten müssen im Header und im Hauptteil der Anfrage enthalten sein.

    Im Header:

    Authorization: Bearer $JWT - where $JWT is the JWT you just created
    Content-Type: application/x-www-form-urlencoded
    

    Im Hauptteil:

    grant_type=urn:ietf:params:oauth:grant-type:jwt-bearer&assertion=$JWT
    

    Ersetzen Sie $JWT durch das gerade erstellte JWT.

    Dadurch wird ein anderes JWT zurückgegeben, das einen von Google signierten id_token enthält.

Senden Sie Ihre GET-/POST-Anfrage an die empfangende Funktion. Fügen Sie das von Google signierte ID-Token in der Anfrage in einen Authorization: Bearer ID_TOKEN_JWT-Header ein.

Nächste Schritte