Google Cloud Storageへのアクセスを制御する方法まとめ

2023.06.14

Google Cloudのデータエンジニアをしています、はんざわです。
この記事では特定のCloud Storage Bucketへのアクセスを制御する方法をまとめて紹介したいと思います。

Cloud Storageへのアクセス制御の方法

アクセスを制御する方法として均一(Uniform)きめ細かい管理(Fine-grained)の2種類が存在します。

  • 均一(Uniform)

管理方法: IAMのみ

管理範囲: バケットレベル

  • きめ細かい管理(Fine-grained)

管理方法: IAM + ACLの両方

管理範囲: オブジェクトレベル

制御方法は2種類存在しますが基本的に均一で制御することが推奨されています

理由として以下のような理由が挙げられます。

1. 管理が複雑になる

IAMに加え、ACLの管理も必要になり、権限の管理がより複雑になります。
また、正しくオブジェクトのアクセス権限を設定しなければ本来制限したいはずのファイルが誤表示されてしまう可能性があります。

2. IAMとACLは並行して作用する

IAMとACLは並行して作用します。
例えば、IAMでオブジェクトの読み取りのみ許可され、ACLでオブジェクトの一般公開が設定されている場合、そのオブジェクトは公開されてしまいます。
この例のように想定していないデータ漏洩の危険性が高まります。

ACLでのIAM権限の使用

対応策

下記の推奨アーキテクチャのようにアクセスを制限したいのであれば1つのバケット内でオブジェクトの権限を設定するのではなく、制限したいオブジェクトをそれぞれ別のバケットに保存し、バケット単位でアクセスの制限をかけるようにしましょう。

IAMでアクセスを制限する

前述した通り、現在は基本的にIAMでバケットへのアクセスを制限することが推奨されています。
しかし、IAMでアクセス制御する方法も2通りあります。

  1. バケットにアクセス権限を付与する
  2. IAM Conditionsで条件を付ける

それぞれ詳しく見ていきましょう。

前準備

2つの検証を進める前にService AccountとStorage Bucketを2つずつ作成します。

# 2つのService Accountを作成

$ gcloud iam service-accounts create test-sa-1 \
    --display-name="Cloud Storage Service Account 1"

$ gcloud iam service-accounts create `` \
    --display-name="Cloud Storage Service Account 2"

# 2つのStorage Bucketを作成

$ gcloud storage buckets create gs://access-control-bucket1 \
    --location="asia-northeast1" \
    --uniform-bucket-level-access

$ gcloud storage buckets create gs://access-control-bucket2 \
    --location="asia-northeast1" \
    --uniform-bucket-level-access

それぞれのバケットにテキストファイルを配置する。

$ echo "Hello World" > test.txt

$ gcloud storage cp test.txt gs://access-control-bucket1
$ gcloud storage cp test.txt gs://access-control-bucket2

Service AccountでCLI操作できるように承認する。

# それぞれのSAのクレデンシャルキーを発行
$ gcloud iam service-accounts keys create credentials_1.json \
    --iam-account=test-sa-1@hanzawa-yuya.iam.gserviceaccount.com

$ gcloud iam service-accounts keys create credentials_2.json \
    --iam-account=test-sa-2@hanzawa-yuya.iam.gserviceaccount.com

# クレデンシャルキーを使ってログイン
$ gcloud auth login --cred-file=credentials_1.json 
$ gcloud auth login --cred-file=credentials_2.json

# 確認
$ gcloud auth list

> Credentialed Accounts

> ACTIVE: 
> ACCOUNT: test-sa-1@hanzawa-yuya.iam.gserviceaccount.com

> ACTIVE:
> ACCOUNT: test-sa-2@hanzawa-yuya.iam.gserviceaccount.com

1. バケットにアクセス権限を付与する

まずは前準備で作成したgs://access-control-bucket1のバケットにtest-sa-1のサービスアカウントがファイルを参照できるように権限を割り当てます。

$ gsutil iam ch serviceAccount:test-sa-1@hanzawa-yuya.iam.gserviceaccount.com:roles/storage.objectViewer \
    gs://access-control-bucket1

次にユーザーアカウントからtest-sa-1に切り替えます。

$ gcloud config set account test-sa-1@hanzawa-yuya.iam.gserviceaccount.com

参照権限を付与しているバケットとそうでないバケットにアクセスしてみる。

$ gcloud storage ls gs://access-control-bucket1

> gs://access-control-bucket1/test.txt

$ gcloud storage ls gs://access-control-bucket2

> ERROR: (gcloud.storage.ls) User [test-sa-1@hanzawa-yuya.iam.gserviceaccount.com] does not have permission to access b instance [access-control-bucket2] (or it may not exist): 
> test-sa-1@hanzawa-yuya.iam.gserviceaccount.com does not have storage.objects.list access to the Google Cloud Storage bucket. 
> Permission 'storage.objects.list' denied on resource (or it may not exist).

権限を付与しているバケットのファイルは参照でき、そうでないバケットはアクセス拒否されていることがわかります。
このように適切にバケットに対し、権限を付与することでファイルの参照や取得などを制御することができます。

2. IAM Conditionsで条件を付ける

そもそもIAM Conditionsとは

IAM Conditionsを使うと指定された条件を満たす場合にのみアクセス権限を付与するように設定することできます。
条件というのは特定のリソースのタイプであったり、特定の接頭語で始まるリソース名であったり、特定のタグを持つリソース名であったりと様々な条件を付与することが可能です。
また、IAM Conditionsはプロジェクトレベルの権限にのみ適用することが可能です

今回の検証ではCloud StorageでIAM Conditionsを使用していますが、他にもBigQueryをはじめとする様々なリソースで使用することができます。
使用可能なリソースの種類は以下のリンクから確認できます。

条件付きロールバインディングを許可するリソースタイプ

ここではIAM Conditionsで特定の接頭語で始まるバケットにのみアクセスできるように制限を掛けてみたいと思います。

検証

設定したい条件を記述したファイルを用意します。
ファイルはJSONかYAML形式で記述し、titleexpressionのフィールドは必須項目です。
expressionでは条件を記述することが可能でCELで定義します。CELの詳細は以下のリンクで確認できます。

条件のCEL

前述した通り、特定の接頭語で始まるリソースにのみアクセスできるように条件を定義します。
以下のファイルではaccess-control-bucket2で始めるバケットにのみアクセスできるように設定しています。

$ cat condition.yaml

> title: test-conditions
> expression: resource.name.startsWith('projects/_/buckets/access-control-bucket2')

前準備で用意したtest-sa-2のサービスアカウントにプロジェクトレベルのファイル参照権限と上記の条件を付与します。
ここではあらかじめcondition.yamlを用意し、--condition-from-fileでファイルを指定していますが--conditionで直接ファイルの中身を指定することも可能です。

$ gcloud projects add-iam-policy-binding hanzawa-yuya \
    --member=serviceAccount:test-sa-2@hanzawa-yuya.iam.gserviceaccount.com \
    --role="roles/storage.objectViewer" \
    --condition-from-file=condition.yaml

それぞれのバケットにアクセスしてみる。

$ gcloud storage ls gs://access-control-bucket1

> ERROR: (gcloud.storage.ls) User [test-sa-2@hanzawa-yuya.iam.gserviceaccount.com] does not have permission to access b instance [access-control-bucket1] (or it may not exist):
> test-sa-2@hanzawa-yuya.iam.gserviceaccount.com does not have storage.objects.list access to the Google Cloud Storage bucket.
> Permission 'storage.objects.list' denied on resource (or it may not exist).

$ gcloud storage ls gs://access-control-bucket2

> gs://access-control-bucket2/test.txt

想定通り、access-control-bucket2で始まるバケットにのみアクセスすることができ、そうでないバケットにはアクセスが拒否されていることがわかります。

結局どっちを使えばいいのか

基本的にバケットにアクセス権限を付与するようにし、どうしてもプロジェクトレベルの権限が必要な場合にのみIAM Conditionsで条件を付けるように権限を割り振れば良いと考えられます。

これは多くのクラウドサービスでは最小権限の原則に従うことが推奨されており、あるリソースに対してその機能に必要なリソースのみへのアクセスを許可するように権限を振り分けることがベストプラクティスとなっているからです。

総評

今回の記事ではバケットのアクセス制御についてまとめました。
Cloud Storageやs3は非常に便利なストレージサービスですが、使い方を少し間違えるだけで情報漏洩のリスクが生じてしまいます。
管理方法を正確に理解し、適切に管理するように心がけましょう。