Autenticazione per le chiamate

Per richiamare una Cloud Function autenticata, l'entità sottostante deve avere l'autorizzazione IAM richiamo:

  • cloudfunctions.functions.invoke per le funzioni di 1ª generazione. In genere questo avviene tramite il ruolo Invoker di Cloud Functions.
  • run.routes.invoke per le funzioni di 2ª generazione. In genere, questo viene eseguito tramite il ruolo Invoker di Cloud Run. Questa autorizzazione deve essere assegnata nella risorsa del servizio Cloud Run.

Per ottenere l'autorizzazione per creare, aggiornare o eseguire altre azioni amministrative su una funzione, devi avere un'entità con un ruolo appropriato. Per ulteriori informazioni, consulta Utilizzo di IAM per autorizzare l'accesso.

Tuttavia, richiamare una funzione può essere un evento più complesso. Le funzioni basate su eventi possono essere richiamate dall'origine evento a cui sono sottoscritte, ma le funzioni HTTP possono essere richiamate da diversi tipi di identità, che hanno origine in posizioni diverse. Il callback può essere uno sviluppatore che sta testando la funzione o un'altra funzione o un altro servizio che vuole utilizzare la funzione. Per impostazione predefinita, queste identità devono fornire un token ID con la richiesta per autenticarsi. Inoltre, è necessario che all'account utilizzato siano state concesse le autorizzazioni appropriate.

L'accesso non autenticato senza un token ID è possibile, ma deve essere abilitato. Per ulteriori informazioni, consulta Utilizzo di IAM per autorizzare l'accesso.

Autenticazione dei test degli sviluppatori

In qualità di sviluppatore, devi disporre dell'accesso per creare, aggiornare ed eliminare le funzioni, e questo viene concesso tramite la procedura normale (IAM).

Tuttavia, in qualità di sviluppatore, potresti dover chiamare le tue funzioni a scopo di test. Per richiamare una funzione utilizzando curl o strumenti simili, tieni presente quanto segue:

  • Assegna un ruolo all'account utente Cloud Functions che contiene l'autorizzazione di chiamata.

    • cloudfunctions.functions.invoke per le funzioni di 1ª generazione. In genere viene assegnato il ruolo Invoker di Cloud Functions. Per impostazione predefinita, i ruoli Amministratore Cloud Functions e Sviluppatore Cloud Functions dispongono di questa autorizzazione. Consulta Ruoli IAM di Cloud Functions per l'elenco completo dei ruoli e delle autorizzazioni associate.
    • run.routes.invoke per le funzioni di 2ª generazione. In genere, questo viene eseguito tramite il ruolo Invoker di Cloud Run. Questa autorizzazione deve essere assegnata nella risorsa del servizio Cloud Run.
  • Se stai lavorando dalla tua macchina locale, configura l'accesso da riga di comando inizializzando Google Cloud CLI.

  • Fornisci alla richiesta le credenziali di autenticazione come token ID generato da Google e archiviato in un'intestazione Authorization. Ad esempio, ottieni un token ID utilizzando gcloud eseguendo questo comando:

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

    dove FUNCTION_URL è l'URL della funzione. Recupera questo URL dalla pagina Cloud Functions della console Google Cloud o eseguendo il comando gcloud functions describe come mostrato nel primo passaggio dell'esempio di comando di deployment di Google Cloud CLI.

Puoi utilizzare i token creati da gcloud per richiamare le funzioni HTTP in qualsiasi progetto, a condizione che il tuo account disponga dell'autorizzazione cloudfunctions.functions.invoke per la funzione che viene richiamata. A scopo di sviluppo, usa i token ID generati da gcloud. Tuttavia, tieni presente che questi token non presentano rivendicazioni sul pubblico, il che li rende vulnerabili agli attacchi. Negli ambienti di produzione, utilizza i token ID emessi per un account di servizio con il segmento di pubblico appropriato specificato. Questo approccio migliora la sicurezza limitando l'utilizzo dei token solo al servizio previsto.

Come sempre, ti consigliamo di allocare l'insieme minimo di autorizzazioni necessarie per sviluppare e utilizzare le tue funzioni. Assicurati che i criteri IAM sulle tue funzioni siano limitati al numero minimo di utenti e account di servizio.

Funzione di autenticazione per le chiamate di funzione

Quando crei servizi che collegano più funzioni, ti consigliamo di assicurarti che ogni funzione possa inviare richieste solo a un sottoinsieme specifico delle altre funzioni. Ad esempio, se disponi di una funzione login, questa dovrebbe essere in grado di accedere alla funzione user profiles, ma probabilmente non dovrebbe essere in grado di accedere alla funzione search.

Per configurare la funzione ricevente in modo che accetti le richieste da una funzione di chiamata specifica, devi concedere il ruolo di richiamata appropriato all'account di servizio della funzione di chiamata nella funzione ricevente. Per le funzioni di 1ª generazione, il ruolo Invoker è Invoker di Cloud Functions (roles/cloudfunctions.invoker). Per le funzioni di 2ª generazione, il ruolo di richiamo è Invoker di Cloud Run (roles/run.invoker) e deve essere concesso sul servizio sottostante.

Cloud Functions (1ª generazione.):

Console

Per le funzioni di 1ª generazione, utilizzi l'Invoker di Cloud Functions:

  1. Vai alla console Google Cloud:

    Vai alla console Google Cloud

  2. Fai clic sulla casella di controllo accanto alla funzione ricevente. Non fare clic sulla funzione stessa.

  3. Fai clic su Autorizzazioni nella parte superiore della schermata. Si apre il riquadro Autorizzazioni.

  4. Fai clic su Aggiungi entità.

  5. Nel campo Nuove entità, inserisci l'identità della funzione chiamante. Deve essere l'indirizzo email di un account di servizio.

  6. Seleziona il ruolo Cloud Functions > Invoker di Cloud Functions dal menu a discesa Seleziona un ruolo.

  7. Fai clic su Salva.

gcloud

Usa il comando gcloud functions add-invoker-policy-binding:

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

Il comando add-invoker-policy-binding aggiunge un'associazione di criteri IAM del ruolo chiamante che consente al membro (entità) specificato di richiamare la funzione specificata. gcloud rileverà automaticamente la generazione della funzione e aggiungerà il ruolo Invoker corretto (cloudfunctions.invoker per 1ª generazione e run.invoker per 2ª generazione).

Sostituisci quanto segue:

  • RECEIVING_FUNCTION: il nome della funzione ricevente.
  • CALLING_FUNCTION_IDENTITY: l'identità della funzione chiamante, un'email dell'account di servizio.

Cloud Functions (2nd gen):

Console

Per le funzioni di 2ª generazione, utilizzi l'Invoker di Cloud Run:

  1. Vai alla console Google Cloud:

    Vai alla console Google Cloud

  2. Nell'elenco dei servizi Cloud Run, fai clic sulla casella di controllo accanto alla funzione di ricezione. Non fare clic sulla funzione stessa.

    Si apre il riquadro Autorizzazioni.

  3. Fai clic su Aggiungi entità.

  4. Inserisci l'identità del servizio chiamante. In genere si tratta di un indirizzo email, per impostazione predefinita PROJECT_NUMBER-compute@developer.gserviceaccount.com.

    Tieni presente che il numero del progetto è diverso dall'ID e dal nome del progetto. Puoi trovare il numero del progetto nella pagina della dashboard della console Google Cloud.

  5. Seleziona il ruolo Cloud Run Invoker dal menu a discesa Seleziona un ruolo.

  6. Fai clic su Salva.

gcloud

Usa il comando gcloud functions add-invoker-policy-binding:

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

Sostituisci quanto segue:

  • RECEIVING_FUNCTION: il nome della funzione ricevente.
  • CALLING_FUNCTION_IDENTITY: l'identità della funzione chiamante, un'email dell'account di servizio.

Poiché vocherà la funzione di ricezione, la funzione chiamante deve fornire anche un token ID firmato da Google per l'autenticazione. Si tratta di una procedura in due passaggi:

  1. Crea un token ID firmato da Google con il campo del pubblico (aud) impostato sull'URL della funzione ricevente.

  2. Includi il token ID in un'intestazione Authorization: Bearer ID_TOKEN nella richiesta alla funzione.

Il modo di gran lunga più semplice e affidabile per gestire questo processo è utilizzare le librerie di autenticazione, come mostrato di seguito, per generare e utilizzare questo token.

Generazione di token in modo programmatico

Dopo che il codice seguente ha generato un token ID, chiama la tua funzione Cloud Function con quel token per tuo conto. Questo codice funziona in qualsiasi ambiente in cui le librerie possono ottenere le credenziali di autenticazione, inclusi gli ambienti che supportano le credenziali predefinite dell'applicazione locali.

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();
  }
}

Generazione manuale di token

Se stai richiamando una funzione e per qualche motivo non puoi utilizzare le librerie di autenticazione, esistono due modi per ottenere il token ID manualmente: utilizzando il server di metadati Compute o creando un JWT autofirmato e scambiandolo con un token ID firmato da Google.

Utilizzo del server dei metadati

Puoi utilizzare il server metadati Compute per recuperare i token ID con un segmento di pubblico specifico, come indicato di seguito:

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

Sostituisci AUDIENCE con l'URL della funzione che stai richiamando. Puoi recuperare questo URL come descritto nella sezione Autenticazione dei test degli sviluppatori sopra riportata.

Scambio di un JWT autofirmato con un token ID firmato da Google

  1. Concedi il ruolo Invoker di Cloud Functions (roles/cloudfunctions.invoker) all'account di servizio della funzione chiamante nella funzione ricevente.

  2. Crea un account di servizio e una chiave e scarica il file con la chiave privata (in formato JSON) nell'host da cui la funzione o il servizio chiamante effettua le sue richieste.

  3. Crea un JWT con l'intestazione impostata su {"alg":"RS256","typ":"JWT"}. Il payload deve includere un'attestazione target_audience impostata sull'URL della funzione ricevente, mentre le attestazioni iss e sub devono essere impostate sull'indirizzo email dell'account di servizio utilizzato in precedenza. Deve includere anche le rivendicazioni exp e iat. L'attestazione aud deve essere impostata su https://www.googleapis.com/oauth2/v4/token.

  4. Usa la chiave privata scaricata in precedenza per firmare il JWT.

  5. Utilizzando questo JWT, invia una richiesta POST a https://www.googleapis.com/oauth2/v4/token. I dati di autenticazione devono essere inclusi nell'intestazione e nel corpo della richiesta.

    Nell'intestazione:

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

    Nel corpo:

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

    Sostituisci $JWT con il JWT che hai appena creato

    Questo restituisce un altro JWT che include un id_token firmato da Google.

Invia la richiesta GET/POST alla funzione di ricezione. Includi il token ID firmato da Google in un'intestazione Authorization: Bearer ID_TOKEN_JWT nella richiesta.

Passaggi successivi