🙅‍♂️

拒否ポリシーでBigQueryのテーブル削除を無効にする

2023/10/17に公開

はじめに

こんにちは、クラウドエース データ ML ディビジョン所属の疋田(ひきた)です。 珍しい苗字でなかなか覚えづらいと思いますので、是非「ヒッキー」と呼んでいただければ嬉しいです。 クラウドエースの IT エンジニアリングを担うシステム開発部の中で、特にデータ基盤構築・分析基盤構築からデータ分析までを含む一貫したデータ課題の解決を専門とするのがデータ ML ディビジョンです。

データML ディビジョンでは活動の一環として、毎週 Google Cloud (旧 Google Cloud Platform、以下「GCP」) の新規リリースを調査・発表し、データ領域のプロダクトのキャッチアップをしています。その中でも重要と考えるリリースを本ページ含め記事として公開しています。
今回ご紹介するリリースは、2023年8月7日にサポートするようになった、拒否ポリシーを介してのアクセス拒否機能です。これにより、誤って権限が付与されたアカウントが BigQuery に対して行う操作の一部を阻止できるようになりました。

前提条件

IAM(Identity and Access Management)

拒否ポリシーの説明の前に、IAM について説明します。IAM とはアクセス制御を管理する機能です。具体的に見ていきます。プリンシパル(=ユーザーアカウントやサービスアカウント等)が GCP 上で作業を行うには権限が必要となります。例えば Google Compute Engine インスタンスの作成や、BigQuery のデータセットを閲覧するにも権限が必要です。このような権限をロール(権限をまとめたもの)にまとめて、プリンシパルに付与するのが IAM の仕組みです。IAM ではプリンシパルに対して与えるロールをポリシーというものに記載します。この時プリンシパルに権限の使用を許可するポリシーを許可ポリシー、権限の使用を拒否するポリシーを拒否ポリシーといいます。

拒否ポリシーとは

改めて拒否ポリシーとは、権限の使用を拒否できる機能です。拒否ポリシーを利用することで、付与されているロールに関係なく、特定のプリンシパルが特定の権限を使用できないようにする設定ができます。以下に許可ポリシーの例(参考資料)、拒否ポリシーの例(参考資料)をそれぞれ示します。それぞれのポリシーは変数名に違いはありますが、どちらも記載されている内容は大きく変わりません。どちらもどのロールについて、どのプリンシパルに対して適用するか、が書かれています。例えば許可ポリシーの例では、"roles/storage.objectAdmin"というロールを、"members"に記載されたプリンシパルに対して許可する、ということを表しています。
また、”maria@example.com”に対しては"roles/storage.objectViewer"を付与する、ということも記載されており、プリンシパルごとにロールの付与が可能となっています。
一方で拒否ポリシーの例では、"//goog/subject/hogehoge@example.com"に対して、"iam.googleapis.com/roles.create"というロールを使用できなくしています。仮に許可ポリシーと拒否ポリシーで同じプリンシパルに対して同じロールについて書かれていた場合、拒否ポリシーの方が強制力が強いため権限が拒否されます。
拒否ポリシーの json ファイルについて詳しく見ていきます。"displayName"では拒否ポリシーの名前を、"rules"では拒否ルールの指定ができます。"deniedPrincipals"では拒否ポリシーを適用したいプリンシパルを、"deniedPermissions"では使用できなくさせたい権限を記述します。これらは省略不可なので必ず記載するようにしましょう。
他にも"exceptionPrincipals"(拒否ポリシー適用対象外のプリンシパル)や"denialCondition"(拒否ポリシー適用時の条件指定)も指定できますが、これらは記述しなくても問題ないため、今回は説明を省略します。

許可ポリシーの例

{
  "bindings": [
    {
      "role": "roles/storage.objectAdmin",
      "members": [
        "user:ali@example.com",
        "serviceAccount:my-other-app@appspot.gserviceaccount.com",
        "group:admins@example.com",
        "domain:google.com"
      ]
    },
    {
      "role": "roles/storage.objectViewer",
      "members": [
        "user:maria@example.com"
      ]
    }
  ]
}

拒否ポリシーの例

{
  "displayName": "My deny policy.",
  "rules": [
    {
      "denyRule": {
        "deniedPrincipals": [
          "principal://goog/subject/hogehoge@example.com"
        ],
        "deniedPermissions": [
          "iam.googleapis.com/roles.create"
        ]
      }
    }
  ]
}

サポートするようになった拒否ポリシー

本リリースでは上記の拒否ポリシーを介して、以下権限を拒否することができるようになりました。これらは全て、BigQuery に関する権限となっています。

  • 予約と容量コミットメントの管理
    • bigquery.googleapis.com/capacityCommitments.*
    • bigquery.googleapis.com/bireservations.*
    • bigquery.googleapis.com/reservationAssignments.*
    • bigquery.googleapis.com/reservations.*
  • リソースの削除
    • bigquery.googleapis.com/datasets.delete
    • bigquery.googleapis.com/tables.delete
    • bigquery.googleapis.com/models.delete
    • bigquery.googleapis.com/routines.delete
    • bigquery.googleapis.com/jobs.delete
    • bigquery.googleapis.com/connections.delete
  • データセットタグ バインディング
    • bigquery.googleapis.com/datasets.createTagBinding
    • bigquery.googleapis.com/datasets.listTagBinding
  • 行アクセスポリシー
    • bigquery.rowAccessPolicies.create
    • bigquery.rowAccessPolicies.delete
    • bigquery.rowAccessPolicies.update
    • bigquery.rowAccessPolicies.setIamPolicy

検証

以下、拒否ポリシーを試していきます。
注意⚠️:検証を行うためには以下の権限が必要となります。組織レベルの権限となっているため、もし試したい場合は管理者に確認を取って権限を付与してもらってから行ってください

・拒否ポリシーを表示する: 拒否審査担当者(roles/iam.denyReviewer)
・拒否ポリシーを表示、作成、更新、削除する: 拒否管理者(roles/iam.denyAdmin)

参考資料:リソースへのアクセスを拒否する

今回は新たに適用できるようになった拒否ポリシーのうち、
"bigquery.googleapis.com/tables.delete"を検証していきます。この拒否ポリシーが適用されたプリンシパルは、BigQuery においてテーブルの削除ができなくなります。今回拒否ポリシーの作成及び BigQuery のテーブルはそれぞれ Google Cloud Shell 上のコマンドで、BigQuery のテーブルの作成は SQL 文にて作成を行いました。検証の前に、GCP のダッシュボードのプロジェクト情報からプロジェクト ID をコピーしておいてください。拒否ポリシー作成の際に使用します。

拒否ポリシーの設定

始めに、拒否ポリシーの指定から始めていきます。まず、Google Cloud Shell を開き、拒否ルールが書かれた json ファイルを作成していきます。
hogehoge@sample.comには、拒否ポリシーを適用したいプリンシパル名(例:自分のアカウント名)を入力してください。

{
  "displayName": "My deny policy.",
  "rules": [
    {
      "denyRule": {
        "deniedPrincipals": [
          "principal://goog/subject/hogehoge@sample.com"
        ],
        "deniedPermissions": [
          "bigquery.googleapis.com/tables.delete"
        ]
      }
    }
  ]
}

json ファイルを作成し終えたら、拒否ポリシーを作成します。以下のコマンドを入力してください。

gcloud iam policies create DISPLAY_NAME \
--attachment-point=cloudresourcemanager.googleapis.com/projects/PROJECT_ID \
--kind=denypolicies \
--policy-file=JSON_PATH

DISPLAY_NAME には json ファイルで設定した名前を入力してください(今回の検証では mydenypolicy )。PROJECT_ID には拒否ポリシーの権限が付与されているアカウントのプロジェクト ID を入力してください。JSON_PATH には、拒否ルールが書かれた json ファイルへのパスを入力してください(ディレクトリ直下であれば直接ファイル名を書いて大丈夫です)。コマンド実行後以下のようなメッセージが出れば拒否ポリシーの作成が完了しています。

Create in progress for denyPolicy [policies/cloudresourcemanager.googleapis.com%2Fprojects...].

作成した拒否ポリシーは以下のコマンドで確認できます。

gcloud iam policies list /
--attachment-point cloudresourcemanager.googleapis.com/projects/PROJECT_ID /
--kind=denypolicies

PROJECT_ID には拒否ポリシー作成時と同じプロジェクト ID を入力してください。実行後、以下のような結果が得られます。

- createTime: '2023-10-10T12:48:17.241823Z'
  displayName: My deny policy.
  kind: DenyPolicy
  name: policies/cloudresourcemanager.googleapis.com...

テーブルの作成及び削除

拒否ポリシーができたら、次に BigQuery でテーブルを作成します。今回は以下のようなテーブルを作成しました。データセット名、テーブル名は任意で大丈夫です(今回はデータセット名を'number_list'、テーブル名を'number_table'としました)。

name number
hikky 1
hikita 2
tomoya 3

作成できましたら、次に Google Cloud Shell上で以下のコマンドを実行してください。

bq rm -f -t PROJECT_ID:DATASET_ID.TABLE_ID

PROJECT_ID ,DATASET_ID ,TABLE_ID にはそれぞれ対応するものを入力してください。
実行後、以下のような出力が出れば、拒否ポリシーが正しく適用されています。

BigQuery error in rm operation: Access Denied: Table eco-condition-401601:number_list.number_table: Permission bigquery.tables.delete denied on table eco-condition-401601:number_list.number_table (or it may not exist).

また、BigQuery 上で直接削除しようとしても、以下のようにエラーが出ます。

alt

最後に、拒否ポリシーを削除します。削除し忘れると、テーブルの削除を行えないままとなってしまうため、注意しましょう。拒否ポリシーの削除は以下のコマンドで行えます。

gcloud iam policies delete POLICY_ID /
--attachment-point=cloudresourcemanager.googleapis.com/projects/PROJECT_ID /
--kind=denypolicies

POLICY_ID 及びPROJECT_ID にはそれぞれ対応するものを入力してください。実行後、拒否ポリシーが削除されたかの確認を行うため、再度以下のコマンドを入力します。何も表示されていなければ削除成功です。

gcloud iam policies list /
--attachment-point cloudresourcemanager.googleapis.com/projects/PROJECT_ID /
--kind=denypolicies

以上で、"bigquery.googleapis.com/tables.delete"に対して拒否ポリシーが適用できることの検証を終わります。

余談

テーブルではなく、データセットごと削除しようとした場合にもエラーメッセージが表示されました。このことから、テーブルの削除について拒否ポリシーが適用されているプリンシパルは、そのテーブルを含むデータセットも削除できないことが分かりました。

alt

まとめ

BigQuery の一部の権限に対して拒否ポリシーが適用できるようになりました。拒否ポリシーはうまく活用できれば、アカウントレベルで強制的に権限の使用を拒否できます。そのため、誤って権限が付与されていた際にも拒否ポリシーを設定しておけば不測の事態には陥らないことでしょう。例えば、BigQuery のOwner ロールを誤って付与してしまった際に、今回のリリースで使用可能となった"bigquery.googleapis.com/datasets.delete"に対する拒否ポリシーを適用しておけば少なくともデータを削除される心配がなくなります。しかし、拒否ポリシーはかなり強い権限であるため、闇雲に扱うと組織全体に被害が及ぶ可能性があります。拒否ポリシー適用の際は最大限注意しましょう。

Discussion