概要
の実践編です。
特定のGCSバケットにのみアクセスできるサービスアカウントを作ってみます。
前提
- 新規で作るサービスアカウントに対してのアクセス制御を行う
- 既存のアカウントに対するアクセス制御は行わない
- 特定のGCSバケットにのみアクセスさせる
作り方
準備
バケットの用意
テスト用のバケットを用意します。
$ gsutil mb -c regional -l us-east1 -b on gs://jun06t-iam-test Creating gs://jun06t-iam-test/...
作成されました。
アクセスするオブジェクトも用意しておきます。
$ echo "Hello World" > sample.txt $ gsutil cp sample.txt gs://jun06t-iam-test
サービスアカウントの用意
次にサービスアカウントを用意します。
$ gcloud iam service-accounts create gcs-sa \ --description="GCSバケットアクセス用" \ --display-name="gcs-sa"
作成されました。
アクセスするためのサービスアカウントキーも作成しておきます。
$ gcloud iam service-accounts keys create ./sa-private-key.json \ --iam-account=gcs-sa@<project_name>.iam.gserviceaccount.com
実行プログラムで使えるように環境変数に読み込ませておきます。
$ export GOOGLE_APPLICATION_CREDENTIALS=./sa-private-key.json
キーを使ってバケットにアクセスするコード
Goでサクッと書いてみます。
func main() { ctx := context.Background() data, err := getObject(ctx) if err != nil { panic(err) } fmt.Printf("%s\n", data) } func getObject(ctx context.Context) ([]byte, error) { client, err := storage.NewClient(ctx) if err != nil { return nil, err } bucketName := "jun06t-iam-test" object := "sample.txt" rc, err := client.Bucket(bucketName).Object(object).NewReader(ctx) if err != nil { return nil, err } defer rc.Close() data, err := ioutil.ReadAll(rc) if err != nil { return nil, err } return data, nil }
動作検証
アクセス権限が無いので当然コケます。
$ go run main.go
panic: googleapi: got HTTP response code 403 with body
アクセス制御は2通りある
IAMを理解すると今回は2通りの方法があることが分かります。
1. リソースレベル(そのバケットのみ)のIAMポリシーを作る
roles/storage.objectViewer
のロールで作成します。
$ gsutil iam ch serviceAccount:gcs-sa@<project_name>.iam.gserviceaccount.com:roles/storage.objectViewer \ gs://jun06t-iam-test
確認してみます。
{ "bindings": [ ... // 基本ロール { "members": [ "serviceAccount:gcs-sa@<project_name>.iam.gserviceaccount.com" ], "role": "roles/storage.objectViewer" } ], "etag": "CAI=" }
アセットの方でもリソースレベルのIAMポリシーが確認できます。
$ gcloud asset search-all-iam-policies \ --scope=projects/<project_name> \ --query="policy:gcs-sa" --- policy: bindings: - members: - serviceAccount:gcs-sa@<project_name>.iam.gserviceaccount.com role: roles/storage.objectViewer project: projects/xxxx resource: //storage.googleapis.com/jun06t-iam-test
動作検証
権限が付与されたので読み込めるようになりました。
$ go run main.go Hello World
2. プロジェクトレベルのIAMポリシーを作る
次は別の方法としてプロジェクトレベルのIAMポリシーを条件付きで作成します。
$ gcloud projects add-iam-policy-binding <project_name> \ --member='serviceAccount:gcs-sa@<project_name>.iam.gserviceaccount.com' \ --role='roles/storage.objectViewer' \ --condition='title=becket limit,expression=resource.name.startsWith("projects/_/buckets/jun06t-iam-test")'
バケット名を指定するために
resource.name.startsWith("projects/_/buckets/バケット名")
という条件を入れています。
実行するとIAMポリシー一覧に新しいポリシーが作成され、
条件も付いています。
アセットの方でもプロジェクトレベルのIAMポリシーが確認できます。
$ gcloud asset search-all-iam-policies \ --scope=projects/<project_name> \ --query="policy:gcs-sa" --- policy: bindings: - condition: expression: resource.name.startsWith("projects/_/buckets/jun06t-iam-test") title: becket limit members: - serviceAccount:gcs-sa@<project_name>.iam.gserviceaccount.com role: roles/storage.objectViewer project: projects/xxxx resource: //cloudresourcemanager.googleapis.com/projects/<project_name>
動作検証
こちらも権限が付与されたので読み込めるようになりました。
$ go run main.go Hello World
まとめ
2通りの方法でサービスアカウントに対して、特定のGCSバケットにのみアクセスできる権限を付与してみました。