Autenticar para la invocación

Para crear, actualizar o realizar otras acciones administrativas en una función, debes tener una cuenta que sea miembro y que tenga una función apropiada. Consulta Autoriza el acceso a través de IAM para obtener más información.

Sin embargo, invocar una función puede ser un evento más complejo. Solo la fuente del evento a la que están suscritas las funciones controladas por eventos solo puede invocarlas, pero las pueden invocar funciones de HTTP. de identidades, que se originan en diferentes lugares. El invocador puede ser un desarrollador que pruebe la función o alguna otra función o servicio que quiera usar la función. De forma predeterminada, estas identidades deben autenticarse a sí mismas (proporcionar prueba de su identidad) y tener los permisos adecuados. El acceso no autenticado es posible, pero debe estar habilitado. Consulta Administra el acceso a través de IAM para obtener más información.

Autentica las pruebas de los desarrolladores

Como desarrollador, necesitas acceso para crear, actualizar y borrar funciones, y esto se otorga mediante el proceso normal (IAM).

Sin embargo, como desarrollador, es probable que también debas invocar las funciones para realizar pruebas. Para invocar una función con curl o herramientas similares, debes hacer lo siguiente:

  • Ten la cuenta que usas para acceder a Cloud Functions con una función que contiene el permiso cloudfunctions.functions.invoke. Según la configuración predeterminada, las funciones de Administrador y de Desarrollador de Cloud Functions tienen este permiso. Consulta las funciones de IAM de Cloud Functions para ver la lista completa de las funciones y los permisos asociados con estas.

  • Si trabajas desde tu máquina local, configura el acceso a la línea de comandos inicializando el SDK de Google Cloud. Asegúrate de haber descargado la clave de la cuenta de servicio y configurado la variable de entorno GOOGLE_APPLICATION_CREDENTIALS.

  • Proporciona credenciales de autenticación en tu solicitud como un token de ID generado por Google que está almacenado en un encabezado Authorization. Por ejemplo, puedes obtener un token por medio de gcloud de la siguiente manera:

    curl https://REGION-PROJECT_ID.cloudfunctions.net/FUNCTION_NAME \
      -H "Authorization: bearer $(gcloud auth print-identity-token)"
    

Como siempre, te recomendamos que asignes el conjunto mínimo de permisos necesarios para desarrollar y usar tus funciones. Asegúrate de que las políticas de IAM en tus funciones estén limitadas a la cantidad mínima de usuarios y cuentas de servicio.

Autentica tu función para realizar llamadas

Cuando compilas servicios que conectan varias funciones, es una buena idea asegurarte de que cada función solo pueda enviar solicitudes a un subconjunto específico de tus otras funciones. Por ejemplo, si tienes una función login, esta debería poder acceder a la función user profiles, pero probablemente no debería poder acceder a la función search.

Si deseas configurar la función receptora para que acepte solicitudes de una función de llamada específica, debes agregar la cuenta de servicio de la función que llama como miembro en la función receptora y otorgar a ese miembro la función invocador de Cloud Functions (roles/cloudfunctions.invoker). El proceso es el mismo que el de otorgar alguna función a cualquier otro miembro.

Console

  1. Ve a Google Cloud Console:

    Ir a Google Cloud Console

  2. Haz clic en la casilla de verificación junto a la función receptora.

  3. Haz clic en Permisos en la parte superior de la pantalla. Se abrirá el panel Permisos.

  4. Haz clic en Agregar miembro.

  5. En el campo Miembros nuevos, ingresa la identidad de la función que llama. Debería ser el correo electrónico de una cuenta de servicio.

  6. Selecciona Cloud Functions > Invocador de Cloud Functions en el menú desplegable Seleccionar una función.

  7. Haz clic en Guardar.

GCloud

Usa el comando gcloud functions add-iam-policy-binding:

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

En el que RECEIVING_FUNCTION es el nombre de la función receptora y CALLING_FUNCTION_IDENTITY es la identidad de la función que llama, un correo electrónico de cuenta de servicio.

Debido a que invocará la función receptora, la función que haga la llamada también deberá proporcionar un token de ID firmado por Google para autenticarse. Este es un proceso en dos pasos:

  1. Crea un token de ID firmado por Google con el campo de público (aud) configurado en la URL de la función receptora.

  2. Incluye el token de ID en un encabezado Authorization: Bearer ID_TOKEN en la solicitud a la función.

La forma más fácil y confiable de administrar este proceso es usar las bibliotecas de autenticación como se muestra a continuación para generar y emplear este token.

Genera tokens de manera programática

Puedes usar el siguiente código para generar un token de ID. Este código funciona en cualquier entorno en el que las bibliotecas puedan obtener credenciales de autenticación, incluidos los entornos que admiten credenciales predeterminadas de la aplicación.

Node.js

/**
 * TODO(developer): Uncomment these variables before running the sample.
 */
// const url = 'https://TARGET_URL';
const {GoogleAuth} = require('google-auth-library');
const auth = new GoogleAuth();

async function request() {
  if (!targetAudience) {
    // Use the request URL hostname as the target audience for requests.
    const {URL} = require('url');
    targetAudience = new URL(url).origin;
  }
  console.info(`request ${url} with target audience ${targetAudience}`);
  const client = await auth.getIdTokenClient(targetAudience);
  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(service_url):
    """
    make_authorized_get_request makes a GET request to the specified HTTP endpoint
    in service_url (must be a complete URL) by authenticating with the
    ID token obtained from the google-auth client library.
    """

    req = urllib.request.Request(service_url)

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

    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.
func makeGetRequest(w io.Writer, targetURL string) error {
	// functionURL := "https://TARGET_URL"
	ctx := context.Background()

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

	resp, err := client.Get(targetURL)
	if err != nil {
		return fmt.Errorf("client.Get: %v", err)
	}
	defer resp.Body.Close()
	if _, err := io.Copy(w, resp.Body); err != nil {
		return fmt.Errorf("io.Copy: %v", 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.
  public static HttpResponse makeGetRequest(String serviceUrl) 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(serviceUrl)
            .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();
  }
}

Genera tokens de forma manual

Si invocas una función y, por algún motivo, no puedes usar las bibliotecas de autenticación, hay dos maneras de obtener el token de ID manualmente, ya sea mediante el Servidor de metadatos de Compute o mediante la creación de un JWT autofirmado y intercambiarlo por un token de ID firmado por Google.

Usa el servidor de metadatos

Puedes usar el servidor de metadatos de Compute para obtener tokens de identidad con un público específico de la siguiente manera:

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

En el que AUDIENCE es la URL de la función que se invoca, como https://GCP_REGION-PROJECT_ID.cloudfunctions.net/my-function.

Intercambia un JWT autofirmado por un token de ID firmado por Google

  1. Asigna la función de Invocador de Cloud Functions (roles/cloudfunctions.invoker) a la cuenta de servicio de la función que llama.

  2. Agrega esta cuenta de servicio como miembro de la función receptora.

  3. Crea una cuenta de servicio y una clave y descarga el archivo con la clave privada (en formato JSON) al host desde el que la función o el servicio que realiza la llamada realiza sus solicitudes.

  4. Crea un JWT con el encabezado configurado como {"alg":"RS256","typ":"JWT"}. La carga útil debe incluir una reclamación target_audience configurada para la URL de la función receptora y las reclamaciones iss y sub establecidas en la dirección de correo electrónico de la cuenta de servicio que se usó antes. También debe incluir reclamos exp y iat. La reclamación aud debe configurarse como https://www.googleapis.com/oauth2/v4/token.

  5. Usa la clave privada que descargaste antes para firmar el JWT.

  6. Con este JWT, envía una solicitud POST a https://www.googleapis.com/oauth2/v4/token. Los datos de autenticación se deben incluir en el encabezado y el cuerpo de la solicitud.

    En el encabezado:

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

    En el cuerpo:

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

    Reemplaza $JWT por el JWT que acabas de crear.

    Esto muestra otro JWT que incluye un id_token firmado por Google.

Envía tu solicitud GET/POST a la función receptora. Incluye el token de ID firmado por Google en un encabezado Authorization: Bearer ID_TOKEN_JWT en la solicitud.