認証済みの Cloud Functions を呼び出す方法を学ぶ

1. はじめに

概要

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

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

  1. gcloud ID トークンを使用して、ローカルでの開発とテスト目的
  2. 本番環境と同じ認証情報を使用して、ローカルで開発およびテストする際にサービス アカウントの権限を借用する
  3. Google クライアント ライブラリを使用して、Google Cloud APIs の認証を処理します。例:サービスが関数を呼び出す必要があるとき

学習内容

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

2. 設定と要件

前提条件

  • Cloud コンソールにログインしています
  • すでに HTTP トリガーの第 2 世代の Cloud Functions 関数をデプロイしています
  • (省略可)この Codelab の 3 つ目のシナリオでは Node.jsnpm を例として使用しますが、Google Auth クライアント ライブラリでサポートされている任意のランタイムを使用できます。

Cloud Shell をアクティブにする

  1. Cloud Console で、[Cloud Shell をアクティブにする] 853e55310c205094.png をクリックします。

55efc1aaa7a4d3ad.png

Cloud Shell を初めて起動する場合は、内容を説明する中間画面が表示されます。中間画面が表示されたら、[続行] をクリックします。

9c92662c6a846a5c.png

Cloud Shell のプロビジョニングと接続に少し時間がかかる程度です。

9f0e51b578fecce5.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 Functions の関数を作成してテストする

この Codelab の手順は、コンソールの Cloud Functions のクイックスタートと同じですが、注意すべき例外が 1 つあります。関数には認証が必要です。

認証を要求するとは、関数を呼び出すプリンシパルに Cloud Functions 起動元(および第 2 世代の場合は Cloud Run 起動元)のロールを付与する必要があるということです。それ以外の場合、関数は 403 Forbidden エラーを返します。この Codelab では、プリンシパルに適切な起動元ロールを付与する方法を説明します。

認証された関数を作成する

Cloud コンソールを使用する手順は次のとおりです。

  1. Cloud Functions の概要ページに移動し、[関数を作成] をクリックします。
  2. [環境] オプションで [第 2 世代] を選択します。
  3. 関数に my-authenticated-function という名前を付けます。
  4. [認証] 欄はデフォルト値の [認証が必要] のままにします。

936eee0d5930d12b.png

  1. [次へ] をクリックします。
  2. この Codelab では、任意の言語を選択できます。
  3. [デプロイ] をクリックします。

関数のデプロイには約 1 分かかります。

gcloud コマンドを簡素化するためにローカル環境変数を設定する

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

関数にリージョンを指定する必要があります。この例では us-central1 を使用しています。

REGION="us-central1"

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

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

匿名の呼び出し元として呼び出しを試行して、関数に認証が必要であることを確認する

認証なしでこの関数を呼び出して、予期される 403 エラーが返されることを確認します。

コマンドラインから、次の curl コマンドを実行します。

curl $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`

正しい ID を使用していることを確認したら、アカウントのメールアドレスを環境変数に保存します。

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

gcloud init のセットアップgcloud auth login について詳しくは、ドキュメントをご覧ください。

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

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

結果は次のようになります。

Hello World!

トラブルシューティング

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

開発中に関数をテストするには、独自の ID トークンを使用するほうが簡単ですが、認証された関数の呼び出し元には適切なロールが必要です。それ以外の場合、呼び出し元は 403 Forbidden エラーを受け取ります。

最小権限の原則に従って、関数を呼び出すロールを持つ ID とサービス アカウントの数を制限します。

新しいサービス アカウントを作成して必要なロールを付与します。

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

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

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

この 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 Function Authentication codelab"

サービス アカウントに Cloud Functions の起動元ロールを付与する

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

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

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

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

サービス アカウントの権限を借用するには、サービス アカウントの ID トークンを生成するサービス アカウント トークン作成者(roles/iam.serviceAccountTokenCreator)ロールがユーザー アカウントに付与されている必要があります。

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 認証クライアント ライブラリアプリケーションのデフォルト認証情報(ADC)を使用してプログラムで関数を呼び出します。Google クライアント ライブラリについて詳しくは、このドキュメントのクライアント ライブラリの説明をご覧ください。

ADC の使用は、関数をローカル(ノートパソコンや Cloud Shell など)で記述してテストしながら、他の Google Cloud リソース(Cloud Storage、Vision API など)とやり取りする場合に特に重要です。この例では、認証が必要な別の関数をサービスから呼び出す方法を示します。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. 新しい Node.js アプリを作成する
npm init
  1. Google 認証クライアント ライブラリをインストールする
npm install google-auth-library
  1. index.js ファイルを作成する
  2. Cloud Functions の関数の URL を取得します。これは、次の手順でコードに追加します。
echo $FUNCTION_URL
  1. index.js に次のコードを追加します。targetAudience 変数は、Cloud Functions の関数の URL に変更してください。

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. アプリを実行する
node index.js

「Hello World!」と表示されるはずです。

トラブルシューティング

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

「Cannot fetch ID token in this environment, use GCE」または「GOOGLE_APPLICATION_CREDENTIALS 環境変数をサービス アカウント認証情報の JSON ファイルに設定」というエラーが表示された場合は、コマンドを実行するのを忘れている可能性があります。

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

7. 完了

これでこの Codelab は完了です。

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

また、Cloud Functions を使用したローカル開発に関するこのブログ投稿で、ローカルの開発環境で Cloud Functions の関数を開発してテストする方法を確認することもおすすめします。

学習した内容

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

8. クリーンアップ

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

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

gcloud auth application-default login

Cloud Functions の関数を削除するには、Cloud Functions のコンソール(https://console.cloud.google.com/functions/)に移動します。ステップ 2 で作成したプロジェクトが、現在選択されているプロジェクトであることを確認します。

先ほどデプロイした my-authenticated-function を選択します。[削除] をクリックします。

プロジェクト全体を削除する場合は、https://console.cloud.google.com/cloud-resource-manager に移動し、手順 2 で作成したプロジェクトを選択して [削除] を選択します。プロジェクトを削除する場合は、Cloud SDK でプロジェクトを変更する必要があります。使用可能なすべてのプロジェクトのリストを表示するには、gcloud projects list を実行します。