〜AWS初学者の資格日記〜 S3編 (ソリューションアーキテクトレベル)

初めまして、つかさです
IT業界で働くようになってから約1年過ぎ、普段はWebエンジニアとして働いてますが、何か次のステップアップをしたいなと思い、とりあえずawsの資格の勉強を始めました!
自分が躓いた箇所や苦手分野などを、記事を通してアウトプットしたいのと同時に、同じ所で躓いている方の参考になればなと思ってます！

よろしくお願いします！
## S3  
Amazon Simple Storage Serviceの略でデータ保存するサービス
<p align="right">
  <img width="50"src="https://www.memo.dayjournal.dev/images/logo/aws/s3.png">
</p>

### 基本構成
- 問題文
- 答え
- なぜその答えなのか
- その答えを理解するための周辺知識
***

<details open><summary>問題</summary>

特定のS3バッケットのオブジェクトへのアクセスログを1年間保存する要件がある。この期間中は誰でも削除することはできないです。保存方法として最適なものは？
</details>

<details><summary>答え</summary>

S3のバージョニングを有効にし、オブジェクトロックのコンプライアンスモードを有効にして1年間保存する
</details>

<details><summary>理由</summary>

問題文に`誰でも`とあるので、たとえルートユーザーであっても解除することは出来ないオブジェクトロックのコンプライアンスモードが正解です。
</details>


この問題でまず押さえないといけないのは`バージョニング`です。
#### バージョニング
簡単に言うと、人的ミスでデータが失われたりしないようにバージョン管理しようっていう機能です。:dividers:
デフォルトでは無効なので、意図的に有効にする必要があります。

例えば誤って上書きした場合、元のバージョンにロールバックする方法として`DeleteObjectVersionアクション`があります。`DeleteObjectVersionアクション`は、特定のバージョンIDを指定して、そのバージョンのオブジェクトを削除します。よって最新のバージョンを削除することで、ロールバック可能になります。

しかし、`DeleteObjectVersionアクション`を行えるユーザーが誤って削除してはならないバージョンを消してしまう可能性があります。そんな時に役に立つ機能として以下2つがあります。

- MFA Delete
- オブジェクトロック

#### オブジェクトロック
オブジェクトロックで設定したオブジェクトは保持期間中`DeleteObjectVersionアクション`ができないようにすることができます。
この機能の中にも3つの使い方があります。

1\. ガバナンスモード
2\. コンプライアンスモード
3\. リーガルホールド

これらの使い方に大きな違いはありません。なので要件によって使い分ける事が大切です!
|  | 保持期間を設定する | ユーザーによって解除できる |
|:-:|:-:|:-:|
| ガバナンスモード  | ◯ | ◯ |
| コンプライアンスモード  | ◯ | ×  |
| リーガルホールド  | × | ◯ |

:::note info
MFA Delete
ユーザーが`DeleteObjectVersionアクション`を行う前にMFA認証をするようにする機能です。
:::
***

<details open><summary>問題</summary>

アカウントAのIAMユーザーがアカウントBのS3バケットへのオブジェクトをアプロードする必要がある。どのポリシーが必要ですか？(2つ)
</details>

<details><summary>答え</summary>

アカウントAのアイデンティティベースのポリシーとアカウントBのS3バケットポリシー
</details>

<details><summary>理由</summary>

S3に直接アクセスするクロスアカウントアクセスを設定する場合、答え2つのポリシーを設定する必要があります。
</details>

この問題でのポイントは`S3バケットポリシー`になります。
#### S3バケットポリシー
S3はリソースベースのポリシーです。

```json:例
{
  "Version": "2012-10-17",
  "Id": "ExamplePolicy",
  "Statement": [
    {
      "Sid": "PublicReadGetObject",
      "Effect": "Allow",
      "Principal": "*",
      "Action": "s3:GetObject",
      "Resource": "arn:aws:s3:::example-bucket/*"
    }
  ]
}
```
|  | 役割 |
|:-:|:-:|
| Version  | ポリシーのバージョンを指定 | 
| Id  | ポリシーに一意の識別子を割り当てるためのオプションのフィールド | 
| Statement  | 実際のアクセス許可を定義するフィールド | 

さらにStatementフィールドの中に複数のフィールド

|  | 役割 |
|:-:|:-:|
| Effect  | アクションを許可するか拒否するかを指定 値は`Allow`または`Deny` | 
| Action  | 許可または拒否する操作を定義 `s3:PutObject`,`s3:GetObject`,`s3:ListBucket`など | 
| Resource | ポリシーが適用されるリソースを指定 | 
| Principal  | アクションを許可または拒否するエンティティ（ユーザー、アカウント、ロール）を指定。すべてのユーザーに対して適用する場合は `*` を使用 | 
| Condition  | 特定の条件を指定。　例えば、IPアドレス範囲やAWSサービスの特定のリクエストでのみアクセスを許可することができます。| 
| Sid | ステートメントに一意のIDを割り当てるためのフィールド | 

今回の問題の場合、`Resource`にアカウントAのアイデンティティベースのポリシーに含める対象のリソースを書く。PrincipalにアカウントAを設定することで要件を満たせます。
***

<details open><summary>問題</summary>

S3バケットにアップロードオブジェクトをサーバー側で暗号化する必要があります。暗号化にするキーはAWS側で保持したくありません。どのような方法が最適ですか？
</details>

<details><summary>答え</summary>

SSE-Cを使用する
</details>

<details><summary>理由</summary>

SSE-Cでは暗号化に使用されたキーをAWSに保持しません。毎回メモリから削除されるので、今回の要件において最適だと言えます。
</details>

今回の問題でのポイントは`暗号化`になります。

#### 暗号化

`暗号化`において、暗号化する`場所`と`キー`を要件ごとに分けることが大切です。
- 場所
`クライアントサイド暗号化`と`サーバーサイド暗号化`に分けることができます。簡単な違いとしては、`暗号化してから保存する`か`保存する際に保存する`の違いになります。

- キー
`S3が管理するキー`,`KMSが管理するキー`, `ユーザーがオンプレミスで管理するキー`の３つに分けることができます。

今回は`サーバーサイド暗号化`に絞り、`キー`のそれぞれの場合にどのように暗号化されるのか見ていきましょう!

|  | 暗号化方法 | 特徴 |
|:-:|:-:|:-:|
| S3が管理するキー  | SSE-S3 | オブジェクトにアクセスする権限さえあれば、使用することが可能です。|
| KMSが管理するキー  | SSE-KMS | KMSで管理しているのでユーザーのアクセス権限の制御ができます。その上で、暗号化キーの無効化や削除を行なうことができます。  |
| ユーザーがオンプレミスで管理するキー  | SSE-C | 独自生成したキーを使用しなければならないケースや、AWSにキーを保持したくない場合に、この暗号化方法がそれらの要件を満たせます。 |

今回の場合、`サーバー側で暗号化する必要がある`と`暗号化にするキーはAWS側で保持したくない`という2つの要件があり、SSE-Cが正解になりました。この問題に限らず、S3の暗号化に関する問題のパターンは様々あります。要件に沿った暗号化方法が導き出せるように頑張っていきましょう！:grin:

***

<details open><summary>問題</summary>

インターネットに公開されている複数のWebサイトから使用するWebフォントをS3から配信しています。Webサイトからの使用を許可するためにS3ではどのような設定が必要ですか？
</details>

<details><summary>答え</summary>

S3のバケットポリシーでフォントオブジェトにパブリックアクセスを許可し、CROSで複数のWebサイトのドメインを許可する。
</details>

<details><summary>理由</summary>

まずオブジェクトに対してインターネット経由でアクセスできるように許可することが必要です。しかし、この状態ではまだ`ブラウザの同一生成元ポリシー（Same-Origin Policy）`によりアクセスをすることができません。そこでCORSを使用することでそのポリシーを緩和することが求められます。
</details>

今回の問題でのポイントは`ブラウザの同一生成元ポリシー`になります。

#### ブラウザの同一生成元ポリシー
一言でいうと、ウェブサイトが実行されている`オリジン`と異なるオリジンからのリソース（データやメディアなど）間のアクセスを制限する仕組みになります。

:::note info
オリジンとは
ドメイン、スキーム(プロトコル)、またはポートによって決められた場所
:::

つまり、ウェブアプリケーションが https://example.com でホストされていて、リソースも同じオリジンから提供される場合、同一生成元ポリシーによる制限はありません。しかし、ウェブアプリケーションがhttps://example.com でホストされているが、リソースが https://example-bucket.s3.amazonaws.com にある場合、これらは異なるオリジンと見なされます。このケースでは、同一生成元ポリシーにより、リソースの読み込みが制限されます。

今回のケースのように異なるオリジンからのアクセスが必要な場合は往々にしてあります。そんな時に役に立つのが`CORS`です。

#### CORS

特定のリクエスト元を許可していることをブラウザに指示する仕組み

```xml:CORSの例
<CORSConfiguration>
 <CORSRule>
   <AllowedOrigin>http://www.example.com</AllowedOrigin>
   <AllowedMethod>GET</AllowedMethod>
   <AllowedMethod>POST</AllowedMethod>
   <AllowedHeader>*</AllowedHeader>
   <MaxAgeSeconds>3000</MaxAgeSeconds>
   <ExposeHeader>x-custom-header</ExposeHeader>
 </CORSRule>
</CORSConfiguration>
```

|  | 役割 |
|:-:|:-:|
| AllowedOrigins | 許可するオリジン | 
| AllowedMethods | 許可するHTTPメソッド | 
| AllowedHeaders | ポリシーが適用されるリソースを指定 | 
| AllowedHeaders | リクエスト中にブラウザがアクセスを許可するヘッダー | 
| MaxAgeSeconds | ブラウザがプリフライトレスポンスをキャッシュする時間（秒）| 
| ExposeHeaders | ブラウザに対して、アプリケーションからアクセス可能とするレスポンスヘッダー | 

今回、複数のWebサイトからS3オブジェクトに対してアクセスする方法が問われる問題でした。
この問題を解くにあたって、2つの要点を理解しておくことが大切です。
- 1つ目
`ブラウザの同一生成元ポリシー`や`バケットポリシー`によってアクセスが制限されていること
- 2つ目
これらの制限は緩和や許可ができること

リクエスト関係の問題のときは、どのようなルートでアクセスされるかやその間にどのような制限があるのかを把握しておくことが大切です！
***

<details open><summary>問題</summary>

ある企業は静的コンテンツをAmazon S3バケットに格納するWebアプリケーションを設計しています。アプリケーションの非機能要件として、このバケットは1秒間に150を超えるPUT要求を迅速に処理する必要があります。

最適なパフォーマンスを確保するために何をすべきですか？
</details>

<details><summary>答え</summary>

オブジェクトキー名に日付などのPrefixを利用する。
</details>

<details><summary>理由</summary>
まずオブジェクトに対してインターネット経由でアクセスできるように許可することが必要です。しかし、この状態ではまだ`ブラウザの同一生成元ポリシー（Same-Origin Policy）`によりアクセスをすることができません。そこでCORSを使用することでそのポリシーを緩和することが求められます。
</details>


### まとめ

読んでいただきありがとうございました！
これからも自分のペースで記事を更新したり、新たな記事を書いていこうと思うので是非見ていただけたらなと思います！:grin: