【AWS CF】「バケットは ObjectOwnership の BucketOwnerEnforced 設定で ACL を設定できません」エラーの原因と解決方法

# 概要
今まで使っていたCloudFormationテンプレートを利用したら、`Bucket cannot have ACLs set with　ObjectOwnership's BucketOwnerEnforced setting`というエラーになり失敗しました。本記事ではその原因と解決方法を記載します。


# エラー内容:

以下がエラー内容です。

```
Bucket cannot have ACLs set with ObjectOwnership's BucketOwnerEnforced setting (Service: Amazon S3; Status Code: 400; Error Code: InvalidBucketAclWithObjectOwnership; Request ID: XXXXXXXXXX; S3 Extended Request ID: XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX=; Proxy: null)
```

S3のオブジェクト所有者(`ObjectOwnership`)を「バケット所有者の強制」(`BucketOwnerEnforced`)の設定にしている状態で、BucketにACLを設定することはできない、というのがエラー内容です。

あれ、「バケット所有者の強制」の設定なんかしていないんだけどなぁ〜
って思ったら、4/28から`ObjectOwnership`はデフォルトで「バケット所有者の強制」になっているとのこと!

[Amazon S3 が新規バケットすべてに 2 つのセキュリティベストプラクティスをデフォルトで適用開始](https://aws.amazon.com/jp/about-aws/whats-new/2023/04/amazon-s3-security-best-practices-buckets-default/)

このデフォルトの設定ではACLはオフになるらしいです。
そのため、「バケット所有者の強制」なのに「ACL有効」なんて、そんなのは無理だよ！って怒られます。



# 解決方法

以下はAWSのrePost記事です。この通りに実施すると解決します。

[CloudFormationの「バケットは ObjectOwnership の BucketOwnerEnforced 設定で ACL を設定できません」というエラーを修正する方法を教えてください。](https://repost.aws/ja/knowledge-center/cloudformation-objectownership-acl-error)

つまり、所有者に明示的に「`ObjectWriter`」を追加すればOKです。
これによりデフォルトの「バケット所有者の強制」ではなく「オブジェクトライター」になるので、ACLを呼び出してもエラーになりません。

### 変更前
```yaml
  BucketLog:
    Type: AWS::S3::Bucket
    Properties:
      AccessControl: LogDeliveryWrite
      BucketEncryption:
        ServerSideEncryptionConfiguration:
          - ServerSideEncryptionByDefault:
              SSEAlgorithm: aws:kms
```

### 変更後

```yaml
  BucketLog:
    Type: AWS::S3::Bucket
    Properties:
      AccessControl: LogDeliveryWrite
      OwnershipControls:　 #追加
        Rules:　 #追加
          - ObjectOwnership: ObjectWriter　 #追加
      BucketEncryption:
        ServerSideEncryptionConfiguration:
          - ServerSideEncryptionByDefault:
              SSEAlgorithm: aws:kms
```

# サンプルYAML比較
以下、
・2023/4以前に作成したS3 BucketFileとLog
および
・2023/8に作成したS3 BucketFileとLog
のYAMLとマネジメントコンソール画面を記します。

## S3 Bucket Fileの比較(ACLに`Private`設定したFileの場合)

### 1: 2023/4以前に作成したS3 BucketFile

```yaml
  BucketFile:
    Type: AWS::S3::Bucket
    DeletionPolicy: Retain
    Properties:
      AccessControl: Private
      LoggingConfiguration:
        DestinationBucketName: !Sub ${EnvTag}-${SysTag}-${BucketNameLog}
        LogFilePrefix: !Sub ${BucketNameFile}/
      BucketEncryption:
        ServerSideEncryptionConfiguration:
          - ServerSideEncryptionByDefault:
              SSEAlgorithm: aws:kms
```

↓↓↓

・マネコンから確認

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2710373/40cad038-1b2e-3795-7618-f2fd62c816ee.png)

→2023/4前のものなので、デフォルトでオブジェクト所有者が「オブジェクトライター」になっていることがわかります=ACL は有効とあり


### 2: 2023/8に作成したS3 BucketFile

```yaml
  BucketFile:
    Type: AWS::S3::Bucket
  #  DeletionPolicy: Retain
    Properties:
      AccessControl: Private
      LoggingConfiguration:
        DestinationBucketName: !Sub ${SysTag}-${BucketNameLog}
        LogFilePrefix: !Sub ${BucketNameFile}/
      BucketEncryption:
        ServerSideEncryptionConfiguration:
          - ServerSideEncryptionByDefault:
              SSEAlgorithm: aws:kms
```

↓↓↓

・マネコンから確認
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2710373/9bf513ab-a1d6-9937-3ce5-50227fbaa269.png)

→2023/8なので、デフォルトでオブジェクト所有者が「バケット所有者の強制」になっていることがわかります=ACL は無効とあり
`Private`に設定した場合は、ACLが無効な状態と実質同じとなり(=オブジェクトへのアクセスはバケット所有者に制限されるため)、上述のエラーは発生しません。

「バケット所有者の強制が適用される場合は、バケットポリシーを使用してアクセスを制御」します。つまり、ACLはS3バケット内のデータへのアクセス許可に影響を与えなくなったということ。デフォルトで無効になっている理由がわかりますね。

コンソールから見ても「ACL無効」→「バケット所有者の強制」ということがわかります

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2710373/bffe1d52-7809-34ec-edea-642797927a75.png)

## S3 BucketLogの比較(ACLに`LogDeliveryWrite`を設定したLogの場合)

### 3: 2023/4以前に作成したS3 BucketLog

```yaml
  BucketLog:
    Type: AWS::S3::Bucket
    DeletionPolicy: Retain
    Properties:
      AccessControl: LogDeliveryWrite
      BucketEncryption:
        ServerSideEncryptionConfiguration:
          - ServerSideEncryptionByDefault:
              SSEAlgorithm: aws:kms
```

↓↓↓
・マネコンから確認

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2710373/19ff64d1-b0d4-3e96-ea3a-af3109548a40.png)

→２023/4以前なので、デフォルトでオブジェクト所有者が「オブジェクトライター」になっていることがわかります=ACL は有効とあり

ちなみに、`LogDeliveryWrite`は、アクセスログのために作られる外部ユーザー(`awslogsdelivery`)にバケットへのREAD/WRITEアクセス権限を付与する設定です。


### 4: 2023/8に作成したS3 BucketLog

```yaml
  BucketLog:
    Type: AWS::S3::Bucket
  #  DeletionPolicy: Retain
    Properties:
      AccessControl: LogDeliveryWrite
      OwnershipControls:
        Rules:
          - ObjectOwnership: ObjectWriter
      BucketEncryption:
        ServerSideEncryptionConfiguration:
          - ServerSideEncryptionByDefault:
              SSEAlgorithm: aws:kms
```

↓↓↓

・マネコンから確認

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2710373/82009169-c326-cf9b-acaf-78e0e29149ed.png)

→2023/8作成。`ObjectWriter`を指定してあげれば、オブジェクト所有者が「オブジェクトライター」になっていることがわかります=ACL は有効とあり
逆に、ここで`ObjectOwnership`に何も設定しないと、デフォルトのままとなり、上述のエラーが発生してしまいます。

ちなみに、ACLを有効にしたい場合、`ObjectOwnership`には以下の2種類があります。

- 「希望するバケット所有者」 
- 「オブジェクトライター」

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2710373/e407b1a9-f27e-4aac-49f0-18b27087890d.png)

上記のテンプレート例ではいずれも「オブジェクトライター」を選んでいますが、「希望するバケット所有者」 もあります。