TaskCatをCodeBuildで動かして、CFnを自動でテスト

# はじめに

CloudFormation(CFn)の自動テストの方法を調べていたら、**TestCat**というツールを知ったので、CodeBuildで使ってみた内容を記事にします。
また前回、CodeBuildでConftestを使ってみたので、

1. Conftestを実行してポリシーチェックを行って
1. TaskCatを実行して作成できるかテスト
 
というようにしてみました。

# 参考
https://qiita.com/chacco38/items/59887ad3ed7fba7eb0ca

https://blog.serverworks.co.jp/how-to-cross-stack-test-on-taskcat

https://aws.amazon.com/jp/solutions/implementations/taskcat-ci/

https://github.com/aws-quickstart/quickstart-taskcat-ci/blob/main/templates/taskcat-ci-entrypoint.template.yaml


# やったこと

## Cloud9上で動かす
まずはCloud9で動かしてみます。インストールコマンドは以下になります。
```bash
python3 -m pip install --upgrade pip
pip3 install taskcat --use-feature=2020-resolver
taskcat -v
```

### チェックするCFnテンプレート

Conftestの際にも使った公式の例を使います。

https://docs.aws.amazon.com/ja_jp/AWSCloudFormation/latest/UserGuide/aws-resource-iam-role.html#aws-resource-iam-role--examples

Actionだけ、以前の記事で使用したConftestのポリシーチェックをパスさせるため、少し変えました。
```yaml:sampleCreateRole.yaml
AWSTemplateFormatVersion: "2010-09-09"
Resources:
  RootRole:
    Type: 'AWS::IAM::Role'
    Properties:
      AssumeRolePolicyDocument:
        Version: "2012-10-17"
        Statement:
          - Effect: Allow
            Principal:
              Service:
                - ec2.amazonaws.com
            Action:
              - 'sts:AssumeRole'
      Path: /
      Policies:
        - PolicyName: root
          PolicyDocument:
            Version: "2012-10-17"
            Statement:
              - Effect: Allow
                Action: 's3:*Object'
                Resource: '*'
  RootInstanceProfile:
    Type: 'AWS::IAM::InstanceProfile'
    Properties:
      Path: /
      Roles:
        - !Ref RootRole
```

###  .taskcat.ymlの作成
TaskCatの設定ファイル`.taskcat.yml`を記述します。ここでは2つのリージョンで作ってみます。自動テストする際は「本番は東京リージョンなので、テスト作成は大阪リージョンで行う」のようにするといいかもしれません。

```yaml: .taskcat.yml
project:
  name: sample-taskcat-project
  package_lambda: false
  regions:
    - ap-northeast-1
    - ap-northeast-3
tests:
  test-my-role:
    template: sampleCreateRole.yaml
```
### 実行
動かすのは、以下のコマンドになります。
```bash
taskcat test run
```

実行の状況は標準出力に出てきます。結果は同ディレクトリに作成される`taskcat_outputs\`以下にファイルが生成されます。
実行中に作成されたS3バケット(バケット名の先頭が"tcat"で始まっている)は、自動では削除されませんので、必要に応じて自分で削除してください。

## CodeBuildに組み込む


### CodeBuild環境一式作成

以前作ったCodeBuild環境を参考にします。

https://qiita.com/a_b_/items/80cb3fe41b4efec1a271#cfn%E3%81%A7%E4%BD%9C%E3%82%8B-1


<details><summary>クリックで表示</summary><div>

TaskCatでは、S3バケットを作ったり、CFnを実行したりなどなど、いろいろやっているので、CodeBuildにアタッチさせるIAMロールは`AdministratorAccess`にしています。
```yaml
AWSTemplateFormatVersion: 2010-09-09

Parameters:
  ProjectName:
    Type: String
    Default: testTaskcatBuild
  RepositoryName:
    Type: String
    Default: forTaskcatBuild

Resources:
  MyCodeCommitRepo:
    Type: AWS::CodeCommit::Repository
    Properties:
      RepositoryName: !Ref RepositoryName

  MyS3Bucket:
    Type: AWS::S3::Bucket

  LogGroupForCB:
    Type: AWS::Logs::LogGroup
    Properties:
      LogGroupName: !Sub "/aws/codebuild/${ProjectName}"
      RetentionInDays: 3653   # 未指定時は「失効しない」

  RoleForCB:
    Type: AWS::IAM::Role
    Properties:
      AssumeRolePolicyDocument:
        Version: 2012-10-17
        Statement:
          - Effect: Allow
            Principal:
              Service:
                - codebuild.amazonaws.com
            Action:
              - 'sts:AssumeRole'
      Path: /
      ManagedPolicyArns:
        - arn:aws:iam::aws:policy/AdministratorAccess

  CBProject:
    Type: AWS::CodeBuild::Project
    Properties:
      Name: !Ref ProjectName
      ServiceRole: !GetAtt RoleForCB.Arn
      Artifacts:
        Type: S3
        Location: !Ref MyS3Bucket
        EncryptionDisabled: true
      Environment:
        Type: LINUX_CONTAINER
        ComputeType: BUILD_GENERAL1_SMALL
        # 以下の Image identifier を参照
        ## https://docs.aws.amazon.com/codebuild/latest/userguide/build-env-ref-available.html
        Image: aws/codebuild/amazonlinux2-x86_64-standard:5.0
      Source:
        Type: CODECOMMIT
        Location: !GetAtt MyCodeCommitRepo.CloneUrlHttp
        GitCloneDepth: 1 # 指定しないと、フル
      SourceVersion: refs/heads/main
      LogsConfig:
        CloudWatchLogs:
          Status: ENABLED
        S3Logs:
          Status: DISABLED
```

</div></details>


### 各ファイルを追加

`.taskcat.yml`と`sampleCreateRole.yaml`をCodeCommitに追加します。
またConftestも一緒に実行したいので、以下の記事で作った`policy/rolePolicy.rego`も追加しました。

https://qiita.com/a_b_/items/022a0181e74c10487470#%E3%83%95%E3%82%A1%E3%82%A4%E3%83%AB

`buildspec.yml`は以下のようにし、追加。


```yaml:buildspec.yaml
version: 0.2

phases:
  install:
    commands:
      - echo Entered the install phase...
      - echo Installing Conftest on `date`
      - LATEST_VERSION=$(wget -O - "https://api.github.com/repos/open-policy-agent/conftest/releases/latest" | grep '"tag_name":' | sed -E 's/.*"([^"]+)".*/\1/' | cut -c 2-)
      - wget "https://github.com/open-policy-agent/conftest/releases/download/v${LATEST_VERSION}/conftest_${LATEST_VERSION}_Linux_x86_64.tar.gz"
      - tar xzf conftest_${LATEST_VERSION}_Linux_x86_64.tar.gz
      - sudo mv conftest /usr/local/bin
      - echo Installing Conftest on `date`
      - python3 -m pip install --upgrade pip
      - pip3 install taskcat
  pre_build:
    commands:
      - echo Conftest started on `date`
      - conftest test sampleCreateRole.yaml
      - echo TascCat started on `date`
      - taskcat test run
    finally:
      - aws s3 ls | awk '{print $3}' | grep "^tcat" | xargs -I {} aws s3 rb s3://{} --force
artifacts:
  files:
    - 'taskcat_outputs/*'
```

- TaskCatの結果を、アーティファクトの保存先のS3バケットに持ってくるようにしました。
- 以下を参考に、作成されるS3バケットを削除するようにしてみました。

https://blog.serverworks.co.jp/how-to-cross-stack-test-on-taskcat#20221201-%E8%BF%BD%E8%A8%98

CodeCommitに4つのファイルを追加して、以下のようになりました。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/553680/aeb46317-568f-a02e-29eb-fddaf1df6574.png)


### 実行
あとはCodeBuildを開始します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/553680/559bb5f3-d059-c3d1-fe64-987d66fef5ef.png)

問題なければ、ステータスが成功になります。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/553680/b4c151e4-1ee1-710d-0036-3b4941a4f325.png)



# 片付け
環境はCFnテンプレートで作成したため、S3バケットを空にした後にスタックの削除を行ってください。
- S3
    - バケットを空にしてから
- CodeCommit
- CodeBuild
- IAMロール
- CloudWatchロググループ


# おわりに
CodeBuildでTaskCatやConftestなどを動かして、CFnのテストやポリシーチェックを自動化することで、開発の負担が減らせることが期待できます。
この記事がどなたかのお役に立てれば幸いです。