Identity-Aware Proxy でコンテキストアウェア アクセスを設定する

このガイドでは、アクセスレベルと Identity and Access Management(IAM)Conditions Framework を使用して、Identity-Aware Proxy(IAP)のアクセス ポリシーを拡張する方法について説明します。 アクセスレベルを使用すると、IP アドレスとエンドユーザーのデバイス属性に基づいてリソースへのアクセスを制限できます。IAM 条件を使用すると、URL パス / ホスト、日時に基づいてアクセスを制限できます。

たとえば、ポリシーの構成に応じて、重要なアプリで次のことを行うことができます。

  • 従業員が信頼できる会社のデバイスを使用して、会社のネットワークからアクセスした場合に、その従業員にアクセスを許可する。
  • リモート アクセス グループの従業員が信頼できる会社のデバイスを使用し、このデバイスに安全なパスワードが設定され、最新のパッチレベルが適用されている場合は、アクセス元のネットワークに関係なく、その従業員にアクセスを許可する。
  • URL パスが /admin で始まる場合にのみ、特権アクセス グループの従業員にアクセス権を付与します。

始める前に

始める前に、次のものが必要になります。

  • IAP で保護され、個別またはグループ アクセスを追加するアプリ。
  • アクセスを許可するユーザー名またはグループ名。

アクセスレベルを設定する

IP アドレスまたはエンドユーザーのデバイス属性に基づいてアクセスを制限するには、アクセスレベルを作成します。デバイス属性などの一部の属性には、Chrome Enterprise Premium ライセンスが必要です。ライセンスの検証は、アクセスレベルを構成するときにのみ行われ、ランタイム アクセスには影響しません。アクセスレベルの作成方法については、Access Context Manager ガイドをご覧ください。 IAP は、アクセスレベル名を使用して、IAP で保護されたアプリとアクセスレベルを関連付けます。

スコープ付きポリシーの使用は IAP でサポートされていません。アクセスレベルは、組織のアクセス ポリシーで設定する必要があります。詳細については、アクセス ポリシーを作成するをご覧ください。

IAM ポリシーを編集する

IAP で保護されたアプリには、IAP ロールをアプリにバインドする IAM ポリシーがあります。

IAM ポリシーに IAM 条件付きバインディングを追加すると、リクエスト属性に基づいてリソースへのアクセスがさらに制限されます。リクエスト属性には、次のようなものがあります。

  • アクセスレベル
  • URL ホスト / パス
  • 日時

IAM 条件付きバインディングで指定された request.host と request.path に比較されるリクエスト値は一致している必要があります。たとえば /internal admin で始まるパスへのアクセスを制限した場合、/internal%20admin に移動すると、この制限を回避できます。ホスト名とパスの条件の詳細については、ホスト名とパスの条件を使用するをご覧ください。

IAM ポリシーに条件付きバインディングを追加して編集するには、次の操作を行います。

コンソール

Google Cloud コンソールを使用して条件付きバインディングを追加するには:

  1. IAP 管理ページに移動します。

    IAP 管理ページに移動

  2. IAM の権限を更新するリソースの横にあるチェックボックスをオンにします。

  3. 右側の情報パネルで [プリンシパルを追加] をクリックします。

  4. [新しいプリンシパル] ボックスに、ロールの割り当て先にするプリンシパルを入力します。

  5. [ロールを選択] プルダウン リストで、[IAP で保護されたウェブアプリ ユーザー] のロールを選択し、プリンシパルがリソースにアクセスするときに満たす必要があるアクセスレベルの条件を指定します。

    • 既存のアクセスレベルを指定するには、[アクセスレベル] プルダウン リストから選択します。[IAP で保護されたウェブアプリ ユーザー] のロールを選択する必要があります。また、既存のアクセスレベルを表示する組織レベルの権限が必要です。次のいずれかのロールが付与されている必要があります。
      • Access Context Manager 管理者
      • Access Context Manager 編集者
      • Access Context Manager 読み取り
    • アクセスレベルを作成または管理するには、Access Context Manager を使用します。
  6. プリンシパルにロールを追加する場合は、[別のロールを追加] をクリックします。

  7. ロールの追加が完了したら、[保存] をクリックします。

    これで、リソースに条件付きバインディングが追加されました。

条件付きバインディングを削除するには:

  1. IAP 管理ページに移動します。

    IAP 管理ページに移動

  2. プリンシパルの Cloud IAM ロールを削除するリソースの横にあるチェックボックスをオンにします。

  3. 右側の情報パネルの [ロール / プリンシパル] で、プリンシパルから削除するロールをクリックします。

  4. プリンシパルの横にある [削除] をクリックします。

  5. 表示される [プリンシパルのロールを削除しますか?] ダイアログで [削除] をクリックします。選択されたリソースのプリンシパルから未継承のロールをすべて削除するには、チェックボックスを選択してから [削除] をクリックします。

gcloud

現時点で gcloud ツールで可能な操作は、プロジェクト レベルでの条件付きバインディングの設定だけです。

条件付きバインディングを設定するには、次の手順でプロジェクトの policy.yaml ファイルを編集します。

  1. 次の gcloud コマンドを使用して、アプリの IAM ポリシーを開きます。

    gcloud iap web get-iam-policy --project=PROJECT_ID > policy.yaml

  2. policy.yaml ファイルを編集して、次のものを指定します。

    • IAM 条件を適用するユーザーとグループ。
    • リソースにアクセス権を付与する iap.httpsResourceAccessor ロール。
    • IAM 条件。

      次のスニペットは、1 つの属性のみが指定された IAM 条件を示しています。この条件により、ACCESS_LEVEL_NAME アクセスレベルの要件を満たし、リソースの URL パスが / で始まる場合、ユーザーとグループにアクセス権が付与されます。

    bindings:
    ...
      - members:
        - group:EXAMPLE_GROUP@GOOGLE.COM
        - user:EXAMPLE_USER@GOOGLE.COM
        role: roles/iap.httpsResourceAccessor
        condition:
                  expression: "accessPolicies/ORGANIZATION_NUMBER/accessLevels/ACCESS_LEVEL_NAME" in
                              request.auth.access_levels && request.path.startsWith("/")
                  title: CONDITION_TITLE
    ...

  3. set-iam-policy コマンドを実行して、ポリシーをアプリケーションにバインドします。

    gcloud iap web set-iam-policy --project=PROJECT_ID policy.yaml

これで IAM ポリシーに条件付きバインディングが追加されました。

API

アプリの policy.json ファイルを編集するには、アプリの種類に応じて以下の手順を行います。IAM API を使用してアクセス ポリシーを管理する方法については、IAP で保護されたリソースへのアクセスの管理をご覧ください。

以下のアプリケーション固有の API の手順を実行する前に、次の変数をエクスポートします。

 export PROJECT_NUM=PROJECT_NUMBER
 export IAP_BASE_URL=https://iap.googleapis.com/v1/projects/${PROJECT_NUM}/iap_web
 # Replace POLICY_FILE.JSON with the name of JSON file to use for setIamPolicy
 export JSON_NEW_POLICY=POLICY_FILE.JSON
 

### App Engine

 1. Export the following App Engine variables:
 <pre class="devsite-click-to-copy prettyprint lang-html" suppresswarning="suppresswarning">
 \# The APP_ID is usually the project ID
 export GAE_APP_ID=<var>APP_ID</var>
 export GAE_BASE_URL=${IAP_BASE_URL}/appengine-${GAE_APP_ID}</pre>

 1. Get the IAM policy for the App Engine app using the `getIamPolicy` method. The empty data bit at the end turns the `curl` request into POST instead of GET.
curl -i -H "Authentication: Bearer $(gcloud auth print-access-token)" \\
    ${GAE_BASE_URL}/:getIamPolicy -d ''
1. IAM 条件バインディングを IAM ポリシーの JSON ファイルに追加します。次の例では、`iap.httpsResourceAccessor` ロールを 2 人のユーザーにバインドして、IAP で保護されたリソースへのアクセス権を付与するように、`policy.json` ファイルを編集しています。ACCESS_LEVEL_NAME アクセスレベルの要件を満たし、リソースの URL パスが「/」で始まる場合にのみリソースへのアクセスを許可する IAM 条件が追加されます。各バインディングに設定できる条件は 1 つだけです。

**policy.json ファイルの例**
{
"policy": {
  "bindings": [
        {
          "role": "roles/iap.httpsResourceAccessor",
          "members": [
              "group:EXAMPLE_GROUP@GOOGLE.COM",
              "user:EXAMPLE_USER@GOOGLE.COM"
          ],
          "condition": {
            "expression": "\"accessPolicies/ORGANIZATION_NUMBER/accessLevels/ACCESS_LEVEL_NAME\" in request.auth.access_levels && request.path.startsWith(\"/\")",
            "title": "CONDITION_NAME"
          }
        }
        ]
  }
}
1. `setIamPolicy` メソッドを使用して、新しい `policy.json` ファイルを設定します。
 curl -i -H "Authentication: Bearer $(gcloud auth print-access-token)" \\
     ${GAE_BASE_URL}:setIamPolicy -d @${JSON_NEW_POLICY}

#### App Engine のサービスとバージョン

 You can also update the IAM policy of a App Engine
 service, all versions, or a specific version of a service. To do this for a specific version of a service:

 1. Export the following additional variables.

    export GAE_SERVICE=SERVICE_NAME
    export GAE_VERSION=VERSION_NAME
    
1. エクスポートされた GAE_BASE_URL 変数を更新します。
export GAE_BASE_URL=${IAP_BASE_URL}/appengine-${GAE_APP_ID}/services/${GAE_SERVICE}/versions/${GAE_VERSION}
1. 上記の getIamPolicy コマンドと setIamPolicy コマンドを使用して、バージョンの IAM ポリシーを取得して設定します。

### GKE と Compute Engine

1. バックエンド サービスのプロジェクト ID をエクスポートします。
     export BACKEND_SERVICE_NAME=BACKEND_SERVICE_NAME

 2. Get the IAM policy for the Compute Engine app using the `getIamPolicy` method. The empty data bit at the end turns the `curl` request into POST instead of GET.
 <pre class="devsite-click-to-copy prettyprint lang-html" suppresswarning="suppresswarning">
 curl -i -H "Authentication: Bearer $(gcloud auth print-access-token)" \\
     ${IAP_BASE_URL}/compute/services/${BACKEND_SERVICE_NAME}:getIamPolicy \\
     -d ''</pre>
 3. Add your IAM conditional binding to the IAM policy JSON file.
    The following is an example of an edited `policy.json` file that binds the
    `iap.httpsResourceAccessor` role to two users, granting them access to the IAP-secured resources. An IAM
    condition has been added to grant them access to the resources only if the <var>ACCESS_LEVEL_NAME</var> access level requirement is met and the resource URL path starts with `/`.
    Each binding can have only one condition.

    <br/>**Example policy.json file**
{
  "policy": {
    "bindings": [
      {
        "role": "roles/iap.httpsResourceAccessor",
        "members": [
          "group:EXAMPLE_GROUP@GOOGLE.COM",
          "user:EXAMPLE_USER@GOOGLE.COM"
        ],
        "condition": {
          "expression": "\"accessPolicies/ORGANIZATION_NUMBER/accessLevels/ACCESS_LEVEL_NAME\" in request.auth.access_levels && request.path.startsWith(\"/\")",
          "title": "CONDITION_NAME"
        }
      }
    ]
  }
}
4. `setIamPolicy` メソッドを使用して、新しい `policy.json` ファイルを設定します。
     curl -i -H "Content-Type:application/json" \\
             -H "Authentication: Bearer $(gcloud auth print-access-token)" \\
             ${IAP_BASE_URL}/compute/services/${BACKEND_SERVICE_NAME}:setIamPolicy \\
             -d @${JSON_NEW_POLICY}

ホスト名とパスの条件を使用する

リクエスト URL のホスト名とパスを使用してアプリへのアクセスを保護できます。たとえば、request.path.startsWith の IAM 条件を使用して、URL パスが /admin で始まる場合に特権アクセス グループの従業員にのみアクセスを許可できます。

ホスト名とパスの条件の使用について詳しくは、リクエスト属性をご覧ください。

文字列の正規化

URL にはホスト名とパスがあります。たとえば、URL https://sheets.google.com/create?query=param では sheets.google.com がホスト名、/create がパスになります。

バックエンドでは、さまざまな方法でホスト名とパスを解釈します。あいまいさを取り除くために、IAP はポリシーのチェック時にホスト名とパスの文字列を正規化します。

リクエストに正規化されていないパスがある場合、IAP は 2 つのポリシー チェックを実行します。正規化されていないパスがポリシー チェックに合格すると、IAP はパスを正規化し、2 回目のポリシー チェックを実行します。正規化されていないパスと正規化されたパスの両方がポリシー チェックに合格すると、アクセスが許可されます。

たとえば、リクエストのパスが /internal;some_param/admin の場合、IAP はまず正規化されていないパス(/internal)に対してポリシー チェックを実行します。テストに合格すると、IAP は正規化されたパス(/internal/admin)に対して 2 回目のポリシー チェックを実行します。

ホスト名

ホスト名は次のように正規化されます。

  • 末尾のドットを削除する
  • 大文字を小文字に変換する
  • ASCII に変換する

ASCII 以外の文字を含むホスト名は、さらに Punycode で正規化されます。マッチングを行うには、ホスト名の文字列を Punycode に変換する必要があります。

ホスト名の文字列を Punycode に変換するには、Punycoder のようなコンバータを使用します。

正規化されたホスト名の例を以下に示します。

  • FOO.com は foo.com に正規化されます。
  • café.fr は xn--caf-dma.fr に正規化されます。

パス

パスは以下の方法で正規化されます。

  • パスパラメータを削除する
  • 相対パスを絶対パスに解決する

パスパラメータには、; から次の / またはパスの末尾までのすべての文字が含まれます。

パスセクションの先頭に ..; を含むリクエストは無効と見なされます。たとえば、/..;bar/ と /bar/..;/ は HTTP 400: Bad Request エラーを返します。

正規化されたパスの例を以下に示します。

  • /internal;some_param/admin は /internal/admin に正規化されます。
  • /a/../b は /b に正規化されます。
  • /bar;param1/baz;baz;param2 は /bar/baz に正規化されます。

サブドメインの末尾

request.host.endsWith("google.com") が設定されたポリシーは、sub_domain.google.com と testgoogle.com のいずれにも一致します。ポリシーの適用先を末尾が google.com のすべてのサブドメインに限定するには、request.host.endsWith(".google.com") のようにポリシーを設定します。

ポリシーを request.host.endsWith(".google.com") に設定すると、sub_domain.google.com とは一致しますが、追加の . があるため、google.com とは一致しません。

Cloud Audit Logs とアクセスレベル

IAP で保護されたプロジェクトで Cloud Audit Logs を有効にすると、承認されたアクセス リクエストと承認されなかったアクセス リクエストを確認できます。リクエストとリクエスト送信者のすべてのアクセスレベルを確認するには、次の操作を行います。

  1. プロジェクトに対応する Google Cloud コンソールの ログ エクスプローラに移動します。
    [ログ] ページに移動
  2. リソース セレクタのプルダウン リストからリソースを選択します。 IAP で保護された HTTPS リソースは、App Engine アプリケーションと Compute Engine バックエンド サービスの下にあります。 IAP で保護された SSH リソースと TCP リソースは、Compute Engine VM インスタンスにあります。
  3. [logs type] プルダウン リストで data_access を選択します。
    • data_access ログタイプは、IAP の Cloud Audit Logs を有効にした後にリソースへのトラフィックがあった場合にのみ表示されます。
  4. クリックして、確認するアクセスの日時を展開します。
    • 承認済みのアクセスには、青色の i アイコンが表示されます。
    • 未承認のアクセスには、オレンジ色の !! アイコンが表示されます。
  5. リクエスト送信者のアクセスレベルを確認するには、[protoPayload] > [requestMetadata] > [requestAttributes] > [auth] > [accessLevels] の順にクリックして、セクションを展開します。

リクエストを表示すると、ユーザーが満たしたすべてのアクセスレベルが表示されます。アクセスに必要のないアクセスレベルも表示されます。未承認のリクエストを表示しても、どのアクセスレベルが満たされなかったかはわかりません。これを確認するには、リソースの条件とリクエストに表示されたアクセスレベルを比較する必要があります。

ログの詳細については、Cloud Audit Logs ガイドをご覧ください。