Hugo + CloudFront + S3 + GitHub Actions でCI/CD付きブログサイトを構築してみる Part2-2 作成するリソースの確認 CloudFront

## 作成経緯
https://qiita.com/Tanamachi_kaoru/items/ade2c4822817d3d80d87

https://qiita.com/Tanamachi_kaoru/items/0686b3a451a5d86d9196

この続き。
参考サイトからcloudformationで作成している部分の要素をterraformに落とし込むため、確認を行う。
今回はCloudFrontを確認します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/185852/b017d04e-b7b4-c304-eef1-6d3a7cd9d9f1.png)
この記事はそのメモやまとめです。
すでに設定済みの項目がいくつかある。
試行錯誤しながらやったので、手順として不要かもしれない。**あくまでメモ用。**


# CloudFront
[参考サイト](https://dev.classmethod.jp/articles/cloudfront-and-s3-using-hugo-with-github-actions/)のCFでは以下のような記載になっている。
今回もひと要素づつ分解して見ていく。
<details>
<summary>CloudFront</summary>

```
  CloudFrontDistribution:
    Type: "AWS::CloudFront::Distribution"
    Properties:
      DistributionConfig:
        PriceClass: PriceClass_All
        Origins:
          - DomainName: !Sub ${ProjectName}-${Environment}-${S3BucketName}-${AWS::AccountId}.s3.${AWS::Region}.amazonaws.com
            Id: !Sub "S3origin-${ProjectName}-${Environment}-${S3BucketName}-${AWS::AccountId}"
            S3OriginConfig:
              OriginAccessIdentity: !Sub "origin-access-identity/cloudfront/${CloudFrontOriginAccessIdentity}"
        DefaultRootObject: index.html
        DefaultCacheBehavior:
          TargetOriginId: !Sub "S3origin-${ProjectName}-${Environment}-${S3BucketName}-${AWS::AccountId}"
          Compress: true
          ViewerProtocolPolicy: redirect-to-https
          # CachePolicyId: 658327ea-f89d-4fab-a63d-7e88639e58f6 # CachingOptimized
          CachePolicyId: 4135ea2d-6df8-44a3-9df3-4b5a84be39ad # CachingDisabled
          AllowedMethods:
            - GET
            - HEAD
          CachedMethods:
            - GET
            - HEAD
          ForwardedValues:
            Cookies:
              Forward: none
            QueryString: false

        Logging:
          Bucket: !GetAtt S3BucketLogs.DomainName
          IncludeCookies: false
        Aliases:
          - !Ref AliasName
        ViewerCertificate:
          SslSupportMethod: sni-only
          MinimumProtocolVersion: TLSv1.2_2021
          AcmCertificateArn: !Sub "arn:aws:acm:us-east-1:${AWS::AccountId}:certificate/${CertificateId}"
        HttpVersion: http2
        IPV6Enabled: true
        Enabled: true
  # OAI
  CloudFrontOriginAccessIdentity:
    Type: AWS::CloudFront::CloudFrontOriginAccessIdentity
    Properties:
      CloudFrontOriginAccessIdentityConfig:
        Comment: Unique Domain Hosting Environment
```

</details>

# そもそもCloudFrontってなんだ？
AWS認定の試験対策として何度か学習はしているが仕事でも自分が触れる機会がなく、実際に触っていなかったのでCDNなんだな～とある程度の機能しか把握していなかったので、今一度AWS公式ドキュメントを読んで理解する。

https://docs.aws.amazon.com/ja_jp/AmazonCloudFront/latest/DeveloperGuide/Introduction.html

https://dev.classmethod.jp/articles/2022_cloudfront_introduction/

しっかりと読んでわかったこと。
- CloudFrontを作成するのではなく、CloudFront ディストリビューションを作成して、コンテンツを配信する場所と、コンテンツ配信の追跡と管理の方法の詳細を CloudFront に指示する

つまり今回作成するのはCloudFront ディストリビューションということになる。
概要欄にCloudFront ディストリビューションを構成する要素が書いてあったのでこれを記載すればいいと思う。

https://docs.aws.amazon.com/ja_jp/AmazonCloudFront/latest/DeveloperGuide/distribution-overview.html

## 大まかな要素の把握。
```
  CloudFrontDistribution:
    Type: "AWS::CloudFront::Distribution"
    Properties:　★
      DistributionConfig:~~~~　★
    CloudFrontOriginAccessIdentity:~~~~　◆
```
★と◆の2つから構成されているようです
まずは`Properties`について確認してきます。

## PriceClass
価格クラスを定義している。
このエッジロケーションの範囲が広ければ広いほど高く、狭いと安くなる。
今回は日本だけに配信できればいいので`料金クラス 200`がよさそう。
```
PriceClass: PriceClass_All
```

https://docs.aws.amazon.com/ja_jp/AmazonCloudFront/latest/DeveloperGuide/PriceClass.html

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/185852/9aa81748-ec1d-e011-f988-8040f4bc219b.png)

## Origins
オリジンの指定を定義している。
### DomainName
オリジンとするリソースを定義します。
参考サイトではs3を指している。s3の場合は`bucket-name.s3.amazonaws.com`のように記載を行う。
その他をオリジンにする場合は以下を参照するとわかりやすい。

https://docs.aws.amazon.com/ja_jp/AmazonCloudFront/latest/DeveloperGuide/DownloadDistS3AndCustomOrigins.html#concept_S3Origin

### Id
オリジンの名前を定義しています。
### S3OriginConfig
OriginAccessIdentity(OAI)の設定を行います

https://docs.aws.amazon.com/ja_jp/AWSCloudFormation/latest/UserGuide/aws-properties-cloudfront-distribution-s3originconfig.html

しかし前回も記載しましたがOriginAccessControl(OAC)を利用するのでこの記載は不要です。
`OriginAccessControlId`へ移行してあげます。
後に記述されている`CloudFrontOriginAccessIdentity`も`CloudFrontOriginAccessControl`へ移行して上げる必要があります。

https://qiita.com/hayao_k/items/8558042d52be4f29c6e6#distribution-origin-の修正

https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-cloudfront-distribution-origin.html


![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/185852/411b664f-8c75-6f32-4d9e-c61906db4d21.png)

## DefaultRootObject
> CloudFrontの機能でデフォルトルートオブジェクトというものがあります。 エンドユーザがディストリビューションのルートURLを指定した場合に特定のオブジェクトを返すようにする機能です。

https://dev.classmethod.jp/articles/cloudfront_s3_difference/

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/185852/55fe5af7-d19f-d779-b6d2-0160273d4d44.png)
## DefaultCacheBehavior
キャッシュの設定のようです。
CacheBehaviorがわからなかったので、調べてみましたがよくわかりませんでした……。

https://docs.aws.amazon.com/ja_jp/AWSCloudFormation/latest/UserGuide/aws-properties-cloudfront-distribution-defaultcachebehavior.html

https://note.com/mtng420/n/n84419b378cb4

こちらのサイトに記載がある項目の設定項目なのでしょうか……。
- キャッシュの動作（キャッシュの有効期限、キャッシュしないオブジェクトの指定、等）
- セキュリティ設定（署名付きURLの使用、許可されたHTTPメソッドの指定、等）
- エラー処理（エラー時の挙動の指定、等）
- リクエストのルーティング（オリジンサーバーの選択、パスのリライト、等）

要素が多いのでまた細かく分解していきます。AWSの公式ドキュメント上の記載と翻訳も記載します。
### TargetOriginId
ターゲットのオリジンのIDです。

> The value of ID for the origin that you want CloudFront to route requests to when they use the default cache behavior.
> CloudFrontがデフォルトのキャッシュ動作を使用する際に、リクエストをルーティングさせたいオリジンのIDの値です。
### Compress
> Whether you want CloudFront to automatically compress certain files for this cache behavior. If so, specify true; if not, specify false.
> このキャッシュの動作のために、CloudFrontが特定のファイルを自動的に圧縮するかどうか。必要な場合はtrueを、必要でない場合はfalseを指定します。
### ViewerProtocolPolicy
> The protocol that viewers can use to access the files in the origin specified by TargetOriginId when a request matches the path pattern in PathPattern.
> PathPatternのパスパターンに合致するリクエストがあった場合に、TargetOriginIdで指定されたオリジンのファイルにアクセスするためにビューアが使用できるプロトコルを指定します。

httpsへリダイレクトさせたいので`redirect-to-https`にしたいと思います。
### CachePolicyId
キャッシュポリシーを選択します。
参考サイトでは
```
          # CachePolicyId: 658327ea-f89d-4fab-a63d-7e88639e58f6 # CachingOptimized
          CachePolicyId: 4135ea2d-6df8-44a3-9df3-4b5a84be39ad # CachingDisabled
```
のように記載されていました。
コンソールで確認するとこれはデフォルトで用意されているもので、「ポリシーを表示」からIDも確認できました。
めちゃくちゃざっくりいうとこの2つでキャッシュのON/OFFを切り替えているようです。
### AllowedMethods/CachedMethods
AllowedMethods
> A complex type that controls which HTTP methods CloudFront processes and forwards to your Amazon S3 bucket or your custom origin. There are three choices:
> CloudFrontがどのHTTPメソッドを処理し、Amazon S3バケットまたはカスタムオリジンに転送するかを制御する複合型です。選択肢は3つあります：

CachedMethods
> A complex type that controls whether CloudFront caches the response to requests using the specified HTTP methods. There are two choices:
> CloudFrontが指定されたHTTPメソッドを使用したリクエストに対するレスポンスをキャッシュするかどうかを制御する複合型です。選択肢は2つあります：

読んでのとおりだと思います。
静的サイトなのでGETとHEADの組み合わせで十分ですね。
### ForwardedValues
> A DefaultCacheBehavior must include either a CachePolicyId or ForwardedValues. We recommend that you use a CachePolicyId.
> CloudFrontがクエリ文字列、クッキー、HTTPヘッダをどのように扱うかを指定する複合型です。

とありますが、公式でこのパラメーターは現在非推奨のようです。
設定したい場合は「キャッシュポリシーまたはオリジンリクエストポリシーを利用してね」とのこと。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/185852/db2c75cc-517c-4134-453d-39aad8201430.png)

## Logging
Cloudfrontのログの格納先の指定です。
クッキーも含めるかの設定もあります。
```
          Bucket: !GetAtt S3BucketLogs.DomainName
          IncludeCookies: false
```
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/185852/473891b3-9683-df2e-ceb1-291f4b371bd7.png)
## Aliases
独自ドメインの設定項目です。
すでにドメインは取得していますので、ここにドメインを記載します。

https://qiita.com/kanadeee/items/752e20af5b071ef0e011


![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/185852/9e4b7449-5429-3efa-54e9-0ca30fb29e83.png)
## ViewerCertificate
証明書の設定です。

https://docs.aws.amazon.com/ja_jp/AWSCloudFormation/latest/UserGuide/aws-properties-cloudfront-distribution-viewercertificate.html

証明書のARN以外このまま利用がよさそうです。
```
          SslSupportMethod: sni-only
          MinimumProtocolVersion: TLSv1.2_2021
          AcmCertificateArn: !Sub "arn:aws:acm:us-east-1:${AWS::AccountId}:certificate/${CertificateId}"
```
コンソールでは証明書を選択するとversionなどの設定を選べるようになります。
## HttpVersion
httpのversionを指定します。
2が主流で3も選択できますが、3を選択することでどのようなメリット/デメリットがあるのか理解していません。
ちょっと調べてみましたが、それでも理解できませんでした。
2で進めます……。
## IPV6Enabled
IPv6を利用するかの設定です。
## Enabled
DistributionConfig:内のディスティネーションを有効化する項目です。
必須項目。
## CloudFrontOriginAccessIdentity
OAIの設定です。
前述で記載しましたが、今はOACが推奨なのでそれに移行します。
```
  # OAI
  CloudFrontOriginAccessIdentity:
    Type: AWS::CloudFront::CloudFrontOriginAccessIdentity
    Properties:
      CloudFrontOriginAccessIdentityConfig:
        Comment: Unique Domain Hosting Environment
```
このあたりの記事が役に立ちそうでした。

https://zenn.dev/kou_pg_0131/articles/tf-cloudfront-oac

# 別途追加したいと思っている項目
特に全世界に公開する必要はないので、日本からのアクセスのみ許可するよう地域制限を設定する予定です。
できるだけコストをかけないようにしたいだけです……。

https://dev.classmethod.jp/articles/lim-cloudfront-security/

# ちょっと思ったこと
まだ理解していないことが多いので、リソース作成はterraformではなくCFnで作成したほうが学習になるのかな……？と思っている。この前受験理点数に届かなかったAWSの認定試験でもCFn部分があまり満足にできていなかった。
ただ、個人的にCFnファイルのめちゃくちゃ長い記載方法があまり好きではなく、リソースとファイルを1対1で利用した思いもある。
とりあえず現段階ではそのまま当時の考え通りterraformでのリソース作成を考えている。

# ハマったところとか
知らないことだらけなので、調べるだけでもかなり時間がかかった。

# 次にやること
- cloudforntログ保存用s3バケットのcfファイルの分解
- 必要なAWSのリソースをterraformで作成
- HUGOでHPをいい感じに編集する
- GitHub Actionsの設定