クロスアカウントでCloudTrailの証跡ログを参照する際にハマったこと

# はじめに

マルチアカウントでAWSを運用している場合、1つのアカウントのS3へCloudTrailの証跡ログを集約して保管するといった構成はよく見られます。
その際に考慮しなければならないのは、クロスアカウントでのアクセス制御です。
ログの書き込みと読み出しの両方において必要な権限を許可する必要があります。
本記事では、主に読み出しの権限を付与する際にハマった内容について記載します。

# 前提とする構成

今回想定している構成は以下です。
各アカウントのCloudTrailから別アカウントのS3へ証跡ログを保存します。
一方で、各アカウントのAthenaサービスを使ってログの分析を行えるようにします。

![CloudTrail構成.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/483600/05f7938d-a665-9441-d625-ffbdd666d3a3.jpeg)

また、以下の前提があります（この条件が今回ハマった内容と大きく関連します）。

- CloudTrailからS3へのログ保管は結構前から実施している

# 最初にやったこと

各アカウントからS3に保存されたログを参照出来るように、以下のようなバケットポリシーを追加しました。
本記事の主目的とは逸れますが、自身のアカウントが送信したログのみが参照出来るように`${aws:PrincipalAccount}`を使っています。

```
{
  "Version": "2012-10-17",
  "Statement": [
      {
          "Effect": "Allow",
          "Principal": "*",
          "Action": "s3:GetBucketLocation",
          "Resource": "arn:aws:s3:::<Bucket名>",
          "Condition": {
              "StringEquals": {
                  "aws:PrincipalOrgID": "<OrganizationsのID>"
              }
          }
      },
      {
          "Effect": "Allow",
          "Principal": "*",
          "Action": [
              "s3:GetObject",
              "s3:ListBucketMultipartUploads",
              "s3:ListMultipartUploadParts",
              "s3:AbortMultipartUpload"
          ],
          "Resource": [
              "arn:aws:s3:::<Bucket名>",
              "arn:aws:s3:::<Bucket名>/AWSLogs/<OrganizationsのID>/${aws:PrincipalAccount}/*"
          ],
          "Condition": {
              "StringEquals": {
                  "aws:PrincipalOrgID": "<OrganizationsのID>"
              }
          }
      },
      {
          "Effect": "Allow",
          "Principal": "*",
          "Action": "s3:ListBucket",
          "Resource": "arn:aws:s3:::<Bucket名>",
          "Condition": {
              "StringEquals": {
                  "aws:PrincipalOrgID": "<OrganizationsのID>"
              },
              "StringLike": {
                  "s3:prefix": "AWSLogs/<OrganizationsのID>/${aws:PrincipalAccount}/*"
              }
          }
      }
      ・・・
      ・・・
      ・・・
  ]
}
```

このポリシーを追加することで、各アカウントからオブジェクト参照が出来るようになる想定でした。

# ハマったこと

想定と反してオブジェクトの参照が出来ず、`Access Denied`となってしまいました。
原因を調べると、以下の事実が分かりました。

- 所有者が`eagle-iad-prod`となっているオブジェクトが存在する（この名前には見覚えがない）
- 正規IDが送信元アカウントのものと異なる

この件についてAWSサポートに問い合わせたところ、以下が分かりました。

- 当該バケットの設定が`ACL有効（オブジェクトライター）`となっていることに起因して発生している
- CloudTrailの証跡では、CloudTrailのサービスプリンシパルから証跡をPUTする仕様となる
- 保存先のS3では`ACL有効（オブジェクトライター）`となっていたため、オブジェクトの所有者はCloudTrail サービスのままとなっている
- 所有者が`eagle-iad-prod`となっている点については、CloudTrailサービスがオブジェクトを所有していることを示している（後で分かったことですが`eagle-iad-prod`以外にもいくつか名前があるようです）

図で表現すると以下のような状況になっていたと思われます。

![CloudTrail構成-ページ2.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/483600/60fd34ef-3a12-eea5-7e19-f7db455e91fb.jpeg)

オブジェクト所有者がバケット所有者以外となっている場合、バケットポリシーで許可してあってもオブジェクトへのアクセスを許可することは出来ません。
なお、2020年10月に`オブジェクトライター`ではなく`希望するバケット所有者`とする機能が追加となりましたが、今回のバケットはこれよりも前に作成されたものだったため導入されていませんでした。

https://aws.amazon.com/jp/about-aws/whats-new/2020/10/amazon-s3-object-ownership-enables-bucket-owners-to-automatically-assume-ownership-of-objects-uploaded-to-their-buckets/

そのため、AWSサポートから以下の対応案をいただきました。

- 案1：ACL無効（バケット所有者の強制）に変更する
- 案2：バケットが存在するアカウントのIAMロールを引き受けて別アカウントからアクセスする運用とする

現時点では、Athenaから別アカウントのIAMロールを引き受けた形でのアクセスは出来ないため案1を採用することにしました。

なお、今はACLを使わずにバケットポリシーを使ってアクセス制御を行うことが推奨されているようです。

>Amazon S3 の最新のユースケースの大部分では ACL を使用する必要がなくなっています。そのため、オブジェクトごとに個別にアクセスを制御する必要がある異常な状況を除き、ACL を無効にしておくことをお勧めします。ACL を無効にすると、バケット内のオブジェクトをアップロードしたユーザーに関係なく、ポリシーを使用してバケット内のすべてのオブジェクトへのアクセスをより簡単に制御できます。

https://docs.aws.amazon.com/ja_jp/AmazonS3/latest/userguide/about-object-ownership.html

2023年4月以降、新規で作成されたS3バケットについてはACLがデフォルトで無効となっています。

https://aws.amazon.com/jp/about-aws/whats-new/2023/04/amazon-s3-security-best-practices-buckets-default/

# 対応内容

ACLを無効化するためには前提条件があります。
今回は既にバケットポリシーで許可されていたり、ACLもPrivateになっていたので変更は必要ありませんでしたが、場合によっては対応が必要そうです。

https://docs.aws.amazon.com/ja_jp/AmazonS3/latest/userguide/object-ownership-migrating-acls-prerequisites.html

ACL無効（バケット所有者の強制）に変更するためには、以下のようにバケットの設定を変更するのみです。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/483600/c7b9dbd4-a5b2-732b-c36d-d02d6610270a.png)

オブジェクトの所有者が変更され、バケットポリシーを使用したアクセス制御が可能となります。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/483600/05913e7f-41dc-a52f-875e-381095892984.png)

# 戻したい場合

オブジェクトの所有者を元の設定に戻すことで、元の動作へ戻すことが出来ました。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/483600/827df805-8dbd-eba9-3eba-9cad6a69cc4f.png)

# 最後に

S3のアクセス権限周りは複雑で苦手意識があったのですが、今回の件で理解がだいぶ深まりました。