Aprende a invocar Cloud Functions autenticados

1. Introducción

Descripción general

Cloud Functions es una solución de procesamiento ligera que permite a los desarrolladores crear funciones independientes y de un solo propósito que se pueden activar con HTTPS o responder a CloudEvents sin necesidad de administrar un servidor o un entorno de ejecución.

Existen dos enfoques principales para controlar las invocaciones a Cloud Functions: proteger el acceso según la identidad y proteger el acceso con controles de acceso basados en la red. Este codelab se enfoca en el primer enfoque y te guía a través de 3 situaciones para proteger el acceso basado en la identidad para invocar una función:

  1. Usar tu token de identidad de gcloud a fin de invocar una función para el desarrollo local y con fines de prueba
  2. Usar la identidad de una cuenta de servicio durante el desarrollo y las pruebas locales para usar las mismas credenciales que en la producción
  3. Usa las bibliotecas cliente de Google para administrar la autenticación de las APIs de Google Cloud, p.ej., Cuando un servicio necesita invocar una función

Qué aprenderás

  • Cómo configurar la autenticación en una Cloud Function y verificar que se haya configurado correctamente
  • Invoca una función autenticada desde un entorno de desarrollo local proporcionando el token para tu identidad de gcloud.
  • Cómo crear una cuenta de servicio y otorgarle el rol adecuado para invocar una función
  • Cómo usar la identidad de un servicio de un entorno de desarrollo local que tiene los roles adecuados para invocar una función

2. Configuración y requisitos

Requisitos previos

  • Accediste a la consola de Cloud
  • Ya implementaste una Cloud Function de 2a gen. activada por HTTP
  • (opcional) En la tercera situación, este codelab usa Node.js y npm como ejemplo, pero puedes usar cualquier entorno de ejecución que sea compatible con las bibliotecas cliente de Google Auth.

Activar Cloud Shell

  1. En la consola de Cloud, haz clic en Activar Cloud Shell853e55310c205094.png.

55efc1aaa7a4d3ad.png

Si es la primera vez que inicias Cloud Shell, verás una pantalla intermedia que describe en qué consiste. Si apareció una pantalla intermedia, haz clic en Continuar.

9c92662c6a846a5c.png

El aprovisionamiento y la conexión a Cloud Shell solo tomará unos minutos.

9f0e51b578fecce5.png

Esta máquina virtual está cargada con todas las herramientas de desarrollo necesarias. Ofrece un directorio principal persistente de 5 GB y se ejecuta en Google Cloud, lo que mejora considerablemente el rendimiento de la red y la autenticación. Gran parte de tu trabajo en este codelab, si no todo, se puede hacer con un navegador.

Una vez que te conectes a Cloud Shell, deberías ver que estás autenticado y que el proyecto está configurado con tu ID del proyecto.

  1. En Cloud Shell, ejecuta el siguiente comando para confirmar que tienes la autenticación:
gcloud auth list

Resultado del comando

 Credentialed Accounts
ACTIVE  ACCOUNT
*       <my_account>@<my_domain.com>

To set the active account, run:
    $ gcloud config set account `ACCOUNT`
  1. Ejecuta el siguiente comando en Cloud Shell para confirmar que el comando de gcloud conoce tu proyecto:
gcloud config list project

Resultado del comando

[core]
project = <PROJECT_ID>

De lo contrario, puedes configurarlo con el siguiente comando:

gcloud config set project <PROJECT_ID>

Resultado del comando

Updated property [core/project].

3. Crea y prueba una Cloud Function autenticada

En este codelab, se siguen las mismas instrucciones de la Guía de inicio rápido de Console para Cloud Functions, con una excepción notable: la función requerirá autenticación.

Solicitar autenticación significa que el principio que invoca la función debe tener los roles de Invocador de Cloud Functions (y de Invocador de Cloud Run para 2a gen.). De lo contrario, la función mostrará un error 403 Forbidden. En este codelab, se mostrará cómo otorgar los roles de Invocador adecuados a un principio.

Crea la función autenticada

Estos son los pasos para usar la consola de Cloud:

  1. Ve a la página Descripción general de Cloud Functions y haz clic en Crear función.
  2. En la opción Entorno, selecciona 2nd gen.
  3. Asigna el nombre my-authenticated-function a la función.
  4. En el campo Autenticación, deja la opción predeterminada Solicitar autenticación.

936eee0d5930d12b.png

  1. Haz clic en Siguiente.
  2. En este codelab, puedes elegir cualquier lenguaje
  3. Luego, haz clic en Implementar.

La implementación de la función tarda aproximadamente 1 minuto.

Configura variables de entorno local para comandos simplificados de gcloud

Primero, crearás algunas variables de entorno para mejorar la legibilidad de los comandos gcloud que se usan en este codelab.

Deberás especificar la región para tu Function. En este ejemplo, se usa us-central1.

REGION="us-central1"

Luego, puedes guardar la URL de la función como una variable de entorno para usarla más adelante.

PROJECT_ID=$(gcloud config get-value project)
FUNCTION_URL="$(gcloud functions describe my-authenticated-function --gen2 --region us-central1 --format='get(serviceConfig.uri)')"

Verifica que la función requiera autenticación. Para ello, intenta invocarla como un emisor anónimo

Invocarás la función sin autenticación para verificar que recibas el error 403 esperado.

Desde una línea de comandos, ejecuta el siguiente comando curl:

curl $FUNCTION_URL

Verás el siguiente resultado:

<html><head>
<meta http-equiv="content-type" content="text/html;charset=utf-8">
<title>403 Forbidden</title>
</head>
<body text=#000000 bgcolor=#ffffff>
<h1>Error: Forbidden</h1>
<h2>Your client does not have permission to get URL <code>/</code> from this server.</h2>
<h2></h2>
</body></html>

Ya estás listo para ver 3 situaciones en las que puedes invocar tu función proporcionando autenticación.

4. Situación 1: Usa tu token de identidad de gcloud

Como desarrollador, querrás probar tu función mientras la desarrollas de manera local. En esta sección, realizarás una prueba rápida para verificar que la función se autenticó correctamente con tu propia identidad.

Ejecuta el siguiente comando para verificar que estás autenticado con gcloud:

gcloud auth list

Deberías ver un asterisco junto a tu identidad activa, por ejemplo:

Credentialed Accounts
ACTIVE  ACCOUNT

*       <my_account>@<my_domain.com>

To set the active account, run:
    $ gcloud config set account `ACCOUNT`

Una vez que hayas verificado que usas la identidad correcta, guardarás el correo electrónico de la cuenta en una variable de entorno.

ACCOUNT_EMAIL=$(gcloud auth list --filter=status:ACTIVE --format="value(account)")

Puedes encontrar más información para configurar gcloud init y gcloud auth login en los documentos.

A continuación, invoca la función y pásale tu token de identidad.

curl $FUNCTION_URL -H "Authorization: bearer $(gcloud auth print-identity-token)"

Ahora verás el resultado:

Hello World!

Soluciona problemas

Si recibes un error 403 Forbidden, asegúrate de que tu identidad tenga el rol de invocador de Cloud Functions o el rol de invocador de Cloud Run para las funciones de 2a gen. Puedes usar la consola de IAM para verificar los roles otorgados a una principal.

Aunque usar tu propio token de identidad es una forma rápida de probar tu función durante el desarrollo, el llamador de tu función autenticada necesitará los roles adecuados; De lo contrario, el llamador recibirá un error 403 Forbidden.

Recomendamos que sigas el principio de privilegio mínimo limitando la cantidad de identidades y cuentas de servicio que tienen roles para invocar la función.

crear una cuenta de servicio nueva y otorgarle los roles necesarios,

5. Situación 2: Usa la identidad de una cuenta de servicio

En esta situación, suplantarás la identidad (es decir, supondrás los permisos de) una cuenta de servicio para invocar una función durante el desarrollo y las pruebas locales. Si suplantas la identidad de una cuenta de servicio, puedes probar la función con las mismas credenciales que en producción.

De esta manera, no solo verificarás los roles, sino que también seguirás el principio de privilegio mínimo, ya que no tendrás que otorgar el rol de Invocador de Cloud Function a otras identidades solo con fines de prueba local.

A los fines de este codelab, crearás una nueva cuenta de servicio que solo tendrá roles para invocar la función que creaste en este codelab.

Crear una nueva cuenta de servicio

Primero, crearás algunas variables de entorno adicionales para representar las cuentas de servicio que se usan en los comandos de gcloud.

SERVICE_ACCOUNT_NAME="invoke-functions-codelab"
SERVICE_ACCOUNT_ADDRESS=$SERVICE_ACCOUNT_NAME@$PROJECT_ID.iam.gserviceaccount.com

A continuación, crearás la cuenta de servicio.

gcloud iam service-accounts create $SERVICE_ACCOUNT_NAME \
  --display-name="Cloud Function Authentication codelab"

Y otorga el rol de invocador de Cloud Function de la cuenta de servicio

gcloud functions add-iam-policy-binding my-authenticated-function \
  --region=us-central1 --gen2 \
  --member serviceAccount:$SERVICE_ACCOUNT_ADDRESS \
  --role='roles/cloudfunctions.invoker'

Usa la cuenta de servicio para invocar la función.

Para ello, usarás la identidad de la cuenta de servicio recién creada a través de la obtención de su token de ID.

Agrega los roles necesarios para la suplantación de identidad

Para usar la identidad de una cuenta de servicio, tu cuenta de usuario debe tener el rol de creador de tokens de cuentas de servicio (roles/iam.serviceAccountTokenCreator) para generar un token de ID para la cuenta de servicio.

gcloud iam service-accounts add-iam-policy-binding $SERVICE_ACCOUNT_ADDRESS  \
  --member user:$ACCOUNT_EMAIL \
  --role='roles/iam.serviceAccountTokenCreator'

Usa el token de ID de la cuenta de servicio

Ahora puedes invocar la función pasando el token de ID de la cuenta de servicio.

curl $FUNCTION_URL -H "Authorization: bearer $(gcloud auth print-identity-token --impersonate-service-account $SERVICE_ACCOUNT_ADDRESS)" 

Verás lo siguiente:

WARNING: This command is using service account impersonation. All API calls will be executed as [invoke-functions-codelab@<project-id>.iam.gserviceaccount.com].
Hello World!

6. Situación 3: Usa bibliotecas cliente de Google

En esta última parte del codelab, ejecutarás un servicio pequeño de forma local con el objetivo de generar un token de ID para una cuenta de servicio y, luego, llamarás de manera programática a la función con las bibliotecas cliente de autenticación de Google y las credenciales predeterminadas de la aplicación (ADC). Puedes obtener más información sobre las bibliotecas cliente de Google en la sección explicada sobre bibliotecas cliente de los documentos.

El uso de ADC es especialmente importante cuando deseas escribir y probar tu función de manera local (p.ej., en tu laptop, en Cloud Shell, etc.) mientras interactúas con otros recursos de Google Cloud (p.ej., Cloud Storage, la API de Vision, etcétera). En este ejemplo, verás cómo hacer que un servicio invoque otra función que requiera autenticación. Para obtener más información sobre ADC y el desarrollo local, consulta la entrada de blog Cómo desarrollar y probar tus Cloud Functions de forma local | Blog de Google Cloud

Ejecuta el comando de gcloud para usar la identidad de una cuenta de servicio

ADC encuentra automáticamente las credenciales en función del entorno de la aplicación y las usa para autenticarse en las APIs de Google Cloud. La marca –impersonate-service-account permite usar la identidad de una cuenta de servicio para la autenticación en las APIs de Google Cloud.

Para actuar en nombre de una cuenta de servicio, puedes ejecutar el siguiente comando:

gcloud auth application-default login --impersonate-service-account=$SERVICE_ACCOUNT_ADDRESS

Ahora estás ejecutando los comandos de gcloud como esa cuenta de servicio, en lugar de tu identidad.

Crea y ejecuta un servicio para invocar una función autenticada

Cada entorno de ejecución tiene su propia biblioteca cliente de Google Auth que puedes instalar. En este codelab, aprenderás a crear y ejecutar una app de Node.js de forma local.

Estos son los pasos para Node.js:

  1. Crea una app de Node.js nueva
npm init
  1. Instala la biblioteca cliente de Google Auth
npm install google-auth-library
  1. Crea un archivo index.js
  2. Recupera la URL de tu Cloud Function, que agregarás a tu código en el siguiente paso.
echo $FUNCTION_URL
  1. Agrega el siguiente código a index.js. Asegúrate de cambiar la variable targetAudience por tu URL de Cloud Function.

index.js

// Cloud Functions uses your function's url as the `targetAudience` value

const targetAudience = '<YOUR-CLOUD-FUNCTION-URL>';

// 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}`);

    // this call retrieves the ID token for the impersonated service account
    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;
});
  1. Ejecuta la app
node index.js

Deberías ver el resultado "Hello World!"

Soluciona problemas

Si ves el error Permiso “iam.serviceAccounts.getOpenIdToken” denegado en el recurso (o es posible que no exista). Espera unos minutos para que se propague el rol de creador de tokens de cuentas de servicio.

Si recibiste el mensaje de error No se puede recuperar el token de ID en este entorno, usa GCE o establece la variable de entorno GOOGLE_APPLICATION_CREDENTIALS en un archivo JSON de credenciales de cuenta de servicio, es posible que hayas olvidado ejecutar el comando.

gcloud auth application-default login --impersonate-service-account=$SERVICE_ACCOUNT_ADDRESS

7. ¡Felicitaciones!

¡Felicitaciones por completar el codelab!

Te recomendamos que revises la documentación sobre cómo proteger Cloud Functions.

También recomendamos esta entrada de blog sobre el desarrollo local con Cloud Functions para aprender a desarrollar y probar tu Cloud Function en tu entorno de desarrollador local.

Temas abordados

  • Cómo configurar la autenticación en una Cloud Function y verificar que se haya configurado correctamente
  • Invoca una función autenticada desde un entorno de desarrollo local proporcionando el token para tu identidad de gcloud.
  • Cómo crear una cuenta de servicio y otorgarle el rol adecuado para invocar una función
  • Cómo usar la identidad de un servicio de un entorno de desarrollo local que tiene los roles adecuados para invocar una función

8. Limpia

Para evitar cargos involuntarios (por ejemplo, esta Cloud Function se invoca de forma involuntaria más veces que tu asignación mensual de invocación de Cloud Function en el nivel gratuito), puedes borrar la Cloud Function o borrar el proyecto que creaste en el paso 2.

Para dejar de usar la identidad de la cuenta de servicio, puedes volver a acceder con tu identidad:

gcloud auth application-default login

Para borrar la Cloud Function, ve a la consola de Cloud Function en https://console.cloud.google.com/functions/. Asegúrate de que el proyecto que creaste en el paso 2 sea el que está seleccionado actualmente.

Selecciona la función my-authenticated-function que implementaste antes. Luego, presiona Borrar.

Si decides borrar el proyecto completo, puedes ir a https://console.cloud.google.com/cloud-resource-manager, seleccionar el proyecto que creaste en el paso 2 y elegir Borrar. Si borras el proyecto, deberás cambiar los proyectos en tu SDK de Cloud. Para ver la lista de todos los proyectos disponibles, ejecuta gcloud projects list.