駆逐してやる！！AWS Security Hubの指摘を…この世から…一匹残らず！！ ～ S3編 (CloudFormation) ～

# Security Hub の指摘、駆逐してますか？

<img width="600" alt="image.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2443303/50a8935b-a8b2-6277-a367-dd5d909ecb42.png">

* **とりあえず、Security Hub を有効化したけど、セキュリティスコアが低くて困っている…**
* **Security Hub の検出結果 (Findings) にどう対処すればよいのかわからない…**
* **S3 のセキュリティを強化したい…**

そんな方々のために、本記事では Security Hub の S3 に関する指摘事項を一匹残らず駆逐する方法を解説します。

また、解説と合わせて、Security Hub に指摘されない S3 バケットを作成するための CloudFormation テンプレートも紹介していきます。
「解説はいいから早よ CloudFormation をよこせ」という方はこちらをどうぞ。
　↓　↓　↓
[**CloudFormation を捧げよ！**](#cloudformation-を捧げよ)

:::note info
本記事は [駆逐してやる！！AWS Security Hubの指摘を…この世から…一匹残らず！！ ～ S3編 (CLI) ～](https://qiita.com/ozzy3/items/de20b000000f5085490b) の CloudFormation 版です。CloudFormation 以外の内容（解説等）は同じです。
:::


# AWS Security Hub とは

一言でいうと、複数のAWSサービスのセキュリティアラートを集約して一元管理するためのサービスです。

https://aws.amazon.com/jp/security-hub/

## セキュリティ標準 (Standards)

Security Hub は、**AWS のベストプラクティスや業界標準に基づいたセキュリティチェック機能** を備えています。
投稿時点 (2022/03/21) では、以下の **セキュリティ標準 (Standards)** が用意されています。

* AWS 基礎セキュリティのベストプラクティス (AWS Foundational Security Best Practices)
* CIS AWS Foundations Benchmark
* Payment Card Industry Data Security Standard (PCI DSS)


## コントロール (Controls)

セキュリティ標準に含まれる個々のチェック項目を **コントロール (Controls)** と呼びます。
例えば、AWS Foundational Security Best Practices には以下のようなコントロール (Controls) が含まれます。

* AWS Foundational Security Best Practices
  * [S3.1] S3 ブロックパブリックアクセス設定を有効にする必要があります
  * [S3.2] S3 バケットではパブリック読み取りアクセスを禁止する必要があります
  ・・・

## 検出結果 (Findings)

セキュリティチェックにより検出された結果を **検出結果 (Findings)** と呼びます。
ただし、本記事ではわかりやすくするために **指摘** と表現します。


# 駆逐してやる！！

ここからは指摘の駆逐方法を解説していきます。

:::note warn
既存バケットの設定を変更する場合、変更による影響を十分に検証してください。
投稿内容を利用したことにより生じた損害について、著者は一切の責任を負いません。
:::


## AWS Foundational Security Best Practices

AWS Foundational Security Best Practices は名前のとおり、AWS における基礎的なベストプラクティスに基づいたセキュリティ標準です。

<img width="600" alt="image.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2443303/0e5510e1-9a2a-8c54-4623-3929abc50f05.png">

https://docs.aws.amazon.com/ja_jp/securityhub/latest/userguide/securityhub-standards-fsbp.html

---


### [S3.1] S3 ブロックパブリックアクセス設定を有効にする必要があります

[[S3.1] S3 Block Public Access setting should be enabled](https://docs.aws.amazon.com/ja_jp/securityhub/latest/userguide/securityhub-standards-fsbp-controls.html#fsbp-s3-1)
重大度：中

この指摘を駆逐するには、アカウントレベルのブロックパブリックアクセス設定を有効にします。

ブロックパブリックアクセス設定には、アカウントレベルとバケットレベルの2種類の設定が存在します。
[S3.1] はアカウントレベルの設定です。バケットレベルの設定は [S3.8] が該当します。

アカウントレベルの設定は、マネジメントコンソール、または、CLI で設定します。
CloudFormation では設定できません。


#### マネジメントコンソール

以下の画面から設定します。

Amazon S3 > このアカウントのブロックパブリックアクセス設定

<img width="800" alt="image.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2443303/744b541c-489a-b644-996a-de1c7dbfbc4a.png">


#### CLI

以下のコマンドで設定します。
[s3control put-public-access-block](https://awscli.amazonaws.com/v2/documentation/api/latest/reference/s3api/put-public-access-block.html)

```shell
INPUT_YAML=$(cat << EOS
AccountId: "${AWS_ACCOUNT_ID}"
PublicAccessBlockConfiguration:
  BlockPublicAcls: true
  IgnorePublicAcls: true
  BlockPublicPolicy: true
  RestrictPublicBuckets: true
EOS
)

aws s3control put-public-access-block --cli-input-yaml "$INPUT_YAML"
```

* **${AWS_ACCOUNT_ID}** には、対象のAWSアカウントID（数字12桁）を指定してください。


#### 参考

https://docs.aws.amazon.com/AmazonS3/latest/userguide/configuring-block-public-access-account.html

https://awscli.amazonaws.com/v2/documentation/api/latest/reference/s3control/put-public-access-block.html

---

### [S3.2] S3 バケットではパブリック読み取りアクセスを禁止する必要があります

[[S3.2] S3 buckets should prohibit public read access](https://docs.aws.amazon.com/ja_jp/securityhub/latest/userguide/securityhub-standards-fsbp-controls.html#fsbp-s3-2)
重大度：重大

この指摘の駆逐方法は [S3.8] に含まれます。
以下を参照してください。

* AWS Foundational Security Best Practices
  [[S3.8] S3 ブロックパブリックアクセス設定は、バケットレベルで有効にする必要があります](#s38-s3-ブロックパブリックアクセス設定はバケットレベルで有効にする必要があります)

---

### [S3.3] S3 バケットはパブリック書き込みアクセスを禁止する必要があります

[[S3.3] S3 buckets should prohibit public write access](https://docs.aws.amazon.com/ja_jp/securityhub/latest/userguide/securityhub-standards-fsbp-controls.html#fsbp-s3-3)
重大度：重大

この指摘の駆逐方法は [S3.8] に含まれます。
以下を参照してください。

* AWS Foundational Security Best Practices
  [[S3.8] S3 ブロックパブリックアクセス設定は、バケットレベルで有効にする必要があります](#s38-s3-ブロックパブリックアクセス設定はバケットレベルで有効にする必要があります)

---

### [S3.4] S3 バケットでは、サーバー側の暗号化を有効にする必要があります

[[S3.4] S3 buckets should have server-side encryption enabled](https://docs.aws.amazon.com/ja_jp/securityhub/latest/userguide/securityhub-standards-fsbp-controls.html#fsbp-s3-4)
重大度：中

この指摘を駆逐するには、S3 バケットのサーバー側の暗号化を有効にします。

デフォルトのサーバー側の暗号化は以下の2種類から選択できます。

* S3 で管理されたキーを使用する **SSE-S3**
* KMS に保存されたキーを使用する **SSE-KMS**


#### CloudFormation

[**BucketEncryption**](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-s3-bucket.html#cfn-s3-bucket-bucketencryption) プロパティで設定します。

```yaml:SSE-S3
  Bucket:
    Type: AWS::S3::Bucket
    Properties:
      BucketEncryption:
        ServerSideEncryptionConfiguration:
          - ServerSideEncryptionByDefault:
              SSEAlgorithm: AES256
```

```yaml:SSE-KMS
  Bucket:
    Type: AWS::S3::Bucket
    Properties:
      BucketEncryption:
        ServerSideEncryptionConfiguration:
          - ServerSideEncryptionByDefault:
              SSEAlgorithm: aws:kms
              KMSMasterKeyID: !Ref EncryptionKeyId
            BucketKeyEnabled: true
```

* **EncryptionKeyId** はパラメータです。暗号化に使用する KMS Key ID を指定します。
* **BucketKeyEnabled** はオプションですが、SSE-KMS の場合は有効化することをおすすめします。バケットキーを有効化することにより、S3 から KMS へのリクエストを減らし、コストを削減することができます。

#### 参考

https://docs.aws.amazon.com/ja_jp/AmazonS3/latest/userguide/bucket-encryption.html

https://docs.aws.amazon.com/ja_jp/AmazonS3/latest/userguide/bucket-key.html

---


### [S3.5] S3 バケットは、Secure Socket Layer を使用するためのリクエストが必要です

[[S3.5] S3 buckets should require requests to use Secure Socket Layer](https://docs.aws.amazon.com/ja_jp/securityhub/latest/userguide/securityhub-standards-fsbp-controls.html#fsbp-s3-5)
重大度：中

この指摘を駆逐するには、S3 バケットに対する操作が HTTPS リクエストのみを受け入れる（HTTP リクエストは拒否する）ように設定します。

#### CloudFormation

バケットポリシーに以下のステートメントを追加します。
ポイントは **aws:SecureTransport** です。
aws:SecureTransport が false の場合＝ HTTPS リクエストではない場合、S3 バケットおよびオブジェクトに対するすべての操作を拒否します。

```yaml
  BucketPolicy:
    Type: AWS::S3::BucketPolicy
    Properties:
      Bucket: !Ref Bucket
      PolicyDocument:
        Version: "2012-10-17"
        Statement:
          - Sid: DenyInsecureRequests
            Effect: Deny
            Principal: "*"
            Action:
              - s3:*
            Resource:
              - !Sub arn:aws:s3:::${Bucket}
              - !Sub arn:aws:s3:::${Bucket}/*
            Condition:
              Bool:
                aws:SecureTransport: false
```

#### 参考

https://aws.amazon.com/jp/premiumsupport/knowledge-center/s3-bucket-policy-for-config-rule/

---


### [S3.6] 他のユーザーに付与された Amazon S3 のアクセス許可AWSバケットポリシーのアカウントは制限する必要があります

[[S3.6] Amazon S3 permissions granted to other AWS accounts in bucket policies should be restricted](https://docs.aws.amazon.com/ja_jp/securityhub/latest/userguide/securityhub-standards-fsbp-controls.html#fsbp-s3-6)
重大度：高

この指摘は、他アカウントのユーザーやロールに対して、以下のいずれかの操作を明示的に許可している場合に指摘されます。

* s3:DeleteBucketPolicy
* s3:PutBucketAcl
* s3:PutBucketPolicy
* s3:PutEncryptionConfiguration
* s3:PutObjectAcl

つまり、他アカウントのユーザーやロールに対して、これらの操作を明示的に許可していなければ、指摘されることはありません。

なお、他アカウントのユーザーやロールに対する **明示的な拒否** を設定しておくと、意図せずに許可してしまうことを防ぐことができます。

#### CloudFormation

バケットポリシーに以下のステートメントを追加します。
ポイントは **NotPrincipal** です。
NotPrincipal に自アカウントIDを指定することにより、自アカウント以外＝他アカウントに対する明示的な拒否を設定しています。

```yaml
  BucketPolicy:
    Type: AWS::S3::BucketPolicy
    Properties:
      Bucket: !Ref Bucket
      PolicyDocument:
        Version: "2012-10-17"
        Statement:
          - Sid: DenySensitiveActionsFromOtherAccounts
            Effect: Deny
            NotPrincipal:
              AWS: !Ref AWS::AccountId
            Action:
              - s3:DeleteBucketPolicy
              - s3:PutBucketAcl
              - s3:PutBucketPolicy
              - s3:PutEncryptionConfiguration
              - s3:PutObjectAcl
            Resource:
              - !Sub arn:aws:s3:::${Bucket}
              - !Sub arn:aws:s3:::${Bucket}/*
```

#### 参考

https://aws.amazon.com/jp/premiumsupport/knowledge-center/explicit-deny-principal-elements-s3/

---


### [S3.7] （欠番）

[S3.7] は存在しません。欠番のようです。

---


### [S3.8] S3 ブロックパブリックアクセス設定は、バケットレベルで有効にする必要があります

[[S3.8] S3 Block Public Access setting should be enabled at the bucket level](https://docs.aws.amazon.com/ja_jp/securityhub/latest/userguide/securityhub-standards-fsbp-controls.html#fsbp-s3-8)
重大度：高

この指摘を駆逐するには、バケットレベルのブロックパブリックアクセス設定を有効にします。

「[[S3.1] S3 ブロックパブリックアクセス設定を有効にする必要があります](#s31-s3-ブロックパブリックアクセス設定を有効にする必要があります)」は、アカウントレベルの設定でしたが、こちらはバケットレベルの設定です。
アカウントレベルで設定していても、Security Hub はバケットレベルの設定も要求してきます。

#### CloudFormation

[**PublicAccessBlockConfiguration**](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-s3-bucket.html#cfn-s3-bucket-publicaccessblockconfiguration) プロパティで設定します。

```yaml
  Bucket:
    Type: AWS::S3::Bucket
    Properties:
      PublicAccessBlockConfiguration:
        BlockPublicAcls: true
        BlockPublicPolicy: true
        IgnorePublicAcls: true
        RestrictPublicBuckets: true
```

#### 参考

https://docs.aws.amazon.com/ja_jp/AmazonS3/latest/userguide/access-control-block-public-access.html

---


### [S3.9] S3 バケットサーバーアクセスログを有効にする必要があります

[[S3.9] S3 bucket server access logging should be enabled](https://docs.aws.amazon.com/ja_jp/securityhub/latest/userguide/securityhub-standards-fsbp-controls.html#fsbp-s3-9)
重大度：中

この指摘を駆逐するには、S3 バケットに対するアクセスログを有効にします。

**ただし、アクセスログ保存用バケット自体のロギング設定は留意する必要があります。**
以下のとおり、ソースバケット（ロギング対象）とターゲットバケット（ログ保存先）が同じ場合、いくつかの留意事項があるため、アクセスログ保存用バケット自体のロギングは設定しない判断が好ましいケースもあります。
この場合、アクセスログ保存用バケットに対する [S3.9] の指摘は抑制するのがよいでしょう。

> ソースバケットとターゲットバケットが同じである場合、バケットに書き込まれるログに関する追加のログが作成されます。これは、ストレージの請求額がいくらか増える可能性があるため、望ましくない場合があります。また、ログに関する追加のログのために、必要なログを見つけにくくなります。

引用：https://docs.aws.amazon.com/ja_jp/AmazonS3/latest/userguide/ServerLogs.html



#### CloudFormation

[**LoggingConfiguration**](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-s3-bucket.html#cfn-s3-bucket-loggingconfig) プロパティで設定します。

```yaml
  Bucket:
    Type: AWS::S3::Bucket
    Properties:
      LoggingConfiguration:
        DestinationBucketName: !Ref LoggingBucketName
        LogFilePrefix: !Ref BucketName
```

* **LoggingBucketName** はパラメータです。ログ保存先のバケット名を指定します。
* **LogFilePrefix** の指定はオプションですが、複数バケットのアクセスログをひとつのバケットに集約する際に、どのバケットのアクセスログかを判別できるよう、バケット名をプレフィックスとして設定することをおすすめします。

#### 参考

https://docs.aws.amazon.com/ja_jp/AmazonS3/latest/userguide/ServerLogs.html

---


## CIS AWS Foundations Benchmark

CIS AWS Foundations Benchmark は CIS (Center of Internet Security) のベンチマークに基づいたセキュリティ標準です。

<img width="600" alt="image.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2443303/af2561c0-2367-bfbc-cfe1-0be7104c1a81.png">

https://docs.aws.amazon.com/ja_jp/securityhub/latest/userguide/securityhub-standards-cis.html

https://www.cisecurity.org/benchmark/amazon_web_services


---


### 2.3 — CloudTrail ログが記録する S3 バケットがパブリックにアクセスできないことを確認します

[2.3 – Ensure the S3 bucket CloudTrail logs to is not publicly accessible](https://docs.aws.amazon.com/ja_jp/securityhub/latest/userguide/securityhub-cis-controls.html#securityhub-cis-controls-2.3)
重大度：重大

この指摘を駆逐するには、CloudTrail ログバケットに対して、ブロックパブリックアクセスを設定します。

ブロックパブリックアクセスの設定方法は、以下を参照してください。

* AWS Foundational Security Best Practices
  [[S3.8] S3 ブロックパブリックアクセス設定は、バケットレベルで有効にする必要があります](#s38-s3-ブロックパブリックアクセス設定はバケットレベルで有効にする必要があります)

---


### 2.6 — CloudTrail S3 バケットアクセスログ記録が CloudTrail S3 バケットで有効になっていることを確認します

[2.6 – Ensure S3 bucket access logging is enabled on the CloudTrail S3 bucket](https://docs.aws.amazon.com/ja_jp/securityhub/latest/userguide/securityhub-cis-controls.html#securityhub-cis-controls-2.6)
重大度：低

この指摘を駆逐するには、CloudTrail ログバケットに対して、アクセスログ記録を設定します。

アクセスログ記録の設定方法は、以下を参照してください。

* AWS Foundational Security Best Practices
  [[S3.9] S3 バケットサーバーアクセスログを有効にする必要があります](#s39-s3-バケットサーバーアクセスログを有効にする必要があります)

---


## Payment Card Industry Data Security Standard (PCI DSS)

Payment Card Industry Data Security Standard (PCI DSS) は、クレジットカード業界のセキュリティ標準です。

<img width="600" alt="image.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2443303/04b035d8-6145-ee3b-a9f5-2861cb539e2d.png">

<!--
<img width="600" alt="image.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2443303/ee58afc4-bac1-a913-bf55-97df5ac8d9f8.png">
-->

https://docs.aws.amazon.com/ja_jp/securityhub/latest/userguide/securityhub-standards-pcidss.html

https://www.jcdsc.org/pci_dss.php

---


### [PCI.S3.1] S3 バケットはパブリック書き込みアクセスを禁止する必要があります

[[PCI.S3.1] S3 buckets should prohibit public write access](https://docs.aws.amazon.com/ja_jp/securityhub/latest/userguide/securityhub-pci-controls.html#pcidss-s3-1)
重大度：重大

以下の指摘と同様です。

* AWS Foundational Security Best Practices
  [[S3.3] S3 バケットはパブリック書き込みアクセスを禁止する必要があります](#s33-s3-バケットはパブリック書き込みアクセスを禁止する必要があります)
    * 駆逐方法
      [[S3.8] S3 ブロックパブリックアクセス設定は、バケットレベルで有効にする必要があります](#s38-s3-ブロックパブリックアクセス設定はバケットレベルで有効にする必要があります)

---


### [PCI.S3.2] S3 バケットではパブリック読み取りアクセスを禁止する必要があります

[[PCI.S3.2] S3 buckets should prohibit public read access](https://docs.aws.amazon.com/ja_jp/securityhub/latest/userguide/securityhub-pci-controls.html#pcidss-s3-2)
重大度：重大

以下の指摘と同様です。

* AWS Foundational Security Best Practices
  [[S3.2] S3 バケットではパブリック読み取りアクセスを禁止する必要があります](#s32-s3-バケットではパブリック読み取りアクセスを禁止する必要があります)
    * 駆逐方法
      [[S3.8] S3 ブロックパブリックアクセス設定は、バケットレベルで有効にする必要があります](#s38-s3-ブロックパブリックアクセス設定はバケットレベルで有効にする必要があります)

---


### [PCI.S3.3] S3 バケットでクロスリージョンレプリケーションを有効にする必要があります

[[PCI.S3.3] S3 buckets should have cross-region replication enabled](https://docs.aws.amazon.com/ja_jp/securityhub/latest/userguide/securityhub-pci-controls.html#pcidss-s3-3)
重大度：低

この指摘を駆逐するには、S3 バケットのクロスリージョンレプリケーションを有効にします。

なお、レプリケーションを有効にするには、予めレプリケート元とレプリケート先の両方のバケットで、バージョニングを有効にしておく必要があります。

#### CloudFormation

クロスリージョンレプリケーションを設定するにあたり、レプリケーション用の IAM Role が必要になります。
クロスリージョンレプリケーションの設定は [**ReplicationConfiguration**](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-s3-bucket.html#cfn-s3-bucket-replicationconfiguration) プロパティで設定します。

```yaml
  ReplicationPolicy:
    Type: AWS::IAM::ManagedPolicy
    Properties:
      PolicyDocument:
        Version: "2012-10-17"
        Statement:
          - Sid: AllowSourceBucketAccess
            Effect: Allow
            Action:
              - s3:GetReplicationConfiguration
              - s3:ListBucket
            Resource:
              - !Sub arn:aws:s3:::${BucketName}
          - Sid: AllowSourceObjectAccess
            Effect: Allow
            Action:
              - s3:GetObjectVersionForReplication
              - s3:GetObjectVersionAcl
              - s3:GetObjectVersionTagging
            Resource:
              - !Sub arn:aws:s3:::${BucketName}/*
          - Sid: AllowDestinationObjectAccess
            Effect: Allow
            Action:
              - s3:ReplicateObject
              - s3:ReplicateDelete
              - s3:ReplicateTags
            Resource:
              - !Sub arn:aws:s3:::${ReplicationBucketName}/*

  ReplicationRole:
    Type: AWS::IAM::Role
    Properties:
      AssumeRolePolicyDocument:
        Version: "2012-10-17"
        Statement:
          - Effect: Allow
            Principal:
              Service:
                - s3.amazonaws.com
            Action:
              - sts:AssumeRole
      ManagedPolicyArns:
        - !Ref ReplicationPolicy

  Bucket:
    Type: AWS::S3::Bucket
    Properties:
      ReplicationConfiguration:
        Role: !GetAtt ReplicationRole.Arn
        Rules:
          - Status: Enabled
            Destination:
              Bucket: !Sub arn:aws:s3:::${ReplicationBucketName}
```

* **BucketName** はパラメータです。作成するバケット名を指定します。
* **ReplicationBucketName** はパラメータです。レプリケーション先のバケット名を指定します。

:::note warn
ここではクロスリージョンレプリケーションを実現する上で最低限の設定を掲載しています。[ReplicationConfiguration](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-s3-bucket.html#cfn-s3-bucket-replicationconfiguration)プロパティの設定は多岐に渡りますので、ユースケースに応じて適宜設定を見直してください。
:::

#### 参考

https://docs.aws.amazon.com/ja_jp/AmazonS3/latest/userguide/replication.html

---


### [PCI.S3.4] S3 バケットでは、サーバー側の暗号化を有効にする必要があります

[[PCI.S3.4] S3 buckets should have server-side encryption enabled](https://docs.aws.amazon.com/ja_jp/securityhub/latest/userguide/securityhub-pci-controls.html#pcidss-s3-4)
重大度：中

以下の指摘と同様です。

* AWS Foundational Security Best Practices
  [[S3.4] S3 バケットでは、サーバー側の暗号化を有効にする必要があります](#s34-s3-バケットではサーバー側の暗号化を有効にする必要があります)

---


### [PCI.S3.5] S3 バケットは、Secure Socket Layer を使用するリクエストを要求する必要があります

[[PCI.S3.5] S3 buckets should require requests to use Secure Socket Layer](https://docs.aws.amazon.com/ja_jp/securityhub/latest/userguide/securityhub-pci-controls.html#pcidss-s3-5)
重大度：中

以下の指摘と同様です。

* AWS Foundational Security Best Practices
  [[S3.5] S3 バケットは、Secure Socket Layer を使用するためのリクエストが必要です](#s35-s3-バケットはsecure-socket-layer-を使用するためのリクエストが必要です)

---


### [PCI.S3.6] S3 ブロックパブリックアクセス設定を有効にする必要があります

[[PCI.S3.6] S3 Block Public Access setting should be enabled](https://docs.aws.amazon.com/ja_jp/securityhub/latest/userguide/securityhub-pci-controls.html#pcidss-s3-6)
重大度：中

以下の指摘と同様です。

* AWS Foundational Security Best Practices
  [[S3.1] S3 ブロックパブリックアクセス設定を有効にする必要があります](#s31-s3-ブロックパブリックアクセス設定を有効にする必要があります)

---


# Security Hub 指摘以外でやるべき設定

ここからは Security Hub では指摘されませんが、やっておくことを推奨する設定を紹介します。

---


## ACL無効化

ACL (Access Control List) の無効化は AWS re:Invent 2021 で発表された機能です。
AWS も無効化を推奨しています。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2443303/47b688cd-c8aa-8d0d-33ff-cf5d7c373e1d.png)

### CloudFormation

[**OwnershipControls**](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-s3-bucket.html#cfn-s3-bucket-ownershipcontrols) プロパティで設定します。
ObjectOwnership の値に **BucketOwnerEnforced** を設定することにより、ACL が無効化されます。

```yaml
  Bucket:
    Type: AWS::S3::Bucket
    Properties:
      OwnershipControls:
        Rules:
          - ObjectOwnership: BucketOwnerEnforced
```

### 参考

https://aws.amazon.com/jp/about-aws/whats-new/2021/11/amazon-s3-object-ownership-simplify-access-management-data-s3/

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

---


## バージョニング

S3 バケットのバージョニングを有効にすると、オブジェクトを誤って削除したり上書きしてしまっても、復元することができます。
ただし、複数のバージョンを保持する分、ストレージコストは増加するので、その点は理解した上で使用しましょう。

### CloudFormation

[**VersioningConfiguration**](https://docs.aws.amazon.com/ja_jp/AWSCloudFormation/latest/UserGuide/aws-properties-s3-bucket.html#cfn-s3-bucket-versioning) プロパティで設定します。

```yaml
  Bucket:
    Type: AWS::S3::Bucket
    Properties:
      VersioningConfiguration:
        Status: Enabled
```

### 参考

https://docs.aws.amazon.com/ja_jp/AmazonS3/latest/userguide/Versioning.html

---


## S3 のセキュリティベストプラクティス

ベストプラクティスは読んでおきましょう。

https://docs.aws.amazon.com/ja_jp/AmazonS3/latest/userguide/security-best-practices.html

---


# CloudFormation を捧げよ！

ここまで解説してきた内容をすべて含めた CloudFormation テンプレートがこちらです。
必ずしも、すべての設定が必要とは限らないので、ユースケースに応じて適宜見直してください。

```yaml:secure_s3_bucket.yaml
#===============================================================================
# CloudFormation Template
#===============================================================================
AWSTemplateFormatVersion: "2010-09-09"
Description: Secure S3 Bucket

#===============================================================================
# Metadata
#===============================================================================
Metadata:
  AWS::CloudFormation::Interface:
    ParameterGroups:
      - Label:
          default: Parameters
        Parameters:
          - BucketName
          - LoggingBucketName
          - ReplicationBucketName
          - EncryptionKeyId

#===============================================================================
# Parameters
#===============================================================================
Parameters:
  BucketName:
    Type: String

  LoggingBucketName:
    Type: String

  ReplicationBucketName:
    Type: String

  EncryptionKeyId:
    Type: String

#===============================================================================
# Resources
#===============================================================================
Resources:
  #-----------------------------------------------------------
  # S3
  #-----------------------------------------------------------
  Bucket:
    Type: AWS::S3::Bucket
    Properties:
      BucketName: !Ref BucketName
      PublicAccessBlockConfiguration:
        BlockPublicAcls: true
        BlockPublicPolicy: true
        IgnorePublicAcls: true
        RestrictPublicBuckets: true
      BucketEncryption:
        ServerSideEncryptionConfiguration:
          - ServerSideEncryptionByDefault:
              SSEAlgorithm: aws:kms
              KMSMasterKeyID: !Ref EncryptionKeyId
            BucketKeyEnabled: true
      LoggingConfiguration:
        DestinationBucketName: !Ref LoggingBucketName
        LogFilePrefix: !Ref BucketName
      VersioningConfiguration:
        Status: Enabled
      ReplicationConfiguration:
        Role: !GetAtt ReplicationRole.Arn
        Rules:
          - Status: Enabled
            Destination:
              Bucket: !Sub arn:aws:s3:::${ReplicationBucketName}
      OwnershipControls:
        Rules:
          - ObjectOwnership: BucketOwnerEnforced

  BucketPolicy:
    Type: AWS::S3::BucketPolicy
    Properties:
      Bucket: !Ref Bucket
      PolicyDocument:
        Version: "2012-10-17"
        Statement:
          - Sid: DenyInsecureRequests
            Effect: Deny
            Principal: "*"
            Action:
              - s3:*
            Resource:
              - !Sub arn:aws:s3:::${Bucket}
              - !Sub arn:aws:s3:::${Bucket}/*
            Condition:
              Bool:
                aws:SecureTransport: false
          - Sid: DenySensitiveActionsFromOtherAccounts
            Effect: Deny
            NotPrincipal:
              AWS: !Ref AWS::AccountId
            Action:
              - s3:DeleteBucketPolicy
              - s3:PutBucketAcl
              - s3:PutBucketPolicy
              - s3:PutEncryptionConfiguration
              - s3:PutObjectAcl
            Resource:
              - !Sub arn:aws:s3:::${Bucket}
              - !Sub arn:aws:s3:::${Bucket}/*

#===============================================================================
# Outputs
#===============================================================================
Outputs:
  BucketName:
    Value: !Ref Bucket

  BucketArn:
    Value: !GetAtt Bucket.Arn
```

---


# CLI を捧げよ！

CLI 版はこちらをご参照ください。
　↓　↓　↓

https://qiita.com/ozzy3/items/de20b000000f5085490b

---


# あとがき

最後まで読んでいただき、ありがとうございます。
本記事によって一匹でも多くの Security Hub 指摘を駆逐できれば幸いです。

本記事が好評でしたら、S3 以外の続編も書いていこうと思います。