委任先で作成したCloudTrail Lakeデータストアからの出力先S3バケットポリシー

CloudTrailの委任で、Organizationsの管理アカウント以外で「組織のデータストア」を作成することができます。この時、このデータストアからクエリ実行結果を出力するS3バケットのポリシーでは、 **アクセス許可対象の記述にOrganizationsの管理アカウントIDを指定** する必要があります。
クエリ実行画面から **自動生成されるS3バケットはここに作業中のAWSアカウントのIDを入れるためクエリ実行が失敗** します（たぶん「組織のデータストア」作成を委任され実施したAWSアカウントで、そのログの検索など監査をしているでしょうから）。

# 前提情報

私自身がCloudTrail Lake初利用なので、概要に触れておく。

* [CloudTrail Lake](https://docs.aws.amazon.com/ja_jp/awscloudtrail/latest/userguide/cloudtrail-user-guide.html)はCloudTrail等のセキュリティ系情報特化のデータウェアハウス（以下DWH）。
* データストアとしてS3＋SQLエンジン入ってる（多分[Athena](https://aws.amazon.com/jp/athena/)、つまり裏はPresto系）。
* セキュリティ系だと[Security Lake](https://docs.aws.amazon.com/ja_jp/security-lake/latest/userguide/what-is-security-lake.html)とかなかったっけと思ったけど、あちらは[OCSF形式](https://github.com/ocsf)でデータレイク（蓄積）してSIEMソリューションとかにアクセス提供するするものらしい。

DWHなのでSQLでクエリできて、クエリ結果はS3にCSVファイル出力させることもできる。S3は自動生成させてもいいし、適切なバケットポリシーを付与して作成しておいてもいい。

* [クエリを実行し、クエリ結果を保存する - AWS CloudTrail](https://docs.aws.amazon.com/ja_jp/awscloudtrail/latest/userguide/query-run-query.html)
* [CloudTrail Lake クエリ結果の Amazon S3 バケットポリシー - AWS CloudTrail](https://docs.aws.amazon.com/ja_jp/awscloudtrail/latest/userguide/s3-bucket-policy-lake-query-results.html)

Organizations環境では「組織の証跡」やCloudTrail Lakeの「組織のデータストア」が作成できるけど、CloudTrailの委任管理者のサポートにより、これを別のアカウント（例えば[ランディングゾーンの考え方](https://docs.aws.amazon.com/ja_jp/prescriptive-guidance/latest/migration-aws-environment/building-landing-zones.html#aws-control-tower)で言うログ保管アカウント）で構成、管理することもできるようになった。

* [AWS CloudTrail が AWS Organizations の委任管理者アカウントのサポートを発表](https://aws.amazon.com/jp/about-aws/whats-new/2022/11/aws-cloudtrail-delegated-account-support-aws-organizations/)

# 問題

じゃあ、まずログ保管アカウントで「組織のデータストア」を作成し、そこでSQLクエリを実行して、S3に結果を出力させたらどうなるか。

* 組織のデータストア … 作れる。
* SQLクエリを実行 … できる。1秒ちょっとで数千件のレコードが返ってきたりする。
* S3出力 … 有効にしてクエリを実行すると、エラーになる。

エラーメッセージは以下の通り。エラーメッセージがリンクになっていて、リンク先も以下の通り。

> [クエリ結果をこの S3 バケットに保存するには、バケットポリシーを更新します。 ](https://docs.aws.amazon.com/ja_jp/awscloudtrail/latest/userguide/s3-bucket-policy-lake-query-results.html)

S3に出力する指定の際、デフォルトではバケットポリシーを付与したS3バケットを作成してくれる。でもその自動作成されたS3バケットでエラーになる。それならばと自分でバケットを作成してバケットポリシーを書いてみたけど、やっぱりエラーになる。エラーメッセージと、S3出力しなければクエリ実行が成功するところからして、問題はやっぱりバケットとバケットポリシーなのだろうけど。

# 原因

結論を言えば、バケットポリシーで指定するAWSアカウントIDが違っていた。

まず[バケットポリシーのサンプル](https://docs.aws.amazon.com/ja_jp/awscloudtrail/latest/userguide/s3-bucket-policy-lake-query-results.html#s3-bucket-policy-lake-query)がこんな感じ。

```
{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Sid": "AWSCloudTrailLake1",
            "Effect": "Allow",
            "Principal": {"Service": "cloudtrail.amazonaws.com"},
            "Action": [
                "s3:PutObject*",
                "s3:Abort*"
            ],
            "Resource": [
                "arn:aws:s3:::myBucketName",
                "arn:aws:s3:::myBucketName/*"
            ],
            "Condition": {
                "StringLike": {
                    "aws:sourceAccount": "myAccountID",
                    "aws:sourceArn": "arn:aws:cloudtrail:myQueryRunningRegion:myAccountID:eventdatastore/*"
                }
            }     
        },
        {
            "Sid": "AWSCloudTrailLake2",
            "Effect": "Allow",
            "Principal": {"Service":"cloudtrail.amazonaws.com"},
            "Action": "s3:GetBucketAcl",
            "Resource": "arn:aws:s3:::myBucketName",
            "Condition": {
                "StringLike": {
                    "aws:sourceAccount": "myAccountID",
                    "aws:sourceArn": "arn:aws:cloudtrail:myQueryRunningRegion:myAccountID:eventdatastore/*"
                }
            }
        }
    ]
}
```

このうち、 `myBucketName` を実際のバケット名、 `myQueryRunningRegion` をクエリを実行するリージョン（ `ap-northeast-1` とか）、 `myAccountID` をAWSアカウントIDで置き換える。ここで、一つ注記がある。

> 注記：
> これが組織のイベントデータストアである場合は、管理アカウントの AWS アカウント ID を使用する必要があります。

これ、組織のイベントデータストアを委任されたログ保管アカウントで作成している場合は、どうなんでしょうね。Organizationsの管理アカウントのことか、組織のイベントデータストアの管理アカウント（この場合ログ保管アカウント）のことか、どちらでしょう。

**正解は、Organizationsの管理アカウントです。**

最初は `aws:sourceArn` の `myAccountID:eventdatastore` という文字列を見て、データストアはここにあるんだから、ここはログ保管アカウントのIDだよなと思った。だとすれば同じConditions内にある `aws:sourceAccount` のアカウントIDが違うというのも妙な感じなので、ログ保管アカウントだろうと。で、エラーになる。もう一度考えてみて、今度は自動生成させたバケットポリシーを確認したりして、やっぱり管理アカウントIDの解釈はあってそうだ、他のところに何か問題があるんだろうと考える。なにをやってもエラーになる。

なにをやってもエラーになるので、委任とか考慮できてないのではと思っていた注記に沿って、試しにOrganizationsの管理アカウントのIDを入れてみる。すると、CSV保存できました。

# 終わりに

僕の解釈が間違ってたわけですが、傷を深くしたのは少なからず **自動生成されるS3バケットとそのバケットポリシーが同じ間違いをしている** ことだったと思います。ぜひとも直していただきたいです……ってこれ、サポートチケットきらないといけないやつ、なのかな……？