【AWS】S3＋CloudFrontのOACでセキュアに静的ウェブサイトを公開する方法

## 初めに
この記事では、AWSのAmazon S3とCloudFrontのオリジンアクセスコントロール (OAC) を活用して、HTTPS通信でセキュリティを強化しつつ静的ウェブサイトを公開する方法を説明します。
## S3で静的ファイルをホスティングする際のリスク
Amazon S3で静的ホスティングする際によくある構成として、S3バケットのブロックパブリックアクセス設定を無効にしてコンテンツにパブリックアクセスさせるというのがあると思います。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3817084/1250e5af-8c02-8b79-6aee-e2a8b390c875.png)

しかし、パブリックアクセスの許可にはいくつかリスクがあります。
主には以下です<sup>(1)</sup>
データ漏洩のリスク:
パブリックアクセスが許可されているバケットやオブジェクトは、インターネット上の誰でもアクセス可能になるため、機密情報が漏洩するリスクが高まります。

不正アクセスのリスク:
パブリックアクセスを許可することで、不正アクセスや悪意のある攻撃のターゲットとなりやすくなります。
## 対策
上記の対策としてはAmazon S3バケットをオリジンとして使用し、CloudFrontを介してコンテンツを配信することができます。セキュリティを確保するために、オリジンアクセスコントロール (OAC) を使用して、CloudFrontディストリビューションのみがS3バケットにアクセスできるように設定します<sup>(2)</sup>。

この構成の利点は、ブロックパブリックアクセス設定を有効にしたまま配信出来ることと、エンドユーザーのリクエストがHTTPSを使用するように強制出来ることです。

以下今回のソリューションのアーキテクチャ図です。

![セキュアな静的ホスティング構成図.drawio.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3817084/9c32175e-a46c-94a1-ebd9-cbd678aba0f0.png)



## 実装手順

### HTMLファイルの準備
まず前提として、今回ホスティングさせる静的ファイルを用意してください。
特にない場合は、以下URLから私のGithubページにあるHTMLファイルをダウンロードできます。
https://github.com/Sorao-high/-Capybara-homepage


![1.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3817084/721fcad2-6698-dcb3-be71-0dcf6749077f.jpeg)

### S3バケットの設定
1). S3バケットを作成します。AWSマネジメントコンソールにログインし、S3を開きます。
「バケットを作成」を押します。
![2.JPG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3817084/70a06ca6-df30-2dfc-bc0f-a4fcd7f4a025.jpeg)

2). バケットタイプは「汎用」を選択し、バケット名を入力します。あとはデフォルトの値のまま「バケットを作成」を押します。

:::note warn
この時、バケット名はグローバルに一意である必要があります。他のAWSアカウントが既に使用しているバケット名は使用できません。あと大文字も使用できないので気を付けましょう<sup>(3)</sup>。バケット名の詳細な命名規則は参考文献を参照ください。
:::
![3.JPG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3817084/1f984187-ba3e-afed-1df1-0e1def842b4a.jpeg)
![4.JPG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3817084/3bd348e8-20d4-4bb5-9aed-3d6d0edec479.jpeg)

![5 - コピー.JPG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3817084/c2d38fb1-9744-5d68-4a70-f16ce8683f14.jpeg)

## コンテンツのアップロード
1). 作成したバケットの「アップロード」を押します。
![7.JPG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3817084/46782a98-f313-b910-4470-fc7dd4dbf779.jpeg)

2). ホスティングさせるファイルをアップロードします。
私のGithubからダウンロードした方は「AWStest.html」と「AWStest.png」をアップロードしてください。このとき「-Capybara-homepage-main」ファイルや「AWStest」ごとまとめてアップロードすると、後述の作業とパスが変わる可能性があるので、「AWStest.html」と「AWStest.png」をひとつずつアップロードしてください。
![9.JPG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3817084/c12532bc-583e-4085-4b57-dcf5e74c06d8.jpeg)

### CloudFrontの設定
1). CloudFrontを開き、「CloudFront ディストリビューションを作成」を押します。
![2.JPG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3817084/7fb76816-17a7-422b-8491-27b193a6e22f.jpeg)

2). 以下項目を入力し、「ディストリビューションを作成」。
Origin Domain：先ほど作成したS3バケットを選択
名前：オリジンの名前
オリジンアクセス：「Origin access control settings(recommended)」を選択
Origin access control：「Creat new OAC」を押下
ウェブアプリケーションファイアウォール(WAF)：「セキュリティを有効にしないでください」を選択

![3.JPG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3817084/3705f587-de9f-59d0-e350-ab8d4968409a.jpeg)
![7.JPG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3817084/ee385318-c18c-27f8-92f7-9b844315d634.jpeg)
![8.JPG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3817084/27023ec1-6d66-86ed-a3c7-4e9e87dda740.jpeg)

3). CloudFrontからS3へのアクセスを許可するための作業です。
「ポリシーをコピー」を押し、念のためにメモなどにペーストしておいてください。
「S3バケットの権限に移動してポリシーを更新する」を押してください。S3に遷移します。
![9.JPG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3817084/adcf98bc-a2cd-91b3-c575-45be25c5fc90.jpeg)

4). S3に遷移したら、「アクセス許可」を押します。
![11.JPG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3817084/efbcc44e-ec4e-179e-4431-107c54396031.jpeg)

5). 下へスクロールしていくとバケットポリシーの項目があるので、「編集」を押します。
![12.JPG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3817084/bb414417-2c18-92aa-93cf-df9576187157.jpeg)

6). 赤枠に、先ほどコピーしたポリシーを貼り付けます。
![13.JPG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3817084/9cc08515-2087-2c22-3aa8-707bc6a400f2.jpeg)

「変更の保存」を押します。
![15.JPG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3817084/8422c5b0-30d6-cb23-7a11-04c653ddc081.jpeg)

7). CloudFrontページに戻り、作成したディストリビューションを選択し詳細設定の「一般」から「最終更新日」に日時が表示されているかと、「ディストリビューションドメイン名」を確認し、作業は完了となります。

:::note warn
ディストリビューションドメイン名はこのあとコンテンツへのアクセスの時に必要になりますのでコピーなどしてください。
:::
![17.JPG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3817084/d1d6be93-364c-b518-b4d7-8062d8685e38.jpeg)


### 結果確認
ちゃんとアクセスできるか確認します。
CloudFrontからコンテンツにアクセスするには、ディストリビューションドメイン名とアクセスさせたいコンテンツファイルのバケット内パスを組み合わせ、ディストリビューションドメイン名/コンテンツパスのようなURLを使用します<sup>(4)</sup>。

今回手順通り私のHTMLファイルを使用していれば、以下のURLになります。「ディストリビューションドメイン名」を自身のものに書き換えてください。

`https://ディストリビューションドメイン名/AWStest.html`

問題なければこのような画面が表示されるはずです。
![1.JPG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3817084/4beb4f38-4d92-3bf0-355a-47f7124ffee5.jpeg)


## 削除手順
このまま運用する予定がない方は必要以上に料金が発生しないようにリソースを削除します。
アーキテクトの構造上まずディストリビューションの削除をして、その次にS3バケットを削除する順番となります。

### ディストリビューションの削除
1). CloudFrontを開いて作成したディストリビューションを選択し、「無効」を押します。
![1.JPG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3817084/dc25664a-a2de-069c-f472-6b92ef38f4b3.jpeg)


2). 「無効」を押します。
![2.JPG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3817084/88ffee66-9621-cf70-35d5-da1ad641c6ac.jpeg)

3). 最終変更日が「デプロイ」から具体的な日時に更新されるまで待ちます。数分かかる場合があります。
![3.JPG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3817084/142f521e-e55b-8c29-4f7d-103596dfc264.jpeg)
日時が更新されたら「削除」を押します。
![5.JPG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3817084/b65ac885-3fee-9244-41b0-4918b890ed96.jpeg)

4). 「削除」を押し、ディストリビューションが消えてることを確認して完了です。
![6.JPG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3817084/1c78be9e-378f-de55-3374-545f3192f70f.jpeg)
![7.JPG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3817084/c3b03ca5-0767-1730-bc0d-2f93277a4133.jpeg)

### S3バケットの削除
1). S3を開き作成したバケットを選択し「空にする」を押します。
![1.JPG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3817084/62660d79-796a-3ecb-ef36-58b143cb5ddc.jpeg)


2). バケット～削除しますか？に「完全に削除」と入力し、「空にする」を押します。
![2.JPG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3817084/5542b3e6-9aa1-b8c5-305e-71aa5db9f0c8.jpeg)

3). もう一度バケットを選択し、「削除」を押します。
バケット～削除しますか？にバケット名を入力し、「バケットを削除」を押します。
![4.JPG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3817084/2fd161fa-680a-662b-1400-6d232397ca4a.jpeg)

4). 削除されたことを確認して削除作業完了です。
![5.JPG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3817084/1a7fcf0b-4fbb-65ab-5ea5-ad6b5d8f354c.jpeg)

## 終わりに
この記事ではAWSのS3とCloudFrontを使用して、セキュリティを重視しつつ静的ウェブサイトを公開する方法についてご紹介しました。パブリックアクセスのリスクを避けつつ、アクセスコントロールをきちんと設定することで、セキュアなウェブサイト運営をすることができます。

この記事が参考になりましたらぜひ「いいね」「フォロー」など励みになるのでよろしくお願いします！

## 参考文献
1. [Amazon S3 ストレージへのパブリックアクセスのブロック](https://docs.aws.amazon.com/ja_jp/AmazonS3/latest/userguide/access-control-block-public-access.html)
2. [安全な静的ウェブサイトの開始方法](https://docs.aws.amazon.com/ja_jp/AmazonCloudFront/latest/DeveloperGuide/getting-started-secure-static-website-cloudformation-template.html). 
3. [バケットの名前付け](https://docs.aws.amazon.com/ja_jp/AmazonS3/latest/userguide/bucketnamingrules.html#general-purpose-bucket-names). 
4. [ステップ 4: CloudFront からコンテンツにアクセスする](https://docs.aws.amazon.com/ja_jp/AmazonCloudFront/latest/DeveloperGuide/GettingStartedAccessingDistributions.html).