S3 バケットポリシーのNotPrincipalによるロール制限ではまった話

# はじめに
今回、バケットポリシーで使えると便利だけど使い方ではまってしまったNotPrincipalの設定について解説をしたいと思います。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/918398/79b7df39-56ec-c3e3-14e5-9468a64b1186.png)


とあるKinesis DataFirehoseからS3へのDirect PUT接続を構築したときのことです。
構築自体は難なく完了。次にセキュリティを高めようと思い、``NotPrincipal``を使ったバケットポリシーを以下のように設定してみました。
``NotPrincipal``でFirehoseに付与したロール以外からのS3アクセスを拒否したつもりでした。
しかしながら、これを設定した瞬間にS3 Access Denied のアクセスエラーが出てしまいました...:sob:


```JSON:Bucket Policy (Bad)
{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Effect": "Deny",
            "NotPrincipal": {
                "AWS": [
                    "arn:aws:iam::<ACCOUNT ID>:role/<ROLE NAME>"
                ]
            },
            "Action": "s3:PutObject",
            "Resource": [
                "arn:aws:s3:::<BUCKET>",
                "arn:aws:s3:::<BUCKET>/*"
            ]
        }
    ]
}

```



# 結論

以下のようにバケットポリシーを設定することで、正しくFirehoseからのデータ連携を受け取ることができるようになりました。以下の例はKinesis DataFirehoseに対応をしていますが、後述のポイント1, 2を見ていただくことで、ご自身の環境に合わせて設定ができるようになります。


```JSON:Bucket Policy (Correct)
{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Effect": "Deny",
            "NotPrincipal": {
                "AWS": [
                    "arn:aws:sts::<ACCOUNT ID>:assumed-role/<ROLE NAME>/AWSFirehoseToS3",
                    "arn:aws:iam::<ACCOUNT ID>:role/<ROLE NAME>",
                    "arn:aws:iam::<ACCOUNT ID>:root"
                ]
            },
            "Action": "s3:PutObject",
            "Resource": [
                "arn:aws:s3:::<BUCKET>",
                "arn:aws:s3:::<BUCKET>/*"
            ]
        }
    ]
}

```


# ポイント1 : NotPrincipalの使い方

まずは公式ドキュメントをしっかりと読み込むべきでした。公式にある通り、NotPrincipalを使用するためには以下のように設定する必要があるようです。

https://docs.aws.amazon.com/ja_jp/IAM/latest/UserGuide/reference_policies_elements_notprincipal.html


```JSON:Bucket Policy
{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Effect": "Deny",
            "NotPrincipal": {
                "AWS": [
                    "arn:aws:sts::<ACCOUNT ID>:assumed-role/<ROLE NAME>/<ROLE SESSION NAME>",
                    "arn:aws:iam::<ACCOUNT ID>:role/<ROLE NAME>",
                    "arn:aws:iam::<ACCOUNT ID>:root"
                ]
            },
            "Action": "s3:PutObject",
            "Resource": [
                "arn:aws:s3:::<BUCKET>",
                "arn:aws:s3:::<BUCKET>/*"
            ]
        }
    ]
}

```

NotPrincipalの場合は以下3つのARNを含める必要があるので要注意です。
1. AssumeRole
1. ロール
1. ルートユーザ


# ポイント2 : ロールセッション名
ポイント1のポリシーの構造がわかったところで、次の壁はAssumeRoleのARNの設定です。特にロールセッション名については記載がなく、Firehoseのロールセッション名が何なのか確認が必要でした。

以下の記事はとても参考になりましたが、EC2とLambdaについて説明されており、自分のケースではうまくいかず...

https://qiita.com/bashishi/items/5446e0f15e663f91fe05


ワイルドカードの使用を試みましたがポリシー検証でエラー、セッション名をFirehoseのリソース名に設定してみるもFirehoseからのアクセスは拒否されたままの結果でした...

あれこれ悩んだ末、Crondtrailでロールセッション名を確認することができるのではと思い、確認をしてみました。
Croudtrailから``イベント名 : AssumeRole``でフィルターをかけると、以下ののようなFirehoseのAssumeRoleの実行履歴を確認することができます。


```JSON:Croudtral Event
{
    :
    :
    "requestParameters" : {
         "roleArn" : "arn:aws:iam::<ACCOUNT ID>:role/<ROLE NAME>" ,
         "roleSessionName" : "AWSFirehoseToS3",
         "durationSeconds" : 3600,
         "externalId" : "<ACCOUNT ID>"
 
    }
    :
    :
}


```

発見！！！
"roleSessionName"をS3のバケットポリシーに設定すると無事疎通しました:sunny: