LoginSignup
0
0

More than 3 years have passed since last update.

理想を追い求めたCI/CDパイプラインをTerraformで実装するためのポイント(production環境編)

Posted at

はじめに

前回の記事の続編。
前回は、クロスアカウントで、ビルド環境でビルドしたコンテナイメージをstage環境にコピーする部分だったが、今回の範囲は、それをproduction環境にコピーする部分だ。

こうだったのが……
crossaccountpipeline.png

こうじゃ!
crossaccountpipeline2.png

前提知識としては、前回のパイプラインを理解できていること。
新しい概念は出てこないので、サクサク書いていく。

プロバイダの設定は前回と同じと考えてほしい。
本来だったらプロバイダを、dev, stage, production とするところを、簡略化するために今回も build_account, service_account としている。

また、ECRのコピー元を一意に特定するためにCommitIDを使っている。
このため、マージコミットはFast Forwardを使うようにする。Non Fast Forwardの場合は別の方法でCommitIDを連携する必要があるため注意が必要だ。

変更点

クロスアカウント設定等は前回と同様に行えばよい。
今回は、差分としてEventBridgeの設定部分を書いておく。

EventBridgeの設定(build_account側)

################################################################################
# EventBridge(Build Account)                                                   #
################################################################################
resource "aws_cloudwatch_event_rule" "codecommit_merge_build_account" {
  provider = aws.build_account

  name          = local.event_rule_name
  description   = "CodeCommit Merge Event Rule"
  event_pattern = data.template_file.event_pattern_build_account.rendered
}

resource "aws_cloudwatch_event_target" "event_bus_build_account" {
  provider = aws.build_account

  rule      = aws_cloudwatch_event_rule.codecommit_merge_build_account.name
  target_id = local.event_target_id
  arn       = "arn:aws:events:ap-northeast-1:${data.aws_caller_identity.service_account.account_id}:event-bus/default"
  role_arn  = aws_iam_role.eventbridge_build_account.arn
}

data "template_file" "event_pattern_build_account" {
  template = file("${path.module}/event_pattern_build_account.json")

  vars = {
    build_account_id          = data.aws_caller_identity.build_account.account_id
    codecommit_repository_arn = data.aws_codecommit_repository.application.arn
  }
}

################################################################################
# IAM Role for EventBridge                                                     #
################################################################################
resource "aws_iam_role" "eventbridge_build_account" {
  provider = aws.build_account

  name               = local.eventbridge_iam_role_name
  assume_role_policy = data.aws_iam_policy_document.eventbridge_build_account_assume.json
}

data "aws_iam_policy_document" "eventbridge_build_account_assume" {
  statement {
    effect = "Allow"

    actions = [
      "sts:AssumeRole",
    ]

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

resource "aws_iam_role_policy_attachment" "eventbridge_build_account" {
  provider = aws.build_account

  role       = aws_iam_role.eventbridge_build_account.name
  policy_arn = aws_iam_policy.eventbridge_build_account_custom.arn
}

resource "aws_iam_policy" "eventbridge_build_account_custom" {
  provider = aws.build_account

  name        = "SendEventToServiceAccountPolicy"
  description = "Send Event to Service-Account Policy"
  policy      = data.aws_iam_policy_document.eventbridge_build_account_custom.json
}

data "aws_iam_policy_document" "eventbridge_build_account_custom" {
  version = "2012-10-17"

  statement {
    effect = "Allow"

    actions = [
      "events:PutEvents",
    ]

    resources = [
      "arn:aws:events:ap-northeast-1:${data.aws_caller_identity.service_account.account_id}:event-bus/default",
    ]
  }
}

event_pattern_build_account.json
{
  "detail-type": [
    "CodeCommit Repository State Change"
  ],
  "resources": [
    "${codecommit_repository_arn}"
  ],
  "detail": {
    "referenceType": [
      "branch"
    ],
    "event": [
      "referenceUpdated"
    ],
    "referenceName": [
      "production"
    ]
  },
  "source": [
    "aws.codecommit"
  ]
}

EventBridgeの設定(service_account側)

################################################################################
# EventBridge(Service Account)                                                 #
################################################################################
resource "aws_cloudwatch_event_rule" "codecommit_merge_service_account" {
  provider = aws.service_account

  name          = local.event_rule_name
  description   = "CodeCommit Merge Event Rule"
  event_pattern = data.template_file.event_pattern_service_account.rendered
}

resource "aws_cloudwatch_event_target" "event_bus_service_account" {
  provider = aws.service_account

  rule      = aws_cloudwatch_event_rule.codecommit_merge_service_account.name
  target_id = local.event_target_id
  arn       = aws_codepipeline.service_account.arn
  role_arn  = aws_iam_role.eventbridge_service_account.arn
}

data "template_file" "event_pattern_service_account" {
  template = file("${path.module}/event_pattern_service_account.json")

  vars = {
    build_account_id          = data.aws_caller_identity.build_account.account_id
    codecommit_repository_arn = data.aws_codecommit_repository.application.arn
  }
}

################################################################################
# IAM Role for EventBridge                                                     #
################################################################################
resource "aws_iam_role" "eventbridge_service_account" {
  provider = aws.service_account

  name               = local.eventbridge_iam_role_name
  assume_role_policy = data.aws_iam_policy_document.eventbridge_service_account_assume.json
}

data "aws_iam_policy_document" "eventbridge_service_account_assume" {
  statement {
    effect = "Allow"

    actions = [
      "sts:AssumeRole",
    ]

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

resource "aws_iam_role_policy_attachment" "eventbridge_service_account" {
  provider = aws.service_account

  role       = aws_iam_role.eventbridge_service_account.name
  policy_arn = aws_iam_policy.eventbridge_service_account_custom.arn
}

resource "aws_iam_policy" "eventbridge_service_account_custom" {
  provider = aws.service_account

  name        = "StartPipelinePolicy"
  description = "Start CodePipeline Policy"
  policy      = data.aws_iam_policy_document.eventbridge_service_account_custom.json
}

data "aws_iam_policy_document" "eventbridge_service_account_custom" {
  version = "2012-10-17"

  statement {
    effect = "Allow"

    actions = [
      "codepipeline:StartPipelineExecution",
    ]

    resources = [
      "arn:aws:codepipeline:ap-northeast-1:${data.aws_caller_identity.service_account.account_id}:*",
    ]
  }
}

event_pattern_service_account.json
{
  "detail-type": [
    "CodeCommit Repository State Change"
  ],
  "account": [
    "${build_account_id}"
  ],
  "resources": [
    "${codecommit_repository_arn}"
  ],
  "detail": {
    "referenceType": [
      "branch"
    ],
    "event": [
      "referenceUpdated"
    ],
    "referenceName": [
      "production"
    ]
  },
  "source": [
    "aws.codecommit"
  ]
}

ポイント

ポイントになるのはイベントパターンの

  "detail": {
    "referenceType": [
      "branch"
    ],
    "event": [
      "referenceUpdated"
    ],
    "referenceName": [
      "production"
    ]
  },

の部分で、これによって、productionブランチの更新を拾える。
つまり、productionブランチに対するマージコミットのタイミングでイベント連携され、パイプラインを起動できるということだ。

CodeCommitのイベント連携であるため、CommitIDもちゃんとservice_account側に通知されるので、あとはbuildspec側で

phases:
  pre_build:
    commands:
      (中略)
      - IMAGE_TAG=$(echo ${CODEBUILD_RESOLVED_SOURCE_VERSION} | cut -c 1-7)

CODEBUILD_RESOLVED_SOURCE_VERSION の環境変数も参照可能になる。

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0