署名済みヘッダーによるアプリの保護

このページでは、署名付きの IAP ヘッダーを使用してアプリを保護する方法について説明します。Identity-Aware Proxy(IAP)を構成すると、JSON Web Token(JWT)によってアプリに対するリクエストが承認されます。これにより、アプリは次のリスクから保護されます。

  • IAP が誤って無効化される
  • ファイアウォールの構成が誤っている
  • プロジェクト内からの不正アクセス

アプリを保護するには、すべてのアプリの種類に対して署名付きヘッダーを使用する必要があります。

また、App Engine スタンダード環境アプリを使用している場合は、Users API を使用できます。

Compute Engine と GKE のヘルスチェックには JWT ヘッダーが含まれていません。このため、IAP はヘルスチェックを処理しません。ヘルスチェックでアクセスエラーが返された場合は、ヘルスチェックが Google Cloud コンソールで正しく構成されていることと、JWT ヘッダーの検証でヘルスチェックのパスが許可されていることを確認してください。詳細については、ヘルスチェックの例外を作成するをご覧ください。

始める前に

署名済みヘッダーを使用してアプリを保護するには、次のものが必要になります。

IAP ヘッダーによるアプリの保護

IAP JWT でアプリを保護するには、JWT のヘッダー、ペイロード、署名を確認します。JWT は、HTTP リクエスト ヘッダー x-goog-iap-jwt-assertion にあります。IAP をバイパスすると、IAP の署名がない ID ヘッダー x-goog-authenticated-user-{email,id} の偽造が可能になります。IAP JWT はより安全な代替手段を提供します。

IAP がバイパスされた場合に備えて、署名付きヘッダーを使用することで補助的なセキュリティを提供します。IAP が有効になっている場合、リクエストが IAP の処理インフラストラクチャを通過するときに、クライアントが設定した x-goog-* ヘッダーが削除されます。

JWT ヘッダーの検証

JWT ヘッダーが次の制約に従っていることを確認します。

JWT ヘッダー クレーム
alg アルゴリズム ES256
kid キー ID IAP キーファイルにある公開鍵のいずれかに対応する必要があります。https://www.gstatic.com/iap/verify/public_key または https://www.gstatic.com/iap/verify/public_key-jwk のいずれかの形式で使用できます。

JWT が、トークンの kid クレームに対応する秘密鍵で署名されていることを確認します。まず、次のいずれかから公開鍵を取得します。

  • https://www.gstatic.com/iap/verify/public_key: この URL には、kid クレームを公開鍵の値にマッピングする JSON 辞書が含まれています。
  • https://www.gstatic.com/iap/verify/public_key-jwk: この URL には、JWK 形式の IAP 公開鍵が含まれています。

公開鍵を取得したら、JWT ライブラリを使用して署名を検証します。

IAP は公開鍵を定期的にローテーションします。JWT を常に検証できるようにするには、公開鍵のキャッシュ保存を自動化するをご覧ください。

JWT ペイロードの検証

JWT ペイロードが次の制約に従っていることを確認します。

JWT ペイロード クレーム
exp 有効期限 将来の時点にする必要があります。この時間は、UNIX エポック時刻からの秒数です。スキューには 30 秒かかります。トークンの最大有効期間は、10 分 + 2 * スキューです。
iat 発行時 過去の時点にする必要があります。この時間は、UNIX エポック時刻からの秒数です。スキューには 30 秒かかります。
aud 対象 次の値を持つ文字列にする必要があります。
  • App Engine: /projects/PROJECT_NUMBER/apps/PROJECT_ID
  • Compute Engine と GKE: /projects/PROJECT_NUMBER/global/backendServices/SERVICE_ID
  • Cloud Run: /projects/PROJECT_NUMBER/locations/REGION/services/SERVICE_NAME
iss 発行元 https://cloud.google.com/iap にする必要があります。
hd アカウント ドメイン アカウントがホスト型ドメインに属する場合、アカウントが関連付けられているドメインを区別するために hd クレームが設定されます。
google Google クレーム リクエストにアクセスレベルが 1 つ以上適用されている場合、その名前は google クレームの JSON オブジェクトの access_levels キーの下に、文字列配列として格納されます。

デバイス ポリシーを指定していて、組織がデバイスデータにアクセスできる場合は、DeviceId も JSON オブジェクトに保存されます。別の組織に送信されるリクエストには、デバイスデータを表示する権限がない可能性があります。

上記の aud 文字列の値を取得するには、Google Cloud コンソールまたは gcloud コマンドライン ツールを使用します。

Google Cloud コンソールから aud 文字列値を取得するには、プロジェクトの Identity-Aware Proxy の設定に移動し、ロードバランサ リソースの横にある [さらに表示] をクリックして、[署名済みヘッダー JWT のユーザー] を選択します。[署名済みヘッダー JWT] ダイアログが開き、選択したリソースの aud クレームが表示されます。

gcloud CLI の gcloud コマンドライン ツールを使用して aud 文字列の値を取得する場合は、プロジェクト ID を知っている必要があります。Google Cloud コンソールまたはプロジェクト情報カードでプロジェクト ID を確認し、その値ごとに指定されたコマンドを実行します。

プロジェクト番号

gcloud コマンドライン ツールを使用してプロジェクト番号を取得するには、次のコマンドを実行します。

gcloud projects describe PROJECT_ID

コマンドから次の出力が返されます。

createTime: '2016-10-13T16:44:28.170Z'
lifecycleState: ACTIVE
name: project_name
parent:
  id: '433637338589'
  type: organization
projectId: PROJECT_ID
projectNumber: 'PROJECT_NUMBER'

サービス ID

gcloud コマンドライン ツールを使用してサービス ID を取得するには、次のコマンドを実行します。

gcloud compute backend-services describe SERVICE_NAME --project=PROJECT_ID --global

コマンドから次の出力が返されます。

affinityCookieTtlSec: 0
backends:
- balancingMode: UTILIZATION
  capacityScaler: 1.0
  group: https://www.googleapis.com/compute/v1/projects/project_name/regions/us-central1/instanceGroups/my-group
connectionDraining:
  drainingTimeoutSec: 0
creationTimestamp: '2017-04-03T14:01:35.687-07:00'
description: ''
enableCDN: false
fingerprint: zaOnO4k56Cw=
healthChecks:
- https://www.googleapis.com/compute/v1/projects/project_name/global/httpsHealthChecks/my-hc
id: 'SERVICE_ID'
kind: compute#backendService
loadBalancingScheme: EXTERNAL
name: my-service
port: 8443
portName: https
protocol: HTTPS
selfLink: https://www.googleapis.com/compute/v1/projects/project_name/global/backendServices/my-