「ルートユーザーでもアクセスできないS3バケット」のバケットポリシーを検証してみた

「ルートユーザーでもアクセスできないS3バケット」のバケットポリシーを検証してみた

バケットポリシーの明示的拒否はルートユーザーも対象です

はじめに

こんにちは、アノテーションの watabo です。

このブログの執筆時点で、SCS (AWS Certified Security - Specialty) の取得に向けて勉強をしています。

勉強中にAWSの公式ドキュメントを漁っていると、気になる記述があったので内容を検証してみました。

AWSドキュメントの気になる記述

https://docs.aws.amazon.com/ja_jp/IAM/latest/UserGuide/troubleshoot_iam-s3.html#troubleshoot_iam-s3_root-bucket-access

場合によっては、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": "許可されたユーザー等"
        }
      }
    }
  ]
}

条件キーの例は公式ドキュメントにも記載があります。

https://docs.aws.amazon.com/ja_jp/AmazonS3/latest/userguide/amazon-s3-policy-keys.html#bucket-keys-in-amazon-s3-policies

検証

本題の検証に話を戻します。

用意した環境

テスト用の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"
        }
      }
    }
  ]
}

image1
コンソールからバケットポリシーを確認した例

結果

この場合、ルートユーザーはConditionステートメントに含まれていないので、アカウントに全権限を持つルートユーザーといえどもアクセスはできません。

image2

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

一方で、バケットポリシーの変更は可能です。

image3

なお、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でのアクセスは問題なくできました。

image4

$ 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

まとめ

検証結果

  1. 明示的な拒否(Explicit Deny)がある場合

    • ルートユーザーでもアクセスが拒否される
    • Conditionで例外を設けても、その条件に含まれていないプリンシパルは拒否される
  2. 明示的な拒否がない場合

    • 特定のIAMユーザーのみを許可するポリシーでも、ルートユーザーはアクセス可能
    • これは既存のIAMポリシー評価ロジックと一致する動作

ポイント

バケットポリシーで**明示的な拒否(Explicit Deny)**が設定されていない限り、ルートユーザーのアクセス権限は維持されます。

  • 「ルートユーザーをプリンシパルとして指定しない場合」= 明示的な拒否がある場合
  • 単にAllowステートメントに含まれていないだけでは、ルートユーザーのアクセスは制限されない

所感

バケットポリシーで明示的な拒否が付与されていなければアクセスできるということが確認できました。
これまでに理解していた評価ロジックの根幹を揺るがすものではなかったので、よかったです。

基本的にルートユーザーで作業をすることはベストプラクティスに反するものなので、今回の事例が役に立つことは少ないかもしれません。ただ、特に初めてバケットポリシーを使用する際は、この「ルートユーザーでもアクセスできなくなる」という挙動を理解しておくことは知っておくと良いかと思います。

本エントリがどなたかの助けになれば幸いです。

Appendix:よくある間違いと対処法

せっかくなので、よく見かける間違い例を置いておきます。
Actions3:*を指定してしまうと、ルートユーザーでないと修正不可能となるケースもあります。
対象のユーザーなどを絞る検証をしたいときは、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/*"
]

参考リンク

https://docs.aws.amazon.com/ja_jp/AmazonS3/latest/userguide/example-bucket-policies.html
https://docs.aws.amazon.com/ja_jp/IAM/latest/UserGuide/reference_policies_evaluation-logic.html
https://docs.aws.amazon.com/ja_jp/AmazonS3/latest/userguide/security-best-practices.html

アノテーション株式会社について

アノテーション株式会社はクラスメソッドグループのオペレーション専門特化企業です。サポート・運用・開発保守・情シス・バックオフィスの専門チームが、最新 IT テクノロジー、高い技術力、蓄積されたノウハウをフル活用し、お客様の課題解決を行っています。当社は様々な職種でメンバーを募集しています。「オペレーション・エクセレンス」と「らしく働く、らしく生きる」を共に実現するカルチャー・しくみ・働き方にご興味がある方は、アノテーション株式会社 採用サイトをぜひご覧ください。

この記事をシェアする

facebookのロゴhatenaのロゴtwitterのロゴ

© Classmethod, Inc. All rights reserved.