認証された Cloud Run 関数を呼び出す方法を学習する

1. はじめに

概要

Cloud Run 関数は軽量なコンピューティング ソリューションで、デベロッパーはサーバーやランタイム環境を管理せずに、HTTPS を使用してトリガーしたり、CloudEvents に応答したりできる単一目的のスタンドアロン関数を作成できます。Cloud Run の関数について詳しくは、ブログ投稿をご覧ください。

Cloud Run の関数の呼び出しを制御するアプローチには、主に 2 つあります。ID に基づくアクセスの保護と、ネットワーク ベースのアクセス制御を使用したアクセスの保護です。この Codelab では、最初のアプローチに焦点を当て、ID に基づいてアクセスを保護して関数を呼び出す 3 つのシナリオについて説明します。

  1. gcloud ID トークンを使用して、ローカルでの開発とテストのために関数を呼び出す
  2. ローカルで開発とテストを行うときにサービス アカウントの権限を借用して、本番環境と同じ認証情報を使用する
  3. Google クライアント ライブラリを使用して、Google Cloud APIs への認証を処理します(サービスが関数を呼び出す必要がある場合など)。

学習内容

  • Cloud Run 関数で認証を設定し、認証が正しく構成されていることを確認する方法
  • gcloud ID のトークンを指定して、ローカル開発環境から認証済み関数を呼び出す
  • サービス アカウントを作成し、関数を呼び出す適切なロールを付与する方法
  • 関数の呼び出しに適切なロールを持つローカル開発環境から、サービスの権限を借用する方法

2. 設定と要件

前提条件

Cloud Shell をアクティブにする

  1. Cloud Console で、[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 起動元ロールが必要です。このロールがないと、関数は 403 Forbidden エラーを返します。この Codelab では、プリンシパルに適切な起動元ロールを付与する方法を説明します。

簡素化された gcloud コマンド用のローカル環境変数を設定する

まず、この Codelab で使用する gcloud コマンドを読みやすくするために、環境変数をいくつか作成します。

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

関数のソースコードを作成する

この Codelab では Node.js を使用しますが、Google 認証クライアント ライブラリでサポートされているランタイムであればどれでも使用できます。

まず、ディレクトリを作成し、そのディレクトリに移動します。

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

関数 URL を環境変数として保存し、後で使用できます。

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

後で使用するために、関数の URL を環境変数として保存できます。

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 ID トークンを使用する

デベロッパーは、ローカルで関数を開発しながらテストする方法が必要です。このセクションでは、簡単なテストを実行して、自分の ID を使用して関数が適切に認証されていることを確認します。

次のコマンドを実行して、gcloud を使用して認証されていることを確認します。

gcloud auth list

アクティブな ID の横にアスタリスクが表示されます。次に例を示します。

Credentialed Accounts
ACTIVE  ACCOUNT

*       <my_account>@<my_domain.com>

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

gcloud init の設定gcloud auth login の詳細については、ドキュメントをご覧ください。

次に、関数を呼び出して、ID トークンを渡します。

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

結果が表示されます。

Hello World!

トラブルシューティング

403 Forbidden エラーが発生した場合は、ID に Cloud Run 起動元ロールがあることを確認します。IAM コンソールを使用して、プリンシパルに付与されているロールを確認できます。

独自の ID トークンを使用すると、開発中に関数を簡単にテストできますが、認証された関数の呼び出し元には適切なロールが必要です。適切なロールがないと、呼び出し元に 403 Forbidden エラーが返されます。

最小権限の原則に従って、関数を呼び出すロールを持つ ID とサービス アカウントの数を制限します。次のシナリオでは、新しいサービス アカウントを作成し、関数を呼び出すための適切なロールを付与する方法について説明します。

5. シナリオ 2: サービス アカウントの権限借用

このシナリオでは、サービス アカウントの権限を借用して、ローカルで開発とテストを行うときに関数を呼び出します。サービス アカウントの権限を借用することで、本番環境と同じ認証情報で関数をテストできます。

これにより、ロールを検証するだけでなく、ローカルテスト目的で他の ID に Cloud Functions 起動元のロールを付与する必要がないため、最小権限の原則に従うことができます。

この 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 起動元ロールを付与します。

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

サービス アカウントの権限借用を使用して関数を呼び出す

そのためには、ID トークンを取得して、新しく作成されたサービス アカウントの権限を借用します。

権限借用に必要なロールを追加する

サービス アカウントの権限を借用するには、ユーザー アカウントにサービス アカウントの ID トークンを生成するためのサービス アカウント トークン作成者(roles/iam.serviceAccountTokenCreator)のロールが必要です。

次のコマンドを実行して、有効なユーザー アカウントにこのロールを付与できます。

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 クライアント ライブラリについて詳しくは、このドキュメントのクライアント ライブラリの説明をご覧ください。

ADC を使用することは、他の Google Cloud リソース(Cloud Storage、Vision API など)を操作しながら、関数をローカル(ラップトップ、Cloud Shell など)で作成してテストする場合に特に重要です。この例では、サービスが認証が必要な別の関数を呼び出す方法について説明します。ADC とローカル開発の詳細については、ブログ投稿の Cloud Functions の関数をローカルで開発してテストする方法 | Google Cloud ブログをご覧ください。

gcloud コマンドを実行してサービス アカウントの権限を借用する

ADC は、アプリケーション環境に基づいて認証情報を自動的に検索し、その認証情報を Google Cloud APIs の認証に使用します。--impersonate-service-account フラグを使用すると、Google Cloud APIs に対する認証にその ID を使用して、サービス アカウントの権限を借用できます。

サービス アカウントの権限を借用するには、次のコマンドを実行します。

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

これで、ID ではなく、このサービス アカウントとして gcloud コマンドを実行するようになりました。

認証された関数を呼び出すサービスを作成して実行する

各ランタイムには、インストールできる独自の Google Auth クライアント ライブラリがあります。この Codelab では、Node.js アプリをローカルで作成して実行する方法について説明します。

Node.js での手順は以下のとおりです。

  1. 新しいディレクトリの作成
mkdir local-dev && cd $_
  1. 新しい Node.js アプリを作成する
npm init -y
  1. Google 認証クライアント ライブラリをインストールする
npm install google-auth-library
  1. index.js ファイルを作成する
  2. Cloud Run 関数の URL を取得します。この URL は、次の手順でコードに追加します。
echo $FUNCTION_URL
  1. index.js に次のコードを追加します。targetAudience 変数は、Cloud Run 関数の URL に変更してください。

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!」と表示されます。

トラブルシューティング

リソースで権限「iam.serviceAccounts.getOpenIdToken」が拒否された(または存在しない可能性がある)というエラーが表示された場合は、サービス アカウント トークン作成者のロールが反映されるまで数分待ってください。

この環境で ID トークンを取得できません。GCE を使用するか、GOOGLE_APPLICATION_CREDENTIALS 環境変数をサービス アカウント認証情報の JSON ファイルに設定してくださいというエラーが表示された場合は、コマンドを実行し忘れている可能性があります。

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

7. 完了

以上で、この Codelab は完了です。

Cloud Run 関数を保護する方法に関するドキュメントを確認することをおすすめします。

また、ローカル開発環境で Cloud Run 関数を開発してテストする方法については、Cloud Run 関数を使用したローカル開発に関するブログ投稿もご覧ください。

学習した内容

  • Cloud Run 関数で認証を設定し、認証が正しく構成されていることを確認する方法
  • gcloud ID のトークンを指定して、ローカル開発環境から認証済み関数を呼び出す
  • サービス アカウントを作成し、関数を呼び出す適切なロールを付与する方法
  • 関数の呼び出しに適切なロールを持つローカル開発環境から、サービスの権限を借用する方法

8. クリーンアップ

不注意による料金(たとえば、この Cloud Functions の関数が無料枠の毎月の Cloud Run 関数呼び出しの割り当てよりも頻繁に呼び出されるなど)を回避するには、Cloud Functions の関数を削除するか、ステップ 2 で作成したプロジェクトを削除します。

サービス アカウントの権限借用を停止するには、自分の ID を使用して再ログインします。

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 を実行すると、使用可能なすべてのプロジェクトのリストが表示されます。