リソースベースのアクセスを構成する

このトピックでは、許可ポリシーで条件付きロール バインディングを使用して、特定のリソースへのアクセスを管理する方法について説明します。条件式でリソース属性を使用すると、リソース名、リソースタイプ、Google Cloud サービスに基づいてロール バインディングのサブスコープを付与できます。

始める前に

  • IAM の条件付きロール バインディングの基本については、Identity and Access Management(IAM)Conditions の概要をご覧ください。
  • 条件式で使用できるリソース属性を確認してください。
  • リソース名属性では、次の Google Cloud サービスへのアクセスを制御できます。
    • Apigee
    • Application Integration
    • BigQuery
    • Binary Authorization
    • Bigtable
    • Cloud Key Management Service
    • Cloud Logging
    • Spanner
    • Cloud SQL
    • Cloud Storage
    • Compute Engine
    • Dataform
    • Google Kubernetes Engine
    • Integration Connectors
    • Pub/Sub Lite
    • Secret Manager

必要なロール

条件付きロール バインディングの管理に必要な権限を取得するには、次の IAM ロールを付与するよう管理者に依頼してください。

  • プロジェクトへのアクセスを管理する: プロジェクトに対するプロジェクト IAM 管理者roles/resourcemanager.projectIamAdmin
  • フォルダへのアクセスを管理する: フォルダに対するフォルダ管理者roles/resourcemanager.folderAdmin
  • プロジェクト、フォルダ、組織へのアクセスを管理する: 組織に対する組織管理者roles/resourcemanager.organizationAdmin
  • ほぼすべての Google Cloud リソースへのアクセスを管理する: リソースへのアクセスを管理するプロジェクト、フォルダ、または組織に対するセキュリティ管理者roles/iam.securityAdmin

ロールの付与の詳細については、アクセスの管理をご覧ください。

これらの事前定義ロールには、条件付きロール バインディングの管理に必要な権限が含まれています。必要な権限を正確に確認するには、[必要な権限] セクションを開いてください。

必要な権限

条件付きロール バインディングを管理するには、次の権限が必要です。

  • プロジェクトへのアクセスを管理するには:
    • プロジェクトに対する resourcemanager.projects.getIamPolicy
    • プロジェクトに対する resourcemanager.projects.setIamPolicy
  • フォルダへのアクセスを管理するには:
    • フォルダに対する resourcemanager.folders.getIamPolicy
    • フォルダに対する resourcemanager.folders.setIamPolicy
  • 組織へのアクセスを管理するには:
    • 組織に対する resourcemanager.organizations.getIamPolicy
    • 組織に対する resourcemanager.organizations.setIamPolicy

カスタムロールや他の事前定義ロールを使用して、これらの権限を取得することもできます。

リソース名の接頭辞に基づいてリソースのグループにアクセス権を付与する

条件付きロール バインディングを使用すると、リソース名が接頭辞と一致するリソースのプリンシパルに、名前が特定の文字列で始まる Compute Engine 仮想マシン(VM)インスタンスなどのアクセスを付与できます。通常、リソース名接頭辞は、特定の機能向けのリソースや特定のプロパティを持つリソースをグループ化するために使用します。

次に例を示します。ソフトウェア企業の ExampleCo は、機密性の高いヘルスケア データを処理する特定の VM インスタンスでワークロードを実行しています。その他の機密性の低いワークロードは同じプロジェクトで実行する必要があり、ExampleCo はデベロッパーが機密データを処理する VM インスタンスへのアクセスを制限しなければなりません。この目的のために、機密性の高いデータが含まれる VM インスタンスの名前には sensitiveAccess 接頭辞が付き、他の VM インスタンスの名前には devAccess 接頭辞が付きます。次に、条件付きロール バインディングを使用して、デベロッパーが通常の devAccess VM インスタンスで生産性を維持できるようにしますが、sensitiveAccess VM インスタンスへのアクセスは付与しません。

resource.name 条件属性のみを使用してアクセスを管理できますが、resource.type 属性と resource.service 属性も使用するのが一般的です。このような追加属性を使用すると、類似した名前の異なるリソースタイプへのアクセスに条件が影響する可能性が低くなります。このセクションの例では、resource.nameresource.type 属性の両方を使用してアクセスを制御します。

プロジェクト内の Compute Engine ディスクとインスタンスに名前接頭辞を使用してアクセスを許可するには、次を行います。

コンソール

  1. Google Cloud コンソールの [IAM] ページに移動します。

    [IAM] ページに移動

  2. プリンシパルのリストから、目的のプリンシパルを見つけて、[] ボタンをクリックします。

  3. [権限の編集] パネルで、条件を構成するロールを見つけます。[IAM の条件(省略可)] で、[IAM の条件を追加] をクリックします。

  4. [条件の編集] パネルで、条件のタイトルとオプションの説明を入力します。

  5. 条件ビルダーまたは条件エディタを使用して条件式を追加できます。条件ビルダーには、目的の条件タイプ、演算子、その他の式に関する適用可能な詳細を選択するためのインタラクティブなインターフェースが用意されています。条件エディタには、CEL 構文を使用して手動で式を入力するためのテキストベースのインターフェースが用意されています。

    条件ビルダー:

    1. [追加] プルダウンをクリックして、[グループ化された条件] をクリックします。
    2. [条件タイプ] プルダウンから、[リソース] > [タイプ] の順に選択します。
    3. [演算子] プルダウンから、[] を選択します。
    4. [リソースタイプ] プルダウンから、[compute.googleapis.com/Disk] を選択します。
    5. 先ほど入力した条件のすぐ下の最初の [追加] ボタンをクリックして、式に別の句を追加します。
    6. [条件タイプ] プルダウンから、[リソース] > [名前] の順に選択します。
    7. [演算子] プルダウンから、[で始まる] を選択します。
    8. [] フィールドに、devAccess で名前が始まるディスクの projects/project-123/zones/us-central1-a/disks/devAccess などの適切な形式でリソース名を入力します。
    9. 各条件タイプの左側で、[] をクリックして、両方の句が true になるようにします。
    10. [保存] ボタンのすぐ上の [追加] ボタンをクリックして、別の条件のグループを追加します。
    11. [条件タイプ] プルダウンから、[リソース] > [タイプ] の順に選択します。
    12. [演算子] プルダウンから、[] を選択します。
    13. [リソースタイプ] プルダウンから、[compute.googleapis.com/Instance] を選択します。
    14. 先ほど入力した条件のすぐ下の最初の [追加] ボタンをクリックして、式に別の句を追加します。
    15. [条件タイプ] プルダウンから、[リソース] > [名前] の順に選択します。
    16. [演算子] プルダウンから、[で始まる] を選択します。
    17. [] フィールドに、devAccess で名前が始まるインスタンスの projects/project-123/zones/us-central1-a/instances/devAccess などの適切な形式でリソース名を入力します。
    18. 各条件タイプの左側で、[] をクリックして、両方の句が true になるようにします。
    19. [保存] ボタンのすぐ上の [追加] ボタンをクリックして、3 番目の条件のグループを追加します。
    20. この条件が他のリソースに影響しないようにするには、次の句も追加します。[条件タイプ] プルダウンから、[リソース] > [タイプ] の順に選択します。
    21. [演算子] プルダウンから、[ではありません] を選択します。
    22. [リソースタイプ] プルダウンから、[compute.googleapis.com/Disk] を選択します。
    23. 先ほど入力した条件のすぐ下の最初の [追加] ボタンをクリックして、式に別の句を追加します。
    24. [条件タイプ] プルダウンから、[リソース] > [タイプ] の順に選択します。
    25. [演算子] プルダウンから、[ではありません] を選択します。
    26. [リソースタイプ] プルダウンから、[compute.googleapis.com/Instance] を選択します。
    27. 各条件タイプの左側で、[] をクリックして、両方の句が true になるようにします。
    28. 終了すると、条件ビルダーは次のようになります。

    29. [保存] をクリックして条件を適用します。

    30. [条件の編集] パネルを閉じたら、[権限の編集] パネルでもう一度 [保存] をクリックし、許可ポリシーを更新します。

    条件エディタ:

    1. [条件エディタ] タブをクリックし、次の式を入力します。

      (resource.type == "compute.googleapis.com/Disk" &&
      resource.name.startsWith("projects/project-123/regions/us-central1/disks/devAccess")) ||
      (resource.type == "compute.googleapis.com/Instance" &&
      resource.name.startsWith("projects/project-123/zones/us-central1-a/instances/devAccess")) ||
      (resource.type != "compute.googleapis.com/Disk" &&
      resource.type != "compute.googleapis.com/Instance")
    2. 式を入力したら、右上のテキスト ボックスの上にある [リンターを実行] をクリックして、CEL 構文を lint にすることもできます。

    3. [保存] をクリックして条件を適用します。

    4. [条件の編集] パネルを閉じたら、[権限の編集] パネルでもう一度 [保存] をクリックし、許可ポリシーを更新します。

gcloud

許可ポリシーは、読み取り、変更、書き込みのパターンを使用して設定されます。

gcloud projects get-iam-policy コマンドを実行し、プロジェクトの現在の許可ポリシーを取得します。次の例では、JSON バージョンの許可ポリシーがディスク上のパスにダウンロードされます。

コマンド:

gcloud projects get-iam-policy project-id --format=json > filepath

JSON 形式の許可ポリシーがダウンロードされます。

{
  "bindings": [
    {
      "members": [
        "user:project-owner@example.com"
      ],
      "role": "roles/owner"
    },
    {
      "members": [
        "group:devs@example.com"
      ],
      "role": "roles/compute.instanceAdmin"
    }
  ],
  "etag": "BwWKmjvelug=",
  "version": 1
}

リソース名接頭辞の条件を指定してポリシーを構成するには、次の条件式(強調表示されている部分)を追加します。gcloud CLI により、バージョンが自動的に更新されます。

{
  "bindings": [
    {
      "members": [
        "user:project-owner@example.com"
      ],
      "role": "roles/owner"
    },
    {
      "members": [
        "group:devs@example.com"
      ],
      "role": "roles/compute.instanceAdmin",
      "condition": {
          "title": "Dev_access_only",
          "description": "Only access to devAccess* VMs",
          "expression":
            "(resource.type == 'compute.googleapis.com/Disk' &&
            resource.name.startsWith('projects/project-123/regions/us-central1/disks/devAccess')) ||
            (resource.type == 'compute.googleapis.com/Instance' &&
            resource.name.startsWith('projects/project-123/zones/us-central1-a/instances/devAccess')) ||
            (resource.type != 'compute.googleapis.com/Instance' &&
            resource.type != 'compute.googleapis.com/Disk')"
      }
    }
  ],
  "etag": "BwWKmjvelug=",
  "version": 3
}

次に、gcloud projects set-iam-policy コマンドを実行して新しい許可ポリシーを設定します。

gcloud projects set-iam-policy project-id filepath

新しい条件付きロール バインディングでは、次の方法で devs@example.com 権限を付与します。

  • リソース名が devAccess で始まる場合に限り、ディスクとインスタンスのすべての権限が付与されます。

  • インスタンス管理者ロールの他のすべての権限は、他のすべてのリソースタイプに対して付与されます。

REST

読み取り、変更、書き込みのパターンを使用して、特定のリソースへのアクセスを許可します。

まず、プロジェクトの許可ポリシーを読み取ります。

Resource Manager API の projects.getIamPolicy メソッドは、プロジェクトの許可ポリシーを取得します。

リクエストのデータを使用する前に、次のように置き換えます。

  • PROJECT_ID: Google Cloud プロジェクト ID。プロジェクト ID は英数字からなる文字列です(例: my-project)。
  • POLICY_VERSION: 返されるポリシー バージョン。リクエストでは、最新のポリシー バージョン(ポリシー バージョン 3)を指定する必要があります。詳細については、ポリシーの取得時にポリシー バージョンを指定するをご覧ください。

HTTP メソッドと URL:

POST https://cloudresourcemanager.googleapis.com/v1/projects/PROJECT_ID:getIamPolicy

リクエストの本文(JSON):

{
  "options": {
    "requestedPolicyVersion": POLICY_VERSION
  }
}

リクエストを送信するには、次のいずれかのオプションを展開します。

次のような JSON レスポンスが返されます。

{
  "version": 1,
  "etag": "BwWKmjvelug=",
  "bindings": [
    {
      "role": "roles/owner",
      "members": [
        "user:project-owner@example.com"
      ]
    },
    {
      "members": [
        "group:devs@example.com"
      ],
      "role": "roles/compute.instanceAdmin"
    }
  ]
}

次に、特定のリソースへのアクセスを許可するように許可ポリシーを変更します。version フィールドを値 3 に変更します。

{
  "version": 3,
  "etag": "BwWKmjvelug=",
  "bindings": [
    {
      "role": "roles/owner",
      "members": [
        "user:project-owner@example.com"
      ]
    },
    {
      "role": "roles/compute.instanceAdmin",
      "members": [
        "group:devs@example.com"
      ],
      "condition": {
          "title": "Dev_access_only",
          "description": "Only access to devAccess* VMs",
          "expression":
            "(resource.type == 'compute.googleapis.com/Disk' &&
            resource.name.startsWith('projects/project-123/regions/us-central1/disks/devAccess')) ||
            (resource.type == 'compute.googleapis.com/Instance' &&
            resource.name.startsWith('projects/project-123/zones/us-central1-a/instances/devAccess')) ||
            (resource.type != 'compute.googleapis.com/Instance' &&
            resource.type != 'compute.googleapis.com/Disk')"
      }
    }
  ]
}

最後に、更新された許可ポリシーを作成します。

Resource Manager API の projects.setIamPolicy メソッドは、リクエストのポリシーをプロジェクトの新しい許可ポリシーとして設定します。

リクエストのデータを使用する前に、次のように置き換えます。

  • PROJECT_ID: Google Cloud プロジェクト ID。プロジェクト ID は英数字からなる文字列です(例: my-project)。

HTTP メソッドと URL:

POST https://cloudresourcemanager.googleapis.com/v1/projects/PROJECT_ID:setIamPolicy

リクエストの本文(JSON):

{
  "policy": {
    "version": 3,
    "etag": "BwWKmjvelug=",
    "bindings": [
      {
        "role": "roles/owner",
        "members": [
          "user:project-owner@example.com"
        ]
      },
      {
        "role": "roles/compute.instanceAdmin",
        "members": [
          "group:devs@example.com"
        ],
        "condition": {
          "title": "Dev_access_only",
          "description": "Only access to devAccess* VMs",
          "expression":
            "(resource.type == 'compute.googleapis.com/Disk' &&
            resource.name.startsWith('projects/project-123/regions/us-central1/disks/devAccess')) ||
            (resource.type == 'compute.googleapis.com/Instance' &&
            resource.name.startsWith('projects/project-123/zones/us-central1-a/instances/devAccess')) ||
            (resource.type != 'compute.googleapis.com/Instance' &&
            resource.type != 'compute.googleapis.com/Disk')"
        }
      }
    ]
  }
}

リクエストを送信するには、次のいずれかのオプションを展開します。

レスポンスには、更新された許可ポリシーが含まれます。


リソース名から値を抽出する

上記の例では、リソース名またはリソース名の先頭と別の値のブール値比較を示しています。ただし、ある値を、リソース名の先頭にない部分と比較する必要がある場合もあります。

たとえば、extract() 関数を使用して抽出テンプレートを指定し、リソース名の関連部分を文字列として抽出できます。必要に応じて、抽出した文字列をタイムスタンプなどの別の型に変換できます。リソース名から値を抽出すると、その値を他の値と比較できます。

次の例では、extract() 関数を使用する条件式を示しています。extract() 関数の詳細については、IAM Conditions 属性のリファレンスをご覧ください。

例: 過去 30 日間の注文の照合

注文情報を複数の Cloud Storage バケットに格納し、各バケット内のオブジェクトが日付順に整理されているとします。一般的なオブジェクト名は、次の例のようになります。

projects/_/buckets/acme-orders-aaa/objects/data_lake/orders/order_date=2019-11-03/aef87g87ae0876

プリンシパルが過去 30 日間のすべての注文にアクセスできるようにします。次の条件は、これらの注文の Cloud Storage オブジェクトと一致します。duration()date() 関数を使用して、リクエスト日から 30 日分(2,592,000 秒)を減算して、そのタイムスタンプを注文日と比較します。

resource.type == 'storage.googleapis.com/Object' &&
  request.time - duration('2592000s') < date(resource.name.extract('/order_date={date_str}/'))

date()duration() 関数の詳細については、日時属性の参照をご覧ください。

例: 任意のロケーションの Compute Engine VM の照合

VM のロケーションに関係なく、名前が dev- で始まる Compute Engine VM のプリンシパルにプロジェクト レベルのロールを付与するとします。また、プリンシパルが、他のすべてのリソースタイプでそのロールを使用できるようにするとします。

VM のリソース名は、projects/project-id/zones/zone-id/instances/instance-name のような形式を使用します。文字列 dev- で始まるインスタンス名の VM と、VM 以外のすべてのリソースタイプの場合、次の条件は true と評価されます。

resource.type != 'compute.googleapis.com/Instance' ||
  resource.name.extract('/instances/{name}').startsWith('dev-')

中かっこ内のテキストは、比較のために抽出されたリソース名の部分を識別します。この例では、抽出テンプレートは文字列 /instances/ が最初に出現した後に任意の文字を抽出します。

リソースベースの条件に関する重要な使用上の考慮事項

リソースベースの条件を追加する場合は、条件がプリンシパルの権限にどのように影響するかを考慮することが重要です。

カスタムロール

カスタムロールにかかわる次の例を考えてみましょう。管理者には、カスタムロールを作成して、アクセス権を付与し、VM インスタンスを作成するという目的があります。ただし、ユーザーに許可するのは、リソース名が名前の接頭辞 staging で始まるプロジェクト内に、同じ名前の接頭辞のディスクを使用して、VM インスタンスを作成することのみです。

この目的のためには、付与されたロールに VM インスタンスを作成するための必要な権限が含まれていることを確認します。これは、ディスク リソースとインスタンス リソース タイプに対する権限です。次に、条件式でリソース名のディスクとインスタンスの両方を確認します。この 2 つのタイプ以外では、ロールの他の権限は付与されません。

次の条件式では、予期しない動作が発生します。Compute Engine VM を操作する権限がブロックされています。

resource.type == 'compute.googleapis.com/Disk' &&
 resource.name.startsWith('projects/project-123/regions/us-central1/disks/staging')

次の条件式にはディスクとインスタンスの両方が含まれ、この 2 つのタイプのリソース名に基づいてアクセスが管理されます。

(resource.type == 'compute.googleapis.com/Disk' &&
  resource.name.startsWith('projects/project-123/regions/us-central1/disks/staging')) ||
 (resource.type == 'compute.googleapis.com/Instance' &&
  resource.name.startsWith('projects/project-123/zones/us-central1-a/instances/staging'))

次の条件式にはディスクとインスタンスの両方が含まれ、この 2 つのタイプのリソース名に基づいてアクセスが管理されます。他のリソースタイプについては、リソース名に関係なくこの条件式でロールが付与されます。

(resource.type == 'compute.googleapis.com/Disk' &&
  resource.name.startsWith('projects/project-123/regions/us-central1/disks/staging')) ||
 (resource.type == 'compute.googleapis.com/Instance' &&
  resource.name.startsWith('projects/project-123/zones/us-central1-a/instances/staging')) ||
 (resource.type != 'compute.googleapis.com/Disk' &&
  resource.type != 'compute.googleapis.com/Instance')

親のみの権限

Google Cloud のリソース階層では、子リソースに影響するロールの一部の権限は、親レベルでのみ適用されます。たとえば、Cloud KMS の暗号鍵をリストするには、ユーザーには、鍵自体ではなく暗号鍵を含むキーリングに対する cloudkms.cryptokeys.list 権限が付与される必要があります。このような種類の権限は親限定権限と呼ばれ、list オペレーションにのみ適用されます。

条件を使用する際の *.*.list 権限へのアクセス権を適切に付与するには、一覧表示するターゲット リソースの親リソースタイプに従って、条件式で resource.service 属性と resource.type 属性を設定する必要があります。

以下の例を考えてみましょう。前述の Compute Engine の例を使用すると、次の式では、compute.disks.listcompute.instances.list 権限へのアクセス権が防止されます。この権限が防止されるリソースは、cloudresourcemanager.googleapis.com/Projectresource.type 属性値を持つためです。

(resource.type == 'compute.googleapis.com/Disk' &&
  resource.name.startsWith('projects/project-123/regions/us-central1/disks/devAccess')) ||
 (resource.type == 'compute.googleapis.com/Instance' &&
  resource.name.startsWith('projects/project-123/zones/us-central1-a/instances/devAccess'))

一般的に、この list 権限は、リソースに対する通常の操作のための他の権限とともに付与されます。この場合の付与の範囲を増やすには、cloudresourcemanager.googleapis.com/Project タイプの範囲のみを拡張するか、インスタンスまたはディスク以外のすべての権限に範囲を拡張します。

(resource.type == 'compute.googleapis.com/Disk' &&
  resource.name.startsWith('projects/project-123/regions/us-central1/disks/devAccess')) ||
 (resource.type == 'compute.googleapis.com/Instance' &&
  resource.name.startsWith('projects/project-123/zones/us-central1-a/instances/devAccess')) ||
 resource.type == 'cloudresourcemanager.googleapis.com/Project'

または

(resource.type == 'compute.googleapis.com/Disk' &&
  resource.name.startsWith('projects/project-123/regions/us-central1/disks/devAccess')) ||
 (resource.type == 'compute.googleapis.com/Instance' &&
  resource.name.startsWith('projects/project-123/zones/us-central1-a/instances/devAccess')) ||
 (resource.type != 'compute.googleapis.com/Disk' &&
  resource.type != 'compute.googleapis.com/Instance')