CloudFormationを使ってみる

# はじめに
[株式会社ピーアールオー（あったらいいな！を作ります）Advent Calendar 2021](https://qiita.com/advent-calendar/2021/pro-japan1) の9日目です。

codeでインフラ設定出来たらいいな。そしたらCloudFormationがありますよ！
一応あったらいいなに寄せました！笑
今回アドベントカレンダー初参加の新人エンジニアです！

最近AWS触るようになって楽しんでいますのでCloudFormationについてまとめました！


# この記事の対象者
AWS CloudFormation(以下CFn)の利用を考えている方。
又は初めてCFnで作業を行う方。

# 事前環境
AWSアカウント
vscode

# 目次
1.CFnの概要
2.S3+S3BucketPolisy+CloudFront
3.終わりに


# 1.CFnの概要（簡単に）
かなり多くの記事で取り上げられてますので今回は簡単に！
CloudFormationはAWSのサービスをコードで書いて作り上げることができるサービスです！

[ CloudFormationの公式が気になる方はこちら](https://docs.aws.amazon.com/ja_jp/AWSCloudFormation/latest/UserGuide/Welcome.html)
[【AWS】CloudFormationまとめ](https://qiita.com/iron-breaker/items/a12d1228de12663e7d32)こちらの記事も大変参考になりました！

### メリットとして簡単にまとめると
- **Infrastructure as Codeを実現する。**（差分が分かりやすい～）
- **同じ環境を簡単に作成できる。**
- スタックにまとめられていることで分かりやすい。
- 似た環境を直ぐに作り直し出来る。
- エラーの際の原因が解決しやすい？？？
- サービスの削除忘れが起きにくい（スタックを削除することで関連するサービスを削除してくれます。）
- AWSリソースを自動で構築できる。（連携部分を自動で組み合わせてくれる。）

### デメリット
初期学習のコストが高く、慣れるまで逆に時間がかかる。

# 2.S3+S3BucketPolicy+CloudFront
コマンドでデプロイなどしたい方はaws-cliをインストールしてaws configureを利用できる状態にしときましょう！
 [AWS-CLIの初期設定のメモ](https://qiita.com/reflet/items/e4225435fe692663b705)　参考になりました！

実務ではコマンドでdeployしてますが、ファイルでアップロードするほうが簡単そうなので今回はファイルで行います！笑
何を上げるか悩みましたが今回はS3をCloudFront経由でアクセスしなければならない構成を例にアウトプットしていきます！
CFnではyaml形式のテンプレートテキストを作成し、そこからスタック（サービスをまとめたようなもの）を作成してくれます。

- ファイル形式　yaml
- サービス構成　S3+S3BucketPolisy+CloudFront

以下参考になりました。
[【CloudFormation入門】5分と6行で始めるAWS CloudFormationテンプレートによるインフラ構築](https://dev.classmethod.jp/articles/cloudformation-beginner01/)


## 基本的的な構造から作成
まずはyamlファイルに以下書いていきます！絶対に必要なものは一行目のバージョンのみです。
parameterはそのままの意味ですが便利なので使いましょう。

```
AWSTemplateFormatVersion: '2010-09-09'
Parameters:
  Project:
    Type: String
    default: test
  Env:
    Type: String
    AllowedValues:
      - dev
      - stg
    default: dev
```

次に必要なものはリソースです。これらを書けばもうスタックを立ち上げることができます！

```
Resources:
  S3Bucket:
    Type: AWS::S3::Bucket
    Properties:
      BucketName: !Sub ${Project}.${Env}.${AWS::Region}
      BucketEncryption:
        ServerSideEncryptionConfiguration:
          - ServerSideEncryptionByDefault:
              SSEAlgorithm: AES256
      AccessControl: Private
```

以上だけでS3を利用することがもうできます！
途中で出てくる!SubはCloudFormationで利用する関数のようなものでパラメータの値を持ってきたりしてくれるので環境毎の構築の際などには必ず利用していくことになると思います。
では一気に行きましょう！次にバケットポリシーとCloudFrontを記述してCloudFrontOAIのみでのアクセスを許可します。

細かい内容は公式に頼らざる得ませんが検索するときはCloudFormationベースで考えるよりも実際に動かすサービスの内容から何を記述するのか選択していくのがベストかなと思います。
BucketPolicyの記述は少ないですがたくさん設定していかないといけないものも多くあります。
（自分は初awsだったので多いと何がいるのか分からなくなってましたｗ）
なので **難しくなったときは実際に手作業でサービスを立ち上げてからCloudFormationに書いていけば** いいかと！最終的にコードでかければ経過は良しです！


[例としてバケットポリシー書く時に見た公式](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-s3-policy.html)

```
BucketPolicy:
    Type: AWS::S3::BucketPolicy
    Properties:
      Bucket: !Ref S3Bucket
      PolicyDocument:
        Version: '2012-10-17'
        Statement:
          - Action:
              - s3:GetObject
            Effect: Allow
            Resource: !Sub "arn:aws:s3:::${S3Bucket}/*"
            Principal:
              AWS: !Sub arn:aws:iam::cloudfront:user/CloudFront Origin Access Identity ${CloudFrontOriginAccessIdentity}


  # CloudFront Origin Access Identity
  CloudFrontOriginAccessIdentity:
    Type: AWS::CloudFront::CloudFrontOriginAccessIdentity
    Properties:
      CloudFrontOriginAccessIdentityConfig:
        Comment: "CloudFront OAI for S3Bucket"

  CloudFrontDistribution:
    Type: AWS::CloudFront::Distribution
    Properties:
      DistributionConfig:
        DefaultCacheBehavior:
          Compress: true
          ForwardedValues:
            QueryString: true
          TargetOriginId: !Ref S3Bucket
          ViewerProtocolPolicy: 'redirect-to-https'
        Enabled: true
        HttpVersion: 'http2'
        DefaultRootObject: 'index.html'
        Origins:
          - DomainName: !GetAtt S3Bucket.RegionalDomainName
            Id: !Ref S3Bucket
            S3OriginConfig:
              OriginAccessIdentity:
                !Sub "origin-access-identity/cloudfront/${CloudFrontOriginAccessIdentity}"
        PriceClass: 'PriceClass_200'
  
```

以上でCloudFormation側の記述は終了です！
次に実際にファイルをアップロードしてスタックを出してみます！
といっても本当に簡単なので流れだけ貼っておきますｗ

![Screenshot_3.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1628058/32cec533-1c30-78b9-7ea6-8b88063938c1.png)

テンプレートのyamlを指定してスタック名を記述したらあとはオッケーです！

これでS3にindex.htmlをアップロードしてある状態でもS3のドメインから直接S3を開けない状態になりました！
CloufFrontのサービスを開いてディストリビューションドメイン名を検索すれば開けるようになってます！


# 3.終わりに
CloudFormationについて今回はあまり丁寧にではないですがイメージだけでも分かって頂ければ幸いです。というのもS3+BucketPolicy+CloudFrontの内容だけなのに記述するの大変だなと思ってましたｗ
なので拙い内容になってしまったかもしれませんがここまで読んで頂いて本当にありがとうございます。
もし参考にして作った方はスタックの削除を忘れずに行うようにして下さい。

アウトプットして感じたことは、最初の学習が慣れるまでやっぱり大変そうだなというところですが、作り直しとか変更するときにはやっぱりかなり便利だなと改めて思いました！

自分的CloudFormationのやり方で一番大事なところは
☆**分からなくなったときは実際に手作業でサービスを立ち上げて何が必要か確認してみる**
でした！

# 参考
[【AWS】CloudFormationまとめ](https://qiita.com/iron-breaker/items/a12d1228de12663e7d32)
[多分わかりやすいCloudFormation入門とチュートリアル](https://qiita.com/ryurock/items/766154e0afb8fdb629e2)