【SSM Inventory】複数アカウントのインベントリデータを集約するS3のバケットポリシーの注意点


<h2>はじめに</h2>

こんにちは、クマ松です。

SSM Inventoryについて、以前幾つか記事を書きました。
[マルチアカウント構成でのSSM Inventoryによるインベントリ収集方法](https://qiita.com/kuma_matsu/items/6c6ce6902674151bc26a "マルチアカウント構成でのSSM Inventoryによるインベントリ収集方法")

今回は<font color="deeppink">__SSM Inventory__</font>機能を使って複数のAWSアカウントのインベントリ情報を集約する場合の<font color="green">__S3バケットのポリシー__</font>の設定について、注意点を記載します。

<h2>複数アカウントのインベントリデータを集約する際のS3バケットポリシー</h2>

公式のドキュメントにS3バケットポリシーの例が記載されています。
[AWS Systems Manager ユーザーガイドインベントリのリソースデータの同期の設定](https://docs.aws.amazon.com/ja_jp/systems-manager/latest/userguide/sysman-inventory-datasync.html#sysman-inventory-datasync-before-you-begin "AWS Systems Manager ユーザーガイドインベントリのリソースデータの同期の設定")

この設定だと上手くいかないケースがあります。

AWS公式ドキュメントに記載されているポリシーは以下の通りです。
```json
{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Sid": "SSMBucketPermissionsCheck",
      "Effect": "Allow",
      "Principal": {
        "Service": "ssm.amazonaws.com"
      },
      "Action": "s3:GetBucketAcl",
      "Resource": "arn:aws:s3:::S3_bucket_name"
    },
    {
      "Sid": " SSMBucketDelivery",
      "Effect": "Allow",
      "Principal": {
        "Service": "ssm.amazonaws.com"
      },
      "Action": "s3:PutObject",
      "Resource": [
        "arn:aws:s3:::S3_bucket_name/*/accountid=ID_number/*",
        "arn:aws:s3:::S3_bucket_name/*/accountid=ID_number/*",
        "arn:aws:s3:::S3_bucket_name/*/accountid=ID_number/*",
        "arn:aws:s3:::S3_bucket_name/*/accountid=ID_number/*"
      ],
      "Condition": {
        "StringEquals": {
          "s3:x-amz-acl": "bucket-owner-full-control",
          "aws:SourceAccount": "123456789012"
        },
        "ArnLike": {
          "aws:SourceArn": "arn:aws:ssm:*:123456789012:resource-data-sync/*"
        }
      }
    }
  ]
}
```

こちらのバケットポリシーの中のSid：SSMBucketDeliveryについて解説すると
- 以下の条件が合致した場合（Condition）
    - 特定の子アカウント(123456789012)からbucket-owner-full-control アクセスコントロールリスト (ACL)オプションが付与されているオブジェクト
    - 特定の子アカウント(123456789012)のリソース同期からのインベントリ収集である
- 中央アカウントのS3内の、子アカウントIDのフォルダ毎に対して、
- インベントリ情報をputするためのPutObjectを実行できる

という意味になります。

子アカウントが1つの場合は上記の設定で問題ありません。

__もし複数の子アカウントからインベントリを集約するためには、このS3バケットのポリシーの2か所を修正する必要があります。__

- StringEquals
- ArnLike

複数AWSアカウントの<font color="deeppink">__SSM__</font>から、<font color="green">__S3__</font>へインベントリデータをputできるよう、集合演算子 __「ForAnyValue」__ を利用します。

```json
    
    {
      "Version": "2012-10-17",
      "Statement": [
        {
          "Sid": "SSMBucketPermissionsCheck",
          "Effect": "Allow",
          "Principal": {
            "Service": "ssm.amazonaws.com"
          },
          "Action": "s3:GetBucketAcl",
          "Resource": "arn:aws:s3:::S3_bucket_name"
        },
        {
          "Sid": " SSMBucketDelivery",
          "Effect": "Allow",
          "Principal": {
            "Service": "ssm.amazonaws.com"
          },
          "Action": "s3:PutObject",
          "Resource": [
            "arn:aws:s3:::S3_bucket_name/*/accountid=中央アカウントのAWSアカウントID/*",
            "arn:aws:s3:::S3_bucket_name/*/accountid=子アカウントのAWSアカウントID/*",
            "arn:aws:s3:::S3_bucket_name/*/accountid=子アカウントのAWSアカウントID/*",
            "arn:aws:s3:::S3_bucket_name/*/accountid=子アカウントのAWSアカウントID/*"
          ],
          "Condition": {
            "ForAnyValue:StringEquals": { ←ココ
              "aws:SourceAccount": [
                  "中央アカウントのAWSアカウントID",
                  "子アカウントのAWSアカウントID",
                  "子アカウントのAWSアカウントID",
                  "子アカウントのAWSアカウントID"
                ],
              "s3:x-amz-acl": "bucket-owner-full-control"
            },
            "ForAnyValue:ArnLike": { ←ココ
              "aws:SourceArn": [
                "arn:aws:ssm:*:中央アカウントのAWSアカウントID:resource-data-sync/*",
                "arn:aws:ssm:*:子アカウントのAWSアカウントID:resource-data-sync/*",
                "arn:aws:ssm:*:子アカウントのAWSアカウントID:resource-data-sync/*",
                "arn:aws:ssm:*:子アカウントのAWSアカウントID:resource-data-sync/*"
              ]
            }
          }
        }
      ]
    }
    
    
```

ForAnyValueを使うことで、複数の要素のうちどれか1つの要素の値が一致している場合に真になります。
複数の子アカウントからのインベントリデータを集約したい場合はこのように設定しましょう。