ドメイン、SSL 証明書を発行し、AWS S3 で静的コンテンツをインターネット公開（Basic 認証）する

## 1. 概要

ドメイン、SSL 証明書を発行し、AWS S3 で静的コンテンツをインターネット公開（Basic 認証）する際、必要になるであろう一連の手順をまとめています。  
細部に注目すると記載量が膨大になってしまいますため、必要手順を漏らさずになぞれるような記載にして備忘としています。

## 2. ハマりどころ

各設定はさほど難易度が高いものではないのですが漏らせば当然動かず、動かない場合に原因を辿ることは難しく感じています。  
そうした背景より、調べたことを記録しておこうと考えた次第です。

- 具体的な箇所
  - AWS Certificate Manager (ACM) で証明書作成時（DNS 検証）には、「Route 53 でレコードの作成」ボタンを押すことで検証用の CNAME レコードが作成されて検証が進む。押さずには進まない。  
  - AWS Certificate Manager (ACM) は **「バージニア北部（us-east-1）」** リージョンで証明書作成する必要あり。  
    CloudFront からの誘導リンクを利用すると **「バージニア北部（us-east-1）」** リージョンで開くので、CloudFront を中心に進めるとよい。
  - Route 53 で A レコードを作成し、CloudFront に紐付ける際の DNS 伝播待ちは必要。  
    こちらは腰を据えて確認することがお勧めで、焦るとよくない印象です。  
    A レコード設定不備なのか、単純に待っていればよいのか観察します。
  - CloudFront Functions で作成した関数のパブリッシュ漏れにも注意。

これらで意図しない症状に直面次第、どの場合にはどうなるか、試行する方法を準備し、想定される挙動を考えておくのも良いかと思います。

## 3. 手順

AWS Management Console にログインし、下記を行います。

### 3.1 AWS S3 でパブリックアクセスを全てブロックする手順

Amazon S3（Simple Storage Service）を静的コンテンツをホストするサービスとして利用します。  
ただ、誤ってパブリックアクセスを許可してしまうとセキュリティリスクが高まるので、S3 バケットのパブリックアクセスを明示的にブロックする設定を行います。  
デフォルトで「パブリックアクセスをすべてブロック」が有効となっていますが、設定を確認・変更する方法を以下にまとめます。

#### 3.1.1 パブリックアクセスをブロックする設定

- パブリックアクセス設定の確認
  AWS マネジメントコンソールにログインし、**Amazon S3** のページを開きます。

  1.  作成したバケットを選択
  2.  **「アクセス許可」** タブを開く
  3.  **「ブロックパブリックアクセス」** セクションを探し、**「編集」** ボタンをクリック

- 全てのパブリックアクセスをブロック
  以下の 4 つのオプションがすべて有効になっていることを確認し、チェックが入っていない場合は有効にする。

  - ✅ **新しい ACL によるパブリックアクセスをブロック**
  - ✅ **新しいバケットポリシーによるパブリックアクセスをブロック**
  - ✅ **ACL によるパブリックアクセスをブロック**
  - ✅ **バケットとオブジェクトのパブリックアクセスをブロック**

- 設定を保存
  「変更を保存」ボタンをクリックし、設定を確定します。

- 参考情報
  - [Amazon S3 のバケットポリシーとアクセス管理](https://docs.aws.amazon.com/ja_jp/AmazonS3/latest/userguide/access-control-block-public-access.html)

### 3.2 AWS Route 53 でインターネット公開用のドメインを取得する手順

Amazon Route 53 は、AWS が提供するドメインネームシステム（DNS）サービスです。  
Route 53 を使用すると、ドメインの登録、DNS レコードの管理、トラフィックのルーティングなどを行うことができます。

#### 3.2.1 ドメインの検索と選択

Route 53 コンソールで取得したいドメイン名を検索・選択し、取得します。

- ドメインの検索

  1.  Route 53 コンソールの左側のメニューから **「ドメインの登録」** を選択
  2.  取得したいドメイン名を入力
  3.  **「チェック」** ボタンをクリックして、ドメインの利用可能状況を確認

- 利用可能なドメインを選択  
  利用可能なドメインが表示されるので、取得したいドメインを選択

#### 3.2.2 ドメインの登録情報を入力してリクエストを送る

ドメインを取得するために、必要な登録情報を入力してリクエストを管理者へ送付します。  
入力項目の詳細や、リクエスト送付、送付リクエストの承認を得る過程を下記より確認できます。  
承認をすぐに実施できる場合、待ち時間はほぼなしに登録を完了できます。

- 連絡先情報の入力  
  ドメインの登録者情報（Registrant Contact）、管理者情報（Admin Contact）、技術担当者情報（Tech Contact）を入力。  
  これらの情報は、ドメインの WHOIS 情報として公開されます。  
  [Route 53 ドメイン登録の詳細](https://docs.aws.amazon.com/ja_jp/Route53/latest/DeveloperGuide/domain-register.html)

- プライバシー保護の設定  
  WHOIS 情報の公開を避けたい場合は、Route 53 が提供するプライバシー保護サービスを有効にする。  
  [WHOIS プライバシー保護サービス](https://docs.aws.amazon.com/ja_jp/Route53/latest/DeveloperGuide/domain-privacy-protection.html)

- 送付リクエストの承認  
  リクエスト送付後、承認を得ることで登録が完了。

- ドメインのステータス確認  
  Route 53 コンソールの **「ドメインの登録」** セクションで、登録したドメインのステータスを確認。

### 3.3 CloudFront で関数を作成し Basic 認証を実装する

Amazon CloudFront は、コンテンツ配信ネットワーク（CDN）サービスであり、CloudFront Functions を使用して、リクエストやレスポンスをカスタマイズすることができます。

#### 3.3.1 CloudFront Functions とは

CloudFront Functions は、CloudFront のエッジロケーションで実行される軽量な JavaScript 関数です。  
これを使用して、リクエストやレスポンスをリアルタイムに変更することができます。

#### 3.3.2 Basic 認証の仕組み

Basic 認証は、HTTP リクエストの `Authorization` ヘッダーにユーザー名とパスワードを Base64 エンコードして送信する認証方式です。  
CloudFront Functions を使用して、このヘッダーを検証し、認証が成功した場合のみコンテンツを返すようにします。

#### 3.3.3 CloudFront Functions の作成

CloudFront Functions を使用して、Basic 認証を実装する手順を以下に示します。

##### 3.3.3.1 CloudFront Functions の作成

1. **CloudFront コンソールにアクセス**: [AWS Management Console](https://aws.amazon.com/console/) にログインし、CloudFront コンソールを開きます。
2. **Functions を選択**: 左側のメニューから「Functions」（関数）を選択し、「Create function」ボタンをクリックします。
3. **関数名を入力**: 関数名を入力し、「Create」（作成）ボタンをクリックします。

##### 3.3.3.2 関数コードの記述

Basic 認証を実装するための関数コードを記述します。以下は、Basic 認証を実装するためのサンプルコードです。

```javascript
function handler(event) {
  var authHeaders = event.request.headers.authorization;
  var authString = "Basic " + btoa("username:password");

  if (authHeaders && authHeaders.value === authString) {
    return event.request;
  }

  return {
    statusCode: 401,
    statusDescription: "Unauthorized",
    headers: {
      "www-authenticate": { value: 'Basic realm="Restricted Area"' },
    },
  };
}
```

##### 3.3.3.3 関数のテスト

1. **テストイベントの作成**: CloudFront Functions コンソールで、テストイベントを作成します。
   - リクエストヘッダーに `Authorization` ヘッダーを含めて、正しい認証情報と間違った認証情報の両方でテストします。
2. **テストの実行**: 「Test」ボタンをクリックして、関数が正しく動作するか確認します。

##### 3.3.3.4 関数の公開

1. **関数を公開**: テストが成功したら、「Publish」ボタンをクリックして関数を公開します。
2. **バージョンを管理**: 公開された関数のバージョンを管理し、必要に応じて新しいバージョンを作成します。

##### 参考情報

- [AWS CloudFront Functions ドキュメント](https://docs.aws.amazon.com/ja_jp/AmazonCloudFront/latest/DeveloperGuide/cloudfront-functions.html)

### 3.4. CloudFront でディストリビューションを作成する

Amazon CloudFront は、AWS が提供するコンテンツ配信ネットワーク（CDN）サービスです。  
CloudFront を使用すると、静的および動的コンテンツを高速に配信することができます。

#### 3.4.1 CloudFront でディストリビューションを作成する

1. AWS マネジメントコンソールで CloudFront にアクセスし、「ディストリビューションを作成」ボタンをクリックします。

1. **オリジンを設定**

   - オリジンとして S3 バケットを指定します。  
     S3 バケットの URL を入力し、必要に応じて Origin access control（OAC）を作成します。  
     ディストリビューション作成後、出力される OAC の内容をコピーし、S3 側へ反映することで設定が完了します。

1. **デフォルトのキャッシュビヘイビアを設定**

   - キャッシュの設定を行います。  
     必要に応じて、キャッシュの有効期限やキャッシュポリシーをカスタマイズします。

1. **設定**

   - 代替ドメイン名 (CNAME) に作成したドメインを指定。
   - Custom SSL certificate は作成・設定について後述。
   - デフォルトルートオブジェクトは検討して設定。（index.html など）

1. **ディストリビューション設定を完了**
   - 他の設定（例: ログ記録、料金クラスなど）を行い、「ディストリビューションを作成」ボタンをクリックします。

#### 3.4.2 CloudFront Functions をディストリビューションに関連付ける

CloudFront Functions を使用して、認証などの処理を追加できます。

1. **CloudFront ディストリビューションを選択**

   - CloudFront コンソールで、対象のディストリビューションを選択します。

2. **ビヘイビアを編集**

   - 「Behaviors」タブで、編集したいビヘイビアを選択し、「Edit」ボタンをクリックします。

3. **関数を関連付ける**

   - 「Function associations」セクションで、作成した関数を「Viewer request」に関連付けます。

4. **変更を保存**
   - 設定を保存し、ディストリビューションのステータスが「Deployed」になるのを待ちます。

#### 3.4.3 CloudFront で SSL 証明書を取得する

- 重要: **ACM のリージョンを us-east-1 に設定する**

  CloudFront でカスタムドメインを使用する場合、ACM で発行する証明書は **「バージニア北部（us-east-1）」** に作成する必要があります。  
   他のリージョンで発行した証明書は CloudFront で使用できないため注意してください。

- 証明書の作成手順

  1.  **AWS Certificate Manager (ACM) にアクセス**

      - [AWS マネジメントコンソール](https://aws.amazon.com/console/)で ACM に移動します。
      - **リージョンを「バージニア北部（us-east-1）」に変更** します。

  2.  **証明書をリクエスト**

      - 「証明書のリクエスト」ボタンをクリックし、ドメイン名を入力します。

  3.  **DNS 検証を設定**

      - ドメインの所有権を確認するために、DNS 検証を行います。  
        ACM で DNS 検証を利用する場合、対象ドメインが Route 53 で管理されていて、なおかつ ACM にそのホストゾーンへの書き込み権限がある場合、ACM コンソールには「Route 53 でレコードの作成」ボタンが表示されます。  
        このボタンをクリックすると、検証用の CNAME レコードが自動的に追加され、ドメイン所有権の検証が行われます。

  4.  **証明書を取得**

      - 検証が完了すると、SSL 証明書が発行されます。

#### 3.4.4 CloudFront で SSL 証明書を設定する

1. **CloudFront ディストリビューションを編集**

   - CloudFront コンソールで、作成したディストリビューションを選択し、「編集」ボタンをクリックします。

2. **SSL 証明書を設定**

   - 「SSL 証明書」セクションで、カスタム SSL 証明書を選択し、ACM で取得した証明書を指定します。

3. **変更を保存**
   - 設定を保存し、ディストリビューションのステータスが「Deployed」になるのを待ちます。

#### 3.4.5 CloudFront で S3 コンテンツへの OAC（Origin Access Control）を作成し、S3 に設定する

3.4.1 で OAC（Origin Access Control）の作成を選択していた場合、ディストリビューション作成時点で S3 への OAC 更新が必要なこと、OAC の内容が出力されます。

- S3 バケットのポリシーを更新し、OAC からのアクセスのみを許可します。

  1.  AWS マネジメントコンソールにログインし、**Amazon S3** のページを開きます。

  1.  作成したバケットを選択
  1.  **「アクセス許可」** タブを開く
  1.  **「バケットポリシー」** セクションを探し、**「編集」** ボタンをクリック
      ポリシーを S3 バケットに適用します。  
      S3 バケットポリシーの例

      ```json
      {
        "Version": "2012-10-17",
        "Statement": [
          {
            "Sid": "AllowCloudFrontAccess",
            "Effect": "Allow",
            "Principal": {
              "Service": "cloudfront.amazonaws.com"
            },
            "Action": "s3:GetObject",
            "Resource": "arn:aws:s3:::your-bucket-name/*",
            "Condition": {
              "StringEquals": {
                "aws:SourceArn": "arn:aws:cloudfront::your-account-id:distribution/your-distribution-id"
              }
            }
          }
        ]
      }
      ```

### 3.5. Route 53 で A レコードを作成し、CloudFront の関数を紐付ける

Route 53 で、カスタムドメインを CloudFront ディストリビューションに紐付けます。

#### 3.5.1 前提条件

- **CloudFront ディストリビューションが作成済み**  
  CloudFront でディストリビューションを作成し、オリジン（S3 など）が設定されていること。
- **CloudFront Functions を作成済み**  
  Basic 認証などを行う CloudFront Functions がすでに作成されていること。
- **Route 53 でドメインを取得済み**  
  Route 53 で管理しているドメインがあり、ホストゾーンが作成されていること。

#### 3.5.2 CloudFront ディストリビューションのドメイン名を確認

まず、CloudFront のドメイン名を取得します。

1. **AWS CloudFront コンソールにアクセス**  
   [AWS マネジメントコンソール](https://aws.amazon.com/console/) で CloudFront を開きます。
2. **CloudFront ディストリビューションを選択**  
   ディストリビューションのリストから、使用するディストリビューションを選択します。
3. **「Domain Name」をコピー**  
   「General」タブにある **「Domain Name」**（例: `d123456789.cloudfront.net`）をメモします。

#### 3.5.3 Route 53 で A レコードを作成

Route 53 で A レコードを作成し、CloudFront に紐付けます。

1. **AWS Route 53 コンソールにアクセス**  
   [Route 53 コンソール](https://console.aws.amazon.com/route53/) にアクセスします。
2. **ホストゾーンを選択**  
   CloudFront で使用するドメインのホストゾーン（例: `example.com`）を開きます。
3. **レコードを作成**  
   「Create record」ボタンをクリックします。
4. **レコードタイプを選択**
   - **レコードタイプ**: `A - IPv4 address` を選択
   - **エイリアスを有効にする**: `Yes` を選択
   - **エイリアスターゲット**: `Alias to CloudFront distribution` を選択し、手順 2 で確認した CloudFront のドメイン名を選択
5. **レコード名を入力**
   - ルートドメイン (`example.com`) を使用する場合 →（空欄のまま）
   - サブドメイン (`www.example.com` など) を使用する場合 → `www` を入力
6. **レコードを作成**  
   「Create records」ボタンをクリックして作成します。

#### 3.5.4 DNS の伝播を待つ

Route 53 の A レコードが作成されると、DNS の伝播が始まります。  
伝播には数分から数十分かかることがあります。  
以下の方法で DNS の伝播を確認できます。

- 方法 1: `nslookup` コマンドを使用

```sh
nslookup example.com
```

CloudFront のドメイン (`d123456789.cloudfront.net`) に正しく解決されていれば成功です。

- 方法 2: `dig` コマンドを使用

```sh
dig example.com
```

回答セクション (`ANSWER SECTION`) に CloudFront のドメインが表示されていれば成功です。

#### 3.5.5 動作確認

1. **ブラウザで `https://example.com` にアクセス**

   - 正しく CloudFront に転送されるか確認。
   - CloudFront Functions の処理（Basic 認証など）が動作するか確認。

2. **エラーメッセージが表示される場合**
   - 403 エラー → **CloudFront のオリジン設定が正しいか確認**
   - 404 エラー → **Route 53 のレコード設定が正しいか確認**
   - 503 エラー → **CloudFront のステータスが「Deployed」になっているか確認**

#### 3.5.6 トラブルシューティング

| 問題                              | 原因                                   | 解決策                                                  |
| --------------------------------- | -------------------------------------- | ------------------------------------------------------- |
| CloudFront にアクセスできない     | DNS の伝播が完了していない             | 伝播が完了するまで待つ（最大 24 時間）                  |
| 403 Forbidden エラー              | CloudFront の OAC 設定が間違っている   | S3 のバケットポリシーを確認する                         |
| CloudFront Functions が動作しない | 関数が適用（パブリッシュ）されていない | CloudFront の設定を確認し、デプロイ、パブリッシュし直す |

### 3.6. Basic 認証の動作確認

CloudFront ディストリビューションに Basic 認証を設定した後、正しく動作するか確認します。

#### 3.6.1 ブラウザでアクセスして確認

1. **CloudFront のドメインにアクセス**  
   `https://<CloudFrontのドメイン>/` にブラウザでアクセスします。
2. **認証ダイアログが表示されるか確認**  
   Basic 認証が正しく設定されていれば認証情報入力用のポップアップが表示されます。

3. **認証情報を入力**  
   設定した **ユーザー名とパスワード** を入力し、「OK」または「ログイン」をクリックします。
4. **コンテンツが正しく表示されることを確認**  
   認証成功後、S3 の静的コンテンツが表示されれば OK です。

#### 3.6.2 認証失敗の動作確認

誤った認証情報を入力した際の挙動も確認します。

1. **間違ったユーザー名またはパスワードを入力**

   - ユーザー名を間違える (`wrong_user`)
   - パスワードを間違える (`wrong_password`)

2. **エラーメッセージを確認**
   - **401 Unauthorized** エラーが返ることを確認
   - 一定回数（通常は 3 回）間違えると、再びログイン画面が表示されないか確認

#### 3.6.3 curl コマンドで確認（CLI 環境向け）

ターミナルで `curl` コマンドを使用し、Basic 認証の動作を確認できます。

### **3.1 正しい認証情報でアクセス**

```sh
curl -u ユーザー名:パスワード https://<CloudFrontのドメイン>/
```

成功すると、HTML のレスポンスが返ります。

### **3.2 誤った認証情報でアクセス**

```sh
curl -u wrong_user:wrong_password https://<CloudFrontのドメイン>/
```

失敗すると、以下のような 401 エラーが表示されます。

```
HTTP/1.1 401 Unauthorized
```

#### 3.6.4 ブラウザキャッシュの影響を確認

Basic 認証はブラウザのキャッシュに保存されるため、ログアウトしたい場合は以下の方法でキャッシュをクリアします。

##### **方法 1: `chrome://settings/clearBrowserData` でキャッシュ削除**

1. Chrome のアドレスバーに `chrome://settings/clearBrowserData` を入力し、Enter。
2. 「パスワードとその他のログインデータ」を選択し、「データを削除」。

##### **方法 2: `curl` で認証情報なしのリクエストを送る**

```sh
curl -I https://<CloudFrontのドメイン>/
```

401 エラーが返れば、キャッシュがクリアされていることを確認できます。