Cloud Storage バケットの保持ポリシーロック設定について

このブログシリーズ 「クラウドセキュリティ 実践集」 では、一般的なセキュリティ課題を取り上げ、「なぜ危険なのか?」 というリスクの解説から、 「どうやって直すのか?」 という具体的な修復手順(コンソール、gcloud CLI、Terraformなど)まで、分かりやすく解説します。
この記事では、Cloud Storageバケットのオブジェクト保持ポリシーをロックする設定手順について、リスクと対策を解説します。

ポリシーの説明
バケットの保持ポリシーをロックし、データとポリシーの保護を強化します。
Cloud Storageの保持ポリシー機能は、オブジェクトが指定された期間中削除されないようにすることで、コンプライアンス要件やレコード管理要件を満たすのに役立ちます。保持ポリシーをロックすることで、ポリシー自体の変更や削除を防ぎ、重要なデータの不正な削除や変更から保護します。
保持ポリシーがロックされると、以下の制限が適用されます:
- 保持ポリシーの削除不可
- 保持期間の短縮不可(延長のみ可能)
- バケットの削除不可(保持期間中のオブジェクトが存在する限り)
修復方法
コンソールでの修復手順
Google Cloud コンソールを使用して、Cloud Storageバケットの保持ポリシーをロックします。
重要な注意事項:
- 保持ポリシーのロックは不可逆的な操作です
- 一度ロックすると、ポリシーの削除や保持期間の短縮はできません
- 保持期間の延長のみ可能です
- バケット内の全オブジェクトに保持ポリシーが適用されます
- 保持期間中はオブジェクトの削除ができません(コスト影響を考慮してください)
- Google Cloud Consoleにログインし、Cloud Storageページに移動します。

- 対象のバケットを選択します。
- バケットの詳細ページで、保護タブをクリックします。
- 保持ポリシーセクションで、まだ保持ポリシーが設定されていない場合:
- 保持ポリシーを設定をクリック
- 保持期間(日、月、年単位)を入力
- 保存をクリック
- 保持ポリシーが設定されている状態で、ポリシーをロックをクリックします。
- ロック確認ダイアログが表示されます:
- ロックの不可逆性について警告が表示されます
- バケット名を入力して確認
- ポリシーをロックをクリック
- ロックが完了すると、保持ポリシーのステータスが「ロック済み」に変わります。
Terraformでの修復手順
Cloud Storageバケットの保持ポリシーを設定し、ロックするTerraformコードと、主要な修正ポイントを説明します。
# -------------------- ① 保持ポリシー付きバケット --------------------
resource "google_storage_bucket" "compliance_bucket" {
name = "compliance-data-${var.environment}"
location = var.region
force_destroy = false # 重要:保持ポリシーのあるバケットは削除保護
# --- 保持ポリシーの設定 ---
retention_policy {
retention_period = 2592000 # 30日間(秒単位)
# 保持期間の計算例:
# 1日 = 86400秒
# 30日 = 2592000秒
# 90日 = 7776000秒
# 1年(365日) = 31536000秒
# 7年(SOX法) = 220752000秒
# is_locked = true # Terraformでは直接ロックできません(後述)
}
# Event-Based Hold(オプション)
# 特定のイベント(訴訟など)に基づく追加の保持制御
default_event_based_hold = false
# --- その他のセキュリティ設定 ---
uniform_bucket_level_access = true # 均一なバケットレベルアクセス
versioning {
enabled = true # バージョニングを有効化
}
# 注意:保持ポリシーが設定されている場合、
# lifecycle_ruleはretention_period経過後にのみ適用されます
lifecycle_rule {
condition {
age = 365 # 保持期間後の追加保存期間
with_state = "ANY" # アーカイブ済みオブジェクトも含む
}
action {
type = "Delete"
}
}
# 暗号化設定
encryption {
default_kms_key_name = google_kms_crypto_key.bucket_key.id
}
# ログ設定
logging {
log_bucket = google_storage_bucket.audit_logs.name
log_object_prefix = "compliance-bucket-logs/"
}
}
# -------------------- ② KMS暗号鍵 --------------------
resource "google_kms_key_ring" "keyring" {
name = "compliance-keyring"
location = var.region
}
resource "google_kms_crypto_key" "bucket_key" {
name = "compliance-bucket-key"
key_ring = google_kms_key_ring.keyring.id
rotation_period = "2592000s" # 30日ごとに自動ローテーション
lifecycle {
prevent_destroy = true # 暗号鍵の削除を防止
}
}
# -------------------- ③ 監査ログ用バケット --------------------
resource "google_storage_bucket" "audit_logs" {
name = "audit-logs-${var.environment}"
location = var.region
force_destroy = false
retention_policy {
retention_period = 7776000 # 90日間
}
lifecycle_rule {
condition {
age = 2555 # 7年間保持
}
action {
type = "Delete"
}
}
}
# -------------------- ④ IAMポリシー --------------------
resource "google_storage_bucket_iam_policy" "compliance_bucket_policy" {
bucket = google_storage_bucket.compliance_bucket.name
policy_data = data.google_iam_policy.bucket_policy.policy_data
}
data "google_iam_policy" "bucket_policy" {
# 読み取り専用アクセス
binding {
role = "roles/storage.objectViewer"
members = [
"<group:compliance-auditors@example.com>",
]
}
# 管理者アクセス(制限付き)
binding {
role = "roles/storage.admin"
members = [
"<group:compliance-admins@example.com>",
]
condition {
title = "Require MFA for admin access"
description = "Require multi-factor authentication for administrative actions"
expression = "request.auth.claims[\"<https://cloud.google.com/mfa_verified\>"] == true"
}
}
}
# -------------------- ⑤ 保持ポリシーロックのためのnullリソース --------------------
# 注意:Terraformでは保持ポリシーのロックを直接サポートしていないため、
# local-execプロビジョナーを使用する必要があります
# セキュリティ上の注意:local-execは実行環境のgcloud CLIを使用するため、
# CI/CD環境では適切な認証設定が必要です
# -------------------- ⑤ 保持ポリシーロックのためのnullリソース --------------------
# 注意:Terraformでは保持ポリシーのロックを直接サポートしていないため、
# local-execプロビジョナーを使用する必要があります
# オプション1: 対話的確認あり(開発環境向け)
resource "null_resource" "lock_retention_policy" {
depends_on = [google_storage_bucket.compliance_bucket]
provisioner "local-exec" {
command = <<-EOT
echo "WARNING: About to lock retention policy for ${google_storage_bucket.compliance_bucket.name}"
echo "This action is IRREVERSIBLE!"
echo "Current retention period: ${google_storage_bucket.compliance_bucket.retention_policy[0].retention_period} seconds"
# CI/CD環境では環境変数で自動確認
if [ "$${CI}" = "true" ] && [ "$${CONFIRM_RETENTION_LOCK}" = "yes" ]; then
gcloud storage buckets lock-retention-policy gs://${google_storage_bucket.compliance_bucket.name} --quiet
else
read -p "Type 'yes' to confirm: " confirm
if [ "$confirm" = "yes" ]; then
gcloud storage buckets lock-retention-policy gs://${google_storage_bucket.compliance_bucket.name}
else
echo "Lock operation cancelled"
exit 1
fi
fi
EOT
interpreter = ["bash", "-c"]
}
# ロック状態の変更を検知するためのトリガー
triggers = {
bucket_id = google_storage_bucket.compliance_bucket.id
retention_period = google_storage_bucket.compliance_bucket.retention_policy[0].retention_period
}
}
# オプション2: Terraform変数による制御(本番環境向け)
variable "enable_retention_lock" {
description = "Enable retention policy lock (IRREVERSIBLE)"
type = bool
default = false
}
resource "null_resource" "lock_retention_policy_controlled" {
count = var.enable_retention_lock ? 1 : 0
depends_on = [google_storage_bucket.compliance_bucket]
provisioner "local-exec" {
command = "gcloud storage buckets lock-retention-policy gs://${google_storage_bucket.compliance_bucket.name} --quiet"
}
}
# -------------------- ⑥ アラート設定 --------------------
resource "google_monitoring_alert_policy" "retention_policy_alert" {
display_name = "Retention Policy Change Alert"
combiner = "OR"
conditions {
display_name = "Retention policy modified"
condition_matched_log {
filter = <<-EOT
resource.type="gcs_bucket"
AND (
protoPayload.methodName="storage.buckets.update"
OR protoPayload.methodName="storage.buckets.lockRetentionPolicy"
)
AND protoPayload.resourceName=~"${google_storage_bucket.compliance_bucket.name}"
AND (
protoPayload.request.retentionPolicy.retentionPeriod
OR protoPayload.request.retentionPolicy.is_locked
)
EOT
}
}
notification_channels = [google_monitoring_notification_channel.email.name]
alert_strategy {
auto_close = "1800s"
}
}
resource "google_monitoring_notification_channel" "email" {
display_name = "Compliance Team Email"
type = "email"
labels = {
email_address = "compliance-team@example.com"
}
}
主要な修正ポイント
- retention_period: 適切な保持期間を秒単位で設定(規制要件に応じて調整)
- force_destroy = false: バケットの誤削除を防止
- null_resource: Terraformが直接サポートしていないロック操作を実行
- 監査とアラート: 保持ポリシーの変更を検知して通知
- uniform_bucket_level_access = true: ACLではなくIAMによる統一的なアクセス制御
- versioning: オブジェクトの履歴管理(保持ポリシーと併用推奨)
最後に
この記事では、Cloud Storageバケットのオブジェクト保持ポリシーをロックする設定手順について、リスクと対策を解説しました。
保持ポリシーのロックは、コンプライアンス要件を満たし、重要なデータを保護するための強力な機能です。ただし、不可逆的な操作であるため、実施前に十分な検討と計画が必要です。
この問題の検出は弊社が提供するSecurifyのCSPM機能で簡単に検出及び管理する事が可能です。 運用が非常に楽に出来る製品になっていますので、ぜひ興味がある方はお問い合わせお待ちしております。 最後までお読みいただきありがとうございました。この記事が皆さんの役に立てば幸いです。