BeeX 事業開発部の榊原です。今まで会社ブログとQiitaに様々な記事を投稿してきましたが、S3メインの記事は実は初めてで驚いています。早速本題に移りましょう。
背景
既に利用されているS3バケットに保管されているCloudTrailの証跡やVPCフローログなど監査で必要なリソースを保護するためのIAMポリシーを設定したい。なお、IAMポリシーはIAMグループにアタッチして利用する。
前提
- S3の汎用バケットを対象とする
- SCPやバケットポリシーを用いた制御は本記事では触れない
- マルチアカウント構成ではない
基本知識
S3のABAC機能
去年2025年11月に登場したアップデートで、S3バケットに付与されたタグベースでS3バケットに対するアクションを制御することができるようになりました。詳細は下記公式記事をご参照ください。
なお、本機能はS3バケット単位のアクセス制限はできますが、バケット内のオブジェクト単位でアクセス権限を設定したい場合はLambda等を用いてオブジェクトにタグが付与される仕組みを整備する必要があります。
S3のAPI
バケットへのアクセス制御のため、今回のケースで抑えておくべき4つのAPIについて紹介します。各APIの文字をクリックするとそれぞれドキュメントに飛べます。
PutBucketAbac
Sets the attribute-based access control (ABAC) property of the general purpose bucket.
S3の汎用バケットのABACを設定するためのAPIでs3:PutBucketAbacの権限が必要です。ABACを有効化した後に注意すべき点としてはバケットのタグ設定や削除はこの後紹介するTagResourceとUntagResourceを使用する必要があります。PutBucketTaggingとDeleteBucketTaggingは利用できなくなります。
TagResource
Creates a new user-defined tag or updates an existing tag. Each tag is a label consisting of a key and value that is applied to your resource. Tags can help you organize, track costs for, and control access to your resources. You can add up to 50 AWS resource tags for each S3 resource.
ユーザー定義の新しいタグを作成したり既存タグの更新をするAPIで、s3:TagResourceの権限が必要です。Tag Editor経由でS3バケットにタグを付与するときもこのAPIが呼び出されるみたいです。

AWS CloudFormation等を利用してリソースをデプロイした際に自動的に付与されるAWS生成のタグは対象外と思われます。
System created tags that begin with aws: are reserved for AWS use, and do not count against this limit. You can't edit or delete a tag that begins with the aws: prefix.
UntagResource
This operation removes the specified user-defined tags from an S3 resource. You can pass one or more tag keys.
ユーザー定義タグを削除するAPIでs3:UntagResourceの権限が必要です。こちらもAWS生成のタグは対象外です。
PutBucketTagging
Sets the tags for a general purpose bucket if attribute based access control (ABAC) is not enabled for the bucket.
ABACを利用する場合はあまり関係がありませんが、知識として抑えて損は無いので一応紹介します。バケットのタグを設定するためのAPIで、利用するためにはs3:PutBucketTaggingの権限が必要です。引用文の記載通り汎用バケットでABACが有効化されていない場合であれば利用可能です。ABAC有効時は先に紹介したTagResourceとUntagResourceのAPIを利用しましょう。
※あとバケットからタグを削除するAPIはDeleteBucketTaggingで、こちらもABAC有効化時は利用できなくなります。こちらも同じくs3:PutBucketTaggingの権限が必要です。s3:DeleteBucketTaggingという権限はありそうで存在しないのでご注意ください。

IAMポリシー案
今回のIAMポリシーの方針は以下の通りです。
- 保護対象バケットには
key=protected/value=Trueのタグが付いている前提 - protectedタグ以外は自由にタグの編集権を持たせつつ、protectedタグの削除と値の変更をさせない
- Resource句ではなく、Condition句メインで制限
以上を踏まえポリシーは下記の形に落ち着きました。
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "DenyVpcFlowLogDeletion",
"Effect": "Deny",
"Action": "ec2:DeleteFlowLogs",
"Resource": "*"
},
{
"Sid": "DenyCloudTrailModification",
"Effect": "Deny",
"Action": [
"cloudtrail:StopLogging",
"cloudtrail:DeleteTrail",
"cloudtrail:UpdateTrail"
],
"Resource": "*"
},
{
"Sid": "DenyProtectedBucketModification",
"Effect": "Deny",
"Action": [
"s3:DeleteObject",
"s3:DeleteObjectVersion",
"s3:DeleteBucket",
"s3:PutLifecycleConfiguration",
"s3:PutBucketPolicy",
"s3:DeleteBucketPolicy",
"s3:PutBucketAcl",
"s3:PutObjectAcl",
"s3:PutBucketOwnershipControls",
"s3:PutBucketVersioning",
"s3:PutEncryptionConfiguration",
"s3:PutBucketPublicAccessBlock"
],
"Resource": "*",
"Condition": {
"StringEquals": {
"aws:ResourceTag/protected": "True"
}
}
},
{
"Sid": "DenyProtectedTagRemoval",
"Effect": "Deny",
"Action": "s3:UntagResource",
"Resource": "*",
"Condition": {
"StringEquals": {
"aws:ResourceTag/protected": "True"
},
"ForAnyValue:StringEquals": {
"aws:TagKeys": "protected"
}
}
},
{
"Sid": "DenyProtectedTagModification",
"Effect": "Deny",
"Action": "s3:TagResource",
"Resource": "*",
"Condition": {
"StringEquals": {
"aws:ResourceTag/protected": "True"
},
"ForAnyValue:StringEquals": {
"aws:TagKeys": "protected"
},
"StringNotEquals": {
"aws:RequestTag/protected": "True"
}
}
},
{
"Sid": "DenyLegacyTagOverwrite",
"Effect": "Deny",
"Action": "s3:PutBucketTagging",
"Resource": "*",
"Condition": {
"StringEquals": {
"aws:ResourceTag/protected": "True"
},
"StringNotEquals": {
"aws:RequestTag/protected": "True"
}
}
},
{
"Sid": "DenyAbacDeactivation",
"Effect": "Deny",
"Action": "s3:PutBucketAbac",
"Resource": "*",
"Condition": {
"StringEquals": {
"aws:ResourceTag/protected": "True"
}
}
}
]
}
各パートの説明は以下の通りです。
- DenyVpcFlowLogDeletion : VPCフローログの削除を無条件で禁止
- DenyCloudTrailModification : CloudTrailの記録停止、削除、設定変更を無条件で禁止
- DenyProtectedBucketModification : protected=True タグが付いたS3バケットに対する、削除操作やバージョニング、KMSキー変更等を禁止
- DenyProtectedTagRemoval : protected=True タグが付いたS3バケットから、protected タグをピンポイントで削除する操作を禁止
- DenyProtectedTagModification : protected=True タグが付いたS3バケットの protected タグを、False など別の値に書き換える操作を禁止
- DenyLegacyTagModification : protected=True タグが付いたS3バケットに対し、protected=True を含まない新しいタグセットで「一括上書き」する操作を禁止(ABAC無効化後の保険)
- DenyAbacDeactivation : protected=True タグが付いたS3バケットの「S3 ABAC機能」自体を無効化する操作を禁止
後で気づきましたが、設定状況によっては下記アクションも記載していいかもしれません。
- s3:PutBucketLogging : サーバーアクセスログの無効化防止
- s3:PutReplicationConfiguration : レプリケーション設定の変更防止
- s3:PutBucketObjectLockConfiguration : Object Lock設定の変更防止
なお、既にCloudTrailやVPCフローログの証跡を取得している各S3バケットに対して、ABACを有効化した後も問題なく取得できるか確認しましたが、問題なく取得されました。CloudTrailの証跡やVPCフローログはIAMポリシーではなくバケットポリシーで書き込みが制御されています。ABACの有効化は既存バケットポリシーに影響を与えなかったので、問題なく出力できたと考えられます。
最後に
今回はS3バケットのABAC機能について説明しました。S3バケットの数が増えたとしても、タグを付与するだけで簡単にアクセス制御をかけられるようになったのは嬉しいですね。今回触れてませんがIAMポリシーやSCPでもS3バケットへのタグ設定を強制できるようになったので、またさらに設計の幅が広がった印象です。ここまでお読みいただきありがとうございました。
※この記事のアイキャッチ画像は生成AIで作成しました。