【コード管理/GitHub】CloudFormationのテンプレートをGitHubにpushすると、S3にもアップロードされるように実装する

# 今回の課題
以前、CloudFormationを使って、AWSのリソースをコードで管理するということに挑戦をしたので、
今回は、CloudFormationのコード履歴をGitHubで管理する方法を調査して、実際に実装してみることにした。


**◼︎前回の記事**

https://qiita.com/Ayumu-y/items/858170a85380babfa190

# 今回実施したこと
GitHub Actionsを使用して、
**GitHubにymlファイルをプッシュしたら、S3にも同じファイルがアップロードされる**
という機能を実装してみた。

下記の記事を参考にしながら進めた。

https://dev.classmethod.jp/articles/github-actions-cfn-quick-create-link/#toc-10

## 実装した手順
### 1)AWSのリソースを用意する

#### 1)-1.ブロックパブリックアクセス（バケット設定）をオフにする
`1)-2`でバケットポリシーの編集をするので、
ブロックパブリックアクセス（バケット設定）を無効にしておく。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/883573/4843bc7f-6993-11f9-da0d-117fd572c96c.png)


※`ブロックパブリックアクセス（バケット設定）`が有効だと、
　バケットポリシーの編集ができない。

#### 1)-2.テンプレートを保存する用のS3バケットを用意する
GitHubにCloudFormationのテンプレートのymlファイルをpushした際に、
ymlファイルが同時にアップロードされるS3バケットを用意しておく。
<font color = "red">※今回は、`cloudformation-git`というバケットを用意した。<font>

バケットポリシーは編集して、下記に書き換える。
```json
{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Sid": "Statement1",
            "Effect": "Allow",
            "Principal": "*",
            "Action": [
                "s3:GetObject",
                "s3:ListBucket",
                "s3:PutObject"
            ],
            "Resource": [
                "arn:aws:s3:::cloudformation-git/*",
                "arn:aws:s3:::cloudformation-git"
            ]
        }
    ]
}
```

#### 1)-3.IAMユーザを作成する
まずは、下記のようにIAMポリシーを作成する。

**◼︎許可しているポリシー一覧**
* `s3:GetObject`：バケット内のオブジェクトを取得する。
* `s3:ListBucket`：バケットの中身の一覧を閲覧する。
* `s3:PutObject`：オブジェクトをバケットに追加する。
```json
{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Effect": "Allow",
            "Action": [
                "s3:ListBucket",
                "s3:GetObject",
                "s3:PutObject"
            ],
            "Resource": [
                "arn:aws:s3:::cloudformation-git",
                "arn:aws:s3:::cloudformation-git/*"
            ]
        }
    ]
}
```


そして、実際にIAMユーザーを作成して、上記のポリシーをアタッチする。
また、IAMユーザーには、`アクセスキーID`と`シークレットアクセスキー`を持たせておく。

※IAMユーザーに`アクセスキーID`と`シークレットアクセスキー`を持たせる方法は、
　下記の記事が参考になった。

https://style.potepan.com/articles/35403.html


### 2)GitHubの用意をする
#### 2)-1.Action Secretsにて変数を用意する
`cloudformation-git`リポジトリの`Settings`>`Secrets and variables`の`Actions`から、
下記のように変数を保存しておく。

`1)-3`でIAMユーザーに持たせた、
`アクセスキーID`を`AWS_ACCESS_KEY_ID`変数、
`シークレットアクセスキー`を`AWS_SECRET_ACCESS_KEY`変数として保存する。

また、S3を作成した、
リージョンを`AWS_DEFAULT_REGION`変数、
バケット名を`BUCKET_NAME`変数として保存しておく。

↓変数の編集画面
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/883573/cf46c1dc-d98a-ab83-9190-562f0c50ed52.png)




#### 2)-2.ディレクトリを用意する
GitHubの`cloudformation-git`リポジトリの配下に、
下記の構成でディレクトリを配置したいので、
ymlファイルを入れるための`.github/workflows`ディレクトリと`cloudformation`ディレクトリを用意しておく。

※ymlファイルは後の行程で作成し、ここで作成したディレクトリの中に配置する。
```
├── .github
│   └── workflows
│       └── cfn_s3_upload.yml
└── cloudformation
    └── sample.yml
```
#### 2)-3.ワークフローファイルの作成をする
リポジトリ内の`.github/workflows/`ディレクトリの中のymlファイルで、
GitHub Actionsのワークフローを定義することができる。

下記のようなコードを、
`cloudformation-git/.github/workflows/cfn_s3_upload.yml`ファイルにて用意し、ワークフローを定義しておく。

※`2)-1`で用意した4つの変数は、下記のコードの`${secrets.変数名}`の部分に代入される。
```yml
# This is a basic workflow to help you get started with Actions

name: CloudFormation S3 Deploy

# Controls when the workflow will run
on:
  # Triggers the workflow on push or pull request events but only for the master branch
  push:
    branches: [ master, main ]

  # Allows you to run this workflow manually from the Actions tab
  workflow_dispatch:

# A workflow run is made up of one or more jobs that can run sequentially or in parallel
jobs:
  # This workflow contains a single job called "build"
  build:
    # The type of runner that the job will run on
    runs-on: ubuntu-latest

    # Steps represent a sequence of tasks that will be executed as part of the job
    steps:
      # Checks-out your repository under $GITHUB_WORKSPACE, so your job can access it
      - uses: actions/checkout@v3

      - name: Configure AWS credentials
        uses: aws-actions/configure-aws-credentials@v1
        with:
          aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID }}
          aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
          aws-region: ${{ secrets.AWS_DEFAULT_REGION }}

      - name: Copy files to the s3 bucket
        env:
          BUCKET_NAME: ${{ secrets.BUCKET_NAME }}
        run: |
          aws s3 sync ./cloudformation s3://${BUCKET_NAME}
```



### 3)AWSでインフラを構築するためのテンプレートを用意する
VScodeなどのエディタでコードを書いて、
下記のような、CloudFormationのテンプレートを用意する。
```yml
Description: VPC Create Sample 

Parameters:
  VpcCIDR:
    Description: Please enter the IP range (CIDR notation) for this VPC
    Type: String
    Default: 10.192.0.0/16

  EnvName:
    Description: An environment name that is prefixed to resource names
    Type: String


Resources:
  VPC:
    Type: AWS::EC2::VPC
    Properties:
      CidrBlock: !Ref VpcCIDR
      EnableDnsSupport: true
      EnableDnsHostnames: true
      Tags:
        - Key: Name
          Value: !Ref EnvName

```
### 4)`3)`で作成したファイルをGitHubにpushする
GitHubの`cloudformation`フォルダに`3)`で作成したテンプレートをpushすると、
`2)-3`で用意したワークフローが動き、S3にも同じテンプレートファイルがアップされる。

↓この通り、GitHubにpushすると、S3にもアップロードされていた。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/883573/cbb0f00f-20c1-83ad-a29b-0fdbfa5cac18.png)


以上で、**GitHubにpushしたらS3にもテンプレートがアップロードされる**機能が実装できた。

### 5)クイック作成リンクでスタックを作成する
今回は、`PracticeStack`という名前のスタックを作成してみる。
下記のURLのフォーマットに`リージョン名`, `バケット名`, `テンプレート名`, `スタック名`を入れてブラウザで検索すると、スタックのクイック作成の画面に遷移することができる。
```
https://ca-central-1.console.aws.amazon.com/cloudformation/home?region=ca-central-1#/stacks/quickcreate?templateUrl=https://cloudformation-git.s3.ca-central-1.amazonaws.com/practice.yml&stackName=PracticeStack
# https://[リージョン名].console.aws.amazon.com/cloudformation/home?region=[リージョン名]#/stacks/quickcreate?templateUrl=https://[バケット名].s3.[リージョン名].amazonaws.com/[スタック化したいテンプレートの名前]&stackName=[作成したいスタックの名前]
```
下記のようにスタック作成画面に遷移できるので、
そのまま`スタックの作成`ボタンを押せば、GitHubにプッシュした`practice.yml`テンプレートの内容でAWSのリソースを構築することができる。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/883573/69ecb567-b68b-b2c7-10e5-8e0af933a280.png)

最後に、VPCが構築されているか確認してみたところ、テンプレートの内容で問題なくVPCが構築されていた。

# まとめ
CloudFormationのテンプレートコードもGitHubで管理できるように実装することができた。

#### 参考記事
https://dev.classmethod.jp/articles/github-actions-cfn-quick-create-link/#toc-10

https://dev.classmethod.jp/articles/github-actions-cfn-quick-create-link/

https://knowledge.sakura.ad.jp/23478/