Cloud Storageバケットの均一なバケットレベルアクセス設定手順

このブログシリーズ 「クラウドセキュリティ 実践集」 では、一般的なセキュリティ課題を取り上げ、「なぜ危険なのか?」 というリスクの解説から、 「どうやって直すのか?」 という具体的な修復手順(コンソール、Google Cloud CLI、Terraformなど)まで、分かりやすく解説します。
この記事では、Cloud Storageバケットで均一なバケットレベルアクセス(Uniform bucket-level access)が無効化されている問題について、リスクと対策を解説します。

ポリシーの説明
Cloud Storageバケットで均一なバケットレベルのアクセス制御を有効化し、一貫した権限管理が適用されている状態を確保します。均一なバケットレベルアクセス(Uniform bucket-level access、以下UBA)は、Google Cloud StorageでIAMのみを使用してアクセス制御を管理する機能です。UBAを有効にすると、オブジェクトレベルのACL(Access Control List)が無効化され、すべてのアクセス制御がバケットレベルのIAMポリシーで一元管理されます。
修復方法
コンソールでの修復手順
Google Cloud コンソールを使用して、Cloud Storageバケットで均一なバケットレベルアクセスを有効化します。
ステップ1: Cloud Storageバケットへのアクセス
- Google Cloud Consoleにログイン
- ナビゲーションメニューから「Cloud Storage」→「バケット」を選択
- 設定を変更したいバケット名をクリック
ステップ2: 権限設定の確認
- バケットの詳細ページで「権限」タブをクリック
- 現在のアクセス制御モードを確認
- 「きめ細かい」(Fine-grained)と表示されている場合は、ACLが有効な状態
- 「均一」(Uniform)と表示されている場合は、既にUBAが有効
- 既存のオブジェクトACL設定を確認(必要に応じてエクスポート)
ステップ3: 均一なバケットレベルアクセスの有効化
- 「アクセス制御」セクションで「切り替え」または「均一に切り替える」をクリック
- 警告ダイアログが表示される:
- 既存のオブジェクトACLが削除されることの確認
- 90日間の取消し可能期間についての説明
- 「均一なアクセス制御を有効にする」にチェック
- 「保存」をクリック
ステップ4: 移行後の確認事項
- 既存のアクセス権限の確認:
- 「IAM」タブですべての必要な権限が設定されているか確認
- 必要に応じて、失われたACL権限をIAMロールで再設定
- 特に
allUsers
やallAuthenticatedUsers
への権限付与がないことを確認
- アプリケーションの動作確認:
- ACL APIに依存していたアプリケーションの動作を確認
- 必要に応じてアプリケーションコードをIAM APIを使用するよう更新
- 署名付きURL(Signed URLs)の動作確認
ステップ5: 90日間の取消し期間の管理
- UBA有効化後90日間は元のACL設定に戻すことが可能
- 「権限」タブで残り日数を確認可能
- 十分な検証後、恒久的に適用する場合は「今すぐロック」をクリック
- ロック後はACLへの復帰は不可能となるため、慎重に判断
Terraformでの修復手順
Cloud Storageバケットで均一なバケットレベルアクセスを有効化するTerraformコードと、主要な修正ポイントを説明します。
# データソース
data "google_project" "current" {}
# 均一なバケットレベルアクセスを有効化したバケット
resource "google_storage_bucket" "secure_bucket" {
name = "${var.project_id}-secure-bucket-${var.environment}"
location = var.region
storage_class = "STANDARD"
# 均一なバケットレベルアクセスの有効化(必須設定)
uniform_bucket_level_access = true
# バージョニングの有効化(推奨)
versioning {
enabled = true
}
# ライフサイクルルール(例:90日後に古いバージョンを削除)
lifecycle_rule {
condition {
age = 90
with_state = "ARCHIVED"
}
action {
type = "Delete"
}
}
# 暗号化設定(KMSを使用)
encryption {
default_kms_key_name = google_kms_crypto_key.bucket_key.id
}
# パブリックアクセス防止(UBAと併用推奨)
public_access_prevention = "enforced"
# ラベル
labels = {
environment = var.environment
team = var.team
compliance = "uba-enabled"
}
}
# KMS暗号鍵
resource "google_kms_key_ring" "bucket_keyring" {
name = "${var.project_id}-bucket-keyring"
location = var.region
}
resource "google_kms_crypto_key" "bucket_key" {
name = "${var.project_id}-bucket-key"
key_ring = google_kms_key_ring.bucket_keyring.id
rotation_period = "7776000s" # 90日
}
# バケットレベルのIAMバインディング
# 注意: iam_bindingは既存の権限を上書きするため、iam_memberの使用も検討
# 読み取り専用アクセス
resource "google_storage_bucket_iam_binding" "viewers" {
bucket = google_storage_bucket.secure_bucket.name
role = "roles/storage.objectViewer"
members = [
"group:${var.viewer_group}@${var.organization_domain}",
]
# 条件付きアクセス(オプション)
# condition {
# title = "Weekday access only"
# description = "Access allowed only on weekdays"
# expression = "request.time.getDayOfWeek() >= 1 && request.time.getDayOfWeek() <= 5"
# }
}
# 書き込みアクセス
resource "google_storage_bucket_iam_binding" "editors" {
bucket = google_storage_bucket.secure_bucket.name
role = "roles/storage.objectUser"
members = [
"group:${var.editor_group}@${var.organization_domain}",
"serviceAccount:${google_service_account.app_sa.email}",
]
}
# 管理者アクセス
resource "google_storage_bucket_iam_binding" "admins" {
bucket = google_storage_bucket.secure_bucket.name
role = "roles/storage.admin"
members = [
"group:${var.admin_group}@${var.organization_domain}",
]
}
# アプリケーション用サービスアカウント
resource "google_service_account" "app_sa" {
account_id = "${var.project_id}-app-sa"
display_name = "Application Service Account"
description = "Service account for application access to storage bucket"
}
# 既存バケットの移行用リソース(既存バケットがある場合)
resource "null_resource" "migrate_existing_bucket" {
count = var.migrate_existing ? 1 : 0
provisioner "local-exec" {
command = <<-EOT
# 既存のACL設定をバックアップ(推奨)
gsutil acl get gs://${var.existing_bucket_name} > bucket_acl_backup.json
# 既存バケットのUBA有効化
gcloud storage buckets update gs://${var.existing_bucket_name} \
--uniform-bucket-level-access
# 移行後のIAMポリシー適用
gcloud storage buckets add-iam-policy-binding gs://${var.existing_bucket_name} \
--member="group:${var.viewer_group}@${var.organization_domain}" \
--role="roles/storage.objectViewer"
EOT
}
}
# 監視アラート(UBAが無効化された場合)
resource "google_monitoring_alert_policy" "uba_disabled" {
display_name = "Uniform Bucket-Level Access Disabled"
combiner = "OR"
enabled = true
conditions {
display_name = "UBA disabled on bucket"
condition_threshold {
filter = <<-EOT
resource.type="gcs_bucket"
AND protoPayload.methodName="storage.buckets.update"
AND protoPayload.request.bucket.iamConfiguration.uniformBucketLevelAccess.enabled=false
EOT
duration = "0s"
comparison = "COMPARISON_GT"
threshold_value = 0
}
}
notification_channels = [google_monitoring_notification_channel.security_team.id]
documentation {
content = <<-EOT
## 均一なバケットレベルアクセスが無効化されました
対象バケットでUBAが無効化され、オブジェクトACLが有効になりました。
### 対応手順
1. Cloud Loggingで変更の詳細を確認
2. 変更が承認されたものか確認
3. 意図しない変更の場合は、即座にUBAを再有効化
4. セキュリティチームに報告
EOT
mime_type = "text/markdown"
}
}
# 通知チャネル
resource "google_monitoring_notification_channel" "security_team" {
display_name = "Security Team Email"
type = "email"
labels = {
email_address = var.security_team_email
}
}
# 変数定義
variable "project_id" {
description = "GCP Project ID"
type = string
}
variable "environment" {
description = "Environment name"
type = string
}
variable "region" {
description = "GCP region"
type = string
default = "asia-northeast1"
}
variable "team" {
description = "Team name for labeling"
type = string
}
variable "organization_domain" {
description = "Organization domain"
type = string
}
variable "viewer_group" {
description = "Google group for read-only access"
type = string
}
variable "editor_group" {
description = "Google group for read-write access"
type = string
}
variable "admin_group" {
description = "Google group for admin access"
type = string
}
variable "security_team_email" {
description = "Security team email for alerts"
type = string
}
variable "migrate_existing" {
description = "Whether to migrate existing bucket"
type = bool
default = false
}
variable "existing_bucket_name" {
description = "Name of existing bucket to migrate"
type = string
default = ""
}
# 出力
output "bucket_name" {
value = google_storage_bucket.secure_bucket.name
description = "Name of the created bucket"
}
output "bucket_url" {
value = google_storage_bucket.secure_bucket.url
description = "URL of the created bucket"
}
output "uba_enabled" {
value = google_storage_bucket.secure_bucket.uniform_bucket_level_access
description = "Status of uniform bucket-level access"
}
まとめ
この記事では、Cloud Storageバケットで均一なバケットレベルアクセス(Uniform bucket-level access)の有効化について、リスクと対策を解説しました。
均一なバケットレベルアクセスを有効化することで、IAMベースの一元的なアクセス制御を実現し、セキュリティと運用効率を大幅に向上させることができます。ACLからの移行は90日間の猶予期間があるため、慎重に計画して実施することが重要です。
この問題の検出は弊社が提供するSecurifyのCSPM機能で簡単に検出及び管理する事が可能です。 運用が非常に楽に出来る製品になっていますので、ぜひ興味がある方はお問い合わせお待ちしております。
最後までお読みいただきありがとうございました。この記事が皆さんの役に立てば幸いです。
参考情報
- Cloud Storage 均一なバケットレベルアクセス公式ドキュメント
- Cloud Storage IAM ベストプラクティス
- ACLからIAMへの移行ガイド
- パブリックアクセス防止の設定
- Cloud Storage セキュリティベストプラクティス