CloudfrontとS3でBasic認証をかける


## S3 bucketの作成
まずはhtmlファイル等を格納するS3のbucketを作成します。
Cloudfrontから配信するのでパブリックアクセス許可やStatic website hostingの設定は不要です。


## lambda関数の作成
次にBasic認証を処理するlambda関数を作成します。
この時、右上のリージョン設定で「バージニア北部」を選択してから「関数の作成」をしてください。

![スクリーンショット 2018-02-07 14.31.16.png](https://qiita-image-store.s3.amazonaws.com/0/37255/a896c84b-eb78-5316-dc3c-3117ac88a8b6.png "スクリーンショット 2018-02-07 14.31.16.png")

名前に"BasicAuthentication"（任意の名前）
ランタイムはNode.js 6.10を選択
ロールは"テンプレートから新しいロールを作成"を選択
ロール名には"lambda_edge_exection"（任意の名前）
ポリシーテンプレートは"Basic Edge Lambdaアクセス権限"を選択

関数の作成をクリックしてしばらくすると次の画面に切り替わります。

- - -

![スクリーンショット 2018-02-07 14.33.43.png](https://qiita-image-store.s3.amazonaws.com/0/37255/aaaf4f8c-2513-05d1-6cf7-02604ec1d82e.png "スクリーンショット 2018-02-07 14.33.43.png")

少しスクロールしたところの「関数コード」のエリアに以下のコードをコピペします。
9行目、10行目のauthUser、authPassでBasic認証のログイン用のIDとパスワードが設定できます。

https://gist.github.com/lmakarov/e5984ec16a76548ff2b278c06027f1a4

```lambda-basic-auth.js
'use strict';
exports.handler = (event, context, callback) => {

    // Get request and request headers
    const request = event.Records[0].cf.request;
    const headers = request.headers;

    // Configure authentication
    const authUser = 'user';
    const authPass = 'pass';

    // Construct the Basic Auth string
    const authString = 'Basic ' + new Buffer(authUser + ':' + authPass).toString('base64');

    // Require Basic authentication
    if (typeof headers.authorization == 'undefined' || headers.authorization[0].value != authString) {
        const body = 'Unauthorized';
        const response = {
            status: '401',
            statusDescription: 'Unauthorized',
            body: body,
            headers: {
                'www-authenticate': [{key: 'WWW-Authenticate', value:'Basic'}]
            },
        };
        callback(null, response);
    }

    // Continue request processing if authentication passed
    callback(null, request);
};

```

入力後、右上の「保存」ボタンをクリックして保存します。

- - -

![スクリーンショット 2018-02-07 14.37.04.png](https://qiita-image-store.s3.amazonaws.com/0/37255/497b475e-b427-fa9a-c507-aef798e2730e.png "スクリーンショット 2018-02-07 14.37.04.png")

その後、「アクション」メニューから「新しいバージョンを発行」を選択します。
出てきたポップアップの「発行」をクリックするとバージョン1として保存されます。

- - -

![スクリーンショット 2018-02-07 14.39.57.png](https://qiita-image-store.s3.amazonaws.com/0/37255/dfa5b1f3-87ee-557c-63f7-09712ae3e35a.png "スクリーンショット 2018-02-07 14.39.57.png")

保存されたら、右上に表示されているARNの値をコピーしておきます。

例）
arn:aws:lambda:us-east-1:xxxxxxxxxxxx:function:BasicAuthentication:1


## Cloudfrontの作成
次にCloudfrontのdistributionを作成します。

![スクリーンショット 2018-02-07 11.46.08.png](https://qiita-image-store.s3.amazonaws.com/0/37255/025a7ed9-80a3-a4f5-f5e2-0ca733e83abc.png "スクリーンショット 2018-02-07 11.46.08.png")
Webの方の"Get Started"をクリックします。

- - -

![スクリーンショット 2018-02-07 14.04.13.png](https://qiita-image-store.s3.amazonaws.com/0/37255/361b556a-d8c0-7807-b2ec-3b682cdfe419.png "スクリーンショット 2018-02-07 14.04.13.png")
Origin Settings
Origin Domain Nameのところに先ほど作成したS3のbucketを選択します。
Restrict Bucket AccessをYes
Origin Access IdentityをCreate a New Identity
Grant Read Permissions on BucketをYes, Update Bucket Policy
とすることで該当のbucketのPolicyがCloudfrontから読み取りできるように設定されます。

- - -

![スクリーンショット 2018-02-07 14.47.55.png](https://qiita-image-store.s3.amazonaws.com/0/37255/9323c44c-3daa-7311-a8ab-7abadf6dc2cf.png "スクリーンショット 2018-02-07 14.47.55.png")
Default Cache Behavior Settings
Object Cachingを"Customize"にして
各TTLを0にすることでキャッシュされないようになるので、テスト環境の構築時には便利です。
そして、今回の設定のポイントである「Lambda Function Associations」の部分に
Event Typeに"Viewer Request"を選択
Lambda Function ARNに先ほどコピーしたARNをペーストします。

Distribution Settingsのところで
Default Root Objectに"index.html"
と設定しておくことでroot URL（ドメイン+/で終わるURL）でアクセスした時のデフォルトファイルを設定できます。


最後に右下の「Create Distoribution」をクリックして完了を待ちます。

- - -

ここまででも使えるのですが、デフォルトの設定でエラーキャッシュが効いてしまうのでそれを無効にしておきます。

作成したDistoributionを選択して、「Error Pages」のタブで「Create Custom Error Response」をクリックします。

- - -

![スクリーンショット 2018-02-07 15.01.22.png](https://qiita-image-store.s3.amazonaws.com/0/37255/8fbea432-8bed-b93c-a96e-ae65ed91c559.png "スクリーンショット 2018-02-07 15.01.22.png")

403エラー時のTTLを0に設定

- - -

![スクリーンショット 2018-02-07 15.04.33.png](https://qiita-image-store.s3.amazonaws.com/0/37255/ecefb9f5-ddcc-912f-4623-688020d269a1.png "スクリーンショット 2018-02-07 15.04.33.png")

angular等のSPAでのルーティングをうまく利用するために404エラーはindex.htmlを開く、のようにしたい場合は
Custom Error ResponseをYes
にすることで設定可能です。
（Response Page Pathは / から始まる必要があります。）


# Basic認証を外すとき

Distoributionの「Behaviors」タブから設定されているBehaviorを選択し、Editをクリックします。

![スクリーンショット 2018-02-07 15.16.09.png](https://qiita-image-store.s3.amazonaws.com/0/37255/3ec1ca9f-cee4-a3ff-b8cb-68501d5d933b.png "スクリーンショット 2018-02-07 15.16.09.png")

Lambda Function Associationsにあるlambda functionの右のXをクリックして削除します。

右下の「Yes, Edit」をクリックします。

しばらくすると設定が反映されます。




# 参考にしたURL
https://hackernoon.com/serverless-password-protecting-a-static-website-in-an-aws-s3-bucket-bfaaa01b8666
http://blog.jicoman.info/2017/10/s3-basic-using-cloudfront-lambda-edge/