すべてのユーザーが読み取り/書き込みを実行できるACLの変更手順

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

ポリシーの説明
[S3.3] S3 汎用バケットではパブリック書き込みアクセスをブロックする必要があります。
Amazon S3 の Security Hub コントロール – AWS Security Hub
このコントロールは、Amazon S3 汎用バケットがパブリック書き込みアクセスを許可するかどうかをチェックします。これにより、ブロックパブリックアクセス設定、バケットポリシー、およびバケットアクセスコントロールリスト (ACL) を評価します。バケットが公開書き込みアクセスを許可している場合、このコントロールは失敗します。
このポリシーは、S3バケットへのパブリック書き込みアクセスを禁止することを求めています。パブリック書き込みアクセスを許可すると、誰でも自由にファイルをアップロードできてしまい、悪意のあるファイルのアップロードやデータの改ざんなどのリスクが高まります。S3バケットには様々なデータが保存されるため、厳格なアクセス制御が必要です。
修復方法
AWSコンソールでの修正手順
- Amazon S3 > 対象バケットを選択し、アクセス許可をクリック
- ブロックパブリックアクセス(バケット限定)で「編集」をクリック

3. パブリックアクセスをすべてブロックにチェックを入れ、「変更の保存」をクリック

4. アクセスコントロールリスト(ACL)の設定で、以下チェックが入っている箇所のチェックを外します。 設定変更後、変更の保存をクリックします。

Terraformでの修復手順
Terraformを使用して、パブリック書き込みアクセスをブロックし、セキュアなS3バケットを構成するためのコード例を以下に示します。
# S3バケットの基本設定
resource "aws_s3_bucket" "secure_bucket" {
bucket = "${var.environment}-${var.bucket_name}-${data.aws_caller_identity.current.account_id}"
force_destroy = false # 安全のため、強制削除を無効化
tags = {
Environment = var.environment
Name = var.bucket_name
Managed_by = "terraform"
}
}
# パブリックアクセスをブロック
resource "aws_s3_bucket_public_access_block" "secure_bucket" {
bucket = aws_s3_bucket.secure_bucket.id
# すべてのパブリックアクセスをブロック
block_public_acls = true
block_public_policy = true
ignore_public_acls = true
restrict_public_buckets = true
}
# バケットのACLを「private」に設定
resource "aws_s3_bucket_acl" "secure_bucket" {
depends_on = [aws_s3_bucket_public_access_block.secure_bucket]
bucket = aws_s3_bucket.secure_bucket.id
acl = "private"
}
# バケットの暗号化設定
resource "aws_s3_bucket_server_side_encryption_configuration" "secure_bucket" {
bucket = aws_s3_bucket.secure_bucket.id
rule {
apply_server_side_encryption_by_default {
sse_algorithm = "AES256"
}
}
}
# バケットのバージョニング設定
resource "aws_s3_bucket_versioning" "secure_bucket" {
bucket = aws_s3_bucket.secure_bucket.id
versioning_configuration {
status = "Enabled"
}
}
# バケットポリシー - 安全な設定例
resource "aws_s3_bucket_policy" "secure_bucket" {
depends_on = [aws_s3_bucket_public_access_block.secure_bucket]
bucket = aws_s3_bucket.secure_bucket.id
policy = jsonencode({
Version = "2012-10-17"
Statement = [
{
Sid = "EnforceSecureTransport"
Effect = "Deny"
Principal = "*"
Action = "s3:*"
Resource = [
aws_s3_bucket.secure_bucket.arn,
"${aws_s3_bucket.secure_bucket.arn}/*"
]
Condition = {
Bool = {
"aws:SecureTransport" = "false"
}
}
},
{
Sid = "AllowSpecificIAMRoleAccess"
Effect = "Allow"
Principal = {
AWS = var.allowed_role_arns
}
Action = [
"s3:GetObject",
"s3:PutObject",
"s3:ListBucket"
]
Resource = [
aws_s3_bucket.secure_bucket.arn,
"${aws_s3_bucket.secure_bucket.arn}/*"
]
}
]
})
}
# アクセスログ用のバケット
resource "aws_s3_bucket" "log_bucket" {
bucket = "access-logs-${var.environment}-${var.bucket_name}-${data.aws_caller_identity.current.account_id}"
force_destroy = false
tags = {
Environment = var.environment
Name = "access-logs"
Managed_by = "terraform"
}
}
# ログバケットのパブリックアクセスブロック
resource "aws_s3_bucket_public_access_block" "log_bucket" {
bucket = aws_s3_bucket.log_bucket.id
block_public_acls = true
block_public_policy = true
ignore_public_acls = true
restrict_public_buckets = true
}
# メインバケットのログ記録設定
resource "aws_s3_bucket_logging" "secure_bucket" {
bucket = aws_s3_bucket.secure_bucket.id
target_bucket = aws_s3_bucket.log_bucket.id
target_prefix = "s3-access-logs/"
}
# 必要な IAM ポリシー
data "aws_iam_policy_document" "s3_access" {
statement {
actions = [
"s3:GetObject",
"s3:PutObject",
"s3:ListBucket"
]
resources = [
aws_s3_bucket.secure_bucket.arn,
"${aws_s3_bucket.secure_bucket.arn}/*"
]
effect = "Allow"
}
}
# 現在のAWSアカウントIDを取得
data "aws_caller_identity" "current" {}
# 変数定義
variable "environment" {
type = string
description = "環境名(例: prod, staging, dev)"
}
variable "bucket_name" {
type = string
description = "バケットのベース名"
}
variable "allowed_role_arns" {
type = list(string)
description = "バケットへのアクセスを許可するIAMロールのARNリスト"
}
# 出力
output "bucket_name" {
value = aws_s3_bucket.secure_bucket.id
description = "作成されたS3バケットの名前"
}
output "bucket_arn" {
value = aws_s3_bucket.secure_bucket.arn
description = "作成されたS3バケットのARN"
}
output "log_bucket_name" {
value = aws_s3_bucket.log_bucket.id
description = "作成されたログバケットの名前"
}
このコードの重要な部分と実装手順を説明します:
- パブリックアクセスの完全ブロック(最重要):
aws_s3_bucket_public_access_block
リソースを使用して、指定したバケット(aws_s3_bucket.secure_bucket.id
)に対する全てのパブリックアクセス設定(ACL経由、ポリシー経由)を一元的にブロックします。これがパブリック書き込みアクセスを防ぐ最も確実な方法です。
resource "aws_s3_bucket_public_access_block" "secure_bucket" {
block_public_acls = true
block_public_policy = true
ignore_public_acls = true
restrict_public_buckets = true
}
2. プライベートACLの設定:
aws_s3_bucket_acl
リソースで、バケットのACLを明示的にprivate
(バケット所有者のみフルコントロール)に設定します。depends_on
でパブリックアクセスブロック設定後にACLが適用されるように依存関係を定義しています。
resource "aws_s3_bucket_acl" "secure_bucket" {
bucket = aws_s3_bucket.secure_bucket.id
acl = "private"
}
使用方法:
- 変数の設定:
# terraform.tfvars
environment = "production"
bucket_name = "my-secure-bucket"
allowed_role_arns = [
"arn:aws:iam::123456789012:role/allowed-role"
]
2. Terraformの実行:
terraform init
terraform plan
terraform apply
セキュリティ強化のポイント:
- アクセス制御: パブリックアクセスの完全ブロック、明示的なACL設定 (
private
)、最小権限の原則に基づくバケットポリシー(例:AllowSpecificIAMRoleAccess
,EnforceSecureTransport
) - 暗号化とログ記録: サーバーサイド暗号化 (SSE-S3:
AES256
) の有効化、アクセスログの有効化、ログの安全な保存(別バケットへ) - その他のセキュリティ機能: バージョニングの有効化(データ保護)、HTTPS強制(
aws:SecureTransport
条件)
注意点:
- 既存バケットへの適用: 既存バケットに適用する際は、現在のアクセス権限への影響を十分に確認し、必要であればデータのバックアップや段階的な移行を検討してください。
- 運用上の考慮事項: ログローテーションやライフサイクルポリシー、バージョン管理によるコスト、コンプライアンス要件(暗号化、ログ保持期間など)を考慮してください。
最後に
今回は、S3バケットのパブリック書き込みアクセス設定について解説しました。パブリック書き込みアクセスを許可すると、悪意のあるファイルのアップロードやデータ改ざんのリスクが高まります。必ずパブリック書き込みアクセスをブロックし、データを保護してください。
この問題の検出は弊社が提供するSecurifyのCSPM機能で簡単に検出及び管理する事が可能です。
運用が非常に楽に出来る製品になっていますので、ぜひ興味がある方はお問い合わせお待ちしております。
最後までお読みいただきありがとうございました。この記事が皆さんの役に立てば幸いです。