【AWS×Webアプリ】CloudFront+Basic認証（Terraform）

## 目的
・AWS上の静的Webサイトホスティングを有効にしたS3をCloudFrontで公開。
・Basic認証を実装。

## 前提条件
・Terraformを使用してAWS上にリソースを作成する。
・Amazon CloudFront KeyValueStore＋CloudFront Functionsを使用して実装する。
・作成する内容は以下と同様

https://qiita.com/Haruki-N/items/89792a38e0febdeecb6e

## TFファイル
```terraform:aws_cloudfront.tf（前回からの追加箇所のみ抜粋）
resource "aws_cloudfront_distribution" "WebBucketDistribution" {
  enabled = true
  default_root_object = "index.html"
  price_class = "PriceClass_200"

  origin {
    origin_id                = "WebBucketOrigin"
    domain_name              = aws_s3_bucket.WebBucket.bucket_regional_domain_name
    origin_access_control_id = aws_cloudfront_origin_access_control.WebBucketOriginAccessControl.id
  }

  viewer_certificate {
    cloudfront_default_certificate = true
  }

  default_cache_behavior {
    target_origin_id       = "WebBucketOrigin"
    viewer_protocol_policy = "redirect-to-https"
    compress = true
    cached_methods         = ["GET", "HEAD"]
    allowed_methods        = ["GET", "HEAD"]

    cache_policy_id = aws_cloudfront_cache_policy.WebBucketCachePolicy.id
    origin_request_policy_id = aws_cloudfront_origin_request_policy.WebBucketOriginRequestPolicy.id

    function_association {
      event_type   = "viewer-request"
      function_arn = aws_cloudfront_function.WebBucketBasicAuthFunction.arn
    }
  }

  restrictions {
    geo_restriction {
      restriction_type = "none"
    }
  }
}

resource "aws_cloudfront_function" "WebBucketBasicAuthFunction" {
  name    = "WebBucketBasicAuthFunction"
  runtime = "cloudfront-js-2.0"
  publish = true
  code    = file("${path.module}/cloudfront_function/WebBucketBasicAuthFunction.js")
  key_value_store_associations = [aws_cloudfront_key_value_store.WebBucketBasicAuthKVS.arn]
}
```

```terraform:aws_cloudfront_kvs.tf

resource "aws_cloudfront_key_value_store" "WebBucketBasicAuthKVS" {
  name    = "WebBucketBasicAuthKVS"
}

resource "aws_cloudfrontkeyvaluestore_key" "Test_User1" {
  key_value_store_arn = aws_cloudfront_key_value_store.WebBucketBasicAuthKVS.arn
  key                 = "Test_User1"
  value               = "Password1"
}

resource "aws_cloudfrontkeyvaluestore_key" "Test_User2" {
  key_value_store_arn = aws_cloudfront_key_value_store.WebBucketBasicAuthKVS.arn
  key                 = "Test_User2"
  value               = "Password2"
}
```

◆aws_cloudfront.tf
・WebBucketDistribution（function_association）：CloudFront Functionの呼び出しを追加
・WebBucketBasicAuthFunction：Basic認証を行うCloudFront Functionの設定


◆aws_cloudfront_kvs.tf
・WebBucketBasicAuthKVS：CloudFront KeyValueStore
・Test_User1：KeyValueStoreに登録する情報１
・Test_User2：KeyValueStoreに登録する情報２

## 動作確認
①コンソールよりKeyValueStoreのIDを関数に設定し、変更を保存および関数の発行を実施
```javascript:WebBucketBasicAuthFunction
import cf from 'cloudfront';
const kvsId = 'KeyValueStoreのIDを設定';
const kvsHandle = cf.kvs(kvsId);
async function handler(event) {
    const request = event.request;
    const headers = request.headers;
    if (
    typeof headers.authorization === 'undefined' ||
    typeof headers.authorization.value === 'undefined'
    ) {
    return return401();
    }
    const encoded = headers.authorization.value.split(' ')[1];
    const decoded = Buffer.from(encoded, 'base64').toString();
    const userRequest = decoded.split(':')[0];
    const passRequest = decoded.split(':')[1];
    const exist = await kvsHandle.exists(userRequest);
    if (!exist) {
    return return401();
    }
    const passStore = await kvsHandle.get(userRequest);
    if (passStore !== passRequest) {
    return return401();
    }
    return request;
}
const return401 = () => {
    return {
    statusCode: 401,
    statusDescription: 'Unauthorized',
    headers: { 'www-authenticate': { value: 'Basic' } },
    };
};
```

※Terrformでのリソース作成時にKeyValueStoreのIDを設定できないため


②Webサイトへアクセス
・ユーザ名とパスワードが要求されることを確認
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3637963/ef3fd6fc-2f23-028d-6c4c-b147efa5d27b.png)

③正しいユーザで認証されることを確認１
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3637963/d51f227c-ca9e-e945-4210-f25e6d708b91.png)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3637963/ce755234-4e40-ca95-df61-721c06d8fcc8.png)

④正しいユーザで認証されることを確認２
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3637963/10e88648-4b7c-9ab3-6ca9-29a3b09ceeb2.png)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3637963/ce755234-4e40-ca95-df61-721c06d8fcc8.png)

⑤未登録のユーザ・誤ったパスワードでの認証が失敗することを確認
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3637963/cfa0c189-cd35-658f-243b-25f8776ebb44.png)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3637963/fdda107b-e15c-c830-e2dc-8ba108968c53.png)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3637963/a739e627-9e1a-5818-d2d3-99e7cec2da65.png)

## 参考（前回記事）
https://qiita.com/Haruki-N/items/63799208a4a7050d0e57