「ルートユーザーでもアクセスできないS3バケット」のバケットポリシーを検証してみた
はじめに
こんにちは、アノテーションの watabo です。
このブログの執筆時点で、SCS (AWS Certified Security - Specialty) の取得に向けて勉強をしています。
勉強中にAWSの公式ドキュメントを漁っていると、気になる記述があったので内容を検証してみました。
AWSドキュメントの気になる記述
場合によっては、IAM と Amazon S3 へのフルアクセス許可を持つ IAM ユーザーがいる場合があります。IAM ユーザーが Amazon S3 バケットにバケットポリシーを割り当て、 ルートユーザーをプリンシパルとして指定しない場合、ルートユーザーはそのバケットへのアクセスを拒否されます。
つまり、「IAMユーザーがバケットポリシーを設定する際に、ルートユーザーを明示的に許可しないと、ルートユーザーでもアクセスできなくなる」ということです。
ただ、ドキュメントの文面だけ見ると、明示的にDenyポリシーがなくてもルートユーザーのアクセスが拒否されるようにも読み取れます。IAMユーザーの親AWSアカウントがバケット所有者の場合は、IAMユーザーのポリシーとバケットポリシーどちらかで明示的な許可を持っているとき、アクセスできるはずです。
果たして、Denyポリシーがなくてもアクセスは拒否されるのか?
気になったので、実際にバケットポリシーを比較して検証してみることにしました。
S3バケットポリシーとは
このブログをご覧になっている方はすでにある程度ご存知かとは思いますが、念の為S3バケットポリシーについて簡単に説明します。
S3バケットポリシーは、S3バケットへのアクセス権限を制御するJSON形式の設定です。「誰が」「どのリソースに」「何ができるか」を定義します。
基本的な構造はざっくり次のようになっています。
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow または Deny",
"Principal": "誰が",
"Action": "何を",
"Resource": "どのリソースに"
}
]
}
もう一つ例を出します。
許可されているプリンシパル(ユーザー・ロールなど)以外はアクセスさせない、という状況を考えます。
この場合はEffect
ステートメントをDeny
にして全員拒否としていますが、例外をNotInCondition
で指定するパターンとなります。
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Deny",
"Principal": "*",
"Action": "s3:*",
"Resource": "arn:aws:s3:::example-bucket/*",
"Condition": {
"StringNotEquals": {
"aws:PrincipalArn": "許可されたユーザー等"
}
}
}
]
}
条件キーの例は公式ドキュメントにも記載があります。
検証
本題の検証に話を戻します。
用意した環境
テスト用のS3バケット
S3バケットを作成し、バケットポリシーを変えて検証します。
なお、バケットポリシーの設定は後述のjsonの通りとなります。
# バケット名は一意である必要があります
aws s3 mb s3://test-bucket-root-access
検証ユーザ
以下の2ユーザがある環境を想定します。
- ルートユーザー(root)
- 以下の権限を持ったIAMユーザー(s3-test-user)
- S3FullAccess
- IAMFullAccess
元のドキュメントには下記のように記載があったので、文脈に合わせるべくs3-test-userにIAMFullAccess
を付与しています。
なお、バケットポリシーの変更作業は全てこのユーザーで実施しています。
IAM と Amazon S3 へのフルアクセス許可を持つ IAM ユーザーがいる場合
パターンA: 明示的な拒否(Deny)あり
明示的にDeny
ポリシーを設定し、NotInCondition
で設定しています。
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Deny",
"Principal": "*",
"Action": "s3:*",
"Resource": [
"arn:aws:s3:::test-bucket-root-access",
"arn:aws:s3:::test-bucket-root-access/*"
],
"Condition": {
"StringNotEquals": {
"aws:PrincipalArn": "arn:aws:iam::123456789012:user/s3-test-user"
}
}
}
]
}
コンソールからバケットポリシーを確認した例
結果
この場合、ルートユーザーはCondition
ステートメントに含まれていないので、アカウントに全権限を持つルートユーザーといえどもアクセスはできません。
CLIの実行結果も貼っておきます。
$ aws sts get-caller-identity --query 'Arn' --output text
arn:aws:iam::123456789012:root
$ aws s3 ls s3://test-bucket-root-access/
An error occurred (AccessDenied) when calling the ListObjectsV2 operation: User: arn:aws:iam::123456789012:root is not authorized to perform: s3:ListBucket on resource: "arn:aws:s3:::test-bucket-root-access" with an explicit deny in a resource-based policy
一方で、バケットポリシーの変更は可能です。
なお、s3-test-userではすべてのアクセスが許可されます。
パターンB: 明示的な拒否(Deny)なし
今回気になっていたパターンです。
特定のIAMユーザーのみにアクセスを許可し、ルートユーザーを含まないバケットポリシーを設定します。
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Principal": {
"AWS": "arn:aws:iam::123456789012:user/s3-test-user"
},
"Action": "s3:*",
"Resource": [
"arn:aws:s3:::test-bucket-root-access",
"arn:aws:s3:::test-bucket-root-access/*"
]
}
]
}
結果
このポリシーだと、rootでのアクセスは問題なくできました。
$ aws sts get-caller-identity --query 'Arn' --output text
arn:aws:iam::123456789012:root
$ aws s3 ls s3://test-bucket-root-access/
2025-08-29 07:30:25 6 testfile.txt
まとめ
検証結果
-
明示的な拒否(Explicit Deny)がある場合
- ルートユーザーでもアクセスが拒否される
Condition
で例外を設けても、その条件に含まれていないプリンシパルは拒否される
-
明示的な拒否がない場合
- 特定のIAMユーザーのみを許可するポリシーでも、ルートユーザーはアクセス可能
- これは既存のIAMポリシー評価ロジックと一致する動作
ポイント
バケットポリシーで**明示的な拒否(Explicit Deny)**が設定されていない限り、ルートユーザーのアクセス権限は維持されます。
- 「ルートユーザーをプリンシパルとして指定しない場合」= 明示的な拒否がある場合
- 単にAllowステートメントに含まれていないだけでは、ルートユーザーのアクセスは制限されない
所感
バケットポリシーで明示的な拒否が付与されていなければアクセスできるということが確認できました。
これまでに理解していた評価ロジックの根幹を揺るがすものではなかったので、よかったです。
基本的にルートユーザーで作業をすることはベストプラクティスに反するものなので、今回の事例が役に立つことは少ないかもしれません。ただ、特に初めてバケットポリシーを使用する際は、この「ルートユーザーでもアクセスできなくなる」という挙動を理解しておくことは知っておくと良いかと思います。
本エントリがどなたかの助けになれば幸いです。
Appendix:よくある間違いと対処法
せっかくなので、よく見かける間違い例を置いておきます。
Action
にs3:*
を指定してしまうと、ルートユーザーでないと修正不可能となるケースもあります。
対象のユーザーなどを絞る検証をしたいときは、s3:GetObject
などの弱い権限で試すとスタックしないので吉です。
間違い例1:Denyステートメントの過度な使用
{
"Statement": [
{
"Effect": "Deny",
"Principal": "*",
"Action": "s3:*",
"Resource": "*"
}
]
}
このようなポリシーは、すべてのアクセスを拒否してしまい、修正が困難になります。
間違い例2:リソースARNの記述ミス
// 間違い:バケット内のオブジェクトへのアクセスが含まれていない
"Resource": "arn:aws:s3:::my-bucket"
// 正しい:バケットとその中のオブジェクト両方を指定
"Resource": [
"arn:aws:s3:::my-bucket",
"arn:aws:s3:::my-bucket/*"
]
参考リンク
アノテーション株式会社について
アノテーション株式会社はクラスメソッドグループのオペレーション専門特化企業です。サポート・運用・開発保守・情シス・バックオフィスの専門チームが、最新 IT テクノロジー、高い技術力、蓄積されたノウハウをフル活用し、お客様の課題解決を行っています。当社は様々な職種でメンバーを募集しています。「オペレーション・エクセレンス」と「らしく働く、らしく生きる」を共に実現するカルチャー・しくみ・働き方にご興味がある方は、アノテーション株式会社 採用サイトをぜひご覧ください。