Obtén información para invocar funciones de Cloud Run autenticadas

1. Introducción

Descripción general

Cloud Run 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. Obtén más información sobre las funciones de Cloud Run en nuestra entrada de blog.

Existen dos enfoques principales para controlar las invocaciones a las funciones de Cloud Run: proteger el acceso según la identidad y proteger el acceso con controles de acceso basados en la red. En 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. Usa tu token de identidad de gcloud para invocar una función con fines de desarrollo y pruebas locales
  2. Robo de identidad de una cuenta de servicio cuando se desarrolla y prueba de forma local para usar las mismas credenciales que en producción
  3. Usa bibliotecas cliente de Google para controlar la autenticación en 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 función de Cloud Run y verificar que se haya configurado correctamente
  • Proporciona el token de tu identidad de gcloud para invocar una función autenticada desde un entorno de desarrollo local
  • Cómo crear una cuenta de servicio y otorgarle el rol adecuado para invocar una función
  • Cómo suplantar la identidad de un servicio desde un entorno de desarrollo local que tenga los roles adecuados para invocar una función

2. Configuración y requisitos

Requisitos previos

Activar Cloud Shell

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

84688aa223b1c3a2.png

Si es la primera vez que inicias Cloud Shell, aparecerá una pantalla intermedia que describe en qué consiste. Si se te presentó una pantalla intermedia, haz clic en Continuar.

d95252b003979716.png

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

7833d5e1c5d18f54.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 se te autenticó y que el proyecto se configuró con tu ID de 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 función de Cloud Run autenticada

Exigir autenticación significa que el principio que invoca la función debe tener el rol de Invocador de Cloud Run; 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.

Configura variables de entorno locales para comandos de gcloud simplificados

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

REGION=us-central1
PROJECT_ID=$(gcloud config get-value project)

Crea el código fuente para la función

Aunque en este codelab se usa Node.js, puedes usar cualquier entorno de ejecución que admitan las bibliotecas cliente de Google Auth.

Primero, crea un directorio y desplázate a él con el comando cd.

mkdir auth-function-codelab && cd $_

Luego, crea el archivo package.json.

touch package.json

echo '{
  "dependencies": {
    "@google-cloud/functions-framework": "^3.0.0"
  }
}
' > package.json

A continuación, crea el archivo fuente index.js.

touch index.js

echo 'const functions = require("@google-cloud/functions-framework");

functions.http("helloWorld", (req, res) => {
 res.send(`Hello ${req.query.name || req.body.name || "World"}!`);
});' > index.js

Crea la función autenticada

Estos son los pasos para crear una función autenticada para el entorno de ejecución de nodejs20. Sin embargo, puedes usar cualquier entorno de ejecución que admitan las bibliotecas cliente de Google Auth.

FUNCTION_NAME=authenticated-function-codelab
ENTRY_POINT=helloWorld

Para implementar una función de Cloud Run directamente en Cloud Run, ejecuta el siguiente comando:

gcloud beta run deploy $FUNCTION_NAME \
      --source . \
      --function helloWorld \
      --region $REGION \
      --no-allow-unauthenticated

y, luego, puedes guardar la URL de la función como una variable de entorno para usarla más tarde.

FUNCTION_URL="$(gcloud run services describe $FUNCTION_NAME --region $REGION --format 'value(status.url)')"

Si prefieres implementarla como una función de Cloud Functions de 2ª gen., usa el siguiente comando:

gcloud functions deploy nodejs-http-function \
  --gen2 \
  --runtime=nodejs20 \
  --region=$REGION \
  --source=. \
  --entry-point=helloWorld \
  --trigger-http \
  --no-allow-unauthenticated

y, luego, puedes guardar la URL de la función como una variable de entorno para usarla más tarde.

FUNCTION_URL="$(gcloud functions describe $FUNCTION_NAME --gen2 --region us-central1 --format='get(serviceConfig.uri)')"

Verifica que la función requiera autenticación intentando invocar como un llamador anónimo.

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

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

curl -i $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á todo listo para analizar 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 tener una forma de probar tu función mientras la desarrollas de forma local. En esta sección, realizarás una prueba rápida para verificar que la función se autentique correctamente con tu propia identidad.

Ejecuta el siguiente comando para verificar que tienes la autenticación de 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`

Puedes encontrar más información para configurar gcloud init y acceder con gcloud auth en la documentación.

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!

Solución de problemas

Si recibes un error 403 Forbidden, asegúrate de que tu identidad tenga el rol de Invocador de Cloud Run. 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 correspondientes. De lo contrario, el emisor 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. En la siguiente situación, aprenderás a crear una cuenta de servicio nueva y otorgarle los roles adecuados para invocar la función.

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

En esta situación, suplantarás (es decir, asumirás los permisos de) una cuenta de servicio para invocar una función cuando desarrolles y pruebes de forma local. Si suplantas la identidad de una cuenta de servicio, puedes probar tu 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 Functions a otras identidades solo para pruebas locales.

Para los fines de este codelab, crearás una cuenta de servicio nueva que solo tenga 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 Run function Authentication codelab"

Y otorga el rol de invocador de Cloud Run a la cuenta de servicio:

gcloud run services add-iam-policy-binding $FUNCTION_NAME \
  --region=us-central1  \
  --member serviceAccount:$SERVICE_ACCOUNT_ADDRESS \
  --role='roles/run.invoker'

Invoca la función con la identidad de la cuenta de servicio

Para ello, obtendrás su token de ID y suplantarás la identidad de la cuenta de servicio recién creada.

Agrega los roles necesarios para la suplantación de identidad

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

Puedes ejecutar los siguientes comandos para otorgar este rol a tu cuenta de usuario activa:

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

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

Espera unos minutos para que se propaguen los permisos. 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 para generar un token de ID para una cuenta de servicio y, luego, llamarás a la función de forma programática con las bibliotecas cliente de Google Auth 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 forma local (p. ej., en tu laptop, en Cloud Shell, etc.) mientras interactúas con otros recursos de Google Cloud (p. ej., Cloud Storage, API de Vision, etc.). 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 funciones de Cloud Functions de forma local | Blog de Google Cloud.

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

Las ADC encuentran credenciales automáticamente según el entorno de la aplicación y las usan para autenticarse en las APIs de Google Cloud. La marca –impersonate-service-account te permite suplantar la identidad de una cuenta de servicio con su identidad para la autenticación en las APIs de Google Cloud.

Para suplantar la identidad 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 un directorio nuevo
mkdir local-dev && cd $_
  1. Crea una nueva app de Node.js
npm init -y
  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 función de Cloud Run, 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 a la URL de tu función de Cloud Run.

index.js

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

const targetAudience = '<YOUR-CLOUD-RUN-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 mensaje "Hello World!" resultante.

Solución de problemas

Si ves un error que indica que se denegó el permiso "iam.serviceAccounts.getOpenIdToken" en el recurso (o que es posible que no exista), espera unos minutos para que se propague el rol de creador de tokens de la cuenta de servicio.

Si recibiste el error Cannot fetch ID token in this environment, use GCE or set the GOOGLE_APPLICATION_CREDENTIALS environment variable to a service account credentials JSON file, 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 las funciones de Cloud Run.

También te recomendamos esta entrada de blog sobre desarrollo local con funciones de Cloud Run para aprender a desarrollar y probar tu función de Cloud Run en tu entorno de desarrollador local.

Temas abordados

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

8. Limpia

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

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

gcloud auth application-default login

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

Selecciona la my-authenticated-function que implementaste anteriormente. Luego, presiona Borrar.

Si decides borrar todo el proyecto, 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.