Skip to content

指摘 追加課題 保守運用 GitHub Actionsによる定期的なドリフトチェック #181

@skwt20

Description

@skwt20

メモ

  • ハマってたポイント
    terraform_wrapper: falseがなかったせいでexit 0になってSNS通知できなかった。
    example/actions/github/drift-check.ymlを参考にやったらいけた。
    ※AIはここに気づいてくれなかった。

プラクティス

作成したリソースは以下。プラクティスにヒントを加える。

定期ドリフトチェックワークフローの作成

drift-check.ymlを新規作成

name: terraform-drift-check

on:
  schedule:
    # 毎日 01:00 JST(UTC 16:00)
    - cron: '0 16 * * *'
  push:
    # 動作確認用(不要になったら消す)
    branches:
      - 129-add-drift-check*

jobs:
  drift-check:
    runs-on: arc-runner-set

    defaults:
      run:
        working-directory: codes/tfbackend

    steps:
      - name: Setup Node.js
        uses: actions/setup-node@v4
        with:
          node-version: 20

      - name: Checkout
        uses: actions/checkout@v4

      - name: Install AWS CLI
        run: |
          curl "https://awscli.amazonaws.com/awscli-exe-linux-x86_64.zip" -o "awscliv2.zip"
          unzip awscliv2.zip
          sudo ./aws/install
          aws --version

      - name: Setup Terraform
        uses: hashicorp/setup-terraform@v3
        with:
          terraform_version: 1.13.5
          terraform_wrapper: false

      - name: Terraform Init
        run: terraform init -input=false

      - name: Terraform Plan (Drift Check)
        id: plan
        run: |
          set +e
          terraform plan -detailed-exitcode -no-color > /tmp/plan_output.txt 2>&1
          EXIT_CODE=$?
          echo "exit_code=$EXIT_CODE" >> $GITHUB_OUTPUT
          exit $EXIT_CODE

      # -----------------------------
      # Drift detected → SNS notify
      # -----------------------------
      - name: Send SNS Notification on Plan Failure
        if: ${{ failure() }}
        run: |
          PLAN_OUTPUT=$(cat /tmp/plan_output.txt | head -50)
          
          aws sns publish \
            --topic-arn "arn:aws:sns:ap-northeast-1:456247443832:terraform-drift-alert" \
            --subject "Terraform Plan Failed - Drift Detection" \
            --message "$(cat <<EOF
          Terraform plan failed during drift detection.
          
          Workflow: ${{ github.workflow }}
          Run ID: ${{ github.run_id }}
          Repository: ${{ github.repository }}
          Branch: ${{ github.ref_name }}
          
          Plan Output (first 50 lines):
          ${PLAN_OUTPUT}
          
          Full logs: ${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}
          EOF
          )"

arc-runnerのIAMにtfbackendへのアクセス権とAWSへのReadOnlyAccess権を付与

iam_role.tfに以下を追記


############################################
# Terraform backend (S3) drift-check policy
############################################

resource "aws_iam_role_policy_attachment" "my_runner_role_readonly" {
  role       = aws_iam_role.my_runner_role.name
  policy_arn = "arn:aws:iam::aws:policy/ReadOnlyAccess"
}


resource "aws_iam_policy" "tfbackend_read" {
  name = "tfbackend-read-policy"

  policy = jsonencode({
    Version = "2012-10-17"
    Statement = [
      {
        Effect = "Allow"

        Action = [
          # ===== backend lockfile =====
          "s3:GetObject",
          "s3:PutObject",
          "s3:DeleteObject",
          "s3:ListBucket",

          # ===== terraform refresh (aws_s3_bucket) =====
          "s3:GetBucketPolicy",
          "s3:GetBucketAcl",
          "s3:GetBucketCORS",
          "s3:GetBucketVersioning",
          "s3:GetBucketEncryption",
          "s3:GetBucketTagging"
        ]
        Resource = [
          "arn:aws:s3:::cloudnative-practice-bucket110-2",
          "arn:aws:s3:::cloudnative-practice-bucket110-2/*"
        ]
      }
    ]
  })
}


############################################
# Attach drift-check policy to runner role
############################################

resource "aws_iam_role_policy_attachment" "my_runner_role_tfbackend" {
  role       = aws_iam_role.my_runner_role.name
  policy_arn = aws_iam_policy.tfbackend_read.arn
}

s3.tfのActionを追記

resource "aws_s3_bucket_policy" "allow_arc_runner_read_tfstate" {
中略
        Action = [
          "s3:GetObject",
          "s3:PutObject",
          "s3:DeleteObject",
          "s3:ListBucket",
          "s3:GetBucketPolicy",
          "s3:GetBucketAcl"
        ]
中略
}

更に発展的なプラクティス

ドリフト検知時はAWS SNS等を使い通知する

iam_role.tfに以下追記

############################################
# SNS用
############################################
resource "aws_iam_policy" "sns_publish_drift_alert" {
  name = "sns-publish-drift-alert"

  policy = jsonencode({
    Version = "2012-10-17"
    Statement = [
      {
        Effect   = "Allow"
        Action   = "sns:Publish"
        Resource = "arn:aws:sns:ap-northeast-1:456247443832:terraform-drift-alert"
      }
    ]
  })
}

resource "aws_iam_role_policy_attachment" "runner_sns_publish" {
  role       = aws_iam_role.my_runner_role.name
  policy_arn = aws_iam_policy.sns_publish_drift_alert.arn
}

drift-check.ymlに以下追記

      # -----------------------------
      # Drift detected → SNS notify
      # -----------------------------
      - name: Notify drift via SNS
        if: steps.plan.outputs.exitcode == '2'
        run: |
          aws sns publish \
            --topic-arn arn:aws:sns:ap-northeast-1:456247443832:terraform-drift-alert \
            --subject "Terraform Drift Detected" \
            --message "Terraform drift detected in repository: $GITHUB_REPOSITORY
              Commit: $GITHUB_SHA
              Workflow: $GITHUB_RUN_ID
              Directory: codes/tfbackend"

      # -----------------------------
      # Fail job on drift (optional)
      # -----------------------------
      - name: Fail if drift detected
        if: steps.plan.outputs.exitcode == '2'
        run: exit 1

動作確認

  • AWSコンソール画面より、バケットのバージョニングを「停止」に変更しテストすることで、SNS通知が飛ぶことを確認する。

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions