Zum Aufrufen authentifizieren

Zum Aufrufen einer authentifizierten Cloud Functions-Funktion muss das zugrunde liegende Hauptkonto die IAM-Berechtigung zum Aufrufenden haben:

Zum Erstellen, Aktualisieren oder Ausführen anderer administrativer Aktionen für eine Funktion benötigen Sie ein Hauptkonto mit einer entsprechenden Rolle. Weitere Informationen finden Sie unter IAM zum Autorisieren von Zugriff verwenden.

Das Aufrufen einer Funktion kann jedoch ein komplexeres Ereignis sein. 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.

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.

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 zu Testzwecken möglicherweise Ihre Funktionen aufrufen. Beachten Sie Folgendes, um eine Funktion mit curl oder ähnlichen Tools aufzurufen:

  • Weisen Sie Ihrem Cloud Functions-Nutzerkonto eine Rolle zu, die die Aufrufberechtigung enthält.

    • Berechtigung cloudfunctions.functions.invoke. cloudfunctions.functions.invoke für Funktionen der 1. Generation Dies erfolgt normalerweise über die Cloud Functions-Invoker-Rolle. Standardmäßig haben die Rollen Cloud Functions-Administrator und Cloud Functions-Entwickler diese Berechtigung. Eine vollständige Lister der Rollen und zugehörigen Berechtigungen finden Sie unter Cloud Functions-IAM-Rollen.
    • run.routes.invoke für Funktionen der zweiten Generation Dies erfolgt normalerweise über die Rolle "Cloud Run-Aufrufer".
  • 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. Rufen Sie beispielsweise ein ID-Token mit gcloud ab, indem Sie den folgenden Befehl ausführen:

    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 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 Tokens verwenden, die von gcloud erstellt wurden, um HTTP-Funktionen in einem beliebigen Projekt aufzurufen, wenn Ihr Konto die Berechtigung cloudfunctions.functions.invoke für die aufgerufene Funktion hat. Verwenden Sie zu Entwicklungszwecken gcloud-generierte ID-Tokens. Beachten Sie jedoch, dass solche Tokens keine Zielgruppenanforderung haben, wodurch sie anfällig für Relay-Angriffe sind. Verwenden Sie in Produktionsumgebungen ID-Tokens, die für ein Dienstkonto ausgestellt wurden und die entsprechende Zielgruppe angegeben haben. Dieser Ansatz verbessert die Sicherheit, da die Tokennutzung nur 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.

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. Bei Funktionen der 1. Generation ist die Aufruferrolle "Cloud Functions-Aufrufer" (roles/cloudfunctions.invoker). Bei Funktionen der 2. Generation ist die Aufruferrolle "Cloud Run Invoker" (roles/run.invoker) und muss für den zugrunde liegenden Dienst Gewährt werden.

Cloud Functions (1. Generation):

Console

Für Funktionen der 1. Generation verwenden Sie den Cloud Functions-Aufrufer:

  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-iam-policy-binding aus:

gcloud functions add-iam-policy-binding RECEIVING_FUNCTION \
  --member='serviceAccount:CALLING_FUNCTION_IDENTITY' \
  --role='roles/cloudfunctions.invoker'

Dabei ist RECEIVING_FUNCTION der Name der empfangenden Funktion und CALLING_FUNCTION_IDENTITY die aufrufende Funktionsidentität, eine E-Mail-Adresse für das Dienstkonto.

Cloud Functions (2. Generation):

Console

Für Funktionen der 2. Generation verwenden Sie den Cloud Run-Aufrufer:

  1. Öffnen Sie die Google Cloud Console:

    Zur Google Cloud Console

  2. Klicken Sie in der Liste der Cloud Run-Dienste auf das Kästchen neben der empfangenden Funktion. (Klicken Sie nicht auf die Funktion selbst.)

    Der Bereich Berechtigungen wird geöffnet.

  3. Klicken Sie auf Hauptkonto hinzufügen.

  4. Geben Sie die Identität des aufrufenden Dienstes ein. Dies ist normalerweise eine E-Mail-Adresse, standardmäßig PROJECT_NUMBER-compute@developer.gserviceaccount.com.

    Beachten Sie, dass sich die Projektnummer von Projekt-ID und Projektnamen unterscheidet. Sie finden Ihre Projektnummer in der Google Cloud Console auf der Dashboard-Seite.

  5. Wählen Sie im Drop-down-Menü Rolle auswählen die Rolle Cloud Run Invoker aus.

  6. 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'

Dabei ist RECEIVING_FUNCTION der Name der empfangenden Funktion und CALLING_FUNCTION_IDENTITY die aufrufende Funktionsidentität, eine E-Mail-Adresse für das Dienstkonto.

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.

Tokens programmatisch generieren

Nachdem der folgende Code ein ID-Token generiert hat, ruft er Ihre Cloud Functions-Funktion 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()

Einfach loslegen (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 Funktion, die Sie aufrufen. Sie können diese URL wie im Abschnitt Entwicklertests authentifizieren oben abrufen.

Austausch eines selbst signierten JWT für ein von Google signiertes ID-Token

  1. Gewähren Sie dem Dienstkonto der aufrufenden Funktion für die empfangende Funktion die Rolle „Cloud Functions-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