こんにちは!
CodePipeLine を使用して CI.CD 構築を行う時、ソースコードのリポジトリにはいくつかの選択肢がありますが、 AWS 内に閉じて CodePipeLine を実行したい!なんてニーズが多いのではないと考えます。プロジェクトによっては GitHub や BitBucket 等々のサードパーティの使用に稟議が必要で、面倒くさいから CodeCommit で済ませたいなんてケースも有るかと思います。
ただ、AWS ベストプラクティスのマルチアカウント環境でこれを実現しようとすると、CodeCommit が別のアカウントに存在し、設定が難しいなんて声を多く聞きます。
本記事では、ちょっと複雑で実装の難しい 別アカウントの CodeCommit と CodePipeLine の連携方法を、ソースコード付きで AWS サーバーレスエンジニアが解説します!
本記事では、CodePipeLine の Source ステージのみの解説とし、CodeBuild や CodeDeploy の設定方法については触れません。
上記の構成で、以下の点が重要です。
各要点に触れながら後述で解説いたしますが、クロスアカウントの連携の際には上記のような IAM Role のクロスアカウント連携が重要となります。
IAM Role は AssumeRole によって一時的な認可トークン ( STS トークン ) を発行可能で、AssumeRole を行う実行者を Principal と呼ばれるポリシーで制御できます。本件では、Principal に別アカウントの IAM Role を追加し、別アカウントからAssumeRole を可能にすることで、別アカウントのリソースへアクセス ( クロスアカウント制御 )を実現にします。
それでは連携方法をソースコード付きで解説していきます。
CodePipeLine 実行時に各ステージの Artifacts 格納用の S3 Bucket と S3 Bucket Policy 作成します。CodeCommit 側 AWS アカウントによる S3 バケットへの Artifacts の Put とGet/List を認可しています。
CodePipeLineArtifactsBucket:
Type: 'AWS::S3::Bucket'
Properties:
BucketName: 'codepipeline-artifacts-bucket'
AccessControl: Private
VersioningConfiguration:
Status: Enabled
PublicAccessBlockConfiguration:
BlockPublicAcls: true
BlockPublicPolicy: true
IgnorePublicAcls: true
RestrictPublicBuckets: true
CodePipeLineArtifactsBucketPolicy:
Type: 'AWS::S3::BucketPolicy'
DependsOn: CodePipeLineArtifactsBucket
Properties:
Bucket: !Ref CodePipeLineArtifactsBucket
PolicyDocument:
Version: '2012-10-17'
Statement:
- Action:
- s3:PutObject
Effect: Deny
Principal: '*'
Resource:
- 'arn:aws:s3:::codepipeline-artifacts-bucket/*'
- 'arn:aws:s3:::codepipeline-artifacts-bucket'
Condition:
StringNotEquals:
s3:x-amz-server-side-encryption: aws:kms
- Action:
- s3:*
Effect: Deny
Principal: '*'
Resource:
- 'arn:aws:s3:::codepipeline-artifacts-bucket/*'
- 'arn:aws:s3:::codepipeline-artifacts-bucket'
Condition:
Bool:
aws:SecureTransport: false
- Action:
- s3:Get*
- s3:Put*
Effect: Allow
Principal:
AWS:
- arn:aws:iam::${CodeCommit側のAWSアカウントID}:root
- ${CodeCommit側AWSアカウントのIAMRoleARN}
Resource:
- 'arn:aws:s3:::codepipeline-artifacts-bucket/*'
- 'arn:aws:s3:::codepipeline-artifacts-bucket'
- Action:
- s3:ListBucket
Effect: Allow
Principal:
AWS:
- arn:aws:iam::${CodeCommit側のAWSアカウントID}:root
- ${CodeCommit側AWSアカウントのIAMRoleARN}
Resource:
- 'arn:aws:s3:::codepipeline-artifacts-bucket/*'
- 'arn:aws:s3:::codepipeline-artifacts-bucket'
別アカウント CodeCommit から 自身のアカウントの S3 Bucket へ Artifacts を格納するため、暗号化は必須と言えます。暗号化しなくても実現自体は可能ですが、セキュリティを考えれば必須事項です。
CodePipelineProjectKms:
Type: 'AWS::KMS::Key'
Properties:
Description: CMK for codepipeline s3 artifacts
KeyPolicy:
Version: '2012-10-17'
Id: key-default-
Statement:
- Sid: Enable IAM User Permissions
Effect: Allow
Principal:
AWS:
- !Sub arn:aws:iam::${AWS::AccountId}:root
Action: kms:*
Resource: '*'
- Sid: Allow access for Key Administrators
Effect: Allow
Principal:
AWS:
- ${KMSを管理する保守運用者のIAMユーザーARN}
Action:
- 'kms:Create*'
- 'kms:Describe*'
- 'kms:Enable*'
- 'kms:List*'
- 'kms:Put*'
- 'kms:Update*'
- 'kms:Revoke*'
- 'kms:Disable*'
- 'kms:Get*'
- 'kms:Delete*'
- 'kms:ScheduleKeyDeletion'
- 'kms:CancelKeyDeletion'
Resource: '*'
- Sid: Allow use of the key
Effect: Allow
Principal:
AWS:
- !Sub arn:aws:iam::${CodeCommit側のAWSアカウントID}:root
- !GetAtt CodeBuildServiceRole.Arn
- !GetAtt CodePipelineServiceRole.Arn
- ${CodeCommit側AWSアカウントのIAMRoleARN}
Action:
- kms:DescribeKey
- kms:Encrypt
- kms:Decrypt
- kms:ReEncrypt*
- kms:GenerateDataKey
- kms:GenerateDataKeyWithoutPlaintext
Resource: '*'
- Sid: Allow attachment of persistent resources
Effect: Allow
Principal:
AWS:
- !Sub arn:aws:iam::${CodeCommit側のAWSアカウントID}:root
- !GetAtt CodeBuildServiceRole.Arn
- !GetAtt CodePipelineServiceRole.Arn
- ${CodeCommit側AWSアカウントのIAMRoleARN}
Action:
- kms:CreateGrant
- kms:ListGrants
- kms:RevokeGrant
Resource: '*'
Condition:
Bool:
kms:GrantIsForAWSResource: true
CodePipelineProjectKmsAlias:
Type: AWS::KMS::Alias
Properties:
AliasName: alias/CodePipelineArtifact
TargetKeyId: !Ref CodePipelineProjectKms
ではいよいよ、 CodePipeLine を作成します。 CodePipeLine の Source ステージでは、クロスアカウントの IAM Role を指定します。そうすることで、CodePipeLine の IAM Role がクロスアカウントのAssumeRole を実行します。
尚、前述の通り S3 Bucket のオブジェクトは暗号化し双方のアカウントでアクセスするため、Artifacts には先程作成した KMS を指定します。これにより、 CodeCommit の暗号化されたソースコードを、 CodePipeLine の IAM Role が復号化して Source として使用することが可能となります。
CodePipelineProject:
Type: AWS::CodePipeline::Pipeline
Properties:
Name: CodePipeline
RoleArn: !GetAtt CodePipelineServiceRole.Arn
Stages:
- Name: Source
Actions:
- Name: SourceAction
InputArtifacts: []
OutputArtifacts:
- Name: SourceArtifact
Configuration:
RepositoryName: ${CodeCommitのリポジトリ名}'
BranchName: '${CodeCommitのブランチ名}'
PollForSourceChanges: false
ActionTypeId:
Category: Source
Owner: AWS
Provider: CodeCommit
Version: '1'
RoleArn: ${CodeCommit側AWSアカウントのIAMRoleARN}
Namespace: SourceVariables
RunOrder: 1
ArtifactStore:
Type: S3
Location: !Ref CodePipeLineArtifactsBucket
EncryptionKey:
Id: !GetAtt CodePipelineProjectKms.Arn
Type: KMS
CodePipelineServiceRole:
Type: AWS::IAM::Role
Properties:
RoleName: 'CodePipelineServiceRole'
Path: /
AssumeRolePolicyDocument:
Version: '2012-10-17'
Statement:
- Effect: Allow
Principal:
Service:
- codepipeline.amazonaws.com
Action:
- sts:AssumeRole
MaxSessionDuration: 3600
Policies:
- PolicyName: 'CodePipelineServiceRolePolicy'
PolicyDocument:
Version: '2012-10-17'
Statement:
- Effect: Allow
Action:
- sts:AssumeRole
Resource: ${CodeCommit側AWSアカウントのIAMRoleARN}
# Any Polices...
CodePipeLine の AssumeRole を許可します。これにより、CodePipeLine 側のアカウントから CodeCommit が参照可能となります。
Resources:
Repository:
Type: AWS::CodeCommit::Repository
Properties:
RepositoryName: HogeFugaRepository
Role:
Type: AWS::IAM::Role
Properties:
AssumeRolePolicyDocument:
Version: 2012-10-17
Statement:
- Effect: Allow
Principal:
AWS:
- arn:aws:iam::${CodePipeLine側のAWSアカウントID}:root
- ${CodePipeLine側のCodePipelineServiceRole ARN}
Action:
- sts:AssumeRole
Path: /
Policies:
- PolicyName: source
PolicyDocument:
Version: 2012-10-17
Statement:
- Effect: Allow
Action:
- s3:PutObject
- s3:PutObjectAcl
Resource:
- !Sub ${CodePipeLine側のArtifacts用S3BucketARN}/*
- Effect: Allow
Action:
- kms:DescribeKey
- kms:GenerateDataKey*
- kms:Encrypt
- kms:ReEncrypt*
- kms:Decrypt
Resource:
- ${CodePipeLine側のKMS ARN}
- Effect: Allow
Action:
- codecommit:GetBranch
- codecommit:GetCommit
- codecommit:UploadArchive
- codecommit:GetUploadArchiveStatus
- codecommit:CancelUploadArchive
Resource:
- !GetAtt Repository.Arn
やりたいことは単純ですが、AWS 準拠のセキュリティに則って作ろうと意外と本記事の通り手順が多い印象です。ただ本記事の内容を実現することで、リポジトリの設営にサードパーティの用意が不要となり、面倒な社内稟議や、場合によってはサードパーティへの高いランニングコストが不要となります。
CodePipeLine を作っているヒトは、是非取り組んでみてください!
スモールスタート開発支援、サーバーレス・NoSQLのことなら
ラーゲイトまでご相談ください
低コスト、サーバーレスの
モダナイズ開発をご検討なら
下請け対応可能
Sler企業様からの依頼も歓迎