Codepipelineを設定中に別AWSアカウントにあるCodeCommitを使用する機会があったのでブログに残します。
やること
AWSアカウントAにあるCodeCommitにgit pushされたらAWSアカウントBにあるCodePipelineを使用してEC2に自動デプロイする構成を作成します。
簡単にはなりますが構成図は以下になります。
AWSアカウントAにあるCodeCommitにgit pushするとEventBridgeで検知してAWSアカウントBにあるEventBridge Busに連携する構成としています。
構成図には記載していませんが、アーティファクト用のS3バケットとKMSキーをAWSアカウントBに作成しています。
CodePipelineからCodeCommitへアクセスするためAWSアカウントAにクロスアカウントIAMロールを作成します。
こちらのIAMロールの内容は以下のブログを参考に設定しています。
かなり細かく説明が記載されているのでご確認いただければと思います。
作成してみた
AWSアカウントBでデプロイ先のEC2、アーティファクト用S3、CodePipelineの使用するIAMロール作成
まずはAWSアカウントAでデプロイ先のEC2などを作成していきます。
リソース作成は以下のCloudFormationで行っています。
CloudFormationテンプレート (ここをクリックしてください)
AWSTemplateFormatVersion: "2010-09-09"
Description: CI/CD test Stack
Metadata:
# ------------------------------------------------------------#
# Metadata
# ------------------------------------------------------------#
AWS::CloudFormation::Interface:
ParameterGroups:
- Label:
default: Parameters for Policy
Parameters:
- AccountAId
- Label:
default: Parameters for VPC
Parameters:
- VPCCIDR
- Label:
default: Parameters for Subnet
Parameters:
- PublicSubnet01CIDR
- Label:
default: Parameters for ec2
Parameters:
- EC2VolumeSize
- EC2VolumeIOPS
- EC2AMI
- EC2InstanceType
Parameters:
# ------------------------------------------------------------#
# Parameters
# ------------------------------------------------------------#
AccountAId:
Type: String
VPCCIDR:
Default: 172.30.0.0/16
Type: String
PublicSubnet01CIDR:
Default: 172.30.3.0/24
Type: String
EC2VolumeSize:
Default: 32
Type: Number
EC2VolumeIOPS:
Default: 3000
Type: Number
EC2AMI:
Default: '/aws/service/ami-amazon-linux-latest/al2023-ami-kernel-6.1-x86_64'
Type: AWS::SSM::Parameter::Value<AWS::EC2::Image::Id>
EC2InstanceType:
Default: t3.micro
Type: String
Resources:
# ------------------------------------------------------------#
# S3
# ------------------------------------------------------------#
S3:
Type: AWS::S3::Bucket
Properties:
BucketEncryption:
ServerSideEncryptionConfiguration:
- ServerSideEncryptionByDefault:
SSEAlgorithm: AES256
BucketName: !Sub ${AWS::StackName}-${AWS::AccountId}-artifact
OwnershipControls:
Rules:
- ObjectOwnership: BucketOwnerEnforced
PublicAccessBlockConfiguration:
BlockPublicAcls: True
BlockPublicPolicy: True
IgnorePublicAcls: True
RestrictPublicBuckets: True
Tags:
- Key: Name
Value: !Sub ${AWS::StackName}-${AWS::AccountId}-artifact
S3ArtifactBucketPolicy:
Type: AWS::S3::BucketPolicy
Properties:
Bucket: !Ref S3
PolicyDocument:
Version: "2012-10-17"
Statement:
- Effect: Allow
Action: s3:ListBucket
Resource: !Sub arn:aws:s3:::${S3}
Principal:
AWS:
- !Sub arn:aws:iam::${AccountAId}:root
- Effect: Allow
Action:
- s3:Get*
- s3:Put*
Resource: !Sub arn:aws:s3:::${S3}/*
Principal:
AWS:
- !Sub arn:aws:iam::${AccountAId}:root
- Effect: Deny
Action: s3:PutObject
Resource: !Sub arn:aws:s3:::${S3}/*
Principal: "*"
Condition:
StringNotEquals:
s3:x-amz-server-side-encryption: aws:kms
- Effect: Deny
Action: s3:*
Resource: !Sub arn:aws:s3:::${S3}/*
Principal: "*"
Condition:
Bool:
aws:SecureTransport: false
# ------------------------------------------------------------#
# IAM
# ------------------------------------------------------------#
EC2IAMPolicy:
Type: AWS::IAM::ManagedPolicy
Properties:
PolicyDocument:
Version: "2012-10-17"
Statement:
- Effect: Allow
Action:
- "s3:GetObject"
- "s3:ListBucket"
Resource:
- !Join
- ''
- - !GetAtt S3.Arn
- '/*'
- !GetAtt S3.Arn
ManagedPolicyName: iam-policy-deploy-ec2-al2023
EC2IAMRole:
Type: AWS::IAM::Role
Properties:
AssumeRolePolicyDocument:
Version: "2012-10-17"
Statement:
- Effect: Allow
Principal:
Service:
- ec2.amazonaws.com
Action:
- 'sts:AssumeRole'
ManagedPolicyArns:
- arn:aws:iam::aws:policy/AmazonSSMManagedInstanceCore
- !Ref EC2IAMPolicy
RoleName: iam-role-ec2-al2023
Tags:
- Key: Name
Value: iam-role-ec2-al2023
EC2IAMInstanceProfile:
Type: AWS::IAM::InstanceProfile
Properties:
InstanceProfileName: iam-instanceprofile-ec2-al2023
Roles:
- !Ref EC2IAMRole
CodeBuildIAMPolicy:
Type: AWS::IAM::ManagedPolicy
Properties:
PolicyDocument:
Version: "2012-10-17"
Statement:
- Effect: Allow
Action:
- 's3:PutObject'
- 's3:GetObject'
Resource:
- !Join
- ''
- - !GetAtt S3.Arn
- '/*'
- Effect: Allow
Action:
- 'codecommit:GitPull'
Resource: "*"
- Effect: Allow
Action:
- 'logs:CreateLogGroup'
- 'logs:CreateLogStream'
- 'logs:PutLogEvents'
Resource: "*"
ManagedPolicyName: iam-policy-codebuild
CodeBuildIAMRole:
Type: AWS::IAM::Role
Properties:
AssumeRolePolicyDocument:
Version: "2012-10-17"
Statement:
- Effect: Allow
Principal:
Service:
- codebuild.amazonaws.com
Action:
- 'sts:AssumeRole'
ManagedPolicyArns:
- !Ref CodeBuildIAMPolicy
RoleName: iam-role-codebuild
Tags:
- Key: Name
Value: iam-role-codebuild
CodeDeployIAMRole:
Type: AWS::IAM::Role
Properties:
AssumeRolePolicyDocument:
Version: "2012-10-17"
Statement:
- Effect: Allow
Principal:
Service:
- codedeploy.amazonaws.com
Action:
- 'sts:AssumeRole'
ManagedPolicyArns:
- arn:aws:iam::aws:policy/service-role/AWSCodeDeployRole
RoleName: iam-role-codedeploy
Tags:
- Key: Name
Value: iam-role-codedeploy
CodePipelineIAMPolicy:
Type: AWS::IAM::ManagedPolicy
Properties:
PolicyDocument:
Version: "2012-10-17"
Statement:
- Effect: Allow
Action:
- "codebuild:BatchGetBuilds"
- "codebuild:StartBuild"
Resource:
- "*"
- Effect: Allow
Action:
- "codedeploy:CreateDeployment"
- "codedeploy:GetApplication"
- "codedeploy:GetApplicationRevision"
- "codedeploy:GetDeployment"
- "codedeploy:GetDeploymentConfig"
- "codedeploy:RegisterApplicationRevision"
Resource:
- "*"
- Effect: Allow
Action:
- "s3:GetObject"
- "s3:PutObject"
- "s3:ListBucket"
Resource:
- !Join
- ''
- - !GetAtt S3.Arn
- '/*'
- !GetAtt S3.Arn
- Effect: Allow
Action:
- sts:AssumeRole
Resource:
- !Sub arn:aws:iam::${AccountAId}:role/*
ManagedPolicyName: iam-policy-codepipeline
CodePipelineIAMRole:
Type: AWS::IAM::Role
Properties:
AssumeRolePolicyDocument:
Version: "2012-10-17"
Statement:
- Effect: Allow
Principal:
Service:
- codepipeline.amazonaws.com
Action:
- 'sts:AssumeRole'
ManagedPolicyArns:
- !Ref CodePipelineIAMPolicy
RoleName: iam-role-codepipeline
Tags:
- Key: Name
Value: iam-role-codepipeline
# ------------------------------------------------------------#
# KMS
# ------------------------------------------------------------#
KMSKey:
Type: AWS::KMS::Key
Properties:
KeyPolicy:
Version: "2012-10-17"
Id: key-policy
Statement:
- Effect: Allow
Action: kms:*
Sid: Enable IAM User Permissions
Principal:
AWS:
- !Sub arn:aws:iam::${AWS::AccountId}:root
Resource: "*"
- Effect: Allow
Action:
- kms:DescribeKey
- kms:Encrypt
- kms:Decrypt
- kms:ReEncrypt*
- kms:GenerateDataKey
- kms:GenerateDataKeyWithoutPlaintext
Sid: Allow use of the key
Principal:
AWS:
- !Sub arn:aws:iam::${AccountAId}:root
- !GetAtt CodeBuildIAMRole.Arn
- !GetAtt CodePipelineIAMRole.Arn
- !GetAtt EC2IAMRole.Arn
Resource: "*"
- Effect: Allow
Sid: Allow attachment of persistent resources
Action:
- kms:CreateGrant
- kms:ListGrants
- kms:RevokeGrant
Principal:
AWS:
- !Sub arn:aws:iam::${AccountAId}:root
- !GetAtt CodeBuildIAMRole.Arn
- !GetAtt CodePipelineIAMRole.Arn
- !GetAtt EC2IAMRole.Arn
Resource: "*"
Condition:
Bool:
kms:GrantIsForAWSResource: true
KMSAlias:
Type: AWS::KMS::Alias
Properties:
AliasName: alias/CodePipelineS3Bucket
TargetKeyId:
Ref: KMSKey
# ------------------------------------------------------------#
# VPC
# ------------------------------------------------------------#
VPC:
Type: AWS::EC2::VPC
Properties:
CidrBlock: !Ref VPCCIDR
EnableDnsSupport: true
EnableDnsHostnames: true
Tags:
- Key: Name
Value: test-vpc
# ------------------------------------------------------------#
# InternetGateway
# ------------------------------------------------------------#
InternetGateway:
Type: AWS::EC2::InternetGateway
Properties:
Tags:
- Key: Name
Value: !Sub test-igw
InternetGatewayAttachment:
Type: AWS::EC2::VPCGatewayAttachment
Properties:
InternetGatewayId: !Ref InternetGateway
VpcId: !Ref VPC
# ------------------------------------------------------------#
# Subnet
# ------------------------------------------------------------#
PublicSubnet01:
Type: AWS::EC2::Subnet
Properties:
AvailabilityZone: ap-northeast-1a
CidrBlock: !Ref PublicSubnet01CIDR
MapPublicIpOnLaunch: true
Tags:
- Key: Name
Value: !Sub test-public-subnet-01
VpcId: !Ref VPC
# ------------------------------------------------------------#
# RouteTable
# ------------------------------------------------------------#
PublicRouteTable:
Type: AWS::EC2::RouteTable
Properties:
VpcId: !Ref VPC
Tags:
- Key: Name
Value: test-public-rtb
PublicRouteTableRoute:
Type: AWS::EC2::Route
Properties:
DestinationCidrBlock: 0.0.0.0/0
GatewayId: !Ref InternetGateway
RouteTableId: !Ref PublicRouteTable
PublicRtAssociation1:
Type: AWS::EC2::SubnetRouteTableAssociation
Properties:
RouteTableId: !Ref PublicRouteTable
SubnetId: !Ref PublicSubnet01
# ------------------------------------------------------------#
# Security Group
# ------------------------------------------------------------#
EC2SG:
Type: AWS::EC2::SecurityGroup
Properties:
GroupDescription: for ec2
GroupName: test-sg-ec2
SecurityGroupEgress:
- CidrIp: 0.0.0.0/0
FromPort: -1
IpProtocol: -1
ToPort: -1
SecurityGroupIngress:
- FromPort: 80
IpProtocol: tcp
CidrIp: 0.0.0.0/0
ToPort: 80
Tags:
- Key: Name
Value: test-sg-ec2
VpcId: !Ref VPC
# ------------------------------------------------------------#
# EC2
# ------------------------------------------------------------#
EC2:
Type: AWS::EC2::Instance
Properties:
BlockDeviceMappings:
- DeviceName: /dev/xvda
Ebs:
DeleteOnTermination: true
Encrypted: true
Iops: !Ref EC2VolumeIOPS
VolumeSize: !Ref EC2VolumeSize
VolumeType: gp3
DisableApiTermination: false
IamInstanceProfile: !Ref EC2IAMInstanceProfile
ImageId: !Ref EC2AMI
InstanceType: !Ref EC2InstanceType
NetworkInterfaces:
- AssociatePublicIpAddress: true
DeleteOnTermination: true
DeviceIndex: 0
GroupSet:
- !Ref EC2SG
SubnetId: !Ref PublicSubnet01
Tags:
- Key: Name
Value: test-ec2
UserData: !Base64 |
#!/bin/bash
yum update
yum install ruby -y
yum install wget -y
wget https://aws-codedeploy-ap-northeast-1.s3.ap-northeast-1.amazonaws.com/latest/install
cd
chmod +x ./install
./install auto
service codedeploy-agent start
yum install httpd -y
echo "CodeDeploy Test" > /var/www/html/index.html
systemctl start httpd
systemctl enable httpd
Outputs:
# ------------------------------------------------------------#
# Outputs
# ------------------------------------------------------------#
CodeBuildIAMRoleARN:
Value: !GetAtt CodeBuildIAMRole.Arn
Export:
Name: iam-role-codebuild-arn
CodeDeployIAMRoleARN:
Value: !GetAtt CodeDeployIAMRole.Arn
Export:
Name: iam-role-codedeploy-arn
CodePipelineIAMRoleARN:
Value: !GetAtt CodePipelineIAMRole.Arn
Export:
Name: iam-role-codepipeline-arn
S3Name:
Value: !Ref S3
Export:
Name: S3Name
66~120行目でアーティファクト用S3バケットを作成しています。
アーティファクト用S3バケットはAWSアカウントAからアクセスできるようにするためにバケットポリシーを設定しています。
125~292行目でEC2やCodePipelineで使用するIAMロールを作成しています。
IAMロールで重要になるのが、CodePipelineでAWSアカウントAのCodeCommitへアクセスするためにAssumeRoleを行えるポリシーを設定しています。(268~272行目)
297~348行目でKMSキーを作成しています。
KMSキーはキーポリシーでCodePipelineのIAMロール、CodeBuildのIAMロール、EC2のIAMロールとAWSアカウントAからアクセスできるように設定してます。
EC2やVPCの詳細な説明は省かせていただきますが、353~481行目で作成を行っています。
デプロイは以下のAWS CLIコマンドを使用します。
VPCやサブネットのCIDRを変更したい場合は「--parameters」オプションでパラメータを指定してください。
aws cloudformation create-stack --stack-name CloudFormationスタック名 --template-body file://CloudFormationテンプレートファイル名 --parameters ParameterKey=AccountAId,ParameterValue=AWSアカウントAのID --capabilities CAPABILITY_NAMED_IAM
AWSアカウントAでCodeCommitアクセス用IAMロール、CodeCommit、EventBridgeルールの作成
AWSアカウントBでEC2などが作成できたらAWSアカウントAでCodeCommitなどを作成します。
リソース作成は以下のCloudFormationで行っています。
CloudFormationテンプレート (ここをクリックしてください)
AWSTemplateFormatVersion: "2010-09-09"
Description: CodeCommit Stack
Metadata:
# ------------------------------------------------------------#
# Metadata
# ------------------------------------------------------------#
AWS::CloudFormation::Interface:
ParameterGroups:
- Label:
default: Parameters for Policy
Parameters:
- AccountBId
- KMSARN
- ArtifactS3ARN
- Label:
default: Parameters for CodeCommit
Parameters:
- RepositoryDescription
- RepositoryName
Parameters:
# ------------------------------------------------------------#
# Parameters
# ------------------------------------------------------------#
AccountBId:
Type: String
KMSARN:
Type: String
ArtifactS3ARN:
Type: String
RepositoryDescription:
MaxLength: 4000
Type: String
RepositoryName:
MaxLength: 100
Type: String
Resources:
# ------------------------------------------------------------#
# IAM
# ------------------------------------------------------------#
EventBridgeIAMPolicy:
Type: AWS::IAM::ManagedPolicy
Properties:
PolicyDocument:
Version: "2012-10-17"
Statement:
- Effect: Allow
Action:
- "events:PutEvents"
Resource:
- !Sub arn:aws:events:${AWS::Region}:${AccountBId}:event-bus/codepipeline
ManagedPolicyName: iam-policy-eventbridge
EventBridgeIAMRole:
Type: AWS::IAM::Role
Properties:
AssumeRolePolicyDocument:
Version: "2012-10-17"
Statement:
- Effect: Allow
Principal:
Service:
- events.amazonaws.com
Action:
- 'sts:AssumeRole'
ManagedPolicyArns:
- !Ref EventBridgeIAMPolicy
RoleName: iam-role-eventbridge
Tags:
- Key: Name
Value: iam-role-eventbridge
CodePipelineAssumePolicy:
Type: AWS::IAM::ManagedPolicy
Properties:
PolicyDocument:
Version: "2012-10-17"
Statement:
- Effect: Allow
Action:
- "s3:PutObject"
- "s3:PutObjectAcl"
Resource:
- !Sub ${ArtifactS3ARN}/*
- Effect: Allow
Action:
- "kms:DescribeKey"
- "kms:GenerateDataKey*"
- "kms:Encrypt"
- "kms:ReEncrypt*"
- "kms:Decrypt"
Resource:
- !Sub ${KMSARN}
- Effect: Allow
Action:
- "codecommit:GetBranch"
- "codecommit:GetCommit"
- "codecommit:UploadArchive"
- "codecommit:GetUploadArchiveStatus"
- "codecommit:CancelUploadArchive"
Resource:
- !GetAtt CodeCommit.Arn
ManagedPolicyName: iam-policy-codepipelineassume
CodePipelineAssumeRole:
Type: AWS::IAM::Role
Properties:
AssumeRolePolicyDocument:
Version: "2012-10-17"
Statement:
- Effect: Allow
Principal:
AWS:
- !Sub arn:aws:iam::${AccountBId}:root
Action:
- sts:AssumeRole
ManagedPolicyArns:
- !Ref CodePipelineAssumePolicy
RoleName: iam-role-codepipelineassumerole
Tags:
- Key: Name
Value: iam-role-codepipelineassumerole
# ------------------------------------------------------------#
# CodeCommit
# ------------------------------------------------------------#
CodeCommit:
Type: AWS::CodeCommit::Repository
Properties:
RepositoryDescription: !Ref RepositoryDescription
RepositoryName: !Ref RepositoryName
# ------------------------------------------------------------#
# EventBridge
# ------------------------------------------------------------#
EventBridge:
Type: AWS::Events::Rule
Properties:
Description: for codepipeline
EventPattern:
source:
- aws.codecommit
detail-type:
- 'CodeCommit Repository State Change'
resources:
- !GetAtt CodeCommit.Arn
detail:
event:
- referenceCreated
- referenceUpdated
referenceType:
- branch
referenceName:
- main
Name: eventbridge-codepipeline-cross-account
State: ENABLED
Targets:
- Arn: !Sub arn:aws:events:${AWS::Region}:${AccountBId}:event-bus/codepipeline
RoleArn: !GetAtt EventBridgeIAMRole.Arn
Id: EventBridge
Outputs:
# ------------------------------------------------------------#
# Outputs
# ------------------------------------------------------------#
CodeCommitRepositoryName:
Value: !GetAtt CodeCommit.Name
Export:
Name: codecommit-repository-name
CodeCommitRepositoryARN:
Value: !GetAtt CodeCommit.Arn
Export:
Name: codecommit-repository-arn
48~129行目でEventBridgeとCodeCommitへアクセスするためのIAMロールを作成しています。
EventBridgeのIAMロールに設定するIAMポリシーはAWSアカウントBのEventBridge Busへイベントを送れるように"events:PutEvents"を許可しています。
CodeCommitアクセス用IAMロールはAWSアカウントBのCodePipelineからアクセスできるように信頼ポリシーでAWSアカウントBからのアクセスを許可しています。
134~138行目でCodeCommitを作成しています。
143~167行目でEventBridgeルールを作成しています。
EventBridgeルールではCodeCommitのmainブランチで変更があった時に反応するように設定しています。
また、ターゲットとしてAWSアカウントBのEventBridge Busを設定しています。
デプロイは以下のAWS CLIコマンドを使用します。
aws cloudformation create-stack --stack-name CloudFormationスタック名 --template-body file://CloudFormationテンプレートファイル名 --parameters ParameterKey=AccountBId,ParameterValue=AWSアカウントBのID ParameterKey=KMSARN,ParameterValue=AWSアカウントAで作成したKMSキーのARN ParameterKey=ArtifactS3ARN,ParameterValue=アーティファクト用S3バケットARN ParameterKey=RepositoryDescription,ParameterValue=CodeCommitリポジトリの説明 ParameterKey=RepositoryName,ParameterValue=CodeCommitリポジトリ名 --capabilities CAPABILITY_NAMED_IAM
AWSアカウントBでCodeBuild、CodeDeploy、CodePipeline、EventBridgeの作成
最後にAWSアカウントBでCodePipelineなどを作成していきます。
リソース作成は以下のCloudFormationで行っています。
CloudFormationテンプレート (ここをクリックしてください)
AWSTemplateFormatVersion: "2010-09-09"
Description: CodeBuild Stack
Metadata:
# ------------------------------------------------------------#
# Metadata
# ------------------------------------------------------------#
AWS::CloudFormation::Interface:
ParameterGroups:
- Label:
default: Parameters for CodeBuild
Parameters:
- CodeBuildDescription
- CodeBuildName
- Label:
default: Parameters for CodeDeploy
Parameters:
- ApplicationName
- DeploymentGroupName
- Label:
default: Parameters for CodePipeline
Parameters:
- KMSARN
- CodePipelineName
- CodeCommitName
- CodePipelineAssumeRole
- Label:
default: Parameters for EventBridge
Parameters:
- AccountAId
Parameters:
# ------------------------------------------------------------#
# Parameters
# ------------------------------------------------------------#
CodeBuildDescription:
MaxLength: 255
Type: String
CodeBuildName:
MaxLength: 255
Type: String
ApplicationName:
MaxLength: 100
Type: String
DeploymentGroupName:
MaxLength: 100
Type: String
KMSARN:
Type: String
CodePipelineName:
MaxLength: 100
Type: String
CodeCommitName:
Type: String
CodePipelineAssumeRole:
Type: String
AccountAId:
Type: String
Resources:
# ------------------------------------------------------------#
# CodeBuild
# ------------------------------------------------------------#
CodeBuild:
Type: AWS::CodeBuild::Project
Properties:
Artifacts:
Type: CODEPIPELINE
Description: !Ref CodeBuildDescription
EncryptionKey: alias/CodePipelineS3Bucket
Environment:
ComputeType: BUILD_GENERAL1_SMALL
Image: aws/codebuild/amazonlinux2-x86_64-standard:5.0
Type: LINUX_CONTAINER
Name: !Ref CodeBuildName
ServiceRole: !ImportValue iam-role-codebuild-arn
Source:
BuildSpec: buildspec.yml
Type: CODEPIPELINE
Tags:
- Key: Name
Value: test-build
# ------------------------------------------------------------#
# CodeDeploy
# ------------------------------------------------------------#
CodeDeployApplication:
Type: AWS::CodeDeploy::Application
Properties:
ApplicationName: !Ref ApplicationName
ComputePlatform: Server
Tags:
- Key: Name
Value: !Ref ApplicationName
CodeDeployGroup:
Type: AWS::CodeDeploy::DeploymentGroup
Properties:
ApplicationName: !Ref CodeDeployApplication
AutoRollbackConfiguration:
Enabled: true
Events:
- DEPLOYMENT_FAILURE
DeploymentConfigName: CodeDeployDefault.AllAtOnce
DeploymentGroupName: !Ref DeploymentGroupName
Ec2TagFilters:
- Key: Name
Type: KEY_AND_VALUE
Value: test-ec2
ServiceRoleArn: !ImportValue iam-role-codedeploy-arn
Tags:
- Key: Name
Value: !Ref DeploymentGroupName
# ------------------------------------------------------------#
# CodePipeline
# ------------------------------------------------------------#
CodePipeline:
Type: AWS::CodePipeline::Pipeline
Properties:
ArtifactStore:
Location: !ImportValue S3Name
Type: S3
EncryptionKey:
Id: !Ref KMSARN
Type: KMS
Name: !Ref CodePipelineName
RoleArn: !ImportValue iam-role-codepipeline-arn
Stages:
- Actions:
- ActionTypeId:
Category: Source
Owner: AWS
Provider: CodeCommit
Version: 1
Configuration:
RepositoryName: !Ref CodeCommitName
BranchName: main
PollForSourceChanges: false
OutputArtifactFormat: CODE_ZIP
Name: Source
Namespace: SourceVariables
OutputArtifacts:
- Name: SourceArtifact
Region: ap-northeast-1
RunOrder: 1
RoleArn: !Ref CodePipelineAssumeRole
Name: Source
- Actions:
- ActionTypeId:
Category: Build
Owner: AWS
Provider: CodeBuild
Version: 1
Configuration:
ProjectName: !Ref CodeBuildName
InputArtifacts:
- Name: SourceArtifact
Name: Build
Namespace: BuildVariables
OutputArtifacts:
- Name: BuildArtifact
Region: ap-northeast-1
RunOrder: 1
Name: Build
- Actions:
- ActionTypeId:
Category: Deploy
Owner: AWS
Provider: CodeDeploy
Version: 1
Configuration:
ApplicationName: !Ref ApplicationName
DeploymentGroupName: !Ref DeploymentGroupName
Name: Deploy
Namespace: DeployVariables
InputArtifacts:
- Name: BuildArtifact
Region: ap-northeast-1
RunOrder: 1
Name: Deploy
Tags:
- Key: Name
Value: !Ref CodePipelineName
# ------------------------------------------------------------#
# EventBridge
# ------------------------------------------------------------#
EventBus:
Type : AWS::Events::EventBus
Properties:
Name: codepipeline
EventBusPolicy:
Type: AWS::Events::EventBusPolicy
Properties:
StatementId: !Sub codepipeline
EventBusName: codepipeline
Statement:
Effect: Allow
Action: events:PutEvents
Resource: !GetAtt EventBus.Arn
Principal:
AWS: !Sub arn:aws:iam::${AccountAId}:root
EventBridgeIAMPolicy:
Type: AWS::IAM::ManagedPolicy
Properties:
PolicyDocument:
Version: "2012-10-17"
Statement:
- Effect: Allow
Action:
- "codepipeline:StartPipelineExecution"
Resource:
- !Join
- ''
- - !Sub 'arn:aws:codepipeline:${AWS::Region}:'
- !Sub '${AWS::AccountId}:'
- !Ref CodePipeline
ManagedPolicyName: iam-policy-eventbridge
EventBridgeIAMRole:
Type: AWS::IAM::Role
Properties:
AssumeRolePolicyDocument:
Version: "2012-10-17"
Statement:
- Effect: Allow
Principal:
Service:
- events.amazonaws.com
Action:
- 'sts:AssumeRole'
ManagedPolicyArns:
- !Ref EventBridgeIAMPolicy
RoleName: iam-role-eventbridge
Tags:
- Key: Name
Value: iam-role-eventbridge
EventBridge:
Type: AWS::Events::Rule
Properties:
Description: for codepipeline
EventBusName: !GetAtt EventBus.Name
EventPattern:
source:
- aws.codecommit
detail-type:
- 'CodeCommit Repository State Change'
resources:
- !Sub arn:aws:codecommit:${AWS::Region}:${AccountAId}:${CodeCommitName}
detail:
event:
- referenceCreated
- referenceUpdated
referenceType:
- branch
referenceName:
- main
Name: eventbridge-codepipeline
State: ENABLED
Targets:
- Arn: !Join
- ''
- - !Sub 'arn:aws:codepipeline:${AWS::Region}:'
- !Sub '${AWS::AccountId}:'
- !Ref CodePipeline
Id: CodePipeline
RoleArn: !GetAtt EventBridgeIAMRole.Arn
73~91行目でCodeBuildを作成しています。
96~122行目でCodeDeployを作成しています。
127~193行目でCodePipelineを作成しています。
198~280行目でEventBridgeとEventBridgeで使用するIAMロールを作成しています。
EventBridge BusはAWSアカウントAからイベントを受け取れるようにするためにAWSアカウントAからのアクセスを許可するポリシーを設定してます。(203~213行目)
デプロイは以下のAWS CLIコマンドを使用します。
aws cloudformation create-stack --stack-name CloudFormationスタック名 --template-body file://CloudFormationテンプレートファイル名 --parameters ParameterKey=CodeBuildDescription,ParameterValue=CodeBuildの説明 ParameterKey=CodeBuildName,ParameterValue=CodeBuildの名前 ParameterKey=ApplicationName,ParameterValue=CodeDeployアプリケーション名 ParameterKey=DeploymentGroupName,ParameterValue=CodeDeployデプロイグループ名 ParameterKey=KMSARN,ParameterValue=KMSキーのARN ParameterKey=CodePipelineName,ParameterValue=CodePipelineの名前 ParameterKey=CodeCommitName,ParameterValue=CodeCommitリポジトリ名 ParameterKey=CodePipelineAssumeRole,ParameterValue=AWSアカウントAで作成したCodePipelineAssumeRole ParameterKey=AccountAId,ParameterValue=AWSアカウントAのID --capabilities CAPABILITY_NAMED_IAM
動作確認
リソースの作成が完了したらappspec.yml、buildspec.yml、index.htmlを作成します。
CodeCommitリポジトリを以下のドキュメントの手順でクローンしてください。
AWS CodeCommit リポジトリに接続する
クローンしたリポジトリで以下のファイルを作成していきます。
appspec.ymlは以下の内容で作成します。
version: 0.0
os: linux
files:
- source: /
destination: /var/www/html
file_exists_behavior: OVERWRITE
permissions:
- object: /var/www/html
owner: apache
group: apache
mode: 755
type:
- file
- directory
#hooks:
# デプロイする際に動かすシェルスクリプトなどを設定するセクション
buildspec.ymlは以下の内容で作成します。
version: 0.2
phases:
install:
on-failure: ABORT
commands:
- echo "install phases"
- echo "yum install などでビルドに使うパッケージをインストールするのに使用"
pre_build:
on-failure: ABORT
commands:
- echo "pre_build phases"
- echo "Amazon ECR にサインインしたりするのに使用"
build:
on-failure: ABORT
commands:
- echo "build phases"
- echo "ビルド、テストなどを実行するのに使用"
post_build:
on-failure: ABORT
commands:
- echo "post_build phases"
- echo "Docker イメージをAmazon ECR にプッシュしたりZIPとかにアーカイブするのに使用"
artifacts:
files:
- "**/*"
index.htmlの中身は好きな内容でよいですが、今回は以下のようにしました。
<html>
<head>
<meta charset="UTF-8">
<title>テストページ</title>
</head>
<body bgcolor="#10100E" text="#cccccc">
小林 陸<br/>
</body>
</html>
ディレクトリ内は以下のようになります。
ls -la
total 24
drwxr-xr-x. 3 cloudshell-user cloudshell-user 4096 Mar 31 13:02 .
drwxrwxrwx. 5 cloudshell-user cloudshell-user 4096 Mar 31 13:02 ..
-rw-r--r--. 1 cloudshell-user cloudshell-user 360 Mar 30 16:13 appspec.yml
-rw-r--r--. 1 cloudshell-user cloudshell-user 762 Mar 30 16:13 buildspec.yml
drwxr-xr-x. 8 cloudshell-user cloudshell-user 4096 Mar 30 16:15 .git
-rw-r--r--. 1 cloudshell-user cloudshell-user 161 Mar 31 13:02 index.html
ファイルの作成が完了したら以下のコマンドでgit push を行います。
git checkout -b mani
git add .
git commit -m "test"
git push origin main
git pushに成功すると以下のようにCodePipelineが動きだしていることが確認できます。
デプロイが完了すると以下のようにEC2の「/var/www/html/」内にファイルが配置されることが確認できます。
ls -la /var/www/html/
total 12
drwxr-xr-x. 2 root root 64 Mar 31 13:12 .
drwxr-xr-x. 4 root root 33 Mar 30 16:44 ..
-rwxr-xr-x. 1 apache apache 360 Mar 31 13:11 appspec.yml
-rwxr-xr-x. 1 apache apache 762 Mar 31 13:11 buildspec.yml
-rwxr-xr-x. 1 apache apache 161 Mar 31 13:11 index.html
さいごに
クロスアカウントのデプロイになるとKMSやクロスアカウントロールが必要になるため設定が複雑になります。
GitHubやGitLabをご利用されている場合はCodePipelineのソースとして使用が可能なためこちらをご利用されるのもよいと思います。
GitHub 接続
GitLab セルフマネージド の接続