【AWS】S3とCloudFrontでSSL化した独自ドメインの静的Webサイトを公開する


# はじめに
S3+CloudFrontという構成でVue.jsを使用したSPAアプリケーションやLPを公開する機会が多いので、実際に私が行っている公開までの手順をまとめてみました。
S3単体でも静的Webサイトを公開することは可能ですが、CloudFrontを使用することによって独自ドメインの使用やSSL化、グローバルに分散したエッジロケーションを通じて高速なコンテンツの配信が可能になります。

# 公開までの手順
1.Route53で独自ドメインの取得
2.S3でバケットの作成
3.ACM(AWS Certificate Manager)を使用したSSL証明書の取得
4.CloudFrontディストリビューションの作成
5.Route53でホストゾーンとCloudFrontを関連づけ
7.独自ドメインでのアクセス確認

番外編　Basic認証の設定


### 1.Route53で独自ドメインの取得
独自ドメインを取得する方法はいくつかありますが、一連の作業をAWS内で完結させたかったため、今回私は[こちら](https://hiyowa-na-engineer.com/aws-get-domain/)の記事を参考にしてRoute53で独自ドメインの取得を行いました。
Route53コンソールに移動して、取得したドメインがホストゾーンに表示されていることを確認できたら完了です。

### 2.S3でバケットの作成
ドメインの取得を終えたら、S3でバケットの作成を行います。
バケットとはS3で提供されているテキストや画像ファイルなどのオブジェクトをデータとして格納するためのコンテナのことを指します。
S3コンソールに移動し、【バケットを作成】を押下します。

- バケットを作成　
  - バケット名 → `独自ドメイン`を入力
  - AWSリージョン → `アジアパシフィック（東京）ap-northeast1`を選択
  - ブロックパブリックアクセス設定→`パブリックアクセスをすべてブロック`を選択

上記の設定を行った後、【バケットを作成】を押下します。
![S3-bucket.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1739783/7fbadffc-7bdd-1a0f-be9b-4455b4dffe7b.png)

ブロックパブリックアクセス設定はS3バケットに保存されいるデータに対する公開アクセスを制御する機能です。
パブリックアクセスをすべてブロックすることで、意図しないアクセスによるデータ漏えいのリスクを最小限に抑えることが可能になります。
今回の場合では、CloudFront経由からのみS3バケットアクセスを許可したいため、後述のCloudFrontディストリビューション作成の過程で、CloudFrontからのリクエストを認識して許可する設定を行います。

バケットが作成されたことが確認できたら、そのバケットに対して静的ウェブサイトで使用するファイルとフォルダのアップロードを行います。
今回は下記の記事を参照して環境構築を行ったビルド済みのデータを使用します。
[Docker + Viteで Vue3 + TypeScriptの爆速開発環境を構築する](https://qiita.com/generonishimura/items/88742085294bd0b234a6)

作成したバケット内の【アップロード】を押下します。
ファイルとフォルダメニューにて、以下のファイルとフォルダを追加します。
- `index.html`ファイル
- `assets`フォルダ
- `favicon.ico`ファイル

必要なファイルとフォルダの追加を終えたら、【アップロード】を押下します。

   ![S3-Management-Console.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1739783/0e0f10a2-83f2-7ef1-e2d4-4950cd0e625d.png)

アップロードに成功すると、オブジェクトとして下記のように表示されます。
![スクリーンショット 2023-06-05 9.34.05.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1739783/b2dd4291-3c6f-117a-4517-521d9f6a5f31.png)



### 3.ACM(AWS Certificate Manager)を使用してSSL証明書を取得する
独自ドメインをHTTPSでアクセス可能にするためにはSSL証明書が必要なため、ACMから取得を行います

AWS Certificate Managerコンソールに移動します。
CloudFrontで使用できるACM証明書は米国東部(バージニア北部)で取得された証明書である必要があるため、リージョンを`米国東部(バージニア北部)us-east-1`に変更します。

> 証明書の発行者
> AWS Certificate Manager (ACM) で発行された証明書を使用することをお勧めします。ACM からの証明書の取得の詳細 については、AWS Certificate Manager ユーザーガイドを参照してください。CloudFront で ACM 証明書を使用するに は、米国東部 (バージニア北部) リージョン (us-east-1) の証明書をリクエスト (またはインポート) していることを確認します。

https://docs.aws.amazon.com/ja_jp/AmazonCloudFront/latest/DeveloperGuide/cnames-and-https-requirements.html

ダッシュボードから【証明書をリクエスト】を押下します。
 - 証明書リクエスト
    - 証明書タイプ →　`パブリック証明書リクエスト`を選択
    - 完全修飾ドメイン名 → `独自ドメイン`を入力
    - 検証方法 →　`DNS検証`を選択

上記事項の入力を行い、【リクエスト】を押下します。
   ![AWS-Certificate-Manager (1).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1739783/18d9bc43-5712-6dbe-7a8a-367a1dc23531.png)


次に発行された証明書の証明書IDを選択します。
ドメインメニューの【Route53でレコードを作成】を押下し、対象のドメインを選択した後、【レコードを作成】を押下します。
![68747470733a2f2f71696974612d696d6167652d73746f72652e73332e61702d6e6f727468656173742d312e616d617a6f6e6177732e636f6d2f302f313733393738332f65383137313735612d653162332d366434372d653661612d3162653634353666613431382e706e67.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1739783/130489fd-d52b-1789-6607-63bc2b323f6a.png)


レコードの作成を終えたら、以下の2点の確認を行います。
  - 証明書のステータスが`発行済み`となっていること
  - Route53 に移動し、対象のホストゾーンに`CNAME`タイプのレコードが追加されていること

### 4.CloudFrontディストリビューションの作成
CloudFrontはコンテンツ配信ネットワークサービスで、ユーザーに対してウェブコンテンツを高速かつ安全に配信するためのものです。ディストリビューションを作成することでHTTPSでS3バケットにアクセスすることを可能にします。
CloudFrontコンソールに移動し、【CloudFrontでディストリビューションを作成】を押下します。

- ディストリビューションを作成
  - オリジナルドメイン → `作成済みのS3バケット`を選択
  - 名前 →　S3バケットを選択することで自動入力されます
  - オリジンアクセス → `Origin access control settings (recommended)`を選択
    - Origin access control　→　`コントロール設定を作成`を選択
    - バケットポリシー →　`「はい、バケットポリシーを自動で更新します」`を選択
  - ビューワープロトコルポリシー　→　`Redirect HTTP to HTTPS`を選択
  - 代替ドメイン名 →　`独自ドメイン`を入力
  - カスタムSSL証明書 →　`取得済み証明書`を選択
  - デフォルトルートオブジェクト → `index.html`を入力
![作成-ディストリビューション-CloudFront (3).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1739783/11d3b740-d9df-aa45-0c54-917ef7ef16d8.png)


上記の設定を行った後、【ディストリビューションを作成】を押下します。

前述のS3の設定でパブリックアクセスをすべてブロックしましたが、オリジンアクセスでOrigin access control settingsを選択し、OAC設定を作成することで、`CloudFront経由からのみS3へのアクセスが可能`になります。OACはCloudFrontを介してのみAmazon S3のコンテンツにアクセスできるようにする機能です。

従来はCloudFront経由でS3にアクセスする際にOAI（Legacy access identities）が使用されていましたが、2022年8月にHTTPメソッド対応やセキュリティ面が強化されたOACが発表され、現在ではOACを使用することが推奨されています。

OACに関しては下記の記事にて詳しく解説されています。

https://dev.classmethod.jp/articles/amazon-cloudfront-origin-access-control/


ディストリビューションの作成後、下記の画面に切り替わります。
画面上部の【ポリシーをコピー】を押下し、ポリシーをコピーしたら、【バケットの権限に移動してポリシーを更新する 】からS3コンソールのバケットポリシー編集画面に移動します。
![E1A0X41YZL0YQG-ディストリビューション-CloudFront.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1739783/fbca8f41-19c4-8874-f26e-f746b2693304.png)

バケットポリシー項目に【編集】を押下します。コピー済みのポリシーをペーストして、変更を保存したら完了です。


### 5.Route53でホストゾーンとCloudFrontを関連づけ
最後にRoute53を使って、独自ドメインをCloudFrontディストリビューションに関連付けを行います。
Route53コンソールに移動して、対象のホストゾーンでレコードの作成を行います。

Route53コンソールに移動し、対象のホストゾーンで【レコードを作成】を押下します。

- レコードタイプ →　`A`を選択
- `エイリアス`にチェックを入れる
- トラフィック先のルーティング先 → `CloudFrontディストリビューションへのエイリアス`を選択
- ディストリビューションを選択　→　`作成済みのディストリビューション`を選択
![68747470733a2f2f71696974612d696d6167652d73746f72652e73332e61702d6e6f727468656173742d312e616d617a6f6e6177732e636f6d2f302f313733393738332f39363137666234642d303738362d623339322d616333352d6239373632393032343265302e706e67.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1739783/18374732-202f-6132-6031-59d8ccb49a19.png)


上記の設定を行った後、【レコードの作成】を押下します。

ホストゾーンにAレコードが作成されていることを確認しましょう。
上記の設定を行うことで、独自ドメインにリクエストが送信された際に、CloudFrontディストリビューションを参照できるようになります。


### 6.独自ドメインでのアクセス確認
ここまでの対応を終えたら、実際に独自ドメインにアクセスして表示されるか確認しましょう。
問題無く表示されていたら**成功**です！
https://kazukinagahira.com/
![スクリーンショット 2023-06-05 1.32.20.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1739783/4523eac2-402c-6828-e4e7-ac12fdd56271.png)


### 番外編　CloudFront関数を使用してBasic認証を設定する
これまでの手順により、静的なWebサイトの公開が可能となりました。
しかしながら、実際の運用ではデプロイとサイトのリリースは別々のタイミングで行われることがほとんどです。
そのため、サイトは特定の期日までアクセスを制御する必要があります。
CloudFront関数を利用してBasic認証の設定を行うことで、アクセスの制御を実現することが可能になります。

CloudFrontコンソールで関数を選択し、【関数を作成】を押下します。
任意の名前と説明を入力し、関数を作成します。
![スクリーンショット 2023-06-06 0.42.55.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1739783/906cfe2a-506d-bc73-8f0f-ac07f8714669.png)
作成を終えたら、関数コードの項目に以下のBasick認証用コードを入力して、【変更を保存】を押下します。
`authUser`と`authPass`変数には任意の値を入力しましょう。

```
 function handler(event) {
    // Basic認証で使用するユーザー名とパスワード
    var authUser = 'basic_auth_user';
    var authPass = 'sQkBMKHzX2XQ';

    var authString = 'Basic ' + (authUser + ':' + authPass).toString('base64');

    var request = event.request;
    var headers = request.headers;

    if (
      typeof headers.authorization === "undefined" ||
      headers.authorization.value !== authString
    ) {
      return {
        statusCode: 401,
        statusDescription: "Unauthorized",
        headers: { "www-authenticate": { value: 'Basic realm="Please Enter Your Password"' } }
      };
    }

    return request;
    }
```

>CloudFront Functions の JavaScript runtime 環境は ECMAScript (ES) バージョン 5.1 に準拠しており、ES バージョン 6 ～ 9 の一部の機能をサポートしています。


https://docs.aws.amazon.com/ja_jp/AmazonCloudFront/latest/DeveloperGuide/functions-javascript-runtime-features.html

上記の通り、CloudFront関数では`const`や`let`が使用出来ない点に注意が必要です。

![basic_auth_kazukinagahira-関数-CloudFront.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1739783/0d642b03-4bfb-d838-e7b5-5d612b502990.png)




関数コードの変更を保存した後、`発行`項目にて【関数を発行】を押下してます。
次に関連付けられているディストリビューションにて【関連付けを追加】を押下し、作成済みのディストリビューションを選択し、【関連付けを追加】を再度押下します。
これにより、ディストリビューションと関数を紐付けることができました。

![basic_auth_kazukinagahira-関数-CloudFront (2).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1739783/e5bbb86b-ccbc-c66c-12f3-f492678d88f8.png)

改めて、独自ドメインにアクセスして、Basic認証が適用されているか確認しましょう。
下記画像のように認証画面が表示されたら**成功**です！
![スクリーンショット 2023-06-06 1.02.52.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1739783/3fc19513-d6ca-684d-de4f-e03c3526327f.png)

# おわりに

この記事を通じて、AWS S3とCloudFrontを用いた静的Webサイトの公開方法を紹介しました。
今回は、AWSコンソールの手動操作を通じて静的Webサイトを公開しましたが、今後は、AWS CDKを使用してS3バケットの更新やCloudFrontのキャッシュ削除の自動化を検討しています。
また、AWS Amplifyを使用することで、よりシンプルな方法で静的Webサイトの公開が可能になるようです。Amplifyを使った方法と、今回紹介した方法とを比較し、その結果についても記事でまとめようと思います。