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

1. はじめに

概要

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

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

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

学習内容

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

2. 設定と要件

前提条件

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

Cloud Shell をアクティブにする

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

55efc1aaa7a4d3ad.png

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

9c92662c6a846a5c.png

すぐにプロビジョニングが実行され、Cloud Shell に接続されます。

9f0e51b578fecce5.png

この仮想マシンには、必要な開発ツールがすべて用意されています。仮想マシンは Google Cloud で稼働し、永続的なホーム ディレクトリが 5 GB 用意されているため、ネットワークのパフォーマンスと認証が大幅に向上しています。 この 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 initgcloud auth login の設定の詳細については、ドキュメントをご覧ください。

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

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

次の結果が表示されます。

Hello World!

トラブルシューティング

403 Forbidden エラーが表示された場合は、ID に Cloud Functions 起動元ロールまたは Cloud Run 起動元ロールが第 2 世代関数に付与されていることを確認してください。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 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 トークンを取得して、その権限を借用します。

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

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

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. 新しい Node.js アプリを作成する
npm init
  1. Google Auth クライアント ライブラリをインストールする
npm install google-auth-library
  1. index.js ファイルを作成する
  2. Cloud Functions の URL を取得します。この 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' の権限が拒否されました(存在しない可能性があります)」が表示された場合は、サービス アカウント トークン作成者ロールが伝播するまで数分お待ちください。

エラー「この環境で ID トークンを取得できません。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 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 を実行すると、使用可能なすべてのプロジェクトのリストを表示できます。