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

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

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

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

始める前に

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

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

アクセスレベルの設定

IP アドレスまたはエンドユーザーのデバイス属性に基づいてアクセスを制限するには、アクセスレベルを作成する必要があります。アクセスレベルの作成方法については、Access Context Manager のガイドをご覧ください。IAP は、アクセスレベル名を使用して、IAP で保護されたアプリとアクセスレベルを関連付けます。

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

IAM ポリシーの変更

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

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

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

IAM 条件付きバインディングで指定された request.hostrequest.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. 次の App Engine 変数をエクスポートします。

    # The APP_ID is usually the project ID
    export GAE_APP_ID=APP_ID
    export GAE_BASE_URL=${IAP_BASE_URL}/appengine-${GAE_APP_ID}

  2. getIamPolicy メソッドを使用して、App Engine アプリの IAM ポリシーを取得します。最後にある空のデータビットを使用して、curl リクエストを GET ではなく POST に変えます。

    curl -i -H "Authentication: Bearer $(gcloud auth print-access-token)" \
    ${GAE_BASE_URL}/:getIamPolicy -d ''

  3. 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"
      }
    }
    ]
    }
    }

  4. setIamPolicy メソッドを使用して、新しい policy.json ファイルを設定します。

    curl -i -H "Authentication: Bearer $(gcloud auth print-access-token)" \
    ${GAE_BASE_URL}:setIamPolicy -d @${JSON_NEW_POLICY}

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

App Engine サービス、すべてのバージョンまたはサービスの特定のバージョンの IAM ポリシーを更新することもできます。この処理を特定のバージョンのサービスに対して行うには:

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

GKE と Compute Engine

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

    export BACKEND_SERVICE_NAME=BACKEND_SERVICE_NAME

  2. getIamPolicy メソッドを使用して、Compute Engine アプリの IAM ポリシーを取得します。最後にある空のデータビットを使用して、curl リクエストを GET ではなく POST に変えます。

    curl -i -H "Authentication: Bearer $(gcloud auth print-access-token)" \
     ${IAP_BASE_URL}/compute/services/${BACKEND_SERVICE_NAME}:getIamPolicy \
     -d ''

  3. 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"
    }
    }
    ]
    }
    }

  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.comfoo.com に正規化されます。
  • café.frxn--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.comtestgoogle.com のいずれにも一致します。ポリシーの適用先を末尾が google.com のすべてのサブドメインに限定するには、request.host.endsWith(".google.com") のようにポリシーを設定します。

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

Cloud 監査ログとアクセスレベル

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

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

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

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