S3汎用バケットのDeleteBucketをタグ条件でDenyできるのか試してみた
はじめに
クラウド事業本部コンサルティング部の山﨑です。
AWS リソースを、マネジメントコンソールや AWS CLI から誤って削除されないようにしたい、というケースがあります。
今回はその一環として、S3 汎用バケットに付与したタグを条件にして、s3:DeleteBucket を Deny できるのか検証してみました。
最初は「バケットにタグを付けて aws:ResourceTag 条件で Deny すれば削除を防げるのでは」と考えていたのですが、実際に試すと ABAC 無効状態では期待通りに Deny されず、少しハマりました。
この記事では、その検証過程と、S3 汎用バケットの ABAC を有効化することでタグ条件 Deny が効くようになるまでを紹介します。
結論
- S3 汎用バケットでは、タグを付けるだけでは
s3:DeleteBucketのタグ条件 Deny は効きませんでした。 - S3 汎用バケットの ABAC を有効化すると、バケットタグを条件に
s3:DeleteBucketを Deny できました。 - ABAC 有効化後は、バケットタグの追加・削除に使用する API が
TagResource/UntagResourceに変わります。
やりたかったこと
やりたかったことはシンプルです。
管理している S3 汎用バケットに、特定のタグを付与します。
今回は検証として、以下のタグを使用します。
ManagedBy=iac
このタグが付いている S3 汎用バケットは削除できないようにしたいです。
イメージとしては以下です。
| バケットタグ | 期待する動作 |
|---|---|
ManagedBy=iac あり |
削除できない |
ManagedBy=iac なし |
削除できる |
検証したポリシー
まずは、検証用 IAM ロールに以下のようなポリシーを付与しました。
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "AllowS3Baseline",
"Effect": "Allow",
"Action": [
"s3:DeleteBucket",
"s3:DeleteObject",
"s3:ListAllMyBuckets",
"s3:ListBucket",
"s3:GetBucketTagging",
"s3:GetObjectTagging",
"s3:GetBucketAbac",
"s3:PutBucketAbac",
"s3:ListTagsForResource",
"s3:TagResource",
"s3:UntagResource",
"s3:PutBucketTagging"
],
"Resource": "*"
},
{
"Sid": "DenyDeleteBucketIfIac",
"Effect": "Deny",
"Action": "s3:DeleteBucket",
"Resource": "*",
"Condition": {
"StringEquals": {
"aws:ResourceTag/ManagedBy": "iac"
}
}
}
]
}
ManagedBy=iac タグが付いている S3 汎用バケットに対して、s3:DeleteBucket を明示的に Deny するポリシーです。
検証環境
検証用に、以下の 2 つの S3 汎用バケットを用意しました。
| バケット | タグ | 期待結果 |
|---|---|---|
example-abac-bucket-iac-001 |
ManagedBy=iac |
削除失敗 |
example-abac-bucket-notag-001 |
なし | 削除成功 |
なお、今回の検証では s3:DeleteBucket の動作結果を確認するため、検証用バケットはいずれも空の状態にしています。
バケットのタグ状態を確認します。
aws s3api get-bucket-tagging \
--bucket example-abac-bucket-iac-001
実行結果です。
{
"TagSet": [
{
"Key": "ManagedBy",
"Value": "iac"
}
]
}
タグなしバケットでは、タグが存在しないことを確認します。
aws s3api get-bucket-tagging \
--bucket example-abac-bucket-notag-001
実行結果です。
An error occurred (NoSuchTagSet) when calling the GetBucketTagging operation: The TagSet does not exist
ABAC 無効状態で DeleteBucket してみる
まず、S3 汎用バケットの ABAC を有効化していない状態で試します。
ManagedBy=iac タグ付きのバケットを削除してみます。
aws s3api delete-bucket \
--bucket example-abac-bucket-iac-001 \
--region ap-northeast-1
期待としては、明示的 Deny により AccessDenied になるはずでした。
しかし、結果は 削除成功 でした。
存在確認をすると、バケットは削除されています。
aws s3api head-bucket \
--bucket example-abac-bucket-iac-001
実行結果です。
An error occurred (404) when calling the HeadBucket operation: Not Found
つまり、ManagedBy=iac タグが付いているにもかかわらず、aws:ResourceTag/ManagedBy を条件にした Deny は効きませんでした。
なぜ Deny できなかったのか
調べてみると、S3 汎用バケットでは ABAC がデフォルトで無効であることが分かりました。
S3 汎用バケットで、タグベースのアクセス制御を行うには、対象バケットで ABAC を有効化する必要があります。
つまり、最初の検証で Deny が効かなかった理由は、ポリシーの構文ミスではなく、対象バケットで ABAC が有効化されておらず、バケットタグが認可条件として評価されなかったことでした。
ポイントは以下です。
- バケットにタグが付いていること
- そのタグをアクセス制御の条件として評価できること
この 2 つは別です。
今回のケースでは、バケットに ManagedBy=iac タグは付いていましたが、ABAC が無効だったため、aws:ResourceTag/ManagedBy 条件が期待通り評価されませんでした。
S3 汎用バケットの ABAC を有効化する
以降の検証では、ABAC 無効状態の検証で削除された example-abac-bucket-iac-001 を再作成し、再度 ManagedBy=iac タグを付与した状態から進めます。
対象バケットで ABAC を有効化します。
aws s3api put-bucket-abac \
--bucket example-abac-bucket-iac-001 \
--abac-status Status=Enabled \
--region ap-northeast-1
タグなしバケット側も比較用に ABAC を有効化します。
aws s3api put-bucket-abac \
--bucket example-abac-bucket-notag-001 \
--abac-status Status=Enabled \
--region ap-northeast-1
ABAC の状態を確認します。
aws s3api get-bucket-abac \
--bucket example-abac-bucket-iac-001 \
--region ap-northeast-1
実行結果です。
{
"AbacStatus": {
"Status": "Enabled"
}
}
これで、対象バケットの ABAC が有効化されました。
ABAC 有効化後に再度 DeleteBucket してみる
ABAC 有効化後、改めて ManagedBy=iac タグ付きバケットを削除してみます。
aws s3api delete-bucket \
--bucket example-abac-bucket-iac-001 \
--region ap-northeast-1
結果は以下です。
An error occurred (AccessDenied) when calling the DeleteBucket operation:
User: arn:aws:sts::123456789012:assumed-role/example-role/example-session
is not authorized to perform: s3:DeleteBucket
on resource: "arn:aws:s3:::example-abac-bucket-iac-001"
with an explicit deny in an identity-based policy
期待通り、ManagedBy=iac タグ付きバケットの削除が Deny されました。
エラーメッセージにも、explicit deny in an identity-based policy と出ています。
つまり、以下の Deny ステートメントが期待通り評価されたと言えます。
{
"Sid": "DenyDeleteBucketIfIac",
"Effect": "Deny",
"Action": "s3:DeleteBucket",
"Resource": "*",
"Condition": {
"StringEquals": {
"aws:ResourceTag/ManagedBy": "iac"
}
}
}
タグなしバケットでは削除できるか
次に、ManagedBy=iac タグが付いていないバケットを削除します。
aws s3api delete-bucket \
--bucket example-abac-bucket-notag-001 \
--region ap-northeast-1
こちらは成功しました。
存在確認をすると、バケットが削除されていることが分かります。
aws s3api head-bucket \
--bucket example-abac-bucket-notag-001
実行結果です。
An error occurred (404) when calling the HeadBucket operation: Not Found
期待通り、タグなしバケットは Deny 条件に一致しないため削除できました。
検証結果
検証結果をまとめると以下のとおりです。
| ABAC 状態 | バケットタグ | 期待結果 | 実際の結果 |
|---|---|---|---|
| 無効 | ManagedBy=iac |
削除失敗 | 削除成功 |
| 有効 | ManagedBy=iac |
削除失敗 | 削除失敗 |
| 有効 | タグなし | 削除成功 | 削除成功 |
S3 汎用バケットのタグを条件に s3:DeleteBucket を制御したい場合は、対象バケットで ABAC の有効化が必要でした。
分かったこと
今回の検証で分かったことは以下です。
- S3 汎用バケットで ABAC が無効な状態だと、バケットタグを条件にした Deny ポリシーだけではバケット削除を制御できなかった
- S3 汎用バケットでは、バケットタグをアクセス制御に使うために ABAC の有効化が必要
- ABAC 有効化後は、
aws:ResourceTag/ManagedByを条件にs3:DeleteBucketを Deny できた - タグなしバケットは Deny 条件に一致しないため、削除できた
特に重要なのは、タグが付いていることと、そのタグを認可条件として評価できることは別という点です。
注意点:ABAC 有効化後はタグ操作 API が変わる
S3 汎用バケットの ABAC を有効化する場合、タグ操作 API に注意が必要です。
ABAC 有効化後は、対象バケットに対して従来の PutBucketTagging や DeleteBucketTagging は使えなくなり、代わりに TagResource と UntagResource を使ってバケットタグを管理する必要があります。
AWS CLI で ABAC 有効化後にタグを付与する場合は、以下のように aws s3control tag-resource を使います。
aws s3control tag-resource \
--account-id 123456789012 \
--resource-arn arn:aws:s3:::example-abac-bucket-iac-001 \
--tags '[{"Key":"ManagedBy","Value":"iac"}]' \
--region ap-northeast-1
AWS CLI でタグを削除する場合は、以下のように aws s3control untag-resource を使います。
aws s3control untag-resource \
--account-id 123456789012 \
--resource-arn arn:aws:s3:::example-abac-bucket-iac-001 \
--tag-keys '["ManagedBy"]' \
--region ap-northeast-1
既存の IaC や運用スクリプトで PutBucketTagging / DeleteBucketTagging、または AWS CLI の aws s3api put-bucket-tagging / aws s3api delete-bucket-tagging を使っている場合は、ABAC 有効化前に影響確認が必要です。






