S3 汎用バケットの DeleteObject をタグ条件で Deny できるのか試してみた
はじめに
クラウド事業本部コンサルティング部の山﨑です。
先日、以下の記事で「S3 汎用バケットの ABAC を有効化することで、aws:ResourceTag 条件によるバケット削除(s3:DeleteBucket)を Deny 制御する方法」をご紹介しました。
この記事の検証を進めている中で、ある疑問が湧きました。
「バケット削除(DeleteBucket)がバケットタグの ABAC で防げるようになったなら、オブジェクト削除(DeleteObject)もオブジェクト自身のタグ(
s3:ExistingObjectTag)を使って Deny できるのでは?」
オブジェクトに ManagedBy=iac というタグを付けておけば、そのファイルだけ誤削除を防げる。
これなら、より柔軟な保護ができるはずだと考え、追加検証を行いました。
結論
- S3 汎用バケットでは、ABAC を有効化しても、
s3:DeleteObjectはオブジェクト自身のタグ(s3:ExistingObjectTag)による条件評価をサポートしていないため、タグ条件による Deny は効きませんでした。 - オブジェクト削除をタグ条件で Deny したい場合は、オブジェクトのタグではなく、バケットのタグ(
aws:ResourceTag)を条件に指定することで、配下のオブジェクト削除(s3:DeleteObject)を Deny できることを確認しました。
やりたかったこと
管理している S3 汎用バケット内の特定のオブジェクトにタグを付与します。
今回は検証用に、以下のタグを使用します。
ManagedBy=iac
このタグが付いているオブジェクトは削除できないようにしたいです。
イメージとしては以下です。
| オブジェクトタグ | 期待する動作 |
|---|---|
ManagedBy=iac あり |
削除できない |
ManagedBy=iac なし |
削除できる |
検証したポリシー
まず、検証用 IAM ロールに以下のようなポリシーを付与しました。
検証用 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"
],
"Resource": "*"
},
{
"Sid": "DenyDeleteObjectIfIac",
"Effect": "Deny",
"Action": "s3:DeleteObject",
"Resource": "*",
"Condition": {
"StringEquals": {
"s3:ExistingObjectTag/ManagedBy": "iac"
}
}
}
]
}
オブジェクト自身に ManagedBy=iac タグが付いている場合、s3:DeleteObject を明示的に Deny するポリシーです。
検証環境
前回の記事で作成した、ABAC が有効化された S3 汎用バケット example-abac-bucket-iac-001 を使用します。
このバケットには、バケットタグとして ManagedBy=iac が付与されています。
なお、今回の検証では、バケットのバージョニングは無効の状態で確認しています。
バケット内には、以下の 2 つのオブジェクトを用意しました。
まずは「オブジェクト自身のタグで削除制御できるか」を確認したいため、期待結果は以下のとおりです。
| オブジェクト名 | オブジェクトタグ | 期待結果 |
|---|---|---|
object-iac.txt |
ManagedBy=iac |
削除失敗 |
object-notag.txt |
なし | 削除成功 |
タグ付きオブジェクトのタグ確認
aws s3api get-object-tagging \
--bucket example-abac-bucket-iac-001 \
--key object-iac.txt
実行結果です。
{
"TagSet": [
{
"Key": "ManagedBy",
"Value": "iac"
}
]
}
タグなしオブジェクトのタグ確認
aws s3api get-object-tagging \
--bucket example-abac-bucket-iac-001 \
--key object-notag.txt
実行結果です。
{
"TagSet": []
}
準備が整いましたので、実際にロールを切り替えて削除検証を行います。
オブジェクトタグ(s3:ExistingObjectTag)で削除を Deny できるか試す
S3 汎用バケットの ABAC を有効化した状態で試します。
まず、ManagedBy=iac タグ付きのオブジェクトを削除してみます。
タグ付きオブジェクトを削除
aws s3api delete-object \
--bucket example-abac-bucket-iac-001 \
--key object-iac.txt \
--region ap-northeast-1
期待としては、明示的 Deny により AccessDenied になるはずでした。
しかし、結果は 削除成功 でした。
エラーは出力されず、コマンドは正常に実行されました。
削除後の状態確認
削除後の状態を確認します。
aws s3api head-object \
--bucket example-abac-bucket-iac-001 \
--key object-iac.txt
実行結果です。
An error occurred (404) when calling the HeadObject operation: Not Found
オブジェクトは削除されてしまいました。
つまり、オブジェクト自身のタグ s3:ExistingObjectTag/ManagedBy を条件にした Deny は効きませんでした。
なぜ Deny できなかったのか
理由は、s3:DeleteObject というアクション自体が、オブジェクトの既存タグ(s3:ExistingObjectTag)による条件評価をサポートしていないためです。
AWS 公式ドキュメントにも、s3:ExistingObjectTag 条件キーは既存オブジェクトタグのキーと値を確認するために使用できる一方で、PUT Object と DELETE Object ではサポートされないことが記載されています。
つまり、既存のオブジェクトタグに基づいて、オブジェクトの削除や上書きを許可・拒否するポリシーは作成できません。
また、IAM の Service Authorization Reference を確認しても、s3:DeleteObject で利用可能な条件キーの一覧に s3:ExistingObjectTag/<key> は含まれていません。
そのため、削除アクションを実行する際には、オブジェクトのタグ情報が条件として評価されず、Deny ステートメントの条件に一致しません。
結果として、ベースラインの Allow により削除が許可された、ということになります。
解決策:バケットタグ(aws:ResourceTag)で制御する
オブジェクト自身のタグで制御できない場合、どのように誤削除を防げばよいでしょうか。
ここで利用できるのが、バケットのタグ(aws:ResourceTag)です。
S3 汎用バケットで ABAC を有効化すると、バケットタグに基づくアクセス制御として aws:ResourceTag や s3:BucketTag を利用できます。
今回の検証では、aws:ResourceTag/ManagedBy を条件に指定することで、バケット配下の s3:DeleteObject を Deny できることを確認しました。
修正した IAM ポリシー
{
"Sid": "DenyDeleteObjectIfBucketIac",
"Effect": "Deny",
"Action": "s3:DeleteObject",
"Resource": "*",
"Condition": {
"StringEquals": {
"aws:ResourceTag/ManagedBy": "iac"
}
}
}
これは、「バケットに ManagedBy=iac タグが付いている場合、そのバケット配下のすべてのオブジェクト削除を Deny する」という設定です。
再度 DeleteObject してみる
バケットに ManagedBy=iac タグを付与し、ABAC を有効化した状態で、配下のオブジェクト削除を試みます。
aws s3api delete-object \
--bucket example-abac-bucket-iac-001 \
--key object-notag.txt \
--region ap-northeast-1
実行結果です。
An error occurred (AccessDenied) when calling the DeleteObject operation: User: arn:aws:sts::123456789012:assumed-role/example-role/example-session is not authorized to perform: s3:DeleteObject on resource: "arn:aws:s3:::example-abac-bucket-iac-001/object-notag.txt" with an explicit deny in an identity-based policy
期待通り、削除が Deny されました。
バケット単位のタグを条件にすることで、配下オブジェクトの削除を防止できました。
検証結果
検証結果をまとめると、以下のとおりです。
| 条件に指定したタグキー | ターゲット | 期待結果 | 実際の結果 |
|---|---|---|---|
s3:ExistingObjectTag/ManagedBy |
オブジェクトのタグ | 削除失敗 | 削除成功(防げない) |
aws:ResourceTag/ManagedBy |
バケットのタグ | 削除失敗 | 削除失敗(防げる) |
分かったこと
今回の検証で分かったことは以下です。
- S3 汎用バケットの ABAC を有効にしても、オブジェクト自身のタグ(
s3:ExistingObjectTag)を条件にs3:DeleteObjectを防ぐことはできなかった - オブジェクト削除を防ぎたい場合は、オブジェクトではなく、バケット側のタグ(
aws:ResourceTag)を Deny 条件に指定する
前回の検証から派生した疑問でしたが、S3 の「バケット ABAC」における仕様上の切り分けを理解する良い機会になりました。
参考
- https://docs.aws.amazon.com/AmazonS3/latest/userguide/tagging-and-policies.html
- https://docs.aws.amazon.com/service-authorization/latest/reference/list_amazons3.html
- https://docs.aws.amazon.com/AmazonS3/latest/userguide/buckets-tagging.html
- https://docs.aws.amazon.com/AmazonS3/latest/userguide/buckets-tagging-enable-abac.html





