TerraformでCodePipeline + CodeCommit作る際にトリガーでちょっとハマった話

2022.08.17

「TerraformでCodePipelineを作ったが、ファイルの変更してもCodepipelineがトリガー(発火)してくれない」

TerraformでCodeCommitをソースとしたCodePipelineを作っていました。

コンソールからパイプラインの作成はできて、手動トリガーでの実行もできたのですがCodeCommitのファイル変更時にCodePipelineが発火してくれないことがありました。

結論から書くと、CodePipeline用のEventBridgeの定義の作成が漏れていました。 (マネジメントコンソール上からCodePipelineを作ると自動的に作成されます。)

少しはまったので、サンプルコードを含めてブログにします。

事象・原因

以下のようにCodepipelineを作成していました。 しかし、Codecommitでファイルを変更してもパイプラインが動きません。

codepipeline.tf

resource "aws_codepipeline" "sample_app" {
  name     = local.name_prefix
  role_arn = aws_iam_role.codepipeline.arn

  artifact_store {
    location = aws_s3_bucket.codepipeline_artifact.bucket
    type     = "S3"
  }

  stage {
    name = "Source"
    action {
      name             = "Source"
      category         = "Source"
      owner            = "AWS"
      provider         = "CodeCommit"
      version          = 1
      output_artifacts = ["source_output"]
      configuration = {
        RepositoryName       = aws_codecommit_repository.sample_app.repository_name
        BranchName           = "main"
        OutputArtifactFormat = "CODE_ZIP"
      }
    }
  }
  stage {
    name = "Build"
    action {
      name             = "Build"
      category         = "Build"
      owner            = "AWS"
      provider         = "CodeBuild"
      version          = 1
      input_artifacts  = ["source_output"]
      output_artifacts = ["build_output"]

      configuration = {
        ProjectName = aws_codebuild_project.sample_app.id
      }
    }
  }
  stage {
    name = "Deploy"
    action {
      name            = "Deploy"
      category        = "Deploy"
      owner           = "AWS"
      provider        = "ECS"
      version         = 1
      input_artifacts = ["build_output"]
      configuration = {
        ClusterName = aws_ecs_cluster.this.id
        ServiceName = aws_ecs_service.sample_app.name
      }
    }
  }
}

マネジメントコンソールからソースアクションを見てみると、検出オプション「Amazon CloudWatch Events(推奨)」となっています。

この検出オプションでは、CodeCommitの変更イベントをEventBridge Rule(CloudWatch Events)で検出して、CodePipelineをターゲットにイベント送信を行います。 CodePipelineでは、イベントを受け取ってパイプラインの実行を開始します。

ここで、EventBridge Rule(CloudWatch Events)を作っていないことに気づきました。

ちなみに、マネジメントコンソールから手動でCodePipeline作成する場合、EventBridge Ruleは自動で生成されます。

解決策

EventBridge Ruleを追加します。

Terraform修正

マネジメントコンソールから作成時に自動で生成されるリソースを参考に、Terraform書いてみました。

codepipeline.tf

resource "aws_codepipeline" "sample_app" {
  name     = local.name_prefix
  role_arn = aws_iam_role.codepipeline.arn

  artifact_store {
    location = aws_s3_bucket.codepipeline_artifact.bucket
    type     = "S3"
  }

  stage {
    name = "Source"
    action {
      name             = "Source"
      category         = "Source"
      owner            = "AWS"
      provider         = "CodeCommit"
      version          = 1
      output_artifacts = ["source_output"]
      configuration = {
        RepositoryName       = aws_codecommit_repository.sample_app.repository_name
        BranchName           = "main"
        OutputArtifactFormat = "CODE_ZIP"
      }
    }
  }
  stage {
    name = "Build"
    action {
      name             = "Build"
      category         = "Build"
      owner            = "AWS"
      provider         = "CodeBuild"
      version          = 1
      input_artifacts  = ["source_output"]
      output_artifacts = ["build_output"]

      configuration = {
        ProjectName = aws_codebuild_project.sample_app.id
      }
    }
  }
  stage {
    name = "Deploy"
    action {
      name            = "Deploy"
      category        = "Deploy"
      owner           = "AWS"
      provider        = "ECS"
      version         = 1
      input_artifacts = ["build_output"]
      configuration = {
        ClusterName = aws_ecs_cluster.this.id
        ServiceName = aws_ecs_service.sample_app.name
      }
    }
  }
}

# cloudwatch event rule
resource "aws_cloudwatch_event_rule" "codepipeline_sample_app" {
  name = "${local.name_prefix}-codepipeline-sample-app"

  event_pattern = templatefile("./file/codepipeline_event_pattern.json", {
    codecommit_arn : aws_codecommit_repository.sample_app.arn
  })
}

resource "aws_cloudwatch_event_target" "codepipeline_sample_app" {
  rule     = aws_cloudwatch_event_rule.codepipeline_sample_app.name
  arn      = aws_codepipeline.sample_app.arn
  role_arn = aws_iam_role.event_bridge_codepipeline.arn
}

iam.tf

resource "aws_iam_role" "event_bridge_codepipeline" {
  name               = "${local.name_prefix}-event-bridge-codepipeline-role"
  assume_role_policy = data.aws_iam_policy_document.event_bridge_assume_role.json
  inline_policy {
    name   = "codepipeline"
    policy = data.aws_iam_policy_document.event_bridge_codepipeline.json
  }
}

data "aws_iam_policy_document" "event_bridge_assume_role" {
  statement {
    actions = ["sts:AssumeRole"]

    principals {
      type        = "Service"
      identifiers = ["events.amazonaws.com"]
    }
  }
}

data "aws_iam_policy_document" "event_bridge_codepipeline" {
  statement {
    actions   = ["codepipeline:StartPipelineExecution"]
    resources = ["${aws_codepipeline.sample_app.arn}"]
  }
}

file/codepipeline_event_pattern.json

{
  "source": ["aws.codecommit"],
  "detail-type": ["CodeCommit Repository State Change"],
  "resources": ["${codecommit_arn}"],
  "detail": {
    "event": ["referenceCreated", "referenceUpdated"],
    "referenceType": ["branch"],
    "referenceName": ["main"]
  }
}

動作確認

上記をapply後CodeCommitに変更をコミットしたところ、CodePipelineが起動することを確認できました。

おわりに

似たような事象が発生した際の、参考になれば幸いです。

以上、AWS事業本部の佐藤(@chari7311)でした。