了解如何调用经过身份验证的 Cloud Run 函数

1. 简介

概览

Cloud Run functions 是一个轻量级计算解决方案,可供开发者创建单一用途的独立函数,无需管理服务器或运行时环境即可使用 HTTPS 触发或对 CloudEvents 作出响应。如需详细了解 Cloud Run functions,请参阅我们的博文

您可以通过两种主要方法控制对 Cloud Run functions 的调用: 基于身份保护访问权限,以及使用 基于网络的访问权限控制保护访问权限。此 Codelab 重点介绍第一种方法,并引导您了解 3 种基于身份保护访问权限以调用函数的场景:

  1. 使用 gcloud 身份令牌调用函数以进行本地开发和测试
  2. 在本地开发和测试时模拟服务账号,以使用与生产环境相同的凭据
  3. 使用 Google 客户端库处理对 Google Cloud API 的身份验证,例如当服务需要调用函数时

学习内容

  • 如何在 Cloud Run 函数上配置身份验证,以及如何验证身份验证是否已正确配置
  • 通过提供 gcloud 身份的令牌,从本地开发环境调用经过身份验证的函数
  • 如何创建服务账号并向其授予调用函数所需的适当角色
  • 如何从本地开发环境模拟服务,该环境具有调用函数所需的适当角色

2. 设置和要求

前提条件

激活 Cloud Shell

  1. 在 Cloud 控制台中,点击 激活 Cloud Shell d1264ca30785e435.png

84688aa223b1c3a2.png

如果您是首次启动 Cloud Shell,系统会显示一个介绍其功能的过渡页面。如果您看到过渡页面,请点击继续

d95252b003979716.png

预配和连接到 Cloud Shell 只需花几分钟时间。

7833d5e1c5d18f54.png

此虚拟机加载了所有必需的开发工具。它提供了一个持久性 5 GB 主目录,并在 Google Cloud 中运行,从而大大提升了网络性能和身份验证。 只需使用一个浏览器即可完成本 Codelab 中的大部分工作。

在连接到 Cloud Shell 后,您应该会看到自己已通过身份验证,并且相关项目已设置为您的项目 ID。

  1. 在 Cloud Shell 中运行以下命令以确认您已通过身份验证:
gcloud auth list

命令输出

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

To set the active account, run:
    $ gcloud config set account `ACCOUNT`
  1. 在 Cloud Shell 中运行以下命令,以确认 gcloud 命令了解您的项目:
gcloud config list project

命令输出

[core]
project = <PROJECT_ID>

如果不是上述结果,您可以使用以下命令进行设置:

gcloud config set project <PROJECT_ID>

命令输出

Updated property [core/project].

3. 创建并测试经过身份验证的 Cloud Run 函数

要求进行身份验证意味着调用函数的委托人必须具有 Cloud Run Invoker 角色;否则,函数将返回 403 Forbidden 错误。此 Codelab 将展示 如何向委托人授予适当的 Invoker 角色

设置本地环境变量以简化 gcloud 命令

首先,您将创建几个环境变量,以提高此 Codelab 中使用的 gcloud 命令的可读性。

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

创建函数的源代码

虽然此 Codelab 使用 Node.js,但您可以使用 Google Auth 客户端库支持的任何运行时。

首先,创建一个目录并 cd 到该目录。

mkdir auth-function-codelab && cd $_

然后,创建 package.json 文件。

touch package.json

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

接下来,创建 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

创建经过身份验证的函数

以下是为 nodejs20 运行时创建经过身份验证的函数的步骤。不过,您可以使用 Google Auth 客户端库支持的任何运行时。

FUNCTION_NAME=authenticated-function-codelab
ENTRY_POINT=helloWorld

如需将 Cloud Run 函数直接部署到 Cloud Run,请运行以下命令:

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

然后,您可以将函数网址另存为环境变量,以供日后使用。

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

如果您希望部署为 Cloud Functions 第 2 代,请使用以下命令:

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

然后,您可以将函数网址另存为环境变量,以供日后使用。

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

尝试以匿名来电者的身份调用函数,以验证该函数是否需要身份验证

您将调用该函数而不进行身份验证,以验证您是否收到预期的 403 错误。

在命令行中,运行以下 curl 命令:

curl -i $FUNCTION_URL

您将看到以下结果:

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

现在,您已准备好了解 3 种场景,在这些场景中,您可以通过提供身份验证来调用函数。

4. 场景 1:使用 gcloud 身份令牌

作为开发者,您希望在本地开发函数时对其进行 测试。在本部分中,您将执行快速测试,以验证函数是否使用您自己的身份正确通过身份验证。

运行以下命令,验证您是否使用 gcloud 通过身份验证:

gcloud auth list

您应该会在有效身份旁边看到一个星号,例如:

Credentialed Accounts
ACTIVE  ACCOUNT

*       <my_account>@<my_domain.com>

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

如需详细了解如何设置 gcloud initgcloud auth login,请参阅文档。

接下来,调用函数并向其传递您的身份令牌。

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

现在,您将看到以下结果:

Hello World!

问题排查

如果您收到 403 Forbidden 错误,请确保您的身份具有 Cloud Run Invoker 角色。您可以使用 IAM 控制台 验证授予委托人的角色。

虽然使用您自己的身份令牌是在开发期间测试函数的快速方法,但经过身份验证的函数的调用方需要具有适当的角色;否则,调用方将收到 403 Forbidden 错误。

您需要遵循 最小权限原则,限制具有调用函数角色的身份和服务账号的数量。在下一个场景中,您将了解如何创建新的服务账号并向其授予调用函数所需的适当角色。

5. 场景 2:模拟服务账号

在此场景中,您将在本地开发和测试时 模拟(即假定具有权限)服务账号以调用函数。通过模拟服务账号,您可以测试函数,并使用与生产环境相同的凭据。

这样做不仅可以验证角色,还可以遵循最小权限原则,而无需仅出于本地测试目的向其他身份授予 Cloud Functions Invoker 角色。

在此 Codelab 中,您将创建一个新的服务账号,该账号仅具有调用您在此 Codelab 中创建的函数所需的角色。

创建新服务账号

首先,您将创建几个额外的环境变量来表示 gcloud 命令中使用的服务账号。

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

接下来,您将创建服务账号。

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

并向服务账号授予 Cloud Run Invoker 角色:

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

通过模拟服务账号调用函数

为此,您将通过获取新创建的服务账号的 ID 令牌来模拟该账号。

添加模拟所需的角色

如需模拟服务账号,您的用户账号需要具有 Service Account Token Creator (roles/iam.serviceAccountTokenCreator) 角色,才能为服务账号生成 ID 令牌。

您可以运行以下命令,向您的有效用户账号授予此角色:

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'

使用服务账号的 ID 令牌

等待几分钟,让权限传播。现在,您可以通过传递服务账号的 ID 令牌来调用函数。

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

您将看到以下内容:

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. 场景 3:使用 Google 客户端库

在此 Codelab 的最后一部分中,您将在本地运行一个 小型服务,为服务账号生成 ID 令牌,然后使用 Google Auth 客户端库应用默认凭据 (ADC)以程序化方式调用函数。如需详细了解 Google 客户端库,请参阅文档的 客户端库说明部分

当您希望在本地(例如在笔记本电脑、Cloud Shell 等中)编写和测试函数,同时与其他 Google Cloud 资源(例如 Cloud Storage、Vision API 等)进行交互时,使用 ADC 尤为重要。在此示例中,您将了解如何让服务调用另一个需要身份验证的函数。如需详细了解 ADC 和本地开发,请参阅博文 如何在本地开发和测试 Cloud Functions | Google Cloud 博客

运行 gcloud 命令以模拟服务账号

ADC 会根据应用环境自动查找凭据,并使用这些凭据向 Google Cloud API 进行身份验证。借助 –impersonate-service-account 标志,您可以使用服务账号的身份向 Google Cloud API 进行身份验证,从而模拟服务账号。

如需模拟服务账号,您可以运行以下命令:

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

现在,您将以该服务账号的身份(而不是您的身份)运行 gcloud 命令。

创建并运行服务以调用经过身份验证的函数

每个运行时都有自己的 Google Auth 客户端库,您可以安装该库。此 Codelab 将引导您完成在本地创建和运行 Node.js 应用的过程。

以下是 Node.js 的步骤:

  1. 创建新目录
mkdir local-dev && cd $_
  1. 创建新的 Node.js 应用
npm init -y
  1. 安装 Google Auth 客户端库
npm install google-auth-library
  1. 创建 index.js 文件
  2. 检索 Cloud Run 函数的网址,您将在下一步中将其添加到代码中。
echo $FUNCTION_URL
  1. 将以下代码添加到 index.js。请务必将 targetAudience 变量更改为您的 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. 运行应用
node index.js

您应该会看到结果“Hello World!”

问题排查

如果您看到错误 Permission ‘iam.serviceAccounts.getOpenIdToken' denied on resource (or it may not exist).,请等待几分钟,让 Service Account Token Creator 角色传播。

如果您收到错误 Cannot fetch ID token in this environment, use GCE or set the GOOGLE_APPLICATION_CREDENTIALS 环境变量 to a 服务账号 credentials JSON file,则可能是您忘记运行命令

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

7. 恭喜!

恭喜您完成此 Codelab!

我们建议您查看有关如何保护 Cloud Run 函数的文档。

我们还建议您阅读这篇有关 使用 Cloud Run functions 进行本地开发 的博文,了解如何在本地开发者环境中开发和测试 Cloud Run 函数。

所学内容

  • 如何在 Cloud Run 函数上配置身份验证,以及如何验证身份验证是否已正确配置
  • 通过提供 gcloud 身份的令牌,从本地开发环境调用经过身份验证的函数
  • 如何创建服务账号并向其授予调用函数所需的适当角色
  • 如何从本地开发环境模拟服务,该环境具有调用函数所需的适当角色

8. 清理

为避免意外收费(例如,此 Cloud Function 无意中被调用次数超过 免费层级中每月 Cloud Run 函数调用分配的次数),您可以删除 Cloud Function 或删除您在第 2 步中创建的项目。

如需停止模拟服务账号,您可以重新登录并使用您的身份:

gcloud auth application-default login

如需删除 Cloud Run 函数,请前往 Cloud Run 函数 Cloud 控制台,网址为 https://console.cloud.google.com/functions/。确保您在第 2 步中创建的项目是当前所选项目。

选择您之前部署的 my-authenticated-function 。然后点击删除

如果您选择删除整个项目,可以前往 https://console.cloud.google.com/cloud-resource-manager,选择您在第 2 步中创建的项目,然后选择“删除”。如果您删除了项目,则需要在 Cloud SDK 中更改项目。您可以运行 gcloud projects list 查看所有可用项目的列表。