サービス間の認証
エンドユーザーのリクエストを認証するだけでなく、API にリクエストを送信するサービス(人間以外のユーザー)も認証しなければならない場合があります。このページでは、サービス アカウントを使用して人間またはサービスの認証を行う方法について説明します。
概要
API にリクエストを送信するサービスを識別するには、サービス アカウントを使用します。呼び出し元のサービスは、サービス アカウントの秘密鍵を使用して安全な JSON Web Token(JWT)に署名し、署名した JWT をリクエストに含めて API に送信します。
API と呼び出し側のサービスにサービス アカウント認証を実装するには:
- 呼び出し側のサービスのサービス アカウントとキーを作成します。
- API Gateway サービスの API 構成に認証サポートを追加します。
次の処理を行うコードを呼び出し側のサービスに追加します。
- JWT を作成し、サービス アカウントの秘密鍵で署名する。
- リクエストで署名済みの JWT を API に送信する。
API Gateway は、リクエストを API に転送する前に、JWT のクレームが API 構成の構成と一致することを検証します。API Gateway は、サービス アカウントに付与されている Cloud Identity の権限を確認しません。
前提条件
すでに以下を行っていることを前提としています。
サービス アカウントとキーを作成する
呼び出しサービスが JWT の署名に使用する秘密鍵ファイルがあるサービス アカウントが必要です。API にリクエストを送信するサービスが複数ある場合は、1 つのサービス アカウントを作成してすべての呼び出しサービスを表すことができます。サービスによって権限が異なる場合など、サービスを区別する必要がある場合は、呼び出し側のサービスごとにサービス アカウントとキーを作成します。
このセクションでは、 Google Cloud コンソールと gcloud コマンドライン ツールを使用して、サービス アカウントと秘密鍵ファイルを作成し、サービス アカウントにサービス アカウント トークンの作成者役割を割り当てる方法を説明します。この操作を API で行う方法については、サービス アカウントの作成と管理をご覧ください。
サービス アカウントとキーを作成するには、次の手順に従います。
Google Cloud コンソール
サービス アカウントの作成:
Google Cloud コンソールで、[サービス アカウントの作成] に移動します。
プロジェクトを選択します。
[サービス アカウント名] フィールドに名前を入力します。Google Cloud コンソールでは、この名前に基づいて [サービス アカウント ID] フィールドに値が入力されます。
省略可: [サービス アカウントの説明] フィールドに説明を入力します。
[作成] をクリックします。
[ロールを選択] フィールドをクリックします。
[すべてのロール] で、[サービス アカウント] > [サービス アカウント トークン作成者] を選択します。
[続行] をクリックします。
[完了] をクリックして、サービス アカウントの作成を完了します。
ブラウザ ウィンドウは閉じないでください。次の手順でこのページを使用します。
サービス アカウント キーを作成します。
- Google Cloud コンソールで、作成したサービス アカウントのメールアドレスをクリックします。
- [キー] をクリックします。
- [鍵を追加]、[新しい鍵を作成] の順にクリックします。
- [作成] をクリックします。JSON キーファイルがパソコンにダウンロードされます。
- [閉じる] をクリックします。
gcloud
ローカルマシン上の Google Cloud CLI を使用して以下のコマンドを実行します。このコマンドは、Cloud Shell 内でも実行できます。
gcloudにデフォルトのアカウントを設定する。アカウントが複数ある場合は、使用する Google Cloud プロジェクトのアカウントを選択してください。gcloud auth loginGoogle Cloud プロジェクトのプロジェクト ID を表示します。
gcloud projects listデフォルト プロジェクトを設定します。
PROJECT_IDは、使用する Google Cloud プロジェクト ID に置き換えます。gcloud config set project PROJECT_ID
サービス アカウントを作成します。
SA_NAMEとSA_DISPLAY_NAMEは、それぞれ使用する名前と表示名に置き換えます。gcloud iam service-accounts create SA_NAME \ --display-name "SA_DISPLAY_NAME"
作成したサービス アカウントのメールアドレスを表示します。
gcloud iam service-accounts listサービス アカウント トークン作成者の役割を追加します。
SA_EMAIL_ADDRESSは、サービス アカウントのメールアドレスに置き換えます。gcloud projects add-iam-policy-binding PROJECT_ID \ --member serviceAccount:SA_EMAIL_ADDRESS \ --role roles/iam.serviceAccountTokenCreator
現在の作業ディレクトリにサービス アカウント キー ファイルを作成します。
FILE_NAMEは、キーファイルに使用する名前に置き換えます。デフォルトでは、gcloudJSON ファイルが作成されます。gcloud iam service-accounts keys create FILE_NAME.json \ --iam-account SA_EMAIL_ADDRESS
詳しくは gcloud リファレンスをご覧ください。
秘密鍵を保護する方法については、認証情報を管理する際のベスト プラクティスをご覧ください。
認証をサポートするように API を構成する
ゲートウェイの API 構成を作成するときに、ゲートウェイが他のサービスと通信するために使用するサービス アカウントを指定します。ゲートウェイを呼び出すサービスのサービス アカウント認証を有効にするために、セキュリティ要件オブジェクトおよびセキュリティ定義オブジェクトを変更します。以下の手順に従って、API Gateway で、サービスの呼び出しで使用される署名付き JWT のクレームを検証できるようにします。
API 構成で、サービス アカウントを発行元として追加します。
securityDefinitions: DEFINITION_NAME: authorizationUrl: "" flow: "implicit" type: "oauth2" x-google-issuer: "SA_EMAIL_ADDRESS" x-google-jwks_uri: "https://www.googleapis.com/robot/v1/metadata/x509/SA_EMAIL_ADDRESS"DEFINITION_NAMEは、このセキュリティ定義を識別する文字列に置き換えます。サービス アカウント名または呼び出し側のサービスを識別する名前に置き換えることをおすすめします。SA_EMAIL_ADDRESSは、サービス アカウントのメールアドレスに置き換えます。- API 構成では複数のセキュリティ定義を定義できますが、各定義の
x-google-issuerは異なっている必要があります。呼び出し側のサービスごとに別々のサービス アカウントを作成した場合、サービス アカウントごとにセキュリティ定義を作成できます。次に例を示します。
securityDefinitions: service-1: authorizationUrl: "" flow: "implicit" type: "oauth2" x-google-issuer: "service-1@example-project-12345.iam.gserviceaccount.com" x-google-jwks_uri: "https://www.googleapis.com/robot/v1/metadata/x509/service-1@example-project-12345.iam.gserviceaccount.com" service-2: authorizationUrl: "" flow: "implicit" type: "oauth2" x-google-issuer: "service-2@example-project-12345.iam.gserviceaccount.com" x-google-jwks_uri: "https://www.googleapis.com/robot/v1/metadata/x509/service-2@example-project-12345.iam.gserviceaccount.com"必要に応じて、
x-google-audiencesにsecurityDefinitionsセクションを追加してください。x-google-audiencesを追加しない場合、API Gateway では JWT 内の"aud"(オーディエンス)クレームの形式がhttps://SERVICE_NAMEである必要があります。ここで、SERVICE_NAME は、OpenAPI ドキュメントのhostフィールドで構成した API Gateway サービスの名前です。API 全体に適用するには、ファイルの最上位に
securityセクションを追加します。インデントされない場合は、特定のメソッドに適用します。API レベルとメソッドレベルの両方でsecurityセクションを使用する場合、メソッドレベルの設定は API レベルの設定より優先されます。security: - DEFINITION_NAME: []
securityDefinitionsセクションで使用した名前はDEFINITION_NAMEと置き換えます。securityDefinitionsセクションに定義が複数ある場合は、それらをsecurityに追加します。例を次に示します。security: - service-1: [] - service-2: []
更新した API 構成をデプロイします。
API Gateway がリクエストを API に転送する前に、次のことを確認します。
- API 構成の
x-google-jwks_uriフィールドで指定された URI にある公開鍵を使用した JWT の署名。 - その
"iss"JWT での発行者のリクエストが、x-google-issuerフィールドに入力します。 - その
"aud"JWT 内の API Gateway サービス名が含まれているか、またはx-google-audiencesフィールドに入力します。 - トークンが期限切れになっていないことを確認するには、
"exp"(有効期限)クレームを使用します。
x-google-issuer、x-google-jwks_uri、x-google-audiences の詳細については、OpenAPI 拡張機能をご覧ください。
認証されたリクエストを API Gateway API に送信する
認証されたリクエストを行う場合、呼び出し側のサービスは、API 構成に指定されたサービス アカウントで署名された JWT を送信します。呼び出し側のサービスは、次の処理を行う必要があります。
- JWT を作成し、サービス アカウントの秘密鍵で署名します。
- リクエストで署名済みの JWT を API に送信します。
次のサンプルコードは、このプロセスを一部の言語で示しています。他の言語で認証済みリクエストを行うには、jwt.io で、サポートされているライブラリの一覧を参照してください。
- 呼び出し側のサービスに以下の関数を追加し、次のパラメータを渡します。
Java saKeyfile: サービス アカウントの秘密鍵ファイルへのフルパス。-
saEmail: サービス アカウントのメールアドレス。 -
audience:x-google-audiencesフィールドを API 構成に追加すると、x-google-audiencesで指定したいずれかの値にaudienceを設定します。それ以外の場合は、audience~https://SERVICE_NAMEを設定します。ここで、SERVICE_NAMEは、API Gateway のサービス名です。 -
expiryLength: JWT の有効期限(秒)。
Python -
sa_keyfile: サービス アカウントの秘密鍵ファイルへのフルパス。 -
sa_email: サービス アカウントのメールアドレス。 -
audience:x-google-audiencesフィールドを API 構成に追加すると、x-google-audiencesで指定したいずれかの値にaudienceを設定します。それ以外の場合は、audience~https://SERVICE_NAMEを設定します。ここで、SERVICE_NAMEは、API Gateway のサービス名です。 -
expiry_length: JWT の有効期限(秒)。
Go saKeyfile: サービス アカウントの秘密鍵ファイルへのフルパス。-
saEmail: サービス アカウントのメールアドレス。 -
audience:x-google-audiencesフィールドを API 構成に追加すると、x-google-audiencesで指定したいずれかの値にaudienceを設定します。それ以外の場合は、audience~https://SERVICE_NAMEを設定します。ここで、SERVICE_NAMEは、API Gateway のサービス名です。 -
expiryLength: JWT の有効期限(秒)。
この関数は JWT を作成して秘密鍵ファイルで署名し、署名済みの JWT を返します。
Java Python Go - 呼び出し側のサービスに、以下の関数を追加し、署名付き JWT を
Authorization: Bearerヘッダー内で API に送信します。Java Python Go
JWT を使用してリクエストを送信する場合は、セキュリティ上の理由から、認証トークンを Authorization: Bearer ヘッダーに入れることをおすすめします。例:
curl --request POST \
--header "Authorization: Bearer ${TOKEN}" \
"${GATEWAY_URL}/echo"
ここで、GATEWAY_URL と TOKEN はそれぞれ、デプロイされたゲートウェイ URL と認証トークンを格納する環境変数です。
API での認証結果の受信
通常、API Gateway は受信したすべてのヘッダーを転送します。ただし、バックエンド アドレスが API 構成の x-google-backend で指定されている場合は、元の Authorization ヘッダーより優先します。
API Gateway は認証結果を X-Apigateway-Api-Userinfo でバックエンド API に送信します。元の Authorization ヘッダーではなく、このヘッダーを使用することをおすすめします。このヘッダーは base64url エンコードされ、JWT ペイロードが含まれています。