Découvrez comment appeler des fonctions Cloud Run authentifiées.

1. Introduction

Présentation

Cloud Run Functions est une solution de calcul légère permettant aux développeurs de créer des fonctions autonomes à usage unique qui peuvent être déclenchées à l'aide d'HTTPS ou qui répondent aux CloudEvents sans avoir à gérer de serveur ni d'environnement d'exécution. Pour en savoir plus sur les fonctions Cloud Run, consultez cet article de blog.

Il existe deux approches principales pour contrôler les appels aux fonctions Cloud Run: sécuriser l'accès en fonction de l'identité et sécuriser l'accès à l'aide de contrôles des accès basés sur le réseau. Cet atelier de programmation se concentre sur la première approche et vous présente trois scénarios permettant de sécuriser l'accès en fonction de l'identité afin d'appeler une fonction:

  1. Utiliser votre jeton d'identité gcloud pour appeler une fonction à des fins de développement et de test en local
  2. Emprunter l'identité d'un compte de service lors du développement et des tests en local afin d'utiliser les mêmes identifiants qu'en production
  3. Utiliser les bibliothèques clientes Google pour gérer l'authentification auprès des API Google Cloud, par exemple lorsqu'un service doit appeler une fonction

Points abordés

  • Configurer l'authentification sur une fonction Cloud Run et vérifier qu'elle a été correctement configurée
  • Appeler une fonction authentifiée à partir d'un environnement de développement local en fournissant le jeton de votre identité gcloud
  • Créer un compte de service et lui attribuer le rôle approprié pour appeler une fonction
  • Impersonner un service à partir d'un environnement de développement local disposant des rôles appropriés pour appeler une fonction

2. Préparation

Prérequis

Activer Cloud Shell

  1. Dans Cloud Console, cliquez sur Activer Cloud Shell d1264ca30785e435.png.

84688aa223b1c3a2.png

Si vous démarrez Cloud Shell pour la première fois, un écran intermédiaire s'affiche pour décrire de quoi il s'agit. Si tel est le cas, cliquez sur Continuer.

d95252b003979716.png

Le provisionnement et la connexion à Cloud Shell ne devraient pas prendre plus de quelques minutes.

7833d5e1c5d18f54.png

Cette machine virtuelle contient tous les outils de développement nécessaires. Elle comprend un répertoire d'accueil persistant de 5 Go et s'exécute sur Google Cloud, ce qui améliore nettement les performances du réseau et l'authentification. Vous pouvez réaliser une grande partie, voire la totalité, des activités de cet atelier de programmation dans un navigateur.

Une fois connecté à Cloud Shell, vous êtes en principe authentifié, et le projet est défini avec votre ID de projet.

  1. Exécutez la commande suivante dans Cloud Shell pour vérifier que vous êtes authentifié :
gcloud auth list

Résultat de la commande

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

To set the active account, run:
    $ gcloud config set account `ACCOUNT`
  1. Exécutez la commande suivante dans Cloud Shell pour vérifier que la commande gcloud connaît votre projet:
gcloud config list project

Résultat de la commande

[core]
project = <PROJECT_ID>

Si vous obtenez un résultat différent, exécutez cette commande :

gcloud config set project <PROJECT_ID>

Résultat de la commande

Updated property [core/project].

3. Créer et tester une fonction Cloud Run authentifiée

Exiger une authentification signifie que le principe qui appelle la fonction doit disposer du rôle Demandeur Cloud Run. Sinon, la fonction renverra une erreur "403 Accès interdit". Dans cet atelier de programmation, vous allez découvrir comment attribuer les rôles de demandeur appropriés à un principe.

Configurez des variables d'environnement locales pour des commandes gcloud simplifiées

Tout d'abord, vous allez créer quelques variables d'environnement pour améliorer la lisibilité des commandes gcloud utilisées dans cet atelier de programmation.

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

Créer le code source de la fonction

Bien que cet atelier de programmation utilise Node.js, vous pouvez utiliser n'importe quel environnement d'exécution compatible avec les bibliothèques clientes Google Auth.

Commencez par créer un répertoire et utilisez la commande cd pour y accéder.

mkdir auth-function-codelab && cd $_

Créez ensuite le fichier package.json.

touch package.json

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

Créez ensuite le fichier source 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

Créer la fonction authentifiée

Voici la procédure à suivre afin de créer une fonction authentifiée pour l'environnement d'exécution nodejs20. Toutefois, vous pouvez utiliser n'importe quel environnement d'exécution compatible avec les bibliothèques clientes Google Auth.

FUNCTION_NAME=authenticated-function-codelab
ENTRY_POINT=helloWorld

Pour déployer une fonction Cloud Run directement sur Cloud Run, exécutez la commande suivante:

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

puis enregistrer l'URL de la fonction en tant que variable d'environnement pour l'utiliser ultérieurement.

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

Si vous préférez déployer en tant que Cloud Functions (2e génération), utilisez la commande suivante:

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

Vous pouvez ensuite enregistrer l'URL de la fonction en tant que variable d'environnement pour l'utiliser ultérieurement.

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

Vérifier que la fonction nécessite une authentification en essayant de l'appeler en tant qu'appelant anonyme

Vous allez appeler la fonction sans authentification pour vérifier que vous recevez une erreur 403 attendue.

À partir d'une ligne de commande, exécutez la commande curl suivante:

curl -i $FUNCTION_URL

Le résultat suivant s'affiche:

<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>

Vous êtes maintenant prêt à passer en revue trois scénarios dans lesquels vous pouvez appeler votre fonction en fournissant une authentification.

4. Scénario 1: Utiliser votre jeton d'identité gcloud

En tant que développeur, vous avez besoin d'un moyen de tester votre fonction pendant que vous la développez en local. Dans cette section, vous allez effectuer un test rapide pour vérifier que la fonction est correctement authentifiée à l'aide de votre propre identité.

Vérifiez que vous êtes authentifié à l'aide de gcloud en exécutant la commande suivante:

gcloud auth list

Un astérisque doit s'afficher à côté de votre identité active, par exemple:

Credentialed Accounts
ACTIVE  ACCOUNT

*       <my_account>@<my_domain.com>

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

Pour en savoir plus sur la configuration de gcloud init et de gcloud auth login, consultez la documentation.

Ensuite, appelez la fonction et transmettez-lui votre jeton d'identité.

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

Le résultat s'affiche:

Hello World!

Dépannage

Si vous recevez une erreur 403 Forbidden (Interdit), assurez-vous que votre identité dispose du rôle Demandeur Cloud Run. Vous pouvez utiliser la console IAM pour vérifier les rôles attribués à un compte principal.

Bien que l'utilisation de votre propre jeton d'identité soit un moyen rapide de tester votre fonction pendant le développement, l'appelant de votre fonction authentifiée aura besoin des rôles appropriés. Sinon, il recevra une erreur 403 "Forbidden" (Interdit).

Vous devez respecter le principe du moindre privilège en limitant le nombre d'identités et de comptes de service disposant de rôles pour appeler la fonction. Dans le scénario suivant, vous allez apprendre à créer un compte de service et à lui attribuer les rôles appropriés pour appeler la fonction.

5. Scénario 2: Emprunter l'identité d'un compte de service

Dans ce scénario, vous empruntez l'identité d'un compte de service (c'est-à-dire, vous assumez les autorisations de) pour appeler une fonction lors du développement et des tests en local. En empruntant l'identité d'un compte de service, vous pouvez tester votre fonction avec les mêmes identifiants qu'en production.

Ainsi, non seulement vous vérifierez les rôles, mais vous appliquerez également le principe du moindre privilège en vous évitant d'avoir à attribuer le rôle Demandeur de fonction Cloud à d'autres identités uniquement à des fins de test local.

Pour les besoins de cet atelier de programmation, vous allez créer un compte de service qui ne dispose que de rôles permettant d'appeler la fonction que vous avez créée dans cet atelier.

Créer un compte de service

Vous allez d'abord créer quelques variables d'environnement supplémentaires pour représenter les comptes de service utilisés dans les commandes gcloud.

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

Vous allez ensuite créer le compte de service.

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

Attribuez au compte de service le rôle de demandeur Cloud Run:

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

Appeler la fonction en usurpant l'identité du compte de service

Pour cela, vous emprunterez l'identité du compte de service nouvellement créé en obtenant son jeton d'ID.

Ajouter les rôles requis pour l'usurpation d'identité

Pour usurper l'identité d'un compte de service, votre compte utilisateur doit disposer du rôle Créateur de jetons du compte de service (roles/iam.serviceAccountTokenCreator) afin de générer un jeton d'identité pour le compte de service.

Vous pouvez exécuter les commandes suivantes pour attribuer ce rôle à votre compte utilisateur actif:

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'

Utiliser le jeton d'ID du compte de service

Attendez quelques minutes que les autorisations soient propagées. Vous pouvez maintenant appeler la fonction en transmettant le jeton d'ID du compte de service.

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

Les résultats suivants s'affichent:

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. Scénario 3: Utiliser les bibliothèques clientes Google

Pour cette dernière partie de l'atelier de programmation, vous allez exécuter un petit service localement afin de générer un jeton d'ID pour un compte de service, puis appeler de manière programmatique la fonction à l'aide des bibliothèques clientes Google Auth et des identifiants par défaut de l'application (ADC). Pour en savoir plus sur les bibliothèques clientes Google, consultez la section Présentation des bibliothèques clientes de la documentation.

L'utilisation de la stratégie ADC est particulièrement importante lorsque vous souhaitez écrire et tester une fonction en local (par exemple, sur votre ordinateur portable, dans Cloud Shell, etc.) tout en interagissant avec d'autres ressources Google Cloud (par exemple, Cloud Storage, l'API Vision, etc.). Dans cet exemple, vous verrez comment faire en sorte qu'un service appelle une autre fonction nécessitant une authentification. Pour en savoir plus sur l'ADC et le développement local, consultez l'article de blog Développer et tester vos fonctions Cloud localement | Blog Google Cloud.

Exécuter la commande gcloud pour emprunter l'identité d'un compte de service

Les identifiants par défaut de l'application trouvent automatiquement des identifiants en fonction de l'environnement de l'application et les utilisent pour s'authentifier auprès des API Google Cloud. L'indicateur –impersonate-service-account vous permet d'usurper l'identité d'un compte de service pour vous authentifier auprès des API Google Cloud.

Pour usurper l'identité d'un compte de service, vous pouvez exécuter la commande suivante:

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

Vous exécutez désormais des commandes gcloud en tant que compte de service, et non en tant que votre identité.

Créer et exécuter un service pour appeler une fonction authentifiée

Chaque environnement d'exécution dispose de sa propre bibliothèque cliente Google Auth que vous pouvez installer. Cet atelier de programmation vous explique comment créer et exécuter une application Node.js localement.

Voici les étapes à suivre pour Node.js:

  1. Créer un répertoire
mkdir local-dev && cd $_
  1. Créer une application Node.js
npm init -y
  1. Installer la bibliothèque cliente Google Auth
npm install google-auth-library
  1. Créer un fichier index.js
  2. Récupérez l'URL de votre fonction Cloud Run, que vous ajouterez à votre code à l'étape suivante.
echo $FUNCTION_URL
  1. Ajoutez le code suivant à index.js. Veillez à remplacer la variable targetAudience par l'URL de votre fonction 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. Exécuter l'application
node index.js

Le message "Hello World!" devrait s'afficher.

Dépannage

Si vous voyez un message d'erreur indiquant que l'autorisation "iam.serviceAccounts.getOpenIdToken" a été refusée sur la ressource (ou qu'elle n'existe peut-être pas), veuillez patienter quelques minutes pour que le rôle Créateur de jetons de compte de service se propage.

Si le message d'erreur "Impossible de récupérer le jeton d'ID dans cet environnement", utilisez GCE ou définissez la variable d'environnement GOOGLE_APPLICATION_CREDENTIALS sur un fichier JSON d'identifiants de compte de service, vous avez peut-être oublié d'exécuter la commande.

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

7. Félicitations !

Félicitations ! Vous avez terminé cet atelier de programmation.

Nous vous recommandons de consulter la documentation sur la sécurisation des fonctions Cloud Run.

Nous vous recommandons également de lire cet article de blog sur le développement local avec les fonctions Cloud Run pour découvrir comment développer et tester votre fonction Cloud Run dans votre environnement de développement local.

Points abordés

  • Configurer l'authentification sur une fonction Cloud Run et vérifier qu'elle a été correctement configurée
  • Appeler une fonction authentifiée à partir d'un environnement de développement local en fournissant le jeton de votre identité gcloud
  • Créer un compte de service et lui attribuer le rôle approprié pour appeler une fonction
  • Impersonner un service à partir d'un environnement de développement local disposant des rôles appropriés pour appeler une fonction

8. Effectuer un nettoyage

Pour éviter les frais involontaires (par exemple, si cette fonction Cloud est appelée par inadvertance plus de fois que votre quota mensuel d'appels de fonctions Cloud Run dans le niveau sans frais), vous pouvez supprimer la fonction Cloud ou le projet que vous avez créé à l'étape 2.

Pour arrêter d'emprunter l'identité du compte de service, vous pouvez vous reconnecter à l'aide de votre identité:

gcloud auth application-default login

Pour supprimer la fonction Cloud Run, accédez à la console Cloud Console des fonctions Cloud Run à l'adresse https://console.cloud.google.com/functions/. Assurez-vous que le projet que vous avez créé à l'étape 2 est le projet actuellement sélectionné.

Sélectionnez la fonction my-authenticated-function que vous avez déployée précédemment. Appuyez ensuite sur Supprimer.

Si vous choisissez de supprimer l'ensemble du projet, accédez à https://console.cloud.google.com/cloud-resource-manager, sélectionnez le projet que vous avez créé à l'étape 2, puis choisissez "Supprimer". Si vous supprimez le projet, vous devrez le modifier dans Cloud SDK. Vous pouvez afficher la liste de tous les projets disponibles en exécutant gcloud projects list.