はじめに
AWS CodeConnectionsシリーズ第2弾。
過去の記事では、GitLab Self Managedとの接続をAWS CodeConnectionsで行ったが、今回はGitHub(非Enterprise)との接続を行う。
さらに、2025年3月6日には、AWS Resource Access Manager(RAM)を使った簡単なクロスアカウントのAWS CodeConnections共有ができるようになったことで、従来、環境が増えるたびにマネージメントコンソール画面を使ってリソースの作成を完了させる必要があったが、管理アカウントのみの対応で済むようになった。
今回の記事では、以下の構成図の通り、この新しいリソース共有方法も試してみることにする。
関連のリンクはこちら
また、過去のAWS CodeConnections関連記事は以下を参照していただきたい。
なお、本記事を読むにあたっての前提知識は以下の2点である。
- AWS CodePipelineとAWS CodeConnectionsを触ったことがある
- 初歩的なTerraformを読んで内容を理解することができる
GitHubに接続するAWS CodeConnections
AWS CodeConnectionsでGitHubに接続するには、以下の通りaws_codeconnections_connection
のみ定義すれば良い。GitLab Self Managedで使っていたaws_codeconnections_host
については必要ない。
resource "aws_codeconnections_connection" "example" {
name = local.codeconnections_connection_name
provider_type = "GitHub"
}
このリソースを作った直後は、まだ接続が完了していないためすぐには使えない。
AWSマネージメントコンソールで作成したリソースを選択し、AWS公式ユーザーガイドの
2. AWS コネクタの承認 GitHubを選択します。接続ページが表示され、GitHub アプリフィールドが表示されます。
以降の作業を行う。この承認行為のみ、AWSの公開APIが提供されていないため、今回のTerraformによる自動化の範囲外となる。
また、以下の項ではクロスアカウント対象のアカウントが必要になってくるので、以下のデータソースも宣言しておこう。
provider "aws" {
alias = "crossaccount"
profile = "crossaccount"
region = "ap-northeast-1"
}
data "aws_caller_identity" "crossaccount" {
provider = aws.crossaccount
}
AWS Resource Access Managerの設定
管理アカウント側の設定
ここはそんなに難しい部分はない。Terraformの公式ドキュメントとほぼ同じ内容になるはずで、aws_ram_resource_share
を作成し、アクセス元アカウントのプリンシパルについてaws_ram_principal_association
と連携させ、aws_ram_resource_association
もろとも紐づけるイメージだ。
共有先のアカウントを自分のOrganizations外にする場合は、allow_external_principals = true
に設定する必要があるので注意。
resource "aws_ram_resource_share" "example" {
name = local.ram_share_name
allow_external_principals = true
}
resource "aws_ram_resource_association" "example" {
resource_share_arn = aws_ram_resource_share.example.arn
resource_arn = aws_codeconnections_connection.example.id
}
resource "aws_ram_principal_association" "example" {
resource_share_arn = aws_ram_resource_share.example.arn
principal = data.aws_caller_identity.crossaccount.account_id
}
クロスアカウント側の設定
管理アカウントアカウント以外に、クロスアカウントでも接続の招待を受けて承認できるようにしておく必要があるため、以下のaws_ram_resource_share_accepter
を行う。ここはマネージメントコンソール不要で、TerraformのみでスムースにApplyをすることができる。
resource "aws_ram_resource_share_accepter" "example" {
provider = aws.crossaccount
share_arn = aws_ram_principal_association.example.resource_share_arn
}
AWS CodePipelineでの利用方法
AWS RAMの設定が完了したら、あとはクロスアカウント対象のアカウントのリソースを作っていこう。
AWS CodePipeline周辺リソース
Amazon CloudWatch Logs
AWS CodeBuildのデバッグ用に作っておく。
resource "aws_cloudwatch_log_group" "codebuild_crossaccount" {
provider = aws.crossaccount
name = local.clouddwatch_loggroup_name
}
Amazon S3
Amazon S3は普通にAWS CodePipelineからアクセス可能なPrivateな箱を作っておけばよい。
resource "aws_s3_bucket" "example_crossaccount" {
provider = aws.crossaccount
bucket = local.s3_bucket_crossaccount_name
force_destroy = true
}
resource "aws_s3_bucket_ownership_controls" "example_crossaccount" {
provider = aws.crossaccount
bucket = aws_s3_bucket.example_crossaccount.id
rule {
object_ownership = "BucketOwnerEnforced"
}
}
resource "aws_s3_bucket_public_access_block" "example_crossaccount" {
provider = aws.crossaccount
bucket = aws_s3_bucket.example_crossaccount.id
block_public_acls = true
block_public_policy = true
ignore_public_acls = true
restrict_public_buckets = true
}
IAM
IAMは、AWS CodePipelineとAWS CodeBuildについて作成する。
ポイントはcodestar-connections:UseConnection
で管理アカウントのリソースを設定する部分だ。
それ以外は特に難しいところはない。
################################################################################
# IAM for AWS CodeBuild #
################################################################################
resource "aws_iam_role" "codebuild_crossaccount" {
provider = aws.crossaccount
name = local.iam_codebuild_role_name
assume_role_policy = data.aws_iam_policy_document.codebuild_crossaccount_assume.json
}
data "aws_iam_policy_document" "codebuild_crossaccount_assume" {
statement {
effect = "Allow"
actions = [
"sts:AssumeRole",
]
principals {
type = "Service"
identifiers = [
"codebuild.amazonaws.com",
]
}
}
}
resource "aws_iam_role_policy" "codebuild_crossaccount" {
provider = aws.crossaccount
name = local.iam_codebuild_policy_name
role = aws_iam_role.codebuild_crossaccount.id
policy = data.aws_iam_policy_document.codebuild_crossaccount_custom.json
}
data "aws_iam_policy_document" "codebuild_crossaccount_custom" {
statement {
effect = "Allow"
actions = [
"codeBuild:StartBuild",
]
resources = [
aws_codebuild_project.example_crossaccount.arn,
]
}
statement {
effect = "Allow"
actions = [
"s3:GetObject",
]
resources = [
"${aws_s3_bucket.example_crossaccount.arn}/*",
]
}
statement {
effect = "Allow"
actions = [
"logs:CreateLogStream",
"logs:PutLogEvents",
]
resources = [
aws_cloudwatch_log_group.codebuild_crossaccount.arn,
"${aws_cloudwatch_log_group.codebuild_crossaccount.arn}:log-stream:*",
]
}
}
################################################################################
# IAM for AWS CodePipeline #
################################################################################
resource "aws_iam_role" "codepipeline_crossaccount" {
provider = aws.crossaccount
name = local.iam_codepipeline_role_name
assume_role_policy = data.aws_iam_policy_document.codepipeline_crossaccount_assume.json
}
data "aws_iam_policy_document" "codepipeline_crossaccount_assume" {
statement {
effect = "Allow"
actions = [
"sts:AssumeRole",
]
principals {
type = "Service"
identifiers = [
"codepipeline.amazonaws.com",
]
}
}
}
resource "aws_iam_role_policy" "codepipeline_crossaccount" {
provider = aws.crossaccount
name = local.iam_codepipeline_policy_name
role = aws_iam_role.codepipeline_crossaccount.id
policy = data.aws_iam_policy_document.codepipeline_crossaccount_custom.json
}
data "aws_iam_policy_document" "codepipeline_crossaccount_custom" {
statement {
effect = "Allow"
actions = [
"codebuild:StartBuild",
"codebuild:StopBuild",
"codebuild:BatchGet*",
"codebuild:Get*",
"codebuild:List*",
"s3:*",
]
resources = [
"*",
]
}
statement {
sid = "AllowCodeStarConnections"
effect = "Allow"
actions = [
"codestar-connections:UseConnection",
]
resources = [
aws_codeconnections_connection.example.arn,
]
}
}
AWS CodeBuild
################################################################################
# AWS CodeBuild #
################################################################################
resource "aws_codebuild_project" "example_crossaccount" {
provider = aws.crossaccount
name = local.codebuild_project_name
service_role = aws_iam_role.codebuild_crossaccount.arn
source {
type = "CODEPIPELINE"
buildspec = "buildspec.yml"
}
artifacts {
type = "CODEPIPELINE"
}
environment {
type = "LINUX_CONTAINER"
compute_type = "BUILD_GENERAL1_SMALL"
image = "aws/codebuild/amazonlinux2-x86_64-standard:5.0"
}
logs_config {
cloudwatch_logs {
group_name = aws_cloudwatch_log_group.codebuild_crossaccount.name
}
}
}
AWS CodePipeline本体
いよいよAWS CodePipeline本体の作成だ。
AWS CodePipelineでAWS CodeConnectionsを利用する方法は、GitLab Self Managed利用時と大差ない。
trigger.provider_type
をCodeStarSourceConnection
に設定するのと、stage.action.configuration.ConnectionArn
を先に作成しているAWS CodeConnectionの接続のARNを設定しけばよい。
resource "aws_codepipeline" "example_crossaccount" {
provider = aws.crossaccount
name = local.codepipeline_pipeline_name
role_arn = aws_iam_role.codepipeline_crossaccount.arn
pipeline_type = "V2"
trigger {
provider_type = "CodeStarSourceConnection"
git_configuration {
source_action_name = "Source"
push {
branches {
includes = ["main"]
}
}
}
}
artifact_store {
type = "S3"
location = aws_s3_bucket.example_crossaccount.bucket
}
stage {
name = "Source"
action {
run_order = 1
name = "Source"
category = "Source"
owner = "AWS"
provider = "CodeStarSourceConnection"
version = "1"
output_artifacts = ["SourceArtifact"]
namespace = "SourceVariables"
configuration = {
ConnectionArn = aws_codeconnections_connection.example.arn
FullRepositoryId = "${var.github_name}/example"
BranchName = "staging"
}
}
}
stage {
name = "Build"
action {
run_order = 2
name = "Build"
category = "Build"
owner = "AWS"
provider = "CodeBuild"
version = "1"
input_artifacts = ["SourceArtifact"]
configuration = {
ProjectName = aws_codebuild_project.example_crossaccount.name
EnvironmentVariables = jsonencode([
{
type = "PLAINTEXT"
name = "CODEPIPELINE_SRCVAR_AUTHORDATE"
value = "#{SourceVariables.AuthorDate}"
},
{
type = "PLAINTEXT"
name = "CODEPIPELINE_SRCVAR_BRANCHNAME"
value = "#{SourceVariables.BranchName}"
},
{
type = "PLAINTEXT"
name = "CODEPIPELINE_SRCVAR_COMMITID"
value = "#{SourceVariables.CommitId}"
},
{
type = "PLAINTEXT"
name = "CODEPIPELINE_SRCVAR_COMMITMESSAGE"
value = "#{SourceVariables.CommitMessage}"
},
{
type = "PLAINTEXT"
name = "CODEPIPELINE_SRCVAR_CONNECTIONARN"
value = "#{SourceVariables.ConnectionArn}"
},
{
type = "PLAINTEXT"
name = "CODEPIPELINE_SRCVAR_FULLREPOSITORYNAME"
value = "#{SourceVariables.FullRepositoryName}"
},
])
}
}
}
}
ビルドでは、各種環境変数をGitHubが設定してくれているので、それぞれ内容を確認してみる。
なお、今回網羅はしたので改めて確認する必要はないが、利用可能な環境変数の一覧については、ユーザーガイドに記載がある。「CodeStarSourceConnection アクションの出力変数」を確認していただけば良い。
これらの環境変数を参照するために、Buildspecは以下のように作成してみよう。
version: 0.2
phases:
build:
commands:
- echo ${CODEPIPELINE_SRCVAR_AUTHORDATE}
- echo ${CODEPIPELINE_SRCVAR_BRANCHNAME}
- echo ${CODEPIPELINE_SRCVAR_COMMITID}
- echo ${CODEPIPELINE_SRCVAR_COMMITMESSAGE}
- echo ${CODEPIPELINE_SRCVAR_CONNECTIONARN}
- echo ${CODEPIPELINE_SRCVAR_FULLREPOSITORYNAME}
上記Buildspecメインブランチを更新すると、ビルドログに環境変数が出力される。
上記した環境変数設定が設定され、上手く機能している証拠だ。
[Container] 2025/03/09 11:12:40.650869 Running command echo ${CODEPIPELINE_SRCVAR_AUTHORDATE}
2025-03-09T11:12:16Z
[Container] 2025/03/09 11:12:40.656947 Running command echo ${CODEPIPELINE_SRCVAR_BRANCHNAME}
main
[Container] 2025/03/09 11:12:40.662338 Running command echo ${CODEPIPELINE_SRCVAR_COMMITID}
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
[Container] 2025/03/09 11:12:40.667594 Running command echo ${CODEPIPELINE_SRCVAR_COMMITMESSAGE}
Initial commit.
[Container] 2025/03/09 11:12:40.672782 Running command echo ${CODEPIPELINE_SRCVAR_CONNECTIONARN}
arn:aws:codeconnections:ap-northeast-1:XXXXXXXXXXXX:connection/XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX
[Container] 2025/03/09 11:12:40.677835 Running command echo ${CODEPIPELINE_SRCVAR_FULLREPOSITORYNAME}
neruneruo/example
これで、AWS CodeConnectionsを用いた接続方法の選択肢が増えた、
パイプラインのソースにGitHubを使って、より良い開発環境を整えていこう!