【AWS】Amazon S3 のセキュリティに関するベストプラクティスを実践してみた【S3】

## はじめに
AWSを使用してシステムを構築するときにはベストプラクティスというものを意識してその構成を検討する必要があります。プロジェクトの特性やチームの成熟度、あるいは費用対効果など様々な要因を考慮するとベストプラクティスに当てはめることが必ずしも正解ではないですが、AWSの推奨事項がどのようなものであるかを知ることはシステムのあるべき姿を決める際のガイドラインとして有用です。
今回の記事ではベストプラクティスの中でもAmazonS3のベストプラクティスのページで紹介されているS3のセキュリティ関連のベストプラクティスの中から比較的すぐに実施できる設定手順を実際のAWSコンソールでの設定画面のキャプチャをつけて解説します。
##### 参考：Amazon S3 のセキュリティのベストプラクティス
https://docs.aws.amazon.com/ja_jp/AmazonS3/latest/userguide/security-best-practices.html

【この記事で紹介する内容】
①意図しない情報の公開を防ぐ
→バケットポリシー、ブロックパブリックアクセス
②データの改ざんや意図しない削除を防止する
→バージョニング、オブジェクトロック
③データアクセスなどのS3のモニタリングをする
→S3サーバーログ、CloudTrail
## 1．意図しない情報の公開を防ぐ
### ブロックパブリックアクセス
:::note info
ブロックパブリックアクセスの必要性
・パブリックアクセス可能な状態(インターネット経由で任意のユーザがアクセスできる状態)になっているとS3内の情報の漏洩や改ざんが行われる可能性があります
:::

#### 設定方法
・パブリックアクセスのブロックはバケットポリシーでも設定できますが、「アクセス許可」タブのパブリックアクセス設定から設定可能です
![パブリックアクセスブロック設定.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/192949/03d84fb4-e806-937d-24bf-79c587ef36fc.png)
・設定するとブラウザから直接S3オブジェクトのURLを指定してもアクセス拒否されることを確認できます
![パブリックアクセス失敗.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/192949/b9bf7ff0-5603-df2c-1e76-04c10290cec2.png)

***

### バケットポリシー
:::note info
バケットポリシーの必要性
・リソースにアクセス可能なユーザが複数人いる場合、適切ではないユーザの操作はブロックしなければ意図しないデータの削除や不正な更新が加わることがあります。
・バケットポリシーを利用して「適切なユーザ」のみが「適切なリソース」にアクセスできるようにアクセス範囲を定義することが必要です

:::
#### 設定方法
・バケットポリシーも「アクセス許可」タブからJson形式で設定内容を記述して設定します
(バケットポリシー設定例)
特定のタグキーと値を持つオブジェクトの読み取り権限のみをユーザーに許可する
参考：

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

##### 設定例
```json
{
   "Version":"2012-10-17",
   "Statement":[
      {
         "Principal":{
            "AWS":"arn:aws:iam::111122223333:role/JohnDoe"
         },
         "Effect":"Allow",
         "Action":[
            "s3:GetObject",
            "s3:GetObjectVersion"
         ],
         "Resource":"arn:aws:s3:::DOC-EXAMPLE-BUCKET/*",
         "Condition":{
            "StringEquals":{
               "s3:ExistingObjectTag/environment":"production"
            }
         }
      }
   ]
}
```
##### 設定内容
・設定内容は以下の内容を設定します

|設定項目  |設定内容  |設定例
|---|---|---|
|Principal  |アクセス権を持つIAMユーザーやロールを指定します  |* (絞らない時の指定)  |
|Effect  |設定した条件で許可(Allow)するか拒否(Deny) するかを設定します |Allow or Deny |
|Action  |許可または拒否されるアクションを指定します。複数指定したいときは配列の形で指定します  |s3:GetObject  |
|Resource  |アクセス権を設定する対象のS3リソースを指定します  |S3バケットとプレフィックスのARN  |
|Condition  |アクセスするユーザやリソースの条件の詳細を設定します。特定のIPからのアクセスのみ許可するときなどに指定します。  |"IpAddress": {"aws:SourceIp": "IPアドレス"}  |

***
**★補足：バケットポリシー設定**
＜Action(制御 (Allow or Deny) される操作)＞
|値  |説明
|---|---|
|s3:GetObject  |オブジェクトの読み取りする操作 |
|s3:PutObject  |オブジェクトの書き込み（アップロード）する操作 |
|s3:ListBucket  |バケット内のオブジェクト一覧を取得する操作 |
|s3:PutBucketPolicy  |バケットポリシーを設定する操作 |
|s3:GetBucketPolicy  |バケットポリシーを取得する操作 |
|s3:DeleteBucketPolicy  |バケットポリシーを削除する操作 |
|s3:ReplicateObject  |オブジェクトの複製をする操作（S3のクロスリージョンレプリケーション用） |
|s3:ReplicateDelete  |クロスリージョンレプリケーションでオブジェクトの削除する操作 |

＜Condition(制御条件)＞
**書式**
```json
"キー(外側)" { "キー(内側)": "値"}
```
|キー(外側)  |キー(内側) |値例|意味
|---|---|---|---|
|IpAddress|aws:SourceIp|IPアドレス|指定したIPアドレスからの操作を制御する|
|NotIpAddress|aws:SourceIp|IPアドレス|指定したIPアドレス以外からの操作を制御する|
|DateGreaterThan|aws:CurrentTime|2020-04-01T00:00:00Z|特定の日付より後に発生したリクエストを制御する|
|DateLessThan|aws:CurrentTime|2020-04-01T00:00:00Z|特定の日付より前にリクエストがあった場合にのみアクセスを制御する|

※より詳しくはこちらへ
##### 参考：IAM JSON ポリシー要素: 条件演算子
https://docs.aws.amazon.com/ja_jp/IAM/latest/UserGuide/reference_policies_elements_condition_operators.html


**★補足：バケットポリシーとIAMユーザポリシーの違いは？**
・バケットポリシーと似たものにIAMMユーザポリシーがあります。これもAWSリソースに対する操作を制御するときに使うもので混乱しやすいです。
・簡単に違いをここでまとめました
##### IAMユーザポリシー
・**ユーザ単位**にそのユーザはAWSで何ができるかを定義する
・Json形式で定義する
##### バケットポリシー
・**S3バケット単位**にS3リソースに対して誰がアクセスできるかを定義する
・Json形式で定義する

:::note info
IAMユーザポリシーとバケットポリシーで許可/拒否の相反する設定の場合どうなる？(同一アカウントの場合)
・Effectが一方は許可(Allow)、もう一方が拒否(Deny)の場合、そのリソースへのアクセスは拒否される(安全側の判定になる）
・一方が許可で、もう一方にそのリソースへの定義がない場合、そのリソースへのアクセスは許可される
:::

:::note warn
マルチアカウント環境で別アカウントのS3リソースにアクセスするときはどうなる？
・両方に許可設定が必要(一方のアカウント(A)が持つS3のバケットポリシーにもう一方のアカウント(B)のアクセス許可設定をし、アカウントBのIAMポリシーでアカウントAのリソースにアクセスする許可設定が必要
※バケットごとに許可を設定するのは大変なのでアカウントAにアカウントB用のロールを作成しておき、そのロールに対してアカウントA,Bで許可設定をすると管理が簡潔になる(**AssumeRole**)
:::

***

### 送信時のデータの暗号化を強制する

:::note info
データの暗号化の必要性
・データの通信内容が平文のままやり取りされてしまうと通信内容を盗聴されてしまった際に内容が漏洩してしまいます。内容の漏洩を防ぐために送信時のデータの暗号化が必要になります。
:::

#### 設定方法
・このバケットポリシーで「**aws:SecureTransport**」条件を使用して、HTTPS (TLS) 経由での暗号化された接続のみを許可することで送信時のデータの暗号化を強制する(ネットワークトラフィックを盗聴または操作することを防止)することができます
(設定例)
・Actionを「Deny(拒否)」で設定し、ConditionでSecureTransportを「false」に指定しているので、「HTTPS(TLS)以外でs3:GetObjectしようとする操作を拒否する」という設定になっています
```json
{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Effect": "Deny",
            "Principal": "*",
            "Action": "s3:GetObject",
            "Resource": "arn:aws:s3:::bucket-name/*",
            "Condition": {
                "Bool": {
                    "aws:SecureTransport": "false"
                }
            }
        }
    ]
}
```

### 保管時のデータ暗号化
・S3は、サーバーサイド暗号化（Server-Side Encryption）をサポートしています
・SSEを使用すると、S3がデータを自動的に暗号化し、データの保存と取得時に自動的に復号します
![S3マネージドキー.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/192949/0b266d5f-c685-f982-b880-1e8a985c05db.png)


## 2．データの改ざんや意図しない削除を防止する
### S3 バージョニングの有効化
:::note info
バージョニングの必要性
・データを意図せず削除や更新を行った際にバージョニングが無効になっているとAWS上での復旧が困難になります。
・意図しない削除や更新が発生したことを検知したときに速やかに更新前の状態に戻すためにバージョニングの設定を有効にする必要があります
:::

:::note warn
コストに関する注意ポイント
・作成されたバージョンごとのオブジェクトに対して課金が発生するため、バージョニングと合わせて適切なライフサイクル設定を行い、不要なバージョンの自動削除や適切なストレージクラスへの移動をすべきです
:::

#### 設定方法
・バージョン管理の設定はバケットの「プロパティ」タブから設定できます
![バージョン管理1.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/192949/4cd9a296-9579-07b6-f451-98c3d62c03a0.png)
・バケットのバージョニングを編集の設定画面が開くので「有効にする」を選択するとバージョニングが有効になります
![バージョン管理2.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/192949/04652525-fd0b-7421-56e4-3eb727bea998.png)

***

### ライフサイクル設定
:::note info
ライフサイクル設定の必要性
・バージョニングを行ったファイルについて、不要なバージョンが残ると不要なコスト増加につながります
・ライフサイクル設定により、必要なバージョンのファイルのみを保持し、不要なバージョンは削除するようにする必要があります
:::

#### 設定方法
・ライフサイクル設定はバケットの「管理」タブから設定できます
![ライフサイクルルール1.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/192949/d9338227-33b6-d69f-7ec2-6ae9a4de38dc.png)
・バケット内のすべてのオブジェクトに対して適用するルールとオブジェクト内の特定のフィルター条件に一致するオブジェクト(特定フォルダのCSVフォルダのみなど)に対して適用するルールを作成できます
・ライフサイクルルールのアクションではストレージクラスの移動やオブジェクトの削除等の選択ができます。不要オブジェクトを削除したい場合は「オブジェクトの非現行バージョンを完全に削除」を選択します
![ライフサイクルルール2.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/192949/39485d24-9b46-8597-de72-a8b889ccfdf2.png)
・オブジェクトを削除する場合は何日経過したものを削除するか、いくつのバージョンを保持するかを設定します
・この設定をどうするかの考え方はそのオブジェクトよって異なりますが、基本的に**更新頻度**を元に考えるとよいと思います。例えば、「**月に1回更新**されるファイル**1年間保持**したい」となれば、「日数は**365**、バージョン数は月1回更新なので**12**にする」と1年分12個のオブジェクトがバージョン管理で保持できます。
![ライフサイクルルール3.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/192949/9c51b0ac-a08b-b3df-6211-0e5ab8742684.png)
・バージョンニング設定したファイルを削除すると、削除後のオブジェクトは「バージョンの表示」をONに設定することで確認できます
・「削除マーカー」を選択して削除すると、削除されたオブジェクトを復元することが可能です
![バージョン管理されたファイルを削除.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/192949/2b5fa8d5-284a-19aa-aaaf-396e18515330.png)

***

### S3 オブジェクトロックの検討
:::note info
オブジェクトロックの必要性
・監査用のログなどどのユーザにも削除や更新を行わせたくない情報があります。これらの情報に対しオブジェクトロックは削除/上書きを⼀定期間/無期限に防⽌できるWrite Once Read Many（WORM）機能となります。
:::

#### 設定方法
・オブジェクトロックもバージョニングの設定と同じくバケットの「プロパティ」タグから設定が可能です
・デフォルトの保持期間「日」もしくは「年」の単位で指定した数値の期間オブジェクトを保護します
![オブジェクトロック.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/192949/54612f53-b8aa-ab1c-9ed0-3d56e585a96d.png)

### 補足：オブジェクトロックのレベル
#### コンプライアンスモード
・AWSアカウントの**rootユーザを含むすべてのユーザ**に保護されたオブジェクトを更新させないモード
#### ガバナンスモード
・**特別なIAMユーザポリシー**を持つユーザのみに更新を許可するモード

:::note info
リーガルホールド
・オブジェクトをアップロードする際に**LegalHold=ON**を指定するとそのオブジェクトに対して独立した保護を設定することができる。この場合、リーガルホールドの保護中にコンプライアンスモードの保護期限が切れたとしても、そのオブジェクトは保護される。
:::

## 3．データアクセスなどのS3のモニタリングをする
:::note info
モニタリングの必要性
・バケットポリシーで不正な操作を防いでもシステムの実装ミスやコンソールの操作ミスによりS3のファイルに意図せぬ変更が加わることがあり、すぐには気が付かない場合があります。
・ログの保存などモニタリングの仕組みを作ることによりだれがいつどのような操作をしたかを追うことができ、トラブル発生時の調査などが容易になります。
:::
### Amazon S3 サーバーアクセスログを有効にする
・S3バケットのサーバーアクセスログは、AWS S3でバケット内のオブジェクトへのアクセスに関する情報を記録するための仕組みです。これにより、セキュリティ、コンプライアンス、アクセスの監査などの目的でアクセスログを活用できます
・S3のサーバーアクセスログはCSV形式またはApacheログ形式で提供され、これらのログには、以下のような情報が含まれます。
→「アクセスを行ったIAMユーザーやIPアドレス」、「アクセスのタイムスタンプ」、「リクエストの種類 (GET、PUT、DELETE など)」、「応答のHTTPステータスコード」、「アクセスしたオブジェクトのキー」など
参考

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

・料金についてはサーバーアクセスログを有効にすること自体に追加料金はないですが、ログを保存するS3バケットとそこでデータを送受信する料金は発生します
参考

https://docs.aws.amazon.com/ja_jp/AmazonS3/latest/userguide/enable-server-access-logging.html
#### 設定方法
・バケットの「プロパティ」タブを選択して現れる設定項目に「サーバーアクセスログ記録」があるのでこちらを有効にし、ログの送信先バケットを指定することでログを取得することができます
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/192949/90b35b7a-6ec1-e68c-7e79-1b60e7a2864f.png)

***

### AWS CloudTrailの使用
・CloudTrailでもS3のオブジェクトレベルの**APIコール**が記録でき、誰がいつどのオブジェクトにアクセスしたのかのログを残すことができます。
・S3サーバーログとの違いはログの形式がJson形式であることの他、コストがCloudTrailの方が比較的かかる分、ログ配信速度も速く情報量も多いためより厳密な監査ログが必要な場合はCloudTrailを選択したほうがよさそうです。
・ログの分析やAWSの他サービスとの連携についても、Athenaを使う分にはS3サーバーアクセスログの結果でも分析ができますがAWSOrganizationsとの連携ができる点などでCloudTrailにしかできない管理を実現することができます。※CloudTrailでできることについては以下の参考URLの内容をご覧ください
##### 参考：S3サーバログとCloudTrailの比較
https://docs.aws.amazon.com/ja_jp/AmazonS3/latest/userguide/logging-with-S3.html

:::note info
Amazon Macie による不正操作監視
・CloudTrailにより出力されたログを出力したS3バケットを定期的にAmazonMacieでスキャンすることでユーザの不正操作の検知や監視を迅速に行うこともできる
:::

## 参考資料
・この記事で解説した内容と関連したAWSブラックベルトのURLをまとめました。より詳細な内容を知りたい方はぜひ参照してください。

### Amazon S3 セキュリティ編

https://pages.awscloud.com/rs/112-TZM-766/images/AWS-Black-Belt_2023_Amazon_S3_Security_0131_v1.pdf

### Amazon S3 データ保護編

https://pages.awscloud.com/rs/112-TZM-766/images/AWS-Black-Belt_2023_Amazon_S3_DataProtection_0430_v1.pdf

### Amazon S3 コスト最適化編
https://pages.awscloud.com/rs/112-TZM-766/images/AWS-Black-Belt_2023_Amazon-S3-CostOptimization_0602_v1.pdf

### AWS CloudTrail

https://pages.awscloud.com/rs/112-TZM-766/images/20210119_AWSBlackbelt_CloudTrail.pdf


### Amazon Macie

https://pages.awscloud.com/rs/112-TZM-766/images/20200812_AWS-BlackBelt-Macie.pdf