この記事について

CodePipelineのソースステージには検出オプションいう設定があります。ソースプロバイダーとして指定したCodeCommitやGitHubの変更をどのように検出するか?という設定です。

一昔前はCodePipeline自身がソースプロバイダーにポーリングする形式が利用されていましたが、現在ではそれは非推奨となっています。代わりにEventBridgeを利用する検出オプションが推奨されています。

このEventBridgeを検出オプションにした際、いくつか注意点があります。

その注意点について、この記事に記載したいと思います。

前提知識

Amazon EventBridgeとは

Amazon EventBridgeは、イベント駆動型のサービスであり、異なるAWSサービスやカスタムアプリケーションからのイベントをリアルタイムでキャプチャし、それらを監視、統合、処理することができます。イベントソースからのイベントを観察し、ルールやターゲットを使用して、それらのイベントを指定されたAWSサービスやアプリケーションに自動的にルーティング、フィルタリング、アクションを実行します。このサービスを使用することで、システム全体の監視や自動化を容易にし、スケーラビリティを向上させることができます。

https://docs.aws.amazon.com/ja_jp/eventbridge/latest/userguide/eb-what-is.html

CodePipelineの検出オプションの違い

冒頭でも言いましたが、CodePipelineソースステージの検出オプションは以下2種類があります。

  • CodePipeline
  • EventBridge

検出オプション : CodePipeline

ポーリング形式での検出になります。CodePipelineだけでできるというメリットはありますが、即座に検出をすることができません。現在、この検出オプションは非推奨になっています。(利用は可能)

検出オプション : EventBridge

プッシュ形式での検出になります。EventBridgeが必要ですが、検出を即座に行うことができます。現在、この検出オプションを利用することが推奨されています。

CodePipelineの検出オプションをEventBridgeに設定すると、必要なリソース(EventBridgeルール/ターゲットなど)が自動で作成されます。そのため、ほとんどデメリットなしで即座の検出が可能です。

 

ただ実際に私が実装/運用していく中で、注意が必要な点がありました。その注意点を説明していきます。

注意点① : IaCする際はEventBridgeを手動で作成しなくてはいけない

最近だとAWSリソースの作成にCloudFormationやTerraformを利用して、IaCするというのは一般的だと思います。

私はTerraformを利用していました。そしてTerraformでCodePipelineを実装していました。Terraformのaws_codepipelineリソースのソースステージにてPollForSourceChanges = falseと定義すると、検出オプションがEventBridgeになります。

そしてEventBridgeのルールとターゲットが作成されますが、AWS側でよしなに作成してくれるため、このリソースはTerraformの管理下になりません。

もし途中で変更検出対象のブランチなどを変更したい場合、Terraformのコードを変更して適用してもEventBridgeに変更が適用されません。この問題の詳細については、以下の記事で説明しているのでご参照ください。

CodeCommitブランチを変更したら、CodePipelineが自動実行されなくなってしまった

きちんとIaCしたい際はこのEventBridgeのルールとターゲットをTerraformの管理下にする必要があります。

注意点② : CodeCommitとCodePipelineが異なるアカウントにある場合は、アカウント間のEventBridgeを連携させる必要がある

本番環境と開発環境がありAWSアカウントを分けるようなケースでは、CodeCommitを片方のアカウントに配置しておき、クロスアカウントでCodePipelineと連携させることがよくあるかと思います。私も開発環境にCodeCommitを配置して、developブランチに更新があれば開発環境のECSに対してCodePipelineが実行されるように、mainブランチに更新があれば本番環境のECSに対してCodePipelineが実行されるように実装していました。

このケースで考慮が必要なのは、本番環境のCodePipelineを実行するためのEventBridgeルール/ターゲットをどうするかです。

検出オプションをEventBridgeにした場合、同一アカウント内のEventBridgeイベントバスのイベントをキャプチャします。開発環境にあるCodeCommitに変更があったイベントは何もしなければ本番環境アカウントのEventBridgeイベントバスに流れません。そのため、開発環境のEventBridgeから本番環境のEventBridgeイベントバスにCodeCommitの変更イベントを配信できるようにする必要があります。

Terraformで実装する場合は以下のようにリソースを作成します。
(すでに両環境のCodePipelineと開発環境のEventBridgeルール/ターゲットは作成されているものとします。)

開発環境: 本番環境のイベントバスへイベントを配信するEventBridgeルール/ターゲットの作成

resource "aws_cloudwatch_event_rule" "cicd_to_prd" {
  name        = "eventbridge-cicd-dev-to-prd"
  description = "本番環境のイベントバスにCodeCommit変更イベントを配信するためのEventBridgeルール"
  event_pattern = jsonencode({
    source      = ["aws.codecommit"]
    detail-type = ["CodeCommit Repository State Change"]
    resources   = ["${開発環境のCodeCommitレポジトリのARN}"]
    detail = {
      event         = ["referenceCreated", "referenceUpdated"]
      referenceType = ["branch"]
      referenceName = ["main"]
    }
  })
}
resource "aws_cloudwatch_event_target" "cicd_to_prd" {
  target_id = "To-EventBus-Prd"
  arn       = "${本番環境のdefaultイベントバスのARN : arn:aws:events:ap-northeast-1:${開発環境のAWSアカウントID}:event-bus/default}"
  rule      = aws_cloudwatch_event_rule.cicd_to_prd.name
  role_arn  = aws_iam_role.cicd_to_prd.arn
}

また開発環境のEventBridgeルールが本番環境のEventBridgeイベントバスにイベントを配信できるようにするために、aws_cloudwatch_event_target.cicd_to_prdのrole_arnに定義するIAMロールのポリシーに以下権限を付与しておきます。

    {
      "Effect": "Allow",
      "Action": [
        "events:PutEvents"
      ],
      "Resource": [
        "arn:aws:events:ap-northeast-1:${開発環境のAWSアカウントID}:event-bus/default"
      ]
    }

本番環境: EventBridgeルール/ターゲットの作成

開発環境のCodeCommitのmainブランチの変更を検出して、本番環境のCodePipelineを実行するためのEventBridgeルール/ターゲットを作成します。
この時、開発環境アカウントのイベントを本番環境のイベントバスに配信できるように、イベントバスポリシーにて開発環境アカウントからの配信を許可する必要があります。

resource "aws_cloudwatch_event_rule" "cicd" {

  name        = "eventbridge-cicd-prd"
  description = "本番環境のパイプラインを実行するためのEventBridgeルール"
  event_pattern = jsonencode({
    source      = ["aws.codecommit"]
    detail-type = ["CodeCommit Repository State Change"]
    resources   = ["${開発環境のCodeCommitレポジトリのARN}"]
    detail = {
      event         = ["referenceCreated", "referenceUpdated"]
      referenceType = ["branch"]
      referenceName = ["main"]
    }
  })
}
resource "aws_cloudwatch_event_target" "cicd" {
  target_id = "Pipeline-Prd"
  arn       = aws_codepipeline.cicd.arn
  rule      = aws_cloudwatch_event_rule.cicd.name
  role_arn  = aws_iam_role.cicd.arn
}
data "aws_iam_policy_document" "cicd" {
  statement {
    sid    = "cicd"
    effect = "Allow"
    actions = [
      "events:PutEvents",
    ]
    resources = [
      "arn:aws:events:${リージョン}:${本番環境のAWSアカウントID}:event-bus/default"
    ]
    principals {
      type        = "AWS"
      identifiers = ["arn:aws:iam::${開発環境のAWSアカウントID}:root"]
    }
  }
}
resource "aws_cloudwatch_event_bus_policy" "cicd" {
  policy = data.aws_iam_policy_document.cicd.json
}

EventBridgeターゲットが利用するIAMロールも必要なので、作成します。

resource "aws_iam_policy" "cicd" {
  name = "policy-eventbridge-rule-prd"
  policy = templatefile("${path.module}/iam_policies/eventbridge.json", {})
}

resource "aws_iam_role" "cicd" {
  name               = "role-eventbridge-rule-prd"
  assume_role_policy = jsonencode({
    Version = "2012-10-17"
    Statement = [
      {
        Action = "sts:AssumeRole"
        Effect = "Allow"
        Sid    = ""
        Principal = {
          AWS = [
            "arn:aws:iam::events:root"
          ]
        }
      }
    ]
  })
}


resource "aws_iam_role_policy_attachment" "cicd" {
  role       = aws_iam_role.cicd.name
  policy_arn = aws_iam_policy.cicd.arn
}

iam_policies/eventbridge.json

{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Effect": "Allow",
      "Action": [
        "codepipeline:StartPipelineExecution"
      ],
      "Resource": [
        "${本番環境CodePipelineのARN}"
      ]
    }
  ]
}

最後に

CodePipelineの検出オプションをEventBridgeにすると変更検出が早くなるなどメリットがあります。ただ、実際に利用する際はこちらのブログで説明したポイントに注意して実装/運用していただく必要があります。
ただ一度理解してしまえば大した話ではないので、ぜひお試しください。