AWS/Terraform

【Terraform】tfnotifyでTerraformの実行結果をSlackに通知してみた

今回は、GitHubAcitonsとAWSを連携したCI/CD環境に、terraformコマンドの実行結果をSlackに通知する「tfnotify」を実装する方法をご紹介します。

実装のイメージ図は以下です。
terraform plan・applyの実行結果をSlackに通知する手段として、オープンソースの「tfnotify」を利用します。

tfnotifyとは

tfnotifyとは、メルカリで開発されたTerraformの実行結果通知用のツールです。
今回はGitHubAcitonsとの連携をご説明しますが、元々はCircleCIとの連携が前提で開発されています。(参考)
※本記事の「備考」で後述しますが、GitHubActionsでの使用に制限があります。

前提条件

・GitAcitions(Terraform)とAWSを連携したCI/CDが構築されている 参考
・Slackを利用している

Slackの設定

tfnotifyを使用するには、Slack側でアプリの設定が必要です。
手順は以下です。

①Slackの管理ページ https://api.slack.com/apps にアクセスする。

②[Create an App]をクリックする。

③[From scratch]をクリックする。

④[App Name]に「tfnotify」と入力し、[Pick a workspace to develop your app in:]のプルダウンメニューから、通知先のワークスペースを選択する。
[Create App]をクリックする。

⑤[OAuth & Permissions]をクリックする。

⑥[Scopes]の[Bot Token Scopes]にて[Add an OAuth Scope]をクリックする。
chat:write」を選択して追加する。
chat:write.public」選択して追加する。

⑦[Install to Workspace]をクリックする。

⑧Bot用のトークンが発行された事を確認する。

⑨Slackを開いて、[アプリを追加する]から[tfnotify]を追加する。

⑩GitHubAcitosでのTerraform実行結果を通知したいチャンネルを開く。
画面左上のチャンネル名をクリックする。

⑪[インテグレーション]タブにて、[アプリを追加する]をクリックして、[tfnotify]を追加する。

Slack側の準備は以上です。

GitHubの設定

リポジトリの構成は以下です。

<リポジトリ>
├── .github/workflows
│ ├── terraform-plan.yml (terraform plan + 結果通知)
│ └── terraform-apply.yml (terraform apply + 結果通知)
│
├── .tfnotify
│ └── slack.yml (結果通知のフォーマット設定)
│
├──terraform
│ └── main.tf
│
├── .gitattributes
│
└──.gitignore

tfnotifyによる通知のために設定するファイルは「slack.yml」「terraform-plan.yml 」「terraform-apply.yml」の 3つです。
事前に次のGitHubのシークレットを設定しています。

設定値 備考
AWSアクセスキーID Terraform実行用IAMユーザーのアクセスキーID
AWSシークレットアクセスキー Terraform実行用IAMユーザーのシークレットアクセスキー
Sackのトークン 上記の手順⑧で生成したトークン
通知先SlackチャンネルのID 上記の手順⑪の[チャンネル情報]タブで確認

1.slack.yml

ワーフクローでSlackで実行結果を表示する時のフォーマットを定義します。

ci: github-actions
notifier:
  slack:
    token: $SLACK_TOKEN
    channel: $SLACK_CHANNEL_ID
    bot: $SLACK_BOT_NAME
terraform:
  plan:
    template: |
      {{ .Message }}
      {{if .Result}}
      ```
      {{ .Result }}
      ```
      {{end}}
      ```
      {{ .Body }}
      ```
  apply:
    template: |
      {{ .Message }}
      {{if .Result}}
      ```
      {{ .Result }}
      ```
      {{end}}
      ```
      {{ .Body }}
      ```

参考:https://github.com/mercari/tfnotify

2.terraform-plan.yml

name: terraform plan
on:
  pull_request:
    branches:
      - 'master'

jobs:
  plan:
    name: terraform plan
    runs-on: ubuntu-latest
    steps:
      - name: checkout
        uses: actions/checkout@v2

      - name: configure AWS credentials
        uses: aws-actions/configure-aws-credentials@v1
        with:
          aws-access-key-id: ${{ secrets.<AWSアクセスキーIDのシークレット> }}
          aws-secret-access-key: ${{ secrets.<AWSシークレットアクセスキーのシークレット> }}
          aws-region: ap-northeast-1

      - name: setup tfnotify
        run: |
          sudo curl -fL -o tfnotify.tar.gz https://github.com/mercari/tfnotify/releases/download/v0.7.0/tfnotify_linux_amd64.tar.gz
          sudo tar -C /usr/bin -xzf ./tfnotify.tar.gz
      - name: terraform setup
        uses: hashicorp/setup-terraform@v1
        with:
          terraform_version: <Terraformのバージョン>

      - name: terraform fmt
        id: fmt
        run: terraform fmt
        working-directory: ./terraform

      - name: terraform init
        id: init
        run: terraform init
        working-directory: ./terraform


      - name: terraform plan
        id: plan
        working-directory: ./terraform
        run: |
         terraform plan -no-color | tfnotify --config ../.tfnotify/slack.yml plan --message "$(date)"
        env:
         SLACK_TOKEN: ${{ secrets.<Slackのトークンのシークレット> }}
         SLACK_CHANNEL_ID: ${{ secrets.<通知先SlackチャンネルIDのシークレット> }}
         SLACK_BOT_NAME: tfnotify

      - uses: actions/github-script@0.9.0
        env:
          STDOUT: "```${{ steps.plan.outputs.stdout }}```"
        with:
          github-token: ${{ secrets.GITHUB_TOKEN }}
          script: |
            github.issues.createComment({
              issue_number: context.issue.number,
              owner: context.repo.owner,
              repo: context.repo.repo,
              body: process.env.STDOUT
            })

※通知先はSlackだけでなく、GitHub上からでも確認できるよう、「actions/github-script@0.9.0」をワークフローに設定しています。
この設定で、プルリクエストのコメントにterraformコマンドの実行結果をbotが表示してくれます。
terraform-apply.yml も同様です。

3.terraform-apply.yml

name: terraform apply
on:
  pull_request:
    types: [closed]
    branches:
      - 'master'
jobs:
  plan:
    name: terraform apply
    runs-on: ubuntu-latest
    if: github.event.pull_request.merged == true
    steps:
      - name: checkout
        uses: actions/checkout@v2

      - name: configure AWS credentials
        uses: aws-actions/configure-aws-credentials@v1
        with:
          aws-access-key-id: ${{ secrets.<AWSアクセスキーIDのシークレット> }}
          aws-secret-access-key: ${{ secrets.<AWSシークレットアクセスキーのシークレット> }}
          aws-region: ap-northeast-1
      
      - name: setup tfnotify
        run: |
          sudo curl -fL -o tfnotify.tar.gz https://github.com/mercari/tfnotify/releases/download/v0.7.0/tfnotify_linux_amd64.tar.gz
          sudo tar -C /usr/bin -xzf ./tfnotify.tar.gz
      
      - name: terraform setup
        uses: hashicorp/setup-terraform@v1
        with:
          terraform_version: <Terraformのバージョン>

      - id: init
        run: terraform init
        working-directory: ./terraform

      - id: apply
        working-directory: ./terraform
        run: |
         terraform apply -auto-approve -no-color | tfnotify --config ../.tfnotify/slack.yml apply --message "$(date)"
        env:
         SLACK_TOKEN: ${{ secrets.<Skackのトークンのシークレット> }}
         SLACK_CHANNEL_ID: ${{ secrets.<通知先SkackチャンネルIDのシークレット> }}
         SLACK_BOT_NAME: tfnotify


      - uses: actions/github-script@0.9.0
        env:
          STDOUT: "```${{ steps.plan.outputs.stdout }}```"
        with:
          github-token: ${{ secrets.GITHUB_TOKEN }}
          script: |
            github.issues.createComment({
              issue_number: context.issue.number,
              owner: context.repo.owner,
              repo: context.repo.repo,
              body: process.env.STDOUT
            })

動作確認

設定ファイルをGitHubに格納後、プルリクエストを実行してGitHubAcitonsを発火させます。
GitHubActionsでterraform planが実行されると、設定したSlackチャンネルに通知が投稿されます。

リソース変更数が行頭のフォーマットで通知されますが、「slack.yml」を編集してフォーマットを変更できます。(参考)

備考

今回はSlack通知にのみ「tfnotify」を使用しましたが、GitHub上でbotによるコメント表示にも使用することができます。
ただし、ワークフローのトリガーがプルリクエストだとbotでによるコメント表示ができないため、今回GitHub上でのコメント表示には「actions/github-script@0.9.0」を使用しています。
※トリガーがプッシュだとGitHub上でのコメント表示も可能です。(参考)

以上となります。
この記事を通して、少しでもCI/CD環境構築のお役に立てれば幸いです。