この記事は公開されてから1年以上経過しています。情報が古い可能性がありますので、ご注意ください。
はじめに
どうも、クラスメソッドの岡です。
今回アカウントをまたいでCodeCommitで管理しているAngular製SPAを継続的にデプロイする環境を作成するCFnテンプレートを作ってみました。
サーバーレスで作りやすいSPAですが、AWSで開発をする場合実際に稼働している環境と開発する環境はアカウントが分かれているパターンが多いかと思います。
また、ソースコードをCodeCommitで管理している場合はCodePipelineでデプロイフローを作るのが一般的ですがアカウントをまたぐ場合はIAMの設定等に気を使います。
ここでは、CloudFormationでAssumeRole元のIAMロールからCopePipeline、実際にS3にデプロイするCodeBuildプロジェクトまで一気に作成する方法をご紹介したいと思います。
シチュエーション
SPAの構成
まずデプロイ対象のSPAの構成は以下です。
デプロイ構成
- ソース管理は開発アカウントのCodeCommit
- ソースコードの環境の振り分けはブランチ名で
- アカウントをまたいでアクセスするアーティファクト用のS3バケットはKMSで暗号化
- Angularのデプロイ(S3に上書き)はCodeBuildのbuildファイルで設定
AngularをCodeBuildでデプロイする方法はこちらの記事でご紹介しています。
ここではビルドファイルをそれぞれ
- codebuild/buildspec.itg.yml
- codebuild/buildspec.stg.yml
- codebuild/buildspec.prd.yml
で作成済みとします。
CFnテンプレート
まずテンプレートを3つに分けました。 デプロイ先のアカウントとソースアカウントで作るリソースが変わるためです。
- デプロイ先のアカウントにpipeline,buildプロジェクトを作成するテンプレート
- ソースアカウントにAssumeRoleするためのIAMRoleを作成するテンプレート
- ソースアカウントにpipeline,buildプロジェクトを作成するテンプレート
デプロイ先のアカウント(ここではstagingかproduction)
ソースアカウント(ここでは開発アカウント)
デプロイ先のアカウントで実行するテンプレート
デプロイ先のアカウント、stagingとproductionで実行するテンプレートです。
作成するリソースは以下となります。
- CodePipelineのIAMRole
- CodebuildのIAMRole
- アーティファクトバケットの暗号化用のKMSキー
- アーティファクトバケット(S3)
- バケットポリシー
- CodePipelineのパイプライン
- CodeBuildのプロジェクト
AWSTemplateFormatVersion: '2010-09-09'
Description: 'Create resources for automatic deployment of SPA'
Parameters:
Env:
Type: String
Default: stg
AllowedValues:
- stg
- prd
Description: 'Set Enter Environment for SPA'
DeployAccountId:
Type: String
Default: 123456789012
AllowedValues:
- 123456789012
- 098765432109
Description: 'Set Enter Account ID for SPA'
SourceAccountId:
Type: String
Default: 678901234567
Description: 'Set Enter Account ID for SPA source'
SpaName:
Type: String
Default: member-spa
AllowedValues:
- member-spa
- qrcode-spa
- management-console
Description: 'Set Enter SPA name'
BranchName:
Type: String
Default: staging
AllowedValues:
- staging
- master
Description: 'Set Enter BranchName for SPA'
Resources:
#pipeline用のIAMロールを作成
SpaPipelineRole:
Type: AWS::IAM::Role
Properties:
AssumeRolePolicyDocument:
Version: '2012-10-17'
Statement:
- Effect: Allow
Principal:
Service: codepipeline.amazonaws.com
Action: sts:AssumeRole
Policies:
- PolicyDocument:
Version: '2012-10-17'
Statement:
- Effect: Allow
Action:
- s3:*
Resource:
- !Sub arn:aws:s3:::${Env}-auto-deploy-${SpaName}
- !Sub arn:aws:s3:::${Env}-auto-deploy-${SpaName}/*
- Effect: Allow
Action:
- codebuild:StartBuild
- codebuild:BatchGetBuilds
Resource:
- '*'
- Effect: Allow
Action:
- sts:AssumeRole
Resource: !Sub arn:aws:iam::${SourceAccountId}:role/${Env}-auto-deploy-${SpaName}-for-codecommit
PolicyName: !Sub ${Env}-auto-deploy-${SpaName}-for-pipeline
RoleName: !Sub ${Env}-auto-deploy-${SpaName}-for-pipeline
#codebuild用のIAMロールを作成
SpaCodeBuildRole:
Type: AWS::IAM::Role
Properties:
AssumeRolePolicyDocument:
Version: '2012-10-17'
Statement:
- Effect: Allow
Principal:
Service: codebuild.amazonaws.com
Action: sts:AssumeRole
Policies:
- PolicyDocument:
Version: '2012-10-17'
Statement:
- Effect: Allow
Action:
- logs:*
- cloudfront:CreateInvalidation
Resource:
- '*'
- Effect: Allow
Action:
- s3:*
Resource:
- '*'
PolicyName: !Sub ${Env}-auto-deploy-${SpaName}-for-codebuild
RoleName: !Sub ${Env}-auto-deploy-${SpaName}-for-codebuild
#S3暗号化の為のKMSキーを作成
SpaKmsKey:
Type: AWS::KMS::Key
Properties:
Description: SPA deploy
KeyPolicy:
Version: '2012-10-17'
Statement:
- Sid: 'Enable IAM User Permissions'
Effect: Allow
Principal:
AWS: !Sub arn:aws:iam::${DeployAccountId}:root
Action: kms:*
Resource: '*'
- Sid: 'Allow access for Key Administrators'
Effect: Allow
Principal:
AWS:
- !GetAtt SpaCodeBuildRole.Arn
- !GetAtt SpaPipelineRole.Arn
Action:
- kms:Create*
- kms:Describe*
- kms:Enable*
- kms:List*
- kms:Put*
- kms:Update*
- kms:Revoke*
- kms:Disable*
- kms:Get*
- kms:Delete*
- kms:TagResource
- kms:UntagResource
Resource: '*'
- Sid: 'Allow use of the key'
Effect: Allow
Principal:
AWS:
- !Sub arn:aws:iam::${SourceAccountId}:root
- !GetAtt SpaCodeBuildRole.Arn
- !GetAtt SpaPipelineRole.Arn
Action:
- kms:Encrypt
- kms:Decrypt
- kms:ReEncrypt*
- kms:GenerateDataKey*
- kms:DescribeKey
Resource: '*'
- Sid: 'Allow attachment of persistent resources'
Effect: Allow
Principal:
AWS:
- !Sub arn:aws:iam::${SourceAccountId}:root
- !GetAtt SpaCodeBuildRole.Arn
- !GetAtt SpaPipelineRole.Arn
Action:
- kms:CreateGrant
- kms:ListGrants
- kms:RevokeGrant
Resource: '*'
Condition:
Bool:
kms:GrantIsForAWSResource: true
#アーティファクト用S3バケットを作成
SpaSourceS3:
Type: AWS::S3::Bucket
Properties:
BucketName: !Sub ${Env}-auto-deploy-${SpaName}
BucketEncryption:
ServerSideEncryptionConfiguration:
- ServerSideEncryptionByDefault:
SSEAlgorithm: aws:kms
KMSMasterKeyID: !Ref SpaKmsKey
SpaSourceS3BacketPolicy:
Type: AWS::S3::BucketPolicy
Properties:
Bucket: !Ref SpaSourceS3
PolicyDocument:
Version: '2012-10-17'
Id: SSEAndSSLPolicy
Statement:
- Sid: CrossAccountS3GetPutPolicy
Effect: Allow
Principal:
AWS: !Sub arn:aws:iam::${SourceAccountId}:root
Action:
- s3:Get*
- s3:Put*
Resource: !Sub arn:aws:s3:::${Env}-auto-deploy-${SpaName}/*
- Sid: CrossAccountS3ListPolicy
Effect: Allow
Principal:
AWS: !Sub arn:aws:iam::${SourceAccountId}:root
Action: s3:*
Resource: !Sub arn:aws:s3:::${Env}-auto-deploy-${SpaName}/*
- Sid: CodePipeline
Effect: Allow
Principal:
AWS: !GetAtt SpaPipelineRole.Arn
Action: s3:*
Resource: !Sub arn:aws:s3:::${Env}-auto-deploy-${SpaName}/*
#SPAをS3にデプロイするCodebuildプロジェクトを作成
SpaCodebuild:
Type: AWS::CodeBuild::Project
Properties:
Artifacts:
Type: CODEPIPELINE
Description: 'Build a SPA across accounts'
EncryptionKey: !GetAtt SpaKmsKey.Arn
Environment:
Type: LINUX_CONTAINER
ComputeType: BUILD_GENERAL1_SMALL
Image: 'aws/codebuild/nodejs:8.11.0'
Name: !Sub ${Env}-auto-deploy-${SpaName}
ServiceRole: !GetAtt SpaCodeBuildRole.Arn
Source:
Type: CODEPIPELINE
BuildSpec: !Sub codebuild/buildspec.${Env}.yml
#Codecommitからソースを読み込んでCodebuildに受け渡すCodePipelineを作成
SpaPipeline:
Type: AWS::CodePipeline::Pipeline
Properties:
Name: !Sub ${Env}-auto-deploy-${SpaName}
ArtifactStore:
Type: S3
Location: !Sub ${Env}-auto-deploy-${SpaName}
EncryptionKey:
Id: !GetAtt SpaKmsKey.Arn
Type: KMS
RoleArn: !GetAtt SpaPipelineRole.Arn
Stages:
- Name: Source
Actions:
- ActionTypeId:
Category: Source
Owner: AWS
Provider: CodeCommit
Version: 1
Name: Source
Configuration:
BranchName: !Sub ${BranchName}
RepositoryName: !Sub ${SpaName}
OutputArtifacts:
- Name: SpaSourceCode
RoleArn: !Sub arn:aws:iam::${SourceAccountId}:role/${Env}-auto-deploy-${SpaName}-for-codecommit
RunOrder: 1
- Name: build
Actions:
- ActionTypeId:
Category: Build
Owner: AWS
Provider: CodeBuild
Version: 1
Name: Build
Configuration:
ProjectName: !Ref SpaCodebuild
InputArtifacts:
- Name: SpaSourceCode
RunOrder: 1
ソースアカウントにAssumeRoleするためのIAMRoleを作成するテンプレート
こちらは開発アカウントで実行します。 ステージングと本番アカウントからAssumeroleするためのIAMロールを作成するのでパラメーターのEnvにはデプロイ先の環境名を入力しましょう。
- Env:デプロイ先の環境名(staging=stg、production=prd)
- DeployAccountId:デプロイ先のAWSアカウントID
- SourceAccountId:CodeCommitのソースが置いてあるアカウントID
- SpaName:CodeCommitのリポジトリ名
AWSTemplateFormatVersion: '2010-09-09'
Description: 'Create resources for automatic deployment of SPA'
Parameters:
Env:
Type: String
Default: stg
AllowedValues:
- stg
- prd
Description: 'Set Enter Environment for SPA'
DeployAccountId:
Type: String
Default: 123456789012
AllowedValues:
- 123456789012
- 098765432109
Description: 'Set Enter Account ID to deploy SPA'
SourceAccountId:
Type: String
Default: 678901234567
Description: 'Set Enter Account ID for SPA source'
SpaName:
Type: String
Default: my-app
AllowedValues:
- my-app
- my-app2
Description: 'Set Enter SPA name'
Resources:
# Create an IAM role to access codecommit
PipelineRole:
Type: AWS::IAM::Role
Properties:
AssumeRolePolicyDocument:
Version: '2012-10-17'
Statement:
- Effect: Allow
Principal:
AWS: !Sub arn:aws:iam::${DeployAccountId}:root
Action: sts:AssumeRole
Policies:
- PolicyName: !Sub ${Env}-auto-deploy-${SpaName}-for-codecommit
PolicyDocument:
Version: '2012-10-17'
Statement:
- Effect: Allow
Action:
- s3:*
Resource:
- !Sub arn:aws:s3:::${Env}-auto-deploy-${SpaName}
- !Sub arn:aws:s3:::${Env}-auto-deploy-${SpaName}/*
- Effect: Allow
Action:
- kms:DescribeKey
- kms:GenerateDataKey*
- kms:Encrypt
- kms:ReEncrypt*
- kms:Decrypt
Resource:
- '*'
- Effect: Allow
Action:
- codecommit:GetBranch
- codecommit:GetCommit
- codecommit:UploadArchive
- codecommit:GetUploadArchiveStatus
- codecommit:CancelUploadArchive
Resource:
- !Sub arn:aws:codecommit:ap-northeast-1:${SourceAccountId}:${SpaName}
RoleName: !Sub ${Env}-auto-deploy-${SpaName}-for-codecommit
ソースアカウントにpipeline,buildプロジェクトを作成するテンプレート
最後に開発アカウントにPipalineを作成します。 こちらはアカウントは跨がないのでシンプルなテンプレートになります。
AWSTemplateFormatVersion: '2010-09-09'
Description: 'Create resources for automatic deployment of SPA'
Parameters:
Env:
Type: String
Default: itg
Description: 'Set Enter Environment for SPA'
DeployAccountId:
Type: String
Default: 678901234567
AllowedValues:
- 678901234567
Description: 'Set Enter Account ID to deploy SPA'
SpaName:
Type: String
Default: my-app
AllowedValues:
- my-app
- my-app2
Description: 'Set Enter Repository name'
BranchName:
Type: String
Default: integration
AllowedValues:
- integration
Description: 'Set Enter branch name'
Resources:
# create IAM role for pipeline
SpaPipelineRole:
Type: AWS::IAM::Role
Properties:
AssumeRolePolicyDocument:
Version: '2012-10-17'
Statement:
- Effect: Allow
Principal:
Service: codepipeline.amazonaws.com
Action: sts:AssumeRole
Policies:
- PolicyDocument:
Version: '2012-10-17'
Statement:
- Effect: Allow
Action:
- s3:*
Resource:
- !Sub arn:aws:s3:::${Env}-auto-deploy-${SpaName}
- !Sub arn:aws:s3:::${Env}-auto-deploy-${SpaName}/*
- Effect: Allow
Action:
- codebuild:StartBuild
- codebuild:BatchGetBuilds
Resource:
- '*'
PolicyName: !Sub ${Env}-auto-deploy-${SpaName}-for-pipeline
RoleName: !Sub ${Env}-auto-deploy-${SpaName}-for-pipeline
# create IAM role for codebuild project
SpaCodeBuildRole:
Type: AWS::IAM::Role
Properties:
AssumeRolePolicyDocument:
Version: '2012-10-17'
Statement:
- Effect: Allow
Principal:
Service: codebuild.amazonaws.com
Action: sts:AssumeRole
Policies:
- PolicyDocument:
Version: '2012-10-17'
Statement:
- Effect: Allow
Action:
- logs:*
- cloudfront:CreateInvalidation
Resource: '*'
- Effect: Allow
Action:
- s3:*
Resource: '*'
- PolicyName: !Sub ${Env}-auto-deploy-${SpaName}-for-codebuild
RoleName: !Sub ${Env}-auto-deploy-${SpaName}-for-codebuild
# Create artifact S3 bucket
SpaSourceS3:
Type: AWS::S3::Bucket
Properties:
BucketName: !Sub ${Env}-auto-deploy-${SpaName}
SpaCodebuild:
Type: AWS::CodeBuild::Project
Properties:
Artifacts:
Type: CODEPIPELINE
Description: 'Build a SPA'
Environment:
Type: LINUX_CONTAINER
ComputeType: BUILD_GENERAL1_SMALL
Image: 'aws/codebuild/nodejs:8.11.0'
Name: !Sub ${Env}-auto-deploy-${SpaName}
ServiceRole: !GetAtt SpaCodeBuildRole.Arn
Source:
Type: CODEPIPELINE
buildspec: !Sub codebuild/buildspec.${Env}.yml
SpaPipaline:
Type: AWS::CodePipeline::Pipeline
Properties:
ArtifactStore:
Type: S3
Location: !Sub ${Env}-auto-deploy-${SpaName}
Name: !Sub ${Env}-auto-deploy-{SpaName}
RoleArn: !GetAtt SpaPipelineRole.Arn
Stages:
Name: 'Source'
Actions:
-
ActionsTypeId:
Category: Source
Owner: AWS
Provider: CodeCommit
Version: 1
Configuration:
BranchName: !Sub ${BranchName}
RepositoryName: !Sub ${SpaName}
OutputArtifacts:
- Name: SpaSourceCode
RunOrder: 1
Stages:
Name: build
Actions:
-
ActionsTypeId:
Category: Build
Owner: AWS
Provider: CodeBuild
Version: 1
Configuration:
ProjectName: !Ref SpaCodebuild
InputArtifacts:
- Name: SpaSourceCode
RunOrder: 1
注意点
CFnでIAMロールを作成する場合、確認画面で CAPABILITY
項目でチェックを入れる必要があります。
チェックを入れないとスタック作成時に Requires capabilities : [CAPABILITY_NAMED_IAM]
のエラーが発生してIAMロールを作成できません。
CLIで実行する場合は
aws cloudformation create-stack
もしくは aws cloudformation update-stack
実行時のオプション --capabilities
に CAPABILITY_NAMED_IAM を指定します。