【AWS】HTTPSでS3上のWebページにアクセス

2021/11/6　一部手順を修正

#はじめに
独自ドメインでS3上のWebページにHTTPSでアクセスできるように構成していきます。
独自ドメインでのアクセスとするためにCloudFront経由での構成とします。
また、CloudFront - S3バケット間もHTTPS通信とするためにS3バケットではウェブサイトエンドポイントを使用せずにREST API エンドポイントを使用します。

https://aws.amazon.com/jp/premiumsupport/knowledge-center/cloudfront-serve-static-website/

また、S3のURLに直接アクセスしてもWebページが表示されないようにするためにオリジンアクセスアイデンティティ(OAI)を使用してアクセス制御をしていきます。

https://docs.aws.amazon.com/ja_jp/AmazonCloudFront/latest/DeveloperGuide/private-content-restricting-access-to-s3.html

証明書にはACM(AWS Certificate Manager)を使用します。

#構成図
以下のような構成を目指します。
![diagram01.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1410257/142d3837-6ce8-a4d8-6edd-5c6eb7aba3a4.png)

#ドメイン取得/ホストゾーン作成
静的ウェブサイトの構成を進める前にドメインを取得し、Route 53でホストゾーンを作成しておきます。
手順については以下の記事を参照してください。

https://qiita.com/zeems/items/b5f6b38464158dce0166#%E3%83%89%E3%83%A1%E3%82%A4%E3%83%B3%E5%8F%96%E5%BE%97

#S3バケット 作成/ファイルアップロード
S3バケットを作成し、Webページを構成するファイルをアップロードします。
基本的な手順は以下の記事を参照してください。
※今回は静的ウェブサイトホスティング機能は有効化しません。

https://qiita.com/zeems/items/b5f6b38464158dce0166#sorry%E3%83%9A%E3%83%BC%E3%82%B8%E7%94%A8s3%E3%83%90%E3%82%B1%E3%83%83%E3%83%88-%E4%BD%9C%E6%88%90%E8%A8%AD%E5%AE%9A

参照記事ではバケット名としてサブドメイン名としていましたが、今回は任意の名前でOKです。
また、単体のHTMLファイルを参照するのみでしたが、今回はCSS, JavaScriptを使用した簡易的なWebページをアップロードしてみます。
ボタンをクリックしたら文字色が変わるだけのページです。

```html:index.html
<!doctype html>
<html lang="ja">
<head>
    <meta charset="UTF-8">
    <title>Test Website</title>
    <link rel="stylesheet" href="css/style.css">
</head>
<body>
    <div class="main">
        <h1>S3静的Webページ テスト</h1>
        <p class="text-red" id="text">ボタンをクリックすると文字色が変わります。</p>
        <input type="button" value="Change" id="btn">
    </div>

    <script src="js/main.js"></script>
</body>
</html>
```

```css:style.css
h1 {
    color: #FF9900;
}

.text-red {
    color: red;
}

.text-green {
    color: green;
}
```

```javascript:main.js
let text = document.getElementById("text");
let btn = document.getElementById("btn");

btn.onclick = function(){
    if(text.className == "text-red"){
        text.className = "text-green";
    } else {
        text.className = "text-red";
    }
};
```
S3バケットにアップロードした index.html のオブジェクトURLにアクセスすると静的Webページにアクセスすることができます。
現時点では誰からでもアクセスできる状態となっています。

#証明書 リクエスト
CloudFront経由でのアクセスを構成する前に証明書を作成しておきます。
CloudFrontに構成する証明書はバージニア北部リージョンで作成する必要がありますので、リージョンをバージニア北部に変更しておきます。
![スクリーンショット 2021-10-30 11.31.27.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1410257/db379b69-f84f-30e6-2dc8-38ab1343310a.png)

ACM管理画面の左メニューで[証明書をリクエスト]を選択後、`証明書タイプ`で[パブリック証明書をリクエスト]を選択し、[次へ]をクリックします。
![スクリーンショット 2021-10-30 11.31.58.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1410257/5995babf-4ed2-7eb6-c48f-237ce820adbd.png)

`完全修飾ドメイン名`にCloudFrontにアクセスする際のサブドメイン名を入力、`検証方法を選択`で[DNS 検証]を選択し、[リクエスト]をクリックします。
![スクリーンショット 2021-10-30 11.32.28.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1410257/b810407f-2f53-8c3f-6e16-e3ba6b06c5c5.png)

リクエストされた証明書をクリックし、`ドメイン`内の[Route 53 でレコードを作成]をクリックします。
![スクリーンショット 2021-10-30 11.34.06.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1410257/78858d38-9a0a-4a2c-b49b-d58f7946fa04.png)

:::note info
レコード作成ができるようになるまでに少し時間がかかる場合があります。
:::

[レコードを作成]をクリックします。
![スクリーンショット 2021-10-30 11.34.33.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1410257/6473add6-ea50-9583-7111-fc46011e6919.png)

Route 53管理画面でCNAMEレコードが追加されていることを確認します。
![スクリーンショット 2021-10-30 11.35.07.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1410257/122fa7f1-e138-da28-7902-2c0e50b6f840.png)

#CloudFront 構成
証明書が作成できたら、次にCloudFront経由でのアクセスを構成していきます。
CloudFront管理画面で[ディストリビューション]を選択し、[ディストリビューションを作成]をクリックします。
![スクリーンショット 2021-10-30 11.36.08.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1410257/2f0b7b88-301d-a09d-b0b8-1edd598161f5.png)

設定値を入力し、[ディストリビューションを作成]をクリックします。
今回は以下の設定値を使用します。
※OAIは別途作成するためこのウィザード内では作成しません。
※以下に記載のない設定値はデフォルトとします。

| 項目名 | 設定値 |
|:-----------:|:------------:|
| オリジンドメイン       | 作成したS3バケット         |
| S3 バケットアクセス     | OAI を使用しません        |
| ビューワープロトコルポリシー     | HTTPS only        |
| 代替ドメイン名 (CNAME)      | CloudFrontにアクセスする際のサブドメイン名         |
| カスタム SSL 証明書      | 作成したACM証明書         |
| デフォルトルートオブジェクト      | index.html         |

作成したディストリビューションのドメイン名である`ディストリビューションドメイン名`が自動的に付与され、そのドメイン名でHTTPSアクセスすることができますが、代替ドメイン名に指定したサブドメインではDNSレコードが存在しないためアクセスできない状態です。

続けて、サブドメインでのアクセスができるようにDNSレコードを作成していきます。

#DNSレコード 作成
事前に作成したホストゾーンでCloudFrontにアクセスするためのレコードを追加します。
レコード作成手順は以下の記事を参照してください。

https://qiita.com/zeems/items/b5f6b38464158dce0166#dns%E3%83%AC%E3%82%B3%E3%83%BC%E3%83%89-%E4%BD%9C%E6%88%90

今回は`ルーティングポリシー`を[シンプルルーティング]で作成します。
その他の設定値は以下を使用します。

| 項目名 | 設定値 |
|:-----------:|:------------:|
| レコード名       | CloudFront ディストリビューション作成時に指定した代替ドメイン名         |
| レコードタイプ     | A        |
| 値/トラフィックのルーティング先      | CloudFront ディストリビューションのエイリアス         |
| CloudFront ディストリビューション      | 作成したディストリビューション         |

:::note warn
レコード名に入力する値とディストリビューションで指定した代替ドメイン名が一致しないと、ディストリビューションの選択ができません。
:::

#アクセス確認
DNSレコードの作成が完了したら、ブラウザで`https://<サブドメイン名>`にアクセスします。
HTTPSを使用して、S3上のWebページにアクセスすることができます。

ただし、このままでは index.html のオブジェクトURLを直接指定してWebページにアクセスできる状態です。
CloudFrontのOAI(オリジンアクセスアイデンティティ)を設定して制限をかけていきます。

#OAI 設定
CloudFrontの特別なユーザーであるOAIを作成し、OAIに対してのみS3バケットへのアクセスを許可するようにバケットポリシーを構成していきます。
作成したディストリビューションの詳細画面で[オリジン]タブを開き、オリジンを選択し、[編集]をクリックします。
![スクリーンショット 2021-10-30 12.01.19.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1410257/8f4a956d-8958-b1e8-b7a3-db63efb72206.png)

`S3 バケット アクセス`で[はい、OAI を使用します]を選択し、[新しい OAI を作成]をクリックします。
![スクリーンショット 2021-10-30 12.01.44.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1410257/c4070f84-8314-0050-f1c6-c9786c1c8104.png)

デフォルト値のまま[作成]をクリックします。
※画像では消していますが、本来はデフォルト値が表示されます。
![スクリーンショット 2021-10-30 12.02.11.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1410257/36c2c6cd-22de-3d06-f2a2-b0d034bed657.png)

編集ウィザードに戻り、`オリジナルアクセスアイデンティティ`に作成したOAIが選択されることを確認し、`バケットポリシー`で[はい、バケットポリシーを自動で更新します。]を選択後、[変更を保存]をクリックします。
※画像では消していますが、自動的に作成したOAIが選択されます。
![スクリーンショット 2021-10-30 12.03.15.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1410257/65490e9e-e2ca-821e-0956-6cb9cd56b0ff.png)

S3バケット詳細画面で[アクセス許可]タブを開き、`バケットポリシー`を確認すると、OAIへのアクセス許可を示すポリシーが自動的に追加されていることが確認できます。

```bash:BacketPolicyEditor
{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Sid": "PublicReadGetObject",
            "Effect": "Allow",
            "Principal": "*",
            "Action": "s3:GetObject",
            "Resource": "arn:aws:s3:::zeems-website/*"
        },
        {
            "Sid": "2",
            "Effect": "Allow",
            "Principal": {
                "AWS": "arn:aws:iam::cloudfront:user/CloudFront Origin Access Identity E3SK4IDOTT1YJ1"
            },
            "Action": "s3:GetObject",
            "Resource": "arn:aws:s3:::zeems-website/*"
        }
    ]
}
```

はじめに設定していたすべて(*)に対して許可しているポリシーを外さないと、今まで通りオブジェクトURLからアクセスできてしまうので、OAIに対する許可ポリシーのみに修正します。

```bash:BacketPolicyEditor
{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Sid": "2",
            "Effect": "Allow",
            "Principal": {
                "AWS": "arn:aws:iam::cloudfront:user/CloudFront Origin Access Identity E3SK4IDOTT1YJ1"
            },
            "Action": "s3:GetObject",
            "Resource": "arn:aws:s3:::zeems-website/*"
        }
    ]
}
```

また、パブリックアクセスを無効化します。
S3バケット詳細画面で[アクセス許可]タブを選択し、`ブロックパブリックアクセス (バケット設定)`の[編集]をクリックします。
![スクリーンショット 2021-11-06 17.10.04.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1410257/d90b39b6-e634-c9c1-d0d8-c8745f59f737.png)

[パブリックアクセスをすべてブロック]にチェックを入れ、[変更の保存]をクリックします。
![スクリーンショット 2021-11-06 17.10.18.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1410257/757b261c-a72a-e8de-851c-cf5ba49b2d9b.png)

フィールドに「確認」と入力し、[確認]をクリックします。
![スクリーンショット 2021-11-06 17.19.23.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1410257/8e14b6c6-33d8-24e3-8d94-dc2b37d991c4.png)

これでオブジェクトURL直接ではアクセスできない状態になりました。

#あとがき
この記事は CloudTech の課題として作成しました。
動画やハンズオン等で学習を進めることができるので、AWS初学者にはおすすめです。

https://kws-cloud-tech.com