Carpe Diem

備忘録。https://github.com/jun06t

SPAを S3+CloudFront で表示する方法

概要

AngularなどのSPAをS3+CloudFrontで表示する方法についてです。

要件

  1. SSL/TLSを使いたい
  2. https://example.com/hoge のようなサブディレクトリのようなパスで403にならないようにしたい
  3. ↑のようなパスでもOGPがきちんと表示される
  4. リロードしても404にならない
  5. S3バケットのファイルには直接アクセスできないようにしたい

以前のケースとの比較

過去に

S3 + CloudFrontにした時にハマったこと - Carpe Diem
Angularで作ったサイトでリロードすると404エラー - Carpe Diem

で似たようなケースに対応しました。しかしこれらは先の要件である

3. ↑のようなパスでもOGPがきちんと表示される

5. S3バケットのファイルには直接アクセスできないようにしたい

を満たせていませんでした。今回はそちらを考慮します。前提として

S3 + CloudFrontにした時にハマったこと - Carpe Diem

を行った後として進めます。

S3の設定

Static web hosting

Static web hostingをOFFにしておきます。

f:id:quoll00:20170525094540p:plain

CloudFrontの設定

Origins

OriginsをStatic web hostingからS3 Bucketに変更します。

f:id:quoll00:20170525094916p:plain

その際にポイントなのがRestrict Bucket AccessをONにすることです。これでS3側のオブジェクトに別途権限を与えない限り、CloundFront経由のアクセスしかファイルにアクセスできなくなります。
つまり5. S3バケットのファイルには直接アクセスできないようにしたいを保証できます。

これを設定すると、S3側では以下のようにバケットポリシーが自動で追加されます。

f:id:quoll00:20170525101102p:plain

テキストに書き出すと以下です。

{
    "Version": "2008-10-17",
    "Id": "PolicyForCloudFrontPrivateContent",
    "Statement": [
        {
            "Sid": "1",
            "Effect": "Allow",
            "Principal": {
                "AWS": "arn:aws:iam::cloudfront:user/CloudFront Origin Access Identity xxxxxxxxx"
            },
            "Action": "s3:GetObject",
            "Resource": "arn:aws:s3:::バケット名/*"
        }
    ]
}

Error Pages

ただこのままだと

https://example.com/hoge のようなパスで403にならないようにしたい
リロードしても404にならない

が満たせなくなります。そこで Angularで作ったサイトでリロードすると404エラー - Carpe Diem でエラー時のドキュメントを指定したように、CFでもError Pagesに設定をします。

f:id:quoll00:20170525095905p:plain

403, 404で設定をすると以下のようになります。

f:id:quoll00:20170525100035p:plain

まとめ

以前構築したケースでは満たせていなかった要件を解決しました。
S3のエラーページは便利だったのですが、HTTPステータスコード自体は403や404が返ってしまい、OGPが表示されませんでした。
今回の対応でそれが解消されました。

ソース