AWS ConfigでService-Linked Rolesを使用すると定期的にS3バケットへのAccessDeniedが発生してしまう

## 事象
AWS Config の設定で Service-Linked Roles（AWSServiceRoleForConfig）を使用していると
定期的に Config 用の S3バケットへの AccessDenied が CloudTrail に記録されてしまっていた。
具体的には AWS Config の設定で以下のように設定している場合。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/125105/d238f86b-66b7-7aa4-b4d8-fb13a966fe1c.png)
AWS Config 自体は正常に動作しているが、 CloudTrailには
以下のようなログが定期的に記録されているような状況でした。

```json
{
    "eventVersion": "1.06",
    "userIdentity": {
        "type": "AssumedRole",
        "principalId": "ABCDEFGHIJKLMNOPQRSTU:AWSConfig-BucketConfigCheck",
        "arn": "arn:aws:sts::123456789012:assumed-role/AWSServiceRoleForConfig/AWSConfig-BucketConfigCheck",
        "accountId": "123456789012",
        "accessKeyId": "ABCDEFGHIJKLMNOPQRST",
        "sessionContext": {
            "sessionIssuer": {
                "type": "Role",
                "principalId": "ABCDEFGHIJKLMNOPQRST",
                "arn": "arn:aws:iam::123456789012:role/aws-service-role/config.amazonaws.com/AWSServiceRoleForConfig",
                "accountId": "123456789012",
                "userName": "AWSServiceRoleForConfig"
            },
            "attributes": {
                "creationDate": "2020-01-02T03:04:05Z",
                "mfaAuthenticated": "false"
            }
        },
        "invokedBy": "AWS Internal"
    },
    "eventTime": "2020-01-02T03:04:05Z",
    "eventSource": "s3.amazonaws.com",
    "eventName": "PutObject",
    "awsRegion": "sa-east-1",
    "sourceIPAddress": "172.18.106.247",
    "userAgent": "[AWSConfig]",
    "errorCode": "AccessDenied",
    "errorMessage": "Access Denied",
    "requestParameters": {
        "bucketName": "config-bucket-name",
        "Host": "config-bucket-name.s3.sa-east-1.amazonaws.com",
        "x-amz-acl": "bucket-owner-full-control",
        "x-amz-server-side-encryption": "AES256",
        "key": "AWSLogs/123456789012/Config/ConfigWritabilityCheckFile"
    },
    "responseElements": null,
    "additionalEventData": {
        "SignatureVersion": "SigV4",
        "CipherSuite": "ECDHE-RSA-AES128-SHA",
        "bytesTransferredIn": 0,
        "AuthenticationMethod": "AuthHeader",
        "x-amz-id-2": "16gkRe39IMQDZKnEjYtjmoE1vraYgYOAmP7VYqXrMFxk2mVbvHL5XPxUmPrk2VGRGWWGgwog86w=",
        "bytesTransferredOut": 243
    },
    "requestID": "3333333333333333",
    "eventID": "11111111-2222-3333-4444-555555555555",
    "readOnly": false,
    "resources": [
        {
            "type": "AWS::S3::Object",
            "ARN": "arn:aws:s3:::config-bucket-name/AWSLogs/123456789012/Config/ConfigWritabilityCheckFile"
        },
        {
            "accountId": "123456789012",
            "type": "AWS::S3::Bucket",
            "ARN": "arn:aws:s3:::config-bucket-name"
        }
    ],
    "eventType": "AwsApiCall",
    "managementEvent": false,
    "recipientAccountId": "123456789012",
    "vpcEndpointId": "vpce-abcdefgh"
}
```

前提としてS3バケットには以下のドキュメントに記載されているバケットポリシーを追加済みです。

**Amazon S3 バケットへの AWS Config アクセス許可の付与**
https://docs.aws.amazon.com/ja_jp/config/latest/developerguide/s3-bucket-policy.html#granting-access-in-another-account

> このアクセスポリシーにより、AWS Config は Amazon S3 バケットに設定情報を送信することを許可されます。

```BucketPolicy.json
{
    "Version": "2012-10-17",
    "Id": "AWSConfigBucketPermissionsCheck",
    "Statement": [
        {
            "Effect": "Allow",
            "Principal": {
                "Service": "config.amazonaws.com"
            },
            "Action": [
                "s3:GetBucketAcl",
                "s3:ListBucket"
            ],
            "Resource": "arn:aws:s3:::config-bucket-name"
        },
        {
            "Effect": "Allow",
            "Principal": {
                "Service": "config.amazonaws.com"
            },
            "Action": "s3:PutObject",
            "Resource": "arn:aws:s3:::config-bucket-name/AWSLogs/123456789012/Config/*",
            "Condition": {
                "StringEquals": {
                    "s3:x-amz-acl": "bucket-owner-full-control"
                }
            }
        }
    ]
}
```

## 原因
以下のドキュメント内に原因と思われる動作が記載されていました。

**IAM ロール使用時に Amazon S3 バケットに必要なアクセス許可**
https://docs.aws.amazon.com/ja_jp/config/latest/developerguide/s3-bucket-policy.html#required-permissions-in-another-account

> AWS Config では、アカウントの Amazon S3 バケットに設定情報 (履歴ファイルやスナップショット) を送信する場合、AWS Config の設定時に割り当てた IAM ロールを引き受けます。AWS Config では、別のアカウントの Amazon S3 バケットに設定情報を送信する場合、最初に IAM ロールの使用を試行します。ただし、バケットのアクセスポリシーが IAM ロールへの WRITE アクセス許可を付与しない場合、この試行は失敗します。この場合、AWS Config は再度情報を送信しますが、今回は AWS Config サービスプリンシパルとして送信します。

前述のバケットポリシーでは AWS ConfigをサービスプリンシバルとしたWRITE許可のみが記載されています。
Service-Linked Roles（AWSServiceRoleForConfig）は特定のバケットへのWRITE許可を持ちませんので
当然ながら上述されている 最初のIAMロールの試行 では AccessDenied となります。

## 対処法
Config用のS3バケットに以下のようなバケットポリシーを追記し
IAM ロールへ WRITE アクセスを許可します。
バケット名やアカウントIDの箇所は読み替えてください。

```AddBucketPolicy.json
        {
            "Effect": "Allow",
            "Principal": {
                "AWS": [
                    "arn:aws:iam::123456789012:role/aws-service-role/config.amazonaws.com/AWSServiceRoleForConfig",
                    "arn:aws:sts::123456789012:assumed-role/AWSServiceRoleForConfig/AWSConfig-BucketConfigCheck"
                ]
            },
            "Action": "s3:PutObject",
            "Resource": "arn:aws:s3:::config-bucket-name/AWSLogs/123456789012/Config/*",
            "Condition": {
                "StringEquals": {
                    "s3:x-amz-acl": "bucket-owner-full-control"
                }
            }
        }

```

## 参考: Service-Linked Role について
**サービスにリンクされたロールの使用**
https://docs.aws.amazon.com/ja_jp/IAM/latest/UserGuide/using-service-linked-roles.html
**AWS Config のサービスにリンクされたロールの使用**
https://docs.aws.amazon.com/ja_jp/config/latest/developerguide/using-service-linked-roles.html

以上です。
参考になれば幸いです。