CloudFormationを理解する【環境構築〜運用について】

CloudFormationを使うにあたって開発環境構築から勉強しました。
AWS Black Beltの動画から
https://www.youtube.com/watch?v=Viyqh9fNBjw

#環境
macOS Big Sur バージョン11.2

#環境構築
####エディタ
自分的候補はvimかvscodeのどちらかだったが、自動補完プラグインが存在するvscodeを使うことにした。

####プラグイン

**・整合性チェック**

https://github.com/aws-cloudformation/cfn-python-lint

```zsh
brew install cfn-lint
```

**・自動補完**

https://github.com/aws-cloudformation/aws-cloudformation-template-schema/blob/master/docs/vscode/instructions.md

プラグインの追加を行い
>Install YAML support for VSCode. Here is the github repo

vscodeのs`~/Library/Application Support/Code/User/settings.json`に下記を貼り付ける

```json
    "[yaml]": {
        "editor.insertSpaces": true,
        "editor.tabSize": 2,
        "editor.quickSuggestions": {
            "other": true,
            "comments": false,
            "strings": true
        },
        "editor.autoIndent": true
    },
    "editor.renderWhitespace": "all",
    "editor.tabSize": 2,
    "editor.autoIndent": true,
    "yaml.format.enable": true,
    "yaml.trace.server": "verbose",
    "json.schemas": [
        {
            "fileMatch": [
                "*-template.json"
            ],
            "url": "https://s3.amazonaws.com/cfn-resource-specifications-us-east-1-prod/schemas/2.15.0/all-spec.json"
        }
    ],
    "yaml.schemas": {
        "https://s3.amazonaws.com/cfn-resource-specifications-us-east-1-prod/schemas/2.15.0/all-spec.json": [
            "*-template.yaml",
            "*-template.yml",
            "*-cf.yml",
        ]
    }
```
実際にファイルを作成するときはjsonで定義した名付けルールで作成する

**・起動テスト**

https://github.com/aws-quickstart/taskcat


```
pip3 install taskcat
```

**・セキュリティチェック**

https://github.com/stelligent/cfn_nag

```
brew install ruby brew-gem
brew gem install cfn-nag
```

**・ポリシーに沿ったルールになっているかチェック**

https://github.com/aws-cloudformation/cloudformation-guard

```
brew install cloudformation-guard
```

#デプロイ

3通りの方法がある

####CodePipelineを使用したデプロイ
git管理でコミットすると自動的にデプロイされるような仕組みにする方法

####Change Setを使用したデプロイ（更新時）
変更時に影響を受ける箇所を事前に管理コンソール上で確認できる

####StackSets
管理者アカウントからマルチリージョン、マルチアカウントにデプロイしたい場合に使用する

自分が利用する環境的にマルチアカウントへの対応が今後必要になる為StackSetsを勉強しなくては、、


#テスト

####整合性チェック
```zsh
cnf-lint <filename>-cf.yml
```

####セキュリティチェック
（例）セキュリティグループで幅広いIPレンジを公開しているリスクを見つけられる

```zsh
cnf_nag_scan --input-path <filename>-cf.yml
```

####ポリシーに沿ったルールになっているかチェック
（例）EBSボリュームが暗号化されていない、閾値以上のサイズの場合はじく

既存テンプレートからルールの雛形作成

```zsh
cfn-guard rulegen <filename>-cf.yml
```
実際のチェック実行時

```zsh
cfn-guard check -t <filename>-cf.yml -r <rulesetfile>
```

#運用

####スタックの更新
基本的には下記のような流れが良さそう。

ドリフト検出→テンプレートに反映→反映されたテンプレートに対して変更をかける→スタック更新

####リソースの保護
リソースを更新する際に誤ってスタックやリソースが予期せず変更/削除されないように複数レイヤーの保護機能で対策する

**・IAMポリシー**
ユーザーの権限を調整する

**・スタックポリシー**
スタック更新の際の意図しない変更/削除を防ぐためにスタックのリソースに対して個別に設定する
stack-policy.jsonというファイルにポリシーを記載するか、管理コンソールから追加する事もできる
下記はjsonファイルのイメージ

```json
{
 "Statment" : [
  {
   "Effect" : "Deny",
   "Action" : "Update:*",
,,,
```

**・リソースのdeletionポリシー**
リソース自体の保護。削除、保持、スナップショットの取得など定義することが可能。
（例）スタックが削除されてもS3バケットを保持するよう設定することが可能

**・スタックアクションの「削除保護」**
スタック内のリソース全体に対しての削除保護、有効/無効を変更できる


####ライフサイクル別のスタック
ライフサイクルが違うレイヤーはスタックを分割すると良いと言われている
（例）セキュリティ、ネットワーク、監視、バックエンド、ステートフルなリソース（DBなど）、フロントエンド

**・単一ファイルでの管理は依存関係やポリシーの設定が複雑になる**
Cross Stack Reference（アウトプットされたスタックの情報を別スタックでインポート）を活用すると良い
（例）依存関係の少ないネットワークレイヤーをまず構築、次にネットワークに依存するセキュリティレイヤーを構築し、最後によく更新するアプリケーションレイヤーはその前に構築したものを参照するような形にする

####リファクタリング
リソースのインポート機能を利用。

**・できること**
管理コンソールから作成したリソースをスタックにインポート（対象リソースを含むテンプレートを作成してChangeSet実行）
スタックから切り離し別スタックに移動
リソースIDをテンプレートに紐づける必要がある
Former2を使用すれば既存のリソースからテンプレートを作成できる

リソースを分割したい時もリソースを残したままスタックを削除し、テンプレートを分割してインポートすることで実現できる

####Dynamic References
リソースのデータを動的に参照する

**仕組み**
AWS System ManagerのパラメータストアとAWS SecretsManagerに格納されたデータをテンプレートで参照する
CloudFormationのベストプラクティスとしてテンプレートに認証情報は埋め込まない為、これで実現する

#ツール

**・cnf-init**
AmazonLinuxに入っているツール。
AWS：：CloudFormation ::initセクションに記載した設定をEC2で実行できる（パッケージのインストールなど）
※初期起動時しか動作しない、ymlにシェルスクリプトが入ったりすると管理が大変、、

その為現在はStateManagerを利用するのがおすすめ
インスタンスに対し定期的にAnsibleを実行

**・cnf-get-metadatat**
例えばEC2だとパッケージや起動サービスの確認ができる

**・cnf-signal**
EC2が正常に作成、更新されたかをCloudFormationに送信する。
リソースの作成開始後30秒以内にシグナルが飛ばなければロールバックする、というような用途で使用される。

**・cnf-hup**
リソースのメタデータ変更を検知しカスタムフックを実行する。
（EC2の再起動無しで変更の適用を行いたい場合など）