S3のバケットポリシーでハマったので、S3へのアクセスを許可するPrincipalの設定を整理する

S3はデータ置き場としてとても使えるやつで、他のアカウントと共有することも多いです。

複数AWSアカウントを使用していると、「1つのAWSアカウントのS3にデータを集約したい。」なんてニーズがでてきます。

S3のバケットポリシーのPrincipalを設定する際、アクセスができなくてハマったので本ブログはその備忘録です。

S3がリクエストを許可する方法

S3がバケットオペレーションのリクエストを許可する方法は、公式ドキュメントに記載されています。

内容が複雑なのでざっくり説明します。

たとえばIAMユーザーでS3にアクセスする状況を考えます。
IAMユーザーの親AWSアカウントがバケット所有者の場合、IAMユーザーのポリシーとバケットポリシーどちらかの許可を持っているとき、アクセスできます。

一方、IAMユーザーの親AWSアカウントがバケット所有者でない場合、IAMユーザーのポリシーとバケットポリシー両方の許可を持っているとき、アクセスできます。

大枠が理解できたところで、IAMポリシーとバケットポリシーの具体例を交えて、ハマった状況をご紹介します。

下準備

具体例を出すために、S3バケットとIAMユーザーを作成します。

S3バケットとIAMユーザーについては、先日のブログと同様の環境を使用します。作成手順については、こちらのブログを御覧ください。

別アカウントのS3バケットを利用する

別アカウントのS3バケットを利用する場合、IAMユーザーのポリシーとバケットポリシー、両方の許可を持っている必要があります。

バケットがあるAWSアカウントをアカウントA(アカウントID:111111111111)、 IAMユーザーがあるAWSアカウントをアカウントB(アカウントID:222222222222)とします。

ポリシーをこんな感じに設定すると、アクセスできます。

※便宜上、S3バケット名を ${S3_BUCKET_NAME} に変更しています。

{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Effect": "Allow",
            "Principal": {
                "AWS": "222222222222"
            },
            "Action": "s3:ListBucket",
            "Resource": "arn:aws:s3:::${S3_BUCKET_NAME}"
        }
    ]
}

S3のバケットポリシーで特定のAWSアカウントに対してアクセス許可を与えたい場合、PrincipalにAWSアカウントのIDを設定することで、許可を付与するこができます。
詳細は公式ドキュメントを御覧ください。

※便宜上、S3バケット名を ${S3_BUCKET_NAME} に変更しています。

{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Effect": "Allow",
            "Action": "s3:ListBucket",
            "Resource": "arn:aws:s3:::${S3_BUCKET_NAME}"
        }
    ]
}

このようにバケットポリシーとIAMポリシー両方許可することで、別アカウントのS3バケットにアクセスできます。

$ export S3_BUCKET_NAME=<<BUCKET_NAME>>
$ aws s3 ls s3://${S3_BUCKET_NAME}
2019-08-16 15:36:06         13 hello_world.html

どちらかのポリシーを許可していないと、アクセスは拒否されます。

$ export S3_BUCKET_NAME=<<BUCKET_NAME>>
$ aws s3 ls s3://${S3_BUCKET_NAME}
An error occurred (AccessDenied) when calling the ListObjectsV2 operation: Access Denied

同じアカウントのS3バケットを利用する(失敗パターン)

同じアカウントのS3バケットを利用する場合、IAMユーザーのポリシーとバケットポリシー、どちらかの許可をもっている必要があります。

ですので、IAMポリシーでそのバケットに対する操作が許可されていれば、バケットポリシーで許可されていなくてもS3にアクセスできます。

※便宜上、S3バケット名を ${S3_BUCKET_NAME} に変更しています。

{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Effect": "Allow",
            "Action": "s3:ListBucket",
            "Resource": "arn:aws:s3:::${S3_BUCKET_NAME}"
        }
    ]
}
$ export S3_BUCKET_NAME=<<BUCKET_NAME>>
$ aws s3 ls s3://${S3_BUCKET_NAME}
2019-08-16 15:36:06         13 hello_world.html

同様に、バケットポリシーだけ許可の設定をしていればS3にアクセスできるだろうと思っていたのですが、これがうまくいかなくてハマりました。

{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Effect": "Allow",
            "Principal": {
                "AWS": "111111111111"
            },
            "Action": "s3:ListBucket",
            "Resource": "arn:aws:s3:::${S3_BUCKET_NAME}"
        }
    ]
}
$ export S3_BUCKET_NAME=<<BUCKET_NAME>>
$ aws s3 ls s3://${S3_BUCKET_NAME}
An error occurred (AccessDenied) when calling the ListObjectsV2 operation: Access Denied

同じアカウントのS3バケットを利用する(成功パターン)

PrincipalIAMユーザーのArnを明示することで、バケットポリシーのみ許可した設定でアクセスが可能でした。

unauthorized-user という名前で何も許可されていないIAMユーザーを作成します。

そのユーザーArnからのアクセスを許可するバケットポリシーを設定します。

※便宜上、S3バケット名を ${S3_BUCKET_NAME} に変更しています。

{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Effect": "Allow",
            "Principal": {
                "AWS": "arn:aws:iam::111111111111:user/unauthorized-user"
            },
            "Action": "s3:ListBucket",
            "Resource": "arn:aws:s3:::${S3_BUCKET_NAME}"
        }
    ]
}

このバケットポリシーを設定していれば、IAMポリシーでは許可がない unauthorized-user からS3にアクセスできました。

$ export S3_BUCKET_NAME=<<BUCKET_NAME>>
$ aws s3 ls s3://${S3_BUCKET_NAME}
2019-08-16 15:36:06         13 hello_world.html

まとめ

IAMポリシーとバケットポリシーの許可について表でまとめるとこんな感じです。

IAMユーザーとS3が同じアカウントか IAMポリシー バケットポリシー(ユーザーArn指定) バケットポリシー(AWSアカウント指定) 備考
同じ いずれか必要 いずれか必要 - IAMポリシーまたはバケットポリシーのどちらかで許可されていればアクセス可能
異なる 許可必須 いずれか必要 いずれか必要 IAMポリシーとバケットポリシー両方の許可が必要。バケットポリシーはユーザーArnでもAWSアカウント指定でもOK

挙動としてはそうなることが確認できましたが、どういう理屈でそうなるのかはよくわかりませんでした。
知っている方がいれば、こっそり教えてください。