S3 のオブジェクトACLの無効化が推奨となったので、改めて IAM ポリシーと S3 バケットポリシーの評価論理をまとめてみた

バケットに対してアクセスコントロールリストの無効化ができるようになり、評価論理がシンプルになりました。また、制御したい内容によって、IAMポリシー、S3バケットポリシーのどちらのポリシーに記述することが適しているかについても紹介します。
2022.06.10

Amazon S3に対するアクセスコントロールの種類

S3 に対するアクセスコントールは 3 つあり、それぞれの評価論理を考慮しながら使用する必要がありました。

ACL 無効が推奨となった

2021年10月30日より、バケットに対してアクセスコントロールリストの無効化ができるようになりました。

これにより、S3 バケット内のすべてのオブジェクトがバケット所有者に所有されるようになり、評価論理がシンプルになりました。

バケットポリシーと IAM ポリシーの評価論理

バケットポリシー IAM ポリシー 結果
指定なし 指定なし 失敗
許可 指定なし 成功
指定なし 許可 成功
許可 許可 成功
明示的な拒否 許可 失敗
許可 明示的な拒否 失敗
明示的な拒否 明示的な拒否 失敗

IAM ポリシー、バケットポリシーのどちらかが許可しているとアクセスに成功します。

どちらかの許可があっても、明示的な拒否を加えることで失敗します。明示的な拒否は絶対です。

また、制御したい内容によって、どちらのポリシーに記述するかについてを使い分けることも必要です。

バケットポリシーでの制御が適していること

IP アドレスによる制限

特定の IP アドレス以外のアクセスを拒否する場合は、以下のようなバケットポリシーとなります。

{
    "Id": "SourceIP",
    "Version": "2012-10-17",
    "Statement": [
        {
            "Sid": "SourceIP",
            "Action": "s3:*",
            "Effect": "Deny",
            "Resource": [
                "arn:aws:s3:::DOC-EXAMPLE-BUCKET",
                "arn:aws:s3:::DOC-EXAMPLE-BUCKET/*"
            ],
            "Condition": {
                "NotIpAddress": {
                    "aws:SourceIp": [
                        "11.11.11.11/32",
                        "22.22.22.22/32"
                    ]
                }
            },
            "Principal": "*"
        }
    ]
}

これに加えて、IAM ユーザー/ロール でアクセスする場合は、アクセス許可を明示的に追加する必要があります。

参考ドキュメント:Amazon S3 バケットへのアクセスを特定の IP または VPC に制限する

CloudFront のオリジンアクセスアイデンティティ

特定の CloudFront からの読み取りを許可する場合、バケットポリシーは下記となります。

{
    "Version": "2012-10-17",
    "Id": "PolicyForCloudFrontPrivateContent",
    "Statement": [
        {
            "Effect": "Allow",
            "Principal": {
                "AWS": "arn:aws:iam::cloudfront:user/CloudFront Origin Access Identity EH1HDMB1FH2TC"
            },
            "Action": "s3:GetObject",
            "Resource": "arn:aws:s3:::DOC-EXAMPLE-BUCKET/*"
        }
    ]
}

参考ドキュメント:オリジンアクセスアイデンティティ (OAI) を使用して Amazon S3 コンテンツへのアクセスを制限する - Amazon CloudFront

特定のサービスからのアクセス許可(例:CloudWatch Logs から S3 バケットへのエクスポート)

S3 バケットにログを出力するケースがあります。その場合、S3 バケットにログを出力する際に用いる AWS サービスに対して許可を与える必要があります。

{
    "Version": "2012-10-17",
    "Statement": [
      {
          "Action": "s3:GetBucketAcl",
          "Effect": "Allow",
          "Resource": "arn:aws:s3:::my-exported-logs",
          "Principal": { "Service": "logs.ap-northeast-1.amazonaws.com" }
      },
      {
          "Action": "s3:PutObject" ,
          "Effect": "Allow",
          "Resource": "arn:aws:s3:::my-exported-logs/random-string/*",
          "Condition": { "StringEquals": { "s3:x-amz-acl": "bucket-owner-full-control" } },
          "Principal": { "Service": "logs.ap-northeast-1.amazonaws.com" }
      }
    ]
}

参考ドキュメント:コンソールを使用してログデータを Amazon S3 にエクスポートする - Amazon CloudWatch Logs

AWSのリソースに関わらないアクセス制御(例:パブリックアクセスの許可など)

パブリックアクセスを許可する場合、バケットポリシーは下記となります。

{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Sid": "PublicReadGetObject",
            "Effect": "Allow",
            "Principal": "*",
            "Action": [
                "s3:GetObject"
            ],
            "Resource": [
                "arn:aws:s3:::DOC-EXAMPLE-BUCKET/*"
            ]
        }
    ]
}

なお、事前にブロックパブリックアクセスを無効にする必要があります。

参考ドキュメント:ウェブサイトアクセスのアクセス許可の設定 - Amazon Simple Storage Service

IAM ポリシーでの制御が適していること

IAM ユーザー/ロールごとに特定の S3 バケットへのアクセスを制限したい

必要に応じてバケット全体を参照できるポリシー s3:ListAllMyBuckets, s3:GetBucketLocation を付与します。この権限がない場合、マネジメントコンソールでバケット一覧が表示できず、どのバケットも選択できなくなります。

{
    "Version":"2012-10-17",
    "Statement": [
        {
            "Sid": "AllowStatementListBuckets",
            "Action": ["s3:ListAllMyBuckets", "s3:GetBucketLocation"],
            "Effect": "Allow",
            "Resource": ["arn:aws:s3:::*"]
        }
    ]
}

次に、バケット単位、または、バケット内で特定のプレフィックス名が付いているオブジェクトに対して、制御を行います。 下記の例は、DOC-EXAMPLE-BUCKET にあるオブジェクトをリストできる権限、media というプレフィックス名が付いているオブジェクトを参照する権限を付与しています。

{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Sid": "AllowStatementListBucket",
            "Action": [
                "s3:ListBucket"
            ],
            "Effect": "Allow",
            "Resource": [
                "arn:aws:s3:::DOC-EXAMPLE-BUCKET"
            ],
            "Condition": {
                "StringEquals": {
                    "s3:prefix": [
                        "",
                        "media"
                    ]
                }
            }
        },
        {
            "Sid": "AllowStatementListBucketPrefix",
            "Action": [
                "s3:ListBucket"
            ],
            "Effect": "Allow",
            "Resource": [
                "arn:aws:s3:::DOC-EXAMPLE-BUCKET"
            ],
            "Condition": {
                "StringLike": {
                    "s3:prefix": [
                        "media/*"
                    ]
                }
            }
        },
        {
            "Sid": "AllowStatementGetObject",
            "Effect": "Allow",
            "Action": [
                "s3:GetObject"
            ],
            "Resource": [
                "arn:aws:s3:::DOC-EXAMPLE-BUCKET/media/*"
            ]
        }
    ]
}

参考ドキュメント:IAM ユーザーに対し Amazon S3 バケットにあるフォルダーへのアクセス権を付与する

まとめ

  • ACL 無効化が推奨になったことにより、評価論理がシンプルになった
  • 拒否は絶対
  • 制御したい内容によって、どちらのポリシーに記述するかを使い分ける

参考資料

S3のアクセスコントロールが多すぎて訳が解らないので整理してみる | DevelopersIO

Amazon S3 Object Ownership で、S3 内のデータのアクセス管理をシンプル化するためのアクセスコントロールリストの無効化が可能に