column

コラム

Lambdaのマルチアカウントデプロイ 構築編

こんにちは、クラウドCoEの熊谷です。
今回は「Lambdaのマルチアカウントデプロイ」と題し、テスト環境と本番環境とでAWSアカウントを分けるような運用環境において、テスト環境で構築したLambdaを本番環境にデプロイする方法をご紹介します。

構築編となる今回は、利用するCloudFormation(以下、CFn)テンプレートの解説をしつつ、どんどん構築していこうと思います。

構築の流れ

今回は4つのCFnテンプレートを使い、テスト環境と本番環境に対して交互に実行していきます。
前工程で作成したAWSリソースを後の工程で参照しているため、必ずこの順序でテンプレートを実行する必要があります。

なお本コラムではCloud9でLambdaを新規作成する手順やCodeCommitとCloud9の連携については説明を省略いたしますのでご了承ください。

[作業1]テスト環境にCodePipelineを構築!

[作業1]テンプレート 1-stg

AWSTemplateFormatVersion: 2010-09-09
Metadata:
  AWS::CloudFormation::Interface:
    ParameterGroups:
      - Label:
          default: STG Environment Parameter
        Parameters:
          - RepositoryName
          - BuildProjectName
          - STGPipelineName
          - BucketName
      - Label:
          default: Prod Environment Parameter
        Parameters:
          - ProdPipelineName
          - ProdAccountID
Parameters:
  ProdAccountID:
    Type : String
  RepositoryName:
    Type : String
  BuildProjectName:
    Type : String
  STGPipelineName:
    Type : String
  BucketName:
    Type: String
  ProdPipelineName:
    Type : String
Resources:
# ------------------------------------------------------------#
#  EventBridge IAM Role/IAM Policy
# ------------------------------------------------------------#
  IAMPolicyForEventBridge:
    Type: AWS::IAM::ManagedPolicy
    Properties:
      ManagedPolicyName: !Sub STGPolicyForEventBridge-${STGPipelineName}
      Roles:
        - !Ref IAMRoleForEventBridge
      PolicyDocument:
        Version: '2012-10-17'
        Statement:
          - Effect: Allow
            Action:
             - codepipeline:StartPipelineExecution
            Resource:
             - !Sub arn:aws:codepipeline:${AWS::Region}:${AWS::AccountId}:${STGPipelineName}
  IAMRoleForEventBridge:
    Type: AWS::IAM::Role
    Properties:
      RoleName: STGRoleForEventBridgeTriggerdBySTGBranchEvnet
      Path: /service-role/
      AssumeRolePolicyDocument:
        Version: 2012-10-17
        Statement:
        - Effect: Allow
          Action: sts:AssumeRole
          Principal:
            Service: events.amazonaws.com
# ------------------------------------------------------------#
#  EventBridgeTriggerdByMasterBranchEvnet IAM Role/IAM Policy
# ------------------------------------------------------------#
  IAMPolicyForEventBridgeTriggerdByMasterBranchEvnet:
    Type: AWS::IAM::ManagedPolicy
    Properties:
      ManagedPolicyName: !Sub STGPolicyForEventBridge-${ProdPipelineName}
      Roles:
        - !Ref IAMRoleForEventBridgeTriggerdByMasterBranchEvnet
      PolicyDocument:
        Version: '2012-10-17'
        Statement:
          - Effect: Allow
            Action:
             - events:PutEvents
            Resource:
             - !Sub arn:aws:events:${AWS::Region}:${ProdAccountID}:event-bus/default
  IAMRoleForEventBridgeTriggerdByMasterBranchEvnet:
    Type: AWS::IAM::Role
    Properties:
      RoleName: STGRoleForEventBridgeTriggerdByMasterBranchEvnet
      Path: /service-role/
      AssumeRolePolicyDocument:
        Version: 2012-10-17
        Statement:
        - Effect: Allow
          Action: sts:AssumeRole
          Principal:
            Service: events.amazonaws.com
# ------------------------------------------------------------#
#  CodeBuild IAM Role/IAM Policy
#  ref. https://docs.aws.amazon.com/ja_jp/codebuild/latest/userguide/auth-and-access-control-permissions-reference.html
# ------------------------------------------------------------#
  IAMPolicyForCodeBuild:
    Type: AWS::IAM::ManagedPolicy
    Properties:
      ManagedPolicyName: !Sub STGPolicyForCodeBuild-${STGPipelineName}
      Roles:
        - !Ref IAMRoleForCodeBuild
      PolicyDocument:
        Version: '2012-10-17'
        Statement:
          - Sid: CloudWatchLogsPolicy
            Effect: Allow
            Action:
             - logs:CreateLogGroup
             - logs:CreateLogStream
             - logs:PutLogEvents
            Resource:
             - !Sub arn:aws:logs:${AWS::Region}:${AWS::AccountId}:log-group:/aws/codebuild/${CodeBuildProject}
             - !Sub arn:aws:logs:${AWS::Region}:${AWS::AccountId}:log-group:/aws/codebuild/${CodeBuildProject}:*
          - Sid: CodeCommitPull
            Effect: Allow
            Action:
             - codecommit:GitPull
            Resource: !Sub arn:aws:codecommit:${AWS::Region}:${AWS::AccountId}:${RepositoryName}
          - Sid: BuildStageArtifactPushPolicy
            Effect: Allow
            Action:
             - s3:PutObject
            Resource:
             - !Join ['', ['arn:aws:s3:::', !Ref ArtifactBucket, /*]]
          - Sid: SourceStageArtifactGetPolicy
            Effect: Allow
            Action:
             - s3:GetBucketAcl
             - s3:GetBucketLocation
            Resource:
             - !GetAtt ArtifactBucket.Arn
          - Sid: GetArtifactPolicy
            Effect: Allow
            Action:
             - s3:GetObject
             - s3:GetObjectVersion
            Resource:
             - !Join ['', ['arn:aws:s3:::', !Ref ArtifactBucket, /*]]
          - Sid: AllowUseCMK
            Effect: Allow
            Action:
             - kms:GenerateDataKey
             - kms:GenerateDataKeyWithoutPlaintext
             - kms:DescribeKey
             - kms:Encrypt
             - kms:Decrypt
            Resource:
             - !GetAtt Key.Arn
  IAMRoleForCodeBuild:
    Type: AWS::IAM::Role
    Properties:
      RoleName:  !Sub STGRoleForCodeBuild-${STGPipelineName}
      Path: /service-role/
      AssumeRolePolicyDocument:
        Version: 2012-10-17
        Statement:
        - Effect: Allow
          Action: sts:AssumeRole
          Principal:
            Service: codebuild.amazonaws.com
# ------------------------------------------------------------#
#  Deploy Stage IAM Role/IAM Policy
# ------------------------------------------------------------#
  IAMPolicyForDeployStage:
    Type: AWS::IAM::ManagedPolicy
    Properties:
      ManagedPolicyName: !Sub STGPolicyForDeploy-${STGPipelineName}
      Roles:
        - !Ref IAMRoleForDeployStage
      PolicyDocument:
        Version: '2012-10-17'
        Statement:
          - Sid: LambdaDeployPolicy
            Effect: Allow
            Action:
             - lambda:*
            Resource: "*"
          - Sid: APIGatewayPolicy
            Effect: Allow
            Action:
             - apigateway:*
            Resource: "*"
          - Sid: CloudFormationCreateChangeSetPolicy
            Effect: Allow
            Action:
             - cloudformation:CreateChangeSet
            Resource: "*"
          - Sid: IAMPolicy
            Effect: Allow
            Action:
             - iam:GetRole
             - iam:CreateRole
             - iam:DeleteRole
             - iam:PutRolePolicy
             - iam:AttachRolePolicy
             - iam:DeleteRolePolicy
             - iam:DetachRolePolicy
             - iam:PassRole
            Resource: "*"
          - Sid: GetArtifactStorePolicy
            Effect: Allow
            Action:
             - s3:GetBucketLocation
             - s3:GetBucketVersioning
             - s3:GetBucketAcl
            Resource:
             - !GetAtt ArtifactBucket.Arn
          - Sid: GetArtifactPolicy
            Effect: Allow
            Action:
             - s3:GetObject
             - s3:GetObjectVersion
            Resource:
             - !Join ['', ['arn:aws:s3:::', !Ref ArtifactBucket, /*]]
  IAMRoleForDeployStage:
    Type: AWS::IAM::Role
    Properties:
      RoleName: !Sub STGRoleForDeploy-${STGPipelineName}
      AssumeRolePolicyDocument:
        Version: 2012-10-17
        Statement:
         - Effect: Allow
           Action: sts:AssumeRole
           Principal:
             Service: cloudformation.amazonaws.com
      Path: /
# IAMPolicy for CodePipeline
  IAMPolicyForCodePipeline:
    Type: AWS::IAM::ManagedPolicy
    Properties:
      ManagedPolicyName: !Sub STGPolicyForCodePipeline-${STGPipelineName}
      Roles:
        - !Ref IAMRoleFoCodePipeline
      PolicyDocument:
        Version: '2012-10-17'
        Statement:
          - Effect: Allow
            Action:
             - iam:PassRole
            Resource: "*"
            Condition:
              StringEqualsIfExists:
                iam:PassedToService:
                 - cloudformation.amazonaws.com
          - Sid: CodeCommitPolicy
            Effect: Allow
            Action:
             - codecommit:CancelUploadArchive
             - codecommit:GetBranch
             - codecommit:GetCommit
             - codecommit:GetUploadArchiveStatus
             - codecommit:UploadArchive
            Resource:
              - !Sub arn:aws:codecommit:${AWS::Region}:${AWS::AccountId}:${RepositoryName}
          - Sid: CodeBuildPolicy
            Effect: Allow
            Action:
             - codebuild:BatchGetBuilds
             - codebuild:StartBuild
             - codebuild:StopBuild
             - codebuild:RetryBuild
            Resource:
              - !Sub arn:aws:codebuild:${AWS::Region}:${AWS::AccountId}:project/${CodeBuildProject}
          - Sid: LambdaPolicy
            Effect: Allow
            Action:
              - lambda:InvokeFunction
              - lambda:ListFunctions
            Resource: "*"
          - Sid: CloudFormationDeployPolicy
            Effect: Allow
            Action:
             - cloudformation:CreateStack
             - cloudformation:DeleteStack
             - cloudformation:DescribeStacks
             - cloudformation:UpdateStack
             - cloudformation:CreateChangeSet
             - cloudformation:DeleteChangeSet
             - cloudformation:DescribeChangeSet
             - cloudformation:ExecuteChangeSet
             - cloudformation:SetStackPolicy
             - cloudformation:ValidateTemplate
            Resource: "*"
          - Sid: SourceStageArtifactPushPolicy
            Effect: Allow
            Action:
             - s3:PutObject
            Resource:
             - !Join ['', ['arn:aws:s3:::', !Ref ArtifactBucket, /*]]
          - Sid: SourceStageArtifactGetPolicy
            Effect: Allow
            Action:
             - s3:GetBucketAcl
             - s3:GetBucketLocation
            Resource:
             - !GetAtt ArtifactBucket.Arn
          - Sid: GetArtifactStorePolicy
            Effect: Allow
            Action:
             - s3:GetObject
             - s3:GetObjectVersion
            Resource:
             - !Join ['', ['arn:aws:s3:::', !Ref ArtifactBucket, /*]]
  IAMRoleFoCodePipeline:
    Type: AWS::IAM::Role
    Properties:
      RoleName: !Sub STGRoleForCodePipeline-${STGPipelineName}
      AssumeRolePolicyDocument:
        Version: 2012-10-17
        Statement:
        - Effect: Allow
          Action: sts:AssumeRole
          Principal:
            Service: codepipeline.amazonaws.com
# ------------------------------------------------------------#
#  CodeCommit
# ------------------------------------------------------------#
  CodeCommitRepository:
    Type: AWS::CodeCommit::Repository
    Properties:
      RepositoryName: !Ref RepositoryName
      RepositoryDescription: !Sub store ${RepositoryName} source
# ------------------------------------------------------------#
#  CodeBuild
# ------------------------------------------------------------#
  CodeBuildProject:
    Type: AWS::CodeBuild::Project
    Properties:
      Name: !Ref BuildProjectName
      Source:
        BuildSpec: buildspec.yml
        Type: CODEPIPELINE
      Artifacts:
        Type: CODEPIPELINE
      EncryptionKey: !GetAtt Key.Arn
      Environment:
        ComputeType: BUILD_GENERAL1_SMALL
        Image: aws/codebuild/standard:4.0
        Type: LINUX_CONTAINER
        EnvironmentVariables:
          - Name: BUCKET_NAME
            Type: PLAINTEXT
            Value: !Ref BucketName
      ServiceRole: !GetAtt IAMRoleForCodeBuild.Arn
# ------------------------------------------------------------#
#  CpdePipeline
# ------------------------------------------------------------#
  CodePipelineForLambda:
    Type: AWS::CodePipeline::Pipeline
    Properties:
      ArtifactStore:
        Location: !Ref ArtifactBucket
        Type: S3
        EncryptionKey:
          Id: !GetAtt Key.Arn
          Type: KMS
      Name: !Ref STGPipelineName
      RoleArn: !GetAtt IAMRoleFoCodePipeline.Arn
      Stages:
        - Name: Source
          Actions:
            - Name: Commit
              ActionTypeId:
                Category: Source
                Owner: AWS
                Version: 1
                Provider: CodeCommit
              Configuration:
                RepositoryName: !Ref RepositoryName
                BranchName: stg
              RunOrder: 1
              OutputArtifacts:
                - Name: SourceArtifact
        - Name: Build
          Actions:
            - Name: Build
              ActionTypeId:
                Category: Build
                Owner: AWS
                Version: 1
                Provider: CodeBuild
              RunOrder: 1
              Configuration:
                ProjectName: !Ref CodeBuildProject
              InputArtifacts:
                - Name: SourceArtifact # SourceステージのOutputArtifactsの名称と揃える
              OutputArtifacts:
                - Name: BuildArtifact
        - Name: Deploy
          Actions:
            - Name: Deploy
              InputArtifacts:
               - Name: BuildArtifact # BuildステージのOutputArtifactsの名称と揃える
              ActionTypeId:
                Category: Deploy
                Owner: AWS
                Version: 1
                Provider: CloudFormation
              Configuration:
                ActionMode: CHANGE_SET_REPLACE
                Capabilities: CAPABILITY_IAM,CAPABILITY_AUTO_EXPAND,CAPABILITY_NAMED_IAM
                ChangeSetName: lambda-pipeline-changeset
                StackName: lambda-pipeline-changeset
                TemplatePath: 'BuildArtifact::packaged-template.yaml' # CodeBuildのbuildspec.ymlで出力した成果物の名称
                RoleArn: !GetAtt IAMRoleForDeployStage.Arn
              RunOrder: 1
# ------------------------------------------------------------#
#  EventBridge
#  ref. https://docs.aws.amazon.com/ja_jp/codepipeline/latest/userguide/pipelines-trigger-source-repo-changes-cfn.html
# ------------------------------------------------------------#
  EventBridgeTriggerdByCodeCommitSTGBranchMerge:
    Type: AWS::Events::Rule
    Properties:
      Description: !Sub Invoking STG CodePipeline ${RepositoryName}
      Name: !Sub EventBridgeRule-STG-CodePipeline-${RepositoryName}
      EventPattern:
        source:
          - aws.codecommit
        resources:
          - !Sub arn:aws:codecommit:${AWS::Region}:${AWS::AccountId}:${RepositoryName}
        detail:
          event:
            - referenceCreated
            - referenceUpdated
          referenceType:
            - branch
          referenceName:
            - stg
        detail-type:
          - CodeCommit Repository State Change
      Targets:
        - Id: codepipeline
          RoleArn: !GetAtt IAMRoleForEventBridge.Arn
          Arn: !Sub arn:aws:codepipeline:${AWS::Region}:${AWS::AccountId}:${STGPipelineName}
  EventBridgeTriggerdByCodeCommitProdBranchMerge:
    Type: AWS::Events::Rule
    Properties:
      Description: !Sub Invoking Prod CodePipeline ${RepositoryName}
      Name: !Sub EventBridgeRule-Prod-CodePipeline-${RepositoryName}
      EventPattern:
        source:
          - aws.codecommit
        resources:
          - !Sub arn:aws:codecommit:${AWS::Region}:${AWS::AccountId}:${RepositoryName}
        detail:
          event:
            - referenceCreated
            - referenceUpdated
          referenceType:
            - branch
          referenceName:
            - master
        detail-type:
          - CodeCommit Repository State Change
      Targets:
        - Id: prod-event-bus
          RoleArn: !GetAtt IAMRoleForEventBridgeTriggerdByMasterBranchEvnet.Arn
          Arn: !Sub arn:aws:events:${AWS::Region}:${ProdAccountID}:event-bus/default
# ------------------------------------------------------------#
#  KMS
# ------------------------------------------------------------#
  Key:
    Type: AWS::KMS::Key
    Properties:
      Description: CodePipeline CMK
      KeyPolicy:
        Version: 2012-10-17
        Id: key-default-1
        Statement:
        - Sid: Enable IAM User Permissions
          Effect: Allow
          Principal:
            AWS:
            - !Sub arn:aws:iam::${AWS::AccountId}:root
          Action: kms:*
          Resource: "*"
        - Sid: Allow administration of the key
          Effect: Allow
          Principal:
            AWS:
            - !Sub arn:aws:iam::${AWS::AccountId}:root
          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:
            - !GetAtt IAMRoleFoCodePipeline.Arn
            - !GetAtt IAMRoleForCodeBuild.Arn
            - !GetAtt IAMRoleForDeployStage.Arn
          Action:
          - kms:DescribeKey
          - kms:Encrypt
          - kms:Decrypt
          - kms:ReEncrypt*
          - kms:GenerateDataKey
          - kms:GenerateDataKeyWithoutPlaintext
          Resource: "*"
        - Sid: Allow attachment of persistent resources
          Effect: Allow
          Principal:
            AWS:
            - !GetAtt IAMRoleFoCodePipeline.Arn
            - !GetAtt IAMRoleForCodeBuild.Arn
            - !GetAtt IAMRoleForDeployStage.Arn
          Action:
          - kms:CreateGrant
          - kms:ListGrants
          - kms:RevokeGrant
          Resource: "*"
          Condition:
            Bool:
              kms:GrantIsForAWSResource: true
  Alias:
    Type: AWS::KMS::Alias
    Properties:
      AliasName: alias/CodePipelineArtifact
      TargetKeyId:
        Ref: Key
# ------------------------------------------------------------#
#  S3Bucket
# ------------------------------------------------------------#
  ArtifactBucket:
    Type: AWS::S3::Bucket
    Properties:
      BucketName: !Ref BucketName
      BucketEncryption:
        ServerSideEncryptionConfiguration:
          - ServerSideEncryptionByDefault:
              SSEAlgorithm: AES256
      LifecycleConfiguration:
        Rules:
          - ExpirationInDays: 90
            Id: !Sub ${BucketName}-LifeCycle
            Status: Enabled
  S3ArtifactBucketPolicy:
    Type: AWS::S3::BucketPolicy
    Description: Amazon S3 bucket policy for CMK
    Properties:
      Bucket: !Ref ArtifactBucket
      PolicyDocument:
        Statement:
        - Sid: DenyAccessWithoutUsingCMK
          Action:
           - s3:PutObject
          Effect: Deny
          Principal: "*"
          Resource:
           - !Sub arn:aws:s3:::${ArtifactBucket}/*
          Condition:
            StringNotLikeIfExists:
              {"s3:x-amz-server-side-encryption-aws-kms-key-id": !GetAtt Key.Arn}
        - Sid: DenyHTTPAccessPolicy
          Action:
           - s3:*
          Effect: Deny
          Principal: "*"
          Resource:
           - !Sub arn:aws:s3:::${ArtifactBucket}/*
          Condition:
            Bool:
              aws:SecureTransport: false
        - Sid: S3GetPutPolicy
          Action:
           - s3:Get*
           - s3:Put*
          Effect: Allow
          Principal:
            AWS:
             - !Sub arn:aws:iam::${AWS::AccountId}:root
          Resource:
          - !Sub arn:aws:s3:::${ArtifactBucket}/*
        - Sid: S3ListPolicy
          Action:
           - s3:ListBucket
          Effect: Allow
          Principal:
            AWS:
             - !Sub arn:aws:iam::${AWS::AccountId}:root
          Resource:
           - !Sub arn:aws:s3:::${ArtifactBucket}
        Version: 2012-10-17

[作業1]テンプレートの補足 2つのEventBridge

1-stgテンプレートでは2つのEventBridgeを構築します。

  • stgブランチのイベントを拾うEventBridge
  • masterブランチのイベントを拾うEventBridge

1つ目のEventBridgeはstgブランチへのマージイベントを拾ってテスト環境のCodePipelineを動かします。

2つ目のEventBridgeはmasterブランチのイベントを拾い、本番CodePipelineを起動するためのものです。

両者のテンプレート上の記述の違いはイベントパターンのreferenceNameとターゲットです。

stgブランチのイベントを拾うEventBridgeの記述例

  EventBridgeTriggerdByCodeCommitSTGBranchMerge:
    Type: AWS::Events::Rule
    Properties:
     ###省略###
      EventPattern:
        source:
          - aws.codecommit
        resources:
          - !Sub arn:aws:codecommit:${AWS::Region}:${AWS::AccountId}:${RepositoryName}
        detail:
          event:
            - referenceCreated
            - referenceUpdated
          referenceType:
            - branch
          referenceName:
            - stg
        detail-type:
          - CodeCommit Repository State Change
      Targets:
        - Id: codepipeline
          RoleArn: !GetAtt IAMRoleForEventBridge.Arn
          Arn: !Sub arn:aws:codepipeline:${AWS::Region}:${AWS::AccountId}:${STGPipelineName} #テスト環境のCodePipeline

本番環境のCodePipelineを起動させたいとしても、異なるAWSアカウントのCodePipelineを直接ターゲットにしたところで動いてくれません。
よって本番環境のEventBridgeを動かしてくれるEventBusをターゲットに設定します。

masterブランチのイベントを拾うEventBridgeの記述例

EventBridgeTriggerdByCodeCommitProdBranchMerge:
    Type: AWS::Events::Rule
    Properties:
     ###省略###
      EventPattern:
        source:
          - aws.codecommit
        resources:
          - !Sub arn:aws:codecommit:${AWS::Region}:${AWS::AccountId}:${RepositoryName}
        detail:
          event:
            - referenceCreated
            - referenceUpdated
          referenceType:
            - branch
          referenceName:
            - master
        detail-type:
          - CodeCommit Repository State Change
      Targets:
        - Id: prod-event-bus
          RoleArn: !GetAtt IAMRoleForEventBridgeTriggerdByMasterBranchEvnet.Arn
          Arn: !Sub arn:aws:events:${AWS::Region}:${ProdAccountID}:event-bus/default #本番環境のEvnet Bus

masterブランチイベント用のEventBridgeのサービスロールでは、本番環境のEvent Busを動かすための権限が必要です。

master用EventBridgeのサービスロールにアタッチするIAMポリシー

  IAMPolicyForEventBridgeTriggerdByMasterBranchEvnet:
    Type: AWS::IAM::ManagedPolicy
    Properties:
     ###省略###
      PolicyDocument:
        Version: '2012-10-17'
        Statement:
          - Effect: Allow
            Action:
             - events:PutEvents
            Resource:
             - !Sub arn:aws:events:${AWS::Region}:${ProdAccountID}:event-bus/default

[作業1]テンプレートの補足 DeployStageのサービスロール

今回はLambdaとAPI Gatewayをデプロイするため、サービスロールに両サービスの権限を付与しています。
DeployStageのサービスロール

  IAMPolicyForDeployStage:
    Type: AWS::IAM::ManagedPolicy
    Properties:
     ###省略###
      PolicyDocument:
        Version: '2012-10-17'
        Statement:
          - Sid: LambdaDeployPolicy
            Effect: Allow
            Action:
             - lambda:*
            Resource: "*"
          - Sid: APIGatewayPolicy
            Effect: Allow
            Action:
             - apigateway:*
            Resource: "*"

SAMではEventBridge RuleやSNS、Step Functionもデプロイ出来ますので、利用したいサービスに応じてDeploy Stageの権限を変更しましょう。

SAMでデプロイ可能なAWSサービスに関しては以下をご参照ください。

AWS SAM リソースとプロパティの参照

[作業1]テンプレートのパラメータ

Pipeline名やBuildプロジェクト名を自由に設定できるようにパラメータにしました。

スタックが正常に作成されるとCodePipelineが起動しますが、まだCodeCommitにブランチが作成されていない状態ですのでこけます。
気にせず次の工程に進みましょう。

[作業2]本番環境でIAMロール・CMK・S3バケットを作成!

作業2では本番環境のCodePipelineやCodeBuildのサービスロールや、成果物暗号化用のCMK、成果物格納用S3バケットを作成します。
これらのAWSサービスのARNが作業3で必要になります。

[作業2]テンプレート 2-prod

AWSTemplateFormatVersion: 2010-09-09
Metadata:
  AWS::CloudFormation::Interface:
    ParameterGroups:
      - Label:
          default: STG Environment Parameter
        Parameters:
          - STGAccountId
      - Label:
          default: Prod Environment Parameter
        Parameters:
          - BuildProjectName
          - PipelineName
          - BucketName
Parameters:
  STGAccountId:
    Description: Repository Account ID
    MaxLength: 12
    MinLength: 12
    Type: String
  BucketName:
    Type: String
  BuildProjectName:
    Type : String
  PipelineName:
    Type : String
Resources:
# ------------------------------------------------------------#
#  CodeBuild IAM Role/IAM Policy
#  ref. https://docs.aws.amazon.com/ja_jp/codebuild/latest/userguide/auth-and-access-control-permissions-reference.html
# ------------------------------------------------------------#
  IAMPolicyForCodeBuild:
    Type: AWS::IAM::ManagedPolicy
    Properties:
      ManagedPolicyName: !Sub ProdPolicyForCodeBuild-${PipelineName}
      Roles:
        - !Ref IAMRoleForCodeBuild
      PolicyDocument:
        Version: '2012-10-17'
        Statement:
          - Sid: CloudWatchLogsPolicy
            Effect: Allow
            Action:
             - logs:CreateLogGroup
             - logs:CreateLogStream
             - logs:PutLogEvents
            Resource:
             - !Sub arn:aws:logs:${AWS::Region}:${AWS::AccountId}:log-group:/aws/codebuild/${BuildProjectName}
             - !Sub arn:aws:logs:${AWS::Region}:${AWS::AccountId}:log-group:/aws/codebuild/${BuildProjectName}:*
          - Sid: BuildStageArtifactPushPolicy
            Effect: Allow
            Action:
             - s3:PutObject
            Resource:
             - !Join ['', ['arn:aws:s3:::', !Ref ArtifactBucket, /*]]
          - Sid: SourceStageArtifactGetPolicy
            Effect: Allow
            Action:
             - s3:GetBucketAcl
             - s3:GetBucketLocation
            Resource:
             - !GetAtt ArtifactBucket.Arn
          - Sid: GetArtifactPolicy
            Effect: Allow
            Action:
             - s3:GetObject
             - s3:GetObjectVersion
            Resource:
             - !Join ['', ['arn:aws:s3:::', !Ref ArtifactBucket, /*]]
  IAMRoleForCodeBuild:
    Type: AWS::IAM::Role
    Properties:
      RoleName:  !Sub ProdRoleForCodeBuild-${PipelineName}
      Path: /service-role/
      AssumeRolePolicyDocument:
        Version: 2012-10-17
        Statement:
        - Effect: Allow
          Action: sts:AssumeRole
          Principal:
            Service: codebuild.amazonaws.com
# ------------------------------------------------------------#
#  Deploy Stage IAM Role/IAM Policy
# ------------------------------------------------------------#
  IAMPolicyForDeployStage:
    Type: AWS::IAM::ManagedPolicy
    Properties:
      ManagedPolicyName: !Sub ProdPolicyForDeploy-${PipelineName}
      Roles:
        - !Ref IAMRoleForDeployStage
      PolicyDocument:
        Version: '2012-10-17'
        Statement:
          - Sid: LambdaDeployPolicy
            Effect: Allow
            Action:
             - lambda:*
            Resource: "*"
          - Sid: APIGatewayPolicy
            Effect: Allow
            Action:
             - apigateway:*
            Resource: "*"
          - Sid: CloudFormationCreateChangeSetPolicy
            Effect: Allow
            Action:
             - cloudformation:CreateChangeSet
            Resource: "*"
          - Sid: IAMPolicy
            Effect: Allow
            Action:
             - iam:GetRole
             - iam:CreateRole
             - iam:DeleteRole
             - iam:PutRolePolicy
             - iam:AttachRolePolicy
             - iam:DeleteRolePolicy
             - iam:DetachRolePolicy
             - iam:PassRole
            Resource: "*"
          - Sid: GetArtifactStorePolicy
            Effect: Allow
            Action:
             - s3:GetBucketLocation
             - s3:GetBucketVersioning
             - s3:GetBucketAcl
            Resource:
             - !GetAtt ArtifactBucket.Arn
          - Sid: GetArtifactPolicy
            Effect: Allow
            Action:
             - s3:GetObject
             - s3:GetObjectVersion
            Resource:
             - !Join ['', ['arn:aws:s3:::', !Ref ArtifactBucket, /*]]
  IAMRoleForDeployStage:
    Type: AWS::IAM::Role
    Properties:
      RoleName: !Sub ProdRoleForDeploy-${PipelineName}
      AssumeRolePolicyDocument:
        Version: 2012-10-17
        Statement:
         - Effect: Allow
           Action: sts:AssumeRole
           Principal:
             Service: cloudformation.amazonaws.com
      Path: /
# IAMPolicy for CodePipeline
  IAMPolicyForCodePipeline:
    Type: AWS::IAM::ManagedPolicy
    Properties:
      ManagedPolicyName: !Sub ProdPolicyForCodePipeline-${PipelineName}
      Roles:
        - !Ref IAMRoleFoCodePipeline
      PolicyDocument:
        Version: '2012-10-17'
        Statement:
          - Effect: Allow
            Action:
             - iam:PassRole
            Resource: "*"
            Condition:
              StringEqualsIfExists:
                iam:PassedToService:
                 - cloudformation.amazonaws.com
          - Sid: CodeBuildPolicy
            Effect: Allow
            Action:
             - codebuild:BatchGetBuilds
             - codebuild:StartBuild
             - codebuild:StopBuild
             - codebuild:RetryBuild
            Resource:
              - !Sub arn:aws:codebuild:${AWS::Region}:${AWS::AccountId}:project/${BuildProjectName}
          - Sid: LambdaPolicy
            Effect: Allow
            Action:
              - lambda:InvokeFunction
              - lambda:ListFunctions
            Resource: "*"
          - Sid: CloudFormationDeployPolicy
            Effect: Allow
            Action:
             - cloudformation:CreateStack
             - cloudformation:DeleteStack
             - cloudformation:DescribeStacks
             - cloudformation:UpdateStack
             - cloudformation:CreateChangeSet
             - cloudformation:DeleteChangeSet
             - cloudformation:DescribeChangeSet
             - cloudformation:ExecuteChangeSet
             - cloudformation:SetStackPolicy
             - cloudformation:ValidateTemplate
            Resource: "*"
          - Sid: SourceStageArtifactPushPolicy
            Effect: Allow
            Action:
             - s3:PutObject
            Resource:
             - !Join ['', ['arn:aws:s3:::', !Ref ArtifactBucket, /*]]
          - Sid: SourceStageArtifactGetPolicy
            Effect: Allow
            Action:
             - s3:GetBucketAcl
             - s3:GetBucketLocation
            Resource:
             - !GetAtt ArtifactBucket.Arn
          - Sid: STGAccountAssumeRole
            Effect: Allow
            Action:
             - sts:AssumeRole
            Resource:
             - !Sub arn:aws:iam::${STGAccountId}:role/*
          - Sid: GetArtifactStorePolicy
            Effect: Allow
            Action:
             - s3:GetObject
             - s3:GetObjectVersion
            Resource:
             - !Join ['', ['arn:aws:s3:::', !Ref ArtifactBucket, /*]]
  IAMRoleFoCodePipeline:
    Type: AWS::IAM::Role
    Properties:
      RoleName: !Sub ProdRoleForCodePipeline-${PipelineName}
      AssumeRolePolicyDocument:
        Version: 2012-10-17
        Statement:
        - Effect: Allow
          Action: sts:AssumeRole
          Principal:
            Service: codepipeline.amazonaws.com
# ------------------------------------------------------------#
#  KMS
# ref. https://docs.aws.amazon.com/ja_jp/kms/latest/developerguide/key-policy-modifying-external-accounts.html
# ------------------------------------------------------------#
  Key:
    Type: AWS::KMS::Key
    Properties:
      Description: CodePipeline CMK
      KeyPolicy:
        Version: 2012-10-17
        Id: key-default-1
        Statement:
        - Sid: Enable IAM User Permissions
          Effect: Allow
          Principal:
            AWS:
            - !Sub arn:aws:iam::${AWS::AccountId}:root
          Action: kms:*
          Resource: "*"
        - Sid: Allow administration of the key
          Effect: Allow
          Principal:
            AWS:
            - !Sub arn:aws:iam::${AWS::AccountId}:root
            - !Sub arn:aws:iam::${STGAccountId}:root
          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::${STGAccountId}:root
            - !GetAtt IAMRoleFoCodePipeline.Arn
            - !GetAtt IAMRoleForCodeBuild.Arn
            - !GetAtt IAMRoleForDeployStage.Arn
          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::${STGAccountId}:root
            - !GetAtt IAMRoleFoCodePipeline.Arn
            - !GetAtt IAMRoleForCodeBuild.Arn
            - !GetAtt IAMRoleForDeployStage.Arn
          Action:
          - kms:CreateGrant
          - kms:ListGrants
          - kms:RevokeGrant
          Resource: "*"
          Condition:
            Bool:
              kms:GrantIsForAWSResource: true
  Alias:
    Type: AWS::KMS::Alias
    Properties:
      AliasName: alias/CodePipelineArtifact
      TargetKeyId:
        Ref: Key
# ------------------------------------------------------------#
#  S3Bucket
# ------------------------------------------------------------#
  ArtifactBucket:
    Description: Amazon S3 bucket for AWS CodePipeline artifacts
    Type: AWS::S3::Bucket
    Properties:
      BucketName: !Ref BucketName
      BucketEncryption:
        ServerSideEncryptionConfiguration:
          - ServerSideEncryptionByDefault:
              SSEAlgorithm: AES256
      LifecycleConfiguration:
        Rules:
          - ExpirationInDays: 90
            Id: !Sub ${BucketName}-LifeCycle
            Status: Enabled
  S3ArtifactBucketPolicy:
    Type: AWS::S3::BucketPolicy
    Description: Amazon S3 bucket policy for Cross Account access
    Properties:
      Bucket: !Ref ArtifactBucket
      PolicyDocument:
        Statement:
        - Sid: DenyAccessWithoutUsingCMK
          Action:
           - s3:PutObject
          Effect: Deny
          Principal: "*"
          Resource:
           - !Sub arn:aws:s3:::${ArtifactBucket}/*
          Condition:
            StringNotLikeIfExists:
              {"s3:x-amz-server-side-encryption-aws-kms-key-id": !GetAtt Key.Arn}
        - Sid: DenyHTTPAccessPolicy
          Action:
           - s3:*
          Effect: Deny
          Principal: "*"
          Resource:
           - !Sub arn:aws:s3:::${ArtifactBucket}/*
          Condition:
            Bool:
              aws:SecureTransport: false
        - Sid: CrossAccountS3GetPutPolicy
          Action:
           - s3:Get*
           - s3:Put*
          Effect: Allow
          Principal:
            AWS:
             - !Sub arn:aws:iam::${STGAccountId}:root
          Resource:
          - !Sub arn:aws:s3:::${ArtifactBucket}/*
        - Sid: CrossAccountS3ListPolicy
          Action:
           - s3:ListBucket
          Effect: Allow
          Principal:
            AWS:
             - !Sub arn:aws:iam::${STGAccountId}:root
          Resource:
           - !Sub arn:aws:s3:::${ArtifactBucket}
        Version: 2012-10-17

Outputs:
  KMS:
    Description: Prod KMS
    Export:
      Name: PipelineKey
    Value: !GetAtt Key.Arn
  ArtifactBucketName:
    Description: Prod S3Bucket
    Export:
      Name: ProdBucket
    Value: !Ref ArtifactBucket
  ArtifactBucketARN:
    Description: Prod S3Bucket ARN
    Export:
      Name: ProdBucketARN
    Value: !GetAtt ArtifactBucket.Arn
  IAMRoleForCodeBuildARN:
    Description: CodeBuild IAM Role ARN
    Export:
      Name: IAMRoleForCodeBuildARN
    Value: !GetAtt IAMRoleForCodeBuild.Arn
  IAMRoleForDeployStageARN:
    Description: DeployStage IAM Role ARN
    Export:
      Name: IAMRoleForDeployStageARN
    Value: !GetAtt IAMRoleForDeployStage.Arn
  IAMRoleFoCodePipelineARN:
    Description: CodePipeline IAM Role ARN
    Export:
      Name: IAMRoleFoCodePipelineARN
    Value: !GetAtt IAMRoleFoCodePipeline.Arn

[作業2]テンプレートの補足 CodePipelineのサービスロール

作業2で作成するCode系のサービスのIAMロールの設定は、作業1でテスト環境用に作成したものとほぼ同じです。

違いは、本番環境CodePipelineのサービスロールにCodeCommitのpull権限等がないことと、テスト環境のIAMロールへのAssumeRole権限が設定されていることの2点になります。
「Lambdaのマルチアカウントデプロイ 設計編」でも触れましたが、テスト環境のCodeCommitのリポジトリからpullするためにはテスト環境のIAMロールを利用します。

<再掲>本番環境のCodePipelineがテスト環境のCodeCommitリポジトリにアクセスするイメージ

よって本番環境のCodePipelineにはテスト環境のActionロールを利用できる権限が必要です。

CodePipelineのサービスロールにアタッチする権限

  IAMPolicyForCodePipeline:
    Type: AWS::IAM::ManagedPolicy
    Properties:
      ManagedPolicyName: !Sub ProdPolicyForCodePipeline-${PipelineName}
      Roles:
        - !Ref IAMRoleFoCodePipeline
      PolicyDocument:
        Version: '2012-10-17'
        Statement:
       ###省略###
          - Sid: STGAccountAssumeRole
            Effect: Allow
            Action:
             - sts:AssumeRole
            Resource:
             - !Sub arn:aws:iam::${STGAccountId}:role/*

[作業2]テンプレートのパラメータ

[作業3]テスト環境にActionロールを作成!

ではテスト環境に本番環境CodePipelineが利用するActionロールを作りましょう。

[作業3]テンプレート 3-stg

Actionロールには以下の権限が必要です。

  • 本番環境のS3バケットにCodeCommitのソースをPut
  • 本番環境のCMKを使って成果物を暗号化
  • テスト環境のリポジトリの変更情報を取得

AWSTemplateFormatVersion: 2010-09-09
Metadata:
  AWS::CloudFormation::Interface:
    ParameterGroups:
      - Label:
          default: STG Environment Parameter
        Parameters:
          - RepositoryName
      - Label:
          default: Prod Environment Parameter
        Parameters:
          - ProductionAccountId
          - ProductionS3BucketARN
          - ProductionCmkArn
Parameters:
  ProductionAccountId:
    Description: Production Account ID
    MaxLength: 12
    MinLength: 12
    Type: String
  ProductionS3BucketARN:
    Description: Production Account S3 Bucket ARN for Artifact
    Type: String
  ProductionCmkArn:
    Description: Production Account CMK ARN
    Type: String
  RepositoryName:
    Description: STG CodeCommit RepositoryName
    Type: String
Resources:
# ------------------------------------------------------------#
#  IAM Role
# ------------------------------------------------------------#
  MultiAccountCodeCommitRole:
    Type: AWS::IAM::Role
    Properties:
      RoleName: ProdCodePipelineActionRole
      AssumeRolePolicyDocument:
        Version: 2012-10-17
        Statement:
          - Effect: Allow
            Principal:
              AWS:
              - !Sub arn:aws:iam::${ProductionAccountId}:root
            Action:
              - sts:AssumeRole
      Path: /
      Policies:
        - PolicyName: source
          PolicyDocument:
            Version: 2012-10-17
            Statement:
              - Effect: Allow
                Action:
                  - s3:PutObject
                  - s3:PutObjectAcl
                Resource:
                  - !Sub ${ProductionS3BucketARN}/*
              - Effect: Allow
                Action:
                  - kms:DescribeKey
                  - kms:GenerateDataKey*
                  - kms:Encrypt
                  - kms:ReEncrypt*
                  - kms:Decrypt
                Resource:
                  - !Ref ProductionCmkArn
              - Effect: Allow
                Action:
                  - codecommit:GetBranch
                  - codecommit:GetCommit
                  - codecommit:UploadArchive
                  - codecommit:GetUploadArchiveStatus
                  - codecommit:CancelUploadArchive
                Resource:
                  - !Sub arn:aws:codecommit:ap-northeast-1:${AWS::AccountId}:${RepositoryName}

[作業3]テンプレートのパラメータ

[作業4]本番環境にCodePipelineを構築!

ではいよいよ本番環境のCodePipelineを構築します。CFnでの作業はこれが最後になります。

[作業4]テンプレート 4-prod

AWSTemplateFormatVersion: 2010-09-09
Metadata:
  AWS::CloudFormation::Interface:
    ParameterGroups:
      - Label:
          default: STG Environment Parameter
        Parameters:
          - STGCodeCommitIAMRole
          - STGRepositoryName
          - STGAccountId
      - Label:
          default: Prod Environment Parameter
        Parameters:
          - BuildProjectName
          - PipelineName
Parameters:
  BuildProjectName:
    Type : String
  PipelineName:
    Type : String
  STGCodeCommitIAMRole:
    Type : String
  STGRepositoryName:
    Type : String
  STGAccountId:
    Description: Repository Account ID
    MaxLength: 12
    MinLength: 12
    Type: String
Resources:
# ------------------------------------------------------------#
#  EventBridge IAM Role/IAM Policy
# ------------------------------------------------------------#
  IAMPolicyForEventBridge:
    Type: AWS::IAM::ManagedPolicy
    Properties:
      ManagedPolicyName: !Sub ProdPolicyForEventBridge-${PipelineName}
      Roles:
        - !Ref IAMRoleForEventBridge
      PolicyDocument:
        Version: '2012-10-17'
        Statement:
          - Effect: Allow
            Action:
             - codepipeline:StartPipelineExecution
            Resource:
             - !Sub arn:aws:codepipeline:${AWS::Region}:${AWS::AccountId}:${PipelineName}
  IAMRoleForEventBridge:
    Type: AWS::IAM::Role
    Properties:
      RoleName: ProdRoleForEventBridge
      Path: /service-role/
      AssumeRolePolicyDocument:
        Version: 2012-10-17
        Statement:
        - Effect: Allow
          Action: sts:AssumeRole
          Principal:
            Service: events.amazonaws.com

# ------------------------------------------------------------#
#  CodeBuild
# ------------------------------------------------------------#
  CodeBuildProject:
    Type: AWS::CodeBuild::Project
    Properties:
      Artifacts:
        Type: CODEPIPELINE
      EncryptionKey: !ImportValue PipelineKey
      Name: !Ref BuildProjectName
      Source:
        BuildSpec: buildspec.yml
        Type: CODEPIPELINE
      Environment:
        ComputeType: BUILD_GENERAL1_SMALL
        Image: aws/codebuild/standard:4.0
        Type: LINUX_CONTAINER
        EnvironmentVariables:
          - Name: BUCKET_NAME
            Type: PLAINTEXT
            Value: !ImportValue ProdBucket
      ServiceRole:  !ImportValue IAMRoleForCodeBuildARN

# ------------------------------------------------------------#
#  CodePipeline
# ------------------------------------------------------------#
  CodePipelineForLambda:
    Type: AWS::CodePipeline::Pipeline
    Properties:
      ArtifactStore:
        Location: !ImportValue ProdBucket
        Type: S3
        EncryptionKey:
          Id: !ImportValue PipelineKey
          Type: KMS
      Name: !Ref PipelineName
      RoleArn: !ImportValue IAMRoleFoCodePipelineARN
      Stages:
        - Name: Source
          Actions:
            - Name: Commit
              InputArtifacts: []
              OutputArtifacts:
                - Name: SourceArtifact
              ActionTypeId:
                Category: Source
                Owner: AWS
                Version: 1
                Provider: CodeCommit
              RoleArn: !Ref STGCodeCommitIAMRole
              Configuration:
                RepositoryName: !Ref STGRepositoryName
                BranchName: master
                PollForSourceChanges: false
              RunOrder: 1
        - Name: Build
          Actions:
            - Name: Build
              ActionTypeId:
                Category: Build
                Owner: AWS
                Version: 1
                Provider: CodeBuild
              RunOrder: 1
              Configuration:
                ProjectName: !Ref CodeBuildProject
              InputArtifacts:
                - Name: SourceArtifact
              OutputArtifacts:
                - Name: BuildArtifact
        - Name: Deploy
          Actions:
            - Name: Deploy
              InputArtifacts:
               - Name: BuildArtifact
              ActionTypeId:
                Category: Deploy
                Owner: AWS
                Version: 1
                Provider: CloudFormation
              Configuration:
                ActionMode: CHANGE_SET_REPLACE
                Capabilities: CAPABILITY_IAM,CAPABILITY_AUTO_EXPAND,CAPABILITY_NAMED_IAM
                ChangeSetName: lambda-pipeline-changeset
                StackName: lambda-pipeline-changeset
                TemplatePath: 'BuildArtifact::packaged-template.yaml' # CodeBuildのbuildspec.ymlで出力した成果物の名称
                RoleArn: !ImportValue IAMRoleForDeployStageARN
              RunOrder: 3
# ------------------------------------------------------------#
#  EventBridge
#  ref. https://docs.aws.amazon.com/ja_jp/codepipeline/latest/userguide/pipelines-trigger-source-repo-changes-cfn.html
# ------------------------------------------------------------#
  EventBridgeTriggerdByCodeCommitMerge:
    Type: AWS::Events::Rule
    Properties:
      Description: !Sub Invoking CodePipeline prod ${STGRepositoryName}
      Name: !Sub EventBridgeRule-CodePipeline-Prod${STGRepositoryName}
      EventPattern:
        source:
          - aws.codecommit
        resources:
          - !Sub arn:aws:codecommit:${AWS::Region}:${STGAccountId}:${STGRepositoryName}
        detail:
          event:
            - referenceCreated
            - referenceUpdated
          referenceType:
            - branch
          referenceName:
            - master
        detail-type:
          - CodeCommit Repository State Change
      Targets:
        - Id: codepipeline
          RoleArn: !GetAtt IAMRoleForEventBridge.Arn
          Arn: !Sub arn:aws:codepipeline:${AWS::Region}:${AWS::AccountId}:${PipelineName}

[作業4]テンプレートの補足 SourceステージのIAMロール

CodePipeline自体に設定するサービスロールと、Sourceステージに設定するIAMロールを区別することが出来ます。

Sourceステージに作業3で作成したIAMのActionロールを設定することで、テスト環境のCodeCommitリポジトリを操作することが出来ます。
CodePipeline(Sourceステージのみ抜粋)

  CodePipelineForLambda:
    Type: AWS::CodePipeline::Pipeline
    Properties:
     ###省略###
      RoleArn: !ImportValue IAMRoleFoCodePipelineARN
      Stages:
        - Name: Source
          Actions:
            - Name: Commit
          ###省略###
              RoleArn: !Ref STGCodeCommitIAMRole
              Configuration:
                RepositoryName: !Ref STGRepositoryName
                BranchName: master
                PollForSourceChanges: false
              RunOrder: 1

[作業4]テンプレートのパラメータ

以上でCFnでの作業は全て完了しました。あと少しです。

[作業5]本番環境のEventBusのアクセス許可設定変更

この時点で、masterブランチへのマージ作業から本番環境のLambdaをデプロイする為の一連の流れはほぼ完成しています。

[一連の流れ]
1.テスト環境のEventBridge発動
2.★本番環境のEventBus発動
3.本番環境のEventBridge発動
4.本番環境のCodePipeline発動
5.本番環境へLambdaデプロイ

現時点では上記の★の部分が実行できません。
作業5ではテスト環境のEventBridgeが本番環境のEventBusを発動させるためのアクセス許可を設定します。
本番環境のdefaultのEventBusを開き、リソースベースのポリシーに以下を加えます。

{
  "Version": "2012-10-17",
  "Statement": [{
    "Sid": "AllowCodeCommitEvents",
    "Effect": "Allow",
    "Principal": {
      "AWS": "arn:aws:iam::{テスト環境}:root"
    },
    "Action": "*",
    "Resource": "arn:aws:events:ap-northeast-1:{本番環境}:event-bus/default"
  }]
}

操作対象がdefaultのEventBusであることもポイントです。
EventBusはdefaultのもの以外に自分で作成できるものもありますが、AWSサービス間の連携には必ずdefaultのEventBusを使わなくてはなりません。

※2021年3月時点の情報です。

詳しくはEventBridgeのBlackBeltの「EventBridgeのアーキテクチャ」をご参照ください。

AWS Black Belt Online Seminar Amazon EventBridge

[作業6]本番環境へLambdaをデプロイ!

以上で準備が全て完了しました。
少し補足を入れながら、masterブランチにstgをマージして本番環境にLambdaをデプロイしてみます。

補足事項

  • buildspec.ymlの構成と配置場所
  • SAMテンプレート
  • CodeCommitのブランチ

buildspec.ymlの構成

buildspec.ymlのsam packageコマンドでは必ずcmkを指定して成果物を暗号化した上で作成します。

template-fileのパスはbuildspec.yml自身の配置場所によって変わるので注意してください。

version: 0.2
phases:
  install:
    runtime-versions:
        python: 3.8
  build:
    commands: |
     sam package --template-file ./Test-Function/template.yaml --s3-bucket ${BUCKET_NAME} --kms-key-id ${CODEBUILD_KMS_KEY_ID} --output-template-file packaged-template.yaml
artifacts:
  type: zip
  files:
    - packaged-template.yaml

“–kms-key-id ${CODEBUILD_KMS_KEY_ID}”を指定しないと、バケットポリシーによりPutObjectがはじかれます。

buildspec.ymlの配置場所

今回はbuildspec.ymlをlambdaリポジトリの直下に配置しましたが、リポジトリ内に配置されていれば必ずしも直下に置く必要はありません。

配置場所を変更する場合は、CFnのCodeBuildProjectのBuildSpecのパスとbuildspec.yml内のコマンドのパスを変えてください。

BuildSpecのパス

  CodeBuildProject:
    Type: AWS::CodeBuild::Project
    Properties:
    ###省略###
      Source:
        BuildSpec: buildspec.yml #--★
        Type: CODEPIPELINE

SAMテンプレート

今回はCloud9の機能を使い、Cloud9上でLambdaを新規作成しました。

よってSAMのテンプレートもデフォルトのものを使っております。Lambdaの名前だけ「Test-Function」となるよう追加しました。

デフォルトではLambda Functionの直下に配置されていましたのでこのまま利用しております。

CodeCommitのブランチ

今回の構成ではCodeCommitのブランチに少なくともmasterとstgの2つのブランチが必要です。
時流に乗ってprodブランチにしようかとも思ったのですが今回はCodeCommitのデフォルトに従いました。

それではテスト環境のCodeCommitで、stgブランチをmasterへマージしてみます。

pullリクエストの作成

マージ

マージした直後、本番環境のCodePipelineが動き始めます。

CodePipelineが正常に終了した場合、CloudFormationのスタック「lambda-pipeline-changeset」が作成されます。※スタック名はCFnテンプレートで指定可能

「REVIEW_IN_PROGRESS」というステータスで作成されますので、変更セットを実行します。

少し待ったら、Lambdaがデプロイされました。

以上です!この構成であれば、複数の本番AWSアカウントに対してまとめてデプロイすることが可能になります。

ぜひご活用ください。

RECOMMEND

おすすめ記事一覧