# Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. # SPDX-License-Identifier: MIT-0 AWSTemplateFormatVersion : '2010-09-09' Description: > This template deploys a CodePipeline with its required resources. The following stages are predefined in this template: - Source - UpdatePipeline - BuildAndDeployFeatureStack (FeatureGitBranch only) - BuildAndPackage (MainGitBranch only) - DeployTest (MainGitBranch only) - DeployProd (MainGitBranch only) **WARNING** You will be billed for the AWS resources used if you create a stack from this template. # To deploy this template and connect to the main git branch, run this against the leading account: # `sam deploy -t codepipeline.yaml --stack-name --capabilities=CAPABILITY_IAM`. # If later you need to deploy a new CodePipeline to connect to a non-main git branch, run # ``` # sam deploy -t codepipeline.yaml --stack-name --capabilities=CAPABILITY_IAM \ # --parameter-overrides="FeatureGitBranch=" # ``` Parameters: GitProviderType: Type: String Default: "CodeCommit" CodeCommitRepositoryName: Type: String Default: "lambda-container-repo" MainGitBranch: Type: String Default: "main" SamTemplate: Type: String Default: "template.yaml" DeploymentRegion: Type: String Default: "eu-west-2" ToolingCodePipelineExecutionRoleArn: Type: String Default: "ToolingPipelineExecutionRole" ToolingCloudFormationExecutionRoleArn: Type: String Default: "ToolingCloudFormationExecutionRole" TestStackName: Type: String Default: "lambda-container-test" TestCodePipelineCrossAccountRoleArn: Type: String Default: "ToolingPipelineExecutionRole" TestCloudFormationCrossAccountRoleArn: Type: String Default: "ToolingCloudFormationExecutionRole" ArtifactsBucket: Type: String Default: "" ImageRepositoryURI: Type: String Default: "" ProdStackName: Type: String Default: "lambda-container-prod" ProdCodePipelineCrossAccountRoleArn: Type: String Default: "ProdCodePipelineCrossAccountRoleArn" ProdCloudFormationCrossAccountRoleArn: Type: String Default: "ProdCloudFormationExecutionRole" CodeStarConnectionArn: Type: String Default: "" FeatureGitBranch: Type: String Default: "" Conditions: IsMainBranchPipeline: !Equals [!Ref FeatureGitBranch, ""] IsFeatureBranchPipeline: !Not [Condition: IsMainBranchPipeline] Resources: # ____ # / ___| ___ _ _ _ __ ___ ___ # \___ \ / _ \| | | | '__/ __/ _ \ # ___) | (_) | |_| | | | (_| __/ # |____/ \___/ \__,_|_| \___\___| CloudWatchEventRole: Type: AWS::IAM::Role Properties: AssumeRolePolicyDocument: Version: 2012-10-17 Statement: - Effect: Allow Principal: Service: - events.amazonaws.com Action: sts:AssumeRole Policies: - PolicyName: cwe-pipeline-execution PolicyDocument: Version: 2012-10-17 Statement: - Effect: Allow Action: codepipeline:StartPipelineExecution Resource: !Sub "arn:${AWS::Partition}:codepipeline:${AWS::Region}:${AWS::AccountId}:${Pipeline}" CloudWatchEventRule: Type: AWS::Events::Rule Properties: EventPattern: source: - aws.codecommit detail-type: - 'CodeCommit Repository State Change' resources: - !Sub "arn:${AWS::Partition}:codecommit:${AWS::Region}:${AWS::AccountId}:${CodeCommitRepositoryName}" detail: event: - referenceCreated - referenceUpdated referenceType: - branch referenceName: - !If [IsFeatureBranchPipeline, !Ref FeatureGitBranch, !Ref MainGitBranch] Targets: - Arn: !Sub "arn:${AWS::Partition}:codepipeline:${AWS::Region}:${AWS::AccountId}:${Pipeline}" RoleArn: !GetAtt CloudWatchEventRole.Arn Id: codepipeline-AppPipeline # ____ _ _ _ # | _ \(_)_ __ ___| (_)_ __ ___ # | |_) | | '_ \ / _ | | | '_ \ / _ \ # | __/| | |_) | __| | | | | | __/ # |_| |_| .__/ \___|_|_|_| |_|\___| # |_| Pipeline: Type: AWS::CodePipeline::Pipeline Properties: ArtifactStore: Location: !Ref PipelineArtifactsBucket Type: S3 RoleArn: !GetAtt CodePipelineExecutionRole.Arn RestartExecutionOnUpdate: true Stages: - Name: Source Actions: - Name: SourceCodeRepo ActionTypeId: Category: Source Owner: AWS Provider: CodeCommit Version: "1" Configuration: RepositoryName: !Ref CodeCommitRepositoryName PollForSourceChanges: false BranchName: !If [IsFeatureBranchPipeline, !Ref FeatureGitBranch, !Ref MainGitBranch] OutputArtifacts: - Name: SourceCodeAsZip RunOrder: 1 - Name: UpdatePipeline Actions: - Name: CreateChangeSet ActionTypeId: Category: Deploy Owner: AWS Provider: CloudFormation Version: "1" Configuration: ActionMode: CHANGE_SET_REPLACE RoleArn: !GetAtt PipelineStackCloudFormationExecutionRole.Arn StackName: !Ref AWS::StackName ChangeSetName: !Sub ${AWS::StackName}-ChangeSet TemplatePath: SourceCodeAsZip::codepipeline.yaml Capabilities: CAPABILITY_NAMED_IAM TemplateConfiguration: SourceCodeAsZip::codepipeline_parameters.json InputArtifacts: - Name: SourceCodeAsZip RunOrder: 1 - Name: ExecuteChangeSet ActionTypeId: Category: Deploy Owner: AWS Provider: CloudFormation Version: "1" Configuration: ActionMode: CHANGE_SET_EXECUTE RoleArn: !GetAtt PipelineStackCloudFormationExecutionRole.Arn StackName: !Ref AWS::StackName ChangeSetName: !Sub ${AWS::StackName}-ChangeSet OutputArtifacts: - Name: !Sub ${AWS::StackName}ChangeSet RunOrder: 2 # Uncomment and modify the following step for running the unit-tests # - Name: UnitTest # Actions: # - Name: UnitTest # ActionTypeId: # Category: Build # Owner: AWS # Provider: CodeBuild # Version: "1" # Configuration: # ProjectName: !Ref CodeBuildProjectUnitTest # InputArtifacts: # - Name: SourceCodeAsZip - !If - IsFeatureBranchPipeline - Name: BuildAndDeployFeatureStack Actions: - Name: CodeBuild ActionTypeId: Category: Build Owner: AWS Provider: CodeBuild Version: "1" Configuration: ProjectName: !Ref CodeBuildProjectBuildAndDeployFeature InputArtifacts: - Name: SourceCodeAsZip - !Ref AWS::NoValue - !If - IsMainBranchPipeline - Name: BuildAndPackage Actions: - Name: CodeBuild ActionTypeId: Category: Build Owner: AWS Provider: CodeBuild Version: "1" Configuration: ProjectName: !Ref CodeBuildProjectBuildAndPackage InputArtifacts: - Name: SourceCodeAsZip OutputArtifacts: - Name: BuildArtifactAsZip - !Ref AWS::NoValue - !If - IsMainBranchPipeline - Name: DeployTest Actions: - Name: DeployTest ActionTypeId: Category: Build Owner: AWS Provider: CodeBuild Version: "1" Configuration: ProjectName: !Ref CodeBuildProjectDeploy EnvironmentVariables: !Sub | [ {"name": "ENV_TEMPLATE", "value": "packaged-test.yaml"}, {"name": "ENV_REGION", "value": "${DeploymentRegion}"}, {"name": "ENV_STACK_NAME", "value": "${TestStackName}"}, {"name": "ENV_PIPELINE_EXECUTION_ROLE", "value": "${TestCodePipelineCrossAccountRoleArn}"}, {"name": "ENV_CLOUDFORMATION_EXECUTION_ROLE", "value": "${TestCloudFormationCrossAccountRoleArn}"}, {"name": "ENV_BUCKET", "value": "${ArtifactsBucket}"}, {"name": "ENV_IMAGE_REPOSITORY", "value": "${ImageRepositoryURI}"} ] InputArtifacts: - Name: BuildArtifactAsZip RunOrder: 1 # Uncomment the following step for running the integration tests # - Name: IntegrationTest # ActionTypeId: # Category: Build # Owner: AWS # Provider: CodeBuild # Version: "1" # Configuration: # ProjectName: !Ref CodeBuildProjectIntegrationTest # InputArtifacts: # - Name: SourceCodeAsZip # RunOrder: 2 - !Ref AWS::NoValue - !If - IsMainBranchPipeline - Name: DeployProd Actions: # uncomment this to have a manual approval step before deployment to production # - Name: ManualApproval # ActionTypeId: # Category: Approval # Owner: AWS # Provider: Manual # Version: "1" # RunOrder: 1 - Name: DeployProd ActionTypeId: Category: Build Owner: AWS Provider: CodeBuild Version: "1" RunOrder: 2 # keeping run order as 2 in case manual approval is enabled Configuration: ProjectName: !Ref CodeBuildProjectDeploy EnvironmentVariables: !Sub | [ {"name": "ENV_TEMPLATE", "value": "packaged-prod.yaml"}, {"name": "ENV_REGION", "value": "${DeploymentRegion}"}, {"name": "ENV_STACK_NAME", "value": "${ProdStackName}"}, {"name": "ENV_PIPELINE_EXECUTION_ROLE", "value": "${ProdCodePipelineCrossAccountRoleArn}"}, {"name": "ENV_CLOUDFORMATION_EXECUTION_ROLE", "value": "${ProdCloudFormationCrossAccountRoleArn}"}, {"name": "ENV_BUCKET", "value": "${ArtifactsBucket}"}, {"name": "ENV_IMAGE_REPOSITORY", "value": "${ImageRepositoryURI}"} ] InputArtifacts: - Name: BuildArtifactAsZip - !Ref AWS::NoValue PipelineArtifactsBucket: Type: AWS::S3::Bucket DeletionPolicy: Retain UpdateReplacePolicy: Retain Properties: VersioningConfiguration: Status: Enabled LoggingConfiguration: DestinationBucketName: !Ref PipelineArtifactsLoggingBucket LogFilePrefix: "artifacts-logs" BucketEncryption: ServerSideEncryptionConfiguration: - ServerSideEncryptionByDefault: SSEAlgorithm: AES256 PipelineArtifactsBucketPolicy: Type: AWS::S3::BucketPolicy Properties: Bucket: !Ref PipelineArtifactsBucket PolicyDocument: Statement: - Effect: "Deny" Action: "s3:*" Principal: "*" Resource: - !Sub "${PipelineArtifactsBucket.Arn}/*" - !GetAtt PipelineArtifactsBucket.Arn Condition: Bool: aws:SecureTransport: false - Action: - s3:* Effect: Allow Resource: - !Sub arn:${AWS::Partition}:s3:::${PipelineArtifactsBucket} - !Sub arn:${AWS::Partition}:s3:::${PipelineArtifactsBucket}/* Principal: AWS: - !GetAtt CodePipelineExecutionRole.Arn PipelineArtifactsLoggingBucket: Type: AWS::S3::Bucket DeletionPolicy: Retain UpdateReplacePolicy: Retain Properties: AccessControl: "LogDeliveryWrite" VersioningConfiguration: Status: Enabled BucketEncryption: ServerSideEncryptionConfiguration: - ServerSideEncryptionByDefault: SSEAlgorithm: AES256 PipelineArtifactsLoggingBucketPolicy: Type: AWS::S3::BucketPolicy Properties: Bucket: !Ref PipelineArtifactsLoggingBucket PolicyDocument: Statement: - Effect: "Deny" Action: "s3:*" Principal: "*" Resource: - !Sub "${PipelineArtifactsLoggingBucket.Arn}/*" - !GetAtt PipelineArtifactsLoggingBucket.Arn Condition: Bool: aws:SecureTransport: false CodePipelineExecutionRole: Type: AWS::IAM::Role Properties: AssumeRolePolicyDocument: Version: "2012-10-17" Statement: - Action: - "sts:AssumeRole" Effect: Allow Principal: Service: - codepipeline.amazonaws.com Policies: - PolicyName: CodePipelineAccess PolicyDocument: Version: "2012-10-17" Statement: - Effect: Allow Action: - "iam:PassRole" Resource: "*" - PolicyName: CodeCommitAccess PolicyDocument: Version: 2012-10-17 Statement: - Effect: Allow Action: - 'codecommit:CancelUploadArchive' - 'codecommit:GetBranch' - 'codecommit:GetCommit' - 'codecommit:GetUploadArchiveStatus' - 'codecommit:UploadArchive' Resource: - !Sub "arn:${AWS::Partition}:codecommit:${AWS::Region}:${AWS::AccountId}:${CodeCommitRepositoryName}" - PolicyName: CodePipelineCodeAndS3Bucket PolicyDocument: Version: "2012-10-17" Statement: - Action: - s3:GetBucketAcl - s3:GetBucketLocation Effect: Allow Resource: Fn::GetAtt: - PipelineArtifactsBucket - Arn - Action: - "s3:GetObject" - "s3:GetObjectVersion" - "s3:PutObject" Effect: Allow Resource: Fn::Sub: ${PipelineArtifactsBucket.Arn}/* - PolicyName: CodePipelineCodeBuildAndCloudformationAccess PolicyDocument: Version: "2012-10-17" Statement: - Effect: Allow Action: - "codebuild:StartBuild" - "codebuild:BatchGetBuilds" Resource: # Uncomment the line below to enable the unit-tests # - !GetAtt CodeBuildProjectUnitTest.Arn - !If - IsFeatureBranchPipeline - !GetAtt CodeBuildProjectBuildAndDeployFeature.Arn - !Ref AWS::NoValue - !If - IsMainBranchPipeline - !GetAtt CodeBuildProjectBuildAndPackage.Arn - !Ref AWS::NoValue # Uncomment the following step for running the integration tests # - !If # - IsMainBranchPipeline # - !GetAtt CodeBuildProjectIntegrationTest.Arn # - !Ref AWS::NoValue - !If - IsMainBranchPipeline - !GetAtt CodeBuildProjectDeploy.Arn - !Ref AWS::NoValue - Effect: Allow Action: - "cloudformation:CreateStack" - "cloudformation:DescribeStacks" - "cloudformation:DeleteStack" - "cloudformation:UpdateStack" - "cloudformation:CreateChangeSet" - "cloudformation:ExecuteChangeSet" - "cloudformation:DeleteChangeSet" - "cloudformation:DescribeChangeSet" - "cloudformation:SetStackPolicy" - "cloudformation:SetStackPolicy" - "cloudformation:ValidateTemplate" Resource: - !Sub "arn:${AWS::Partition}:cloudformation:${AWS::Region}:${AWS::AccountId}:stack/${AWS::StackName}/*" # PipelineStackCloudFormationExecutionRole is used for the pipeline to self mutate PipelineStackCloudFormationExecutionRole: Type: AWS::IAM::Role Properties: AssumeRolePolicyDocument: Version: "2012-10-17" Statement: Action: "sts:AssumeRole" Effect: Allow Principal: Service: cloudformation.amazonaws.com Policies: - PolicyName: GrantCloudFormationFullAccess PolicyDocument: Version: 2012-10-17 Statement: - Effect: Allow Action: '*' Resource: '*' # ____ _ ____ _ _ _ # / ___|___ __| | ___| __ ) _ _(_| | __| | # | | / _ \ / _` |/ _ | _ \| | | | | |/ _` | # | |__| (_) | (_| | __| |_) | |_| | | | (_| | # \____\___/ \__,_|\___|____/ \__,_|_|_|\__,_| CodeBuildServiceRole: Type: AWS::IAM::Role DependsOn: - PipelineStackCloudFormationExecutionRole Properties: Tags: - Key: Role Value: pipeline-codebuild-service-role AssumeRolePolicyDocument: Version: "2012-10-17" Statement: - Action: - "sts:AssumeRole" Effect: Allow Principal: Service: - codebuild.amazonaws.com Policies: - PolicyName: CodeBuildLogs PolicyDocument: Version: "2012-10-17" Statement: - Effect: Allow Action: - "logs:CreateLogGroup" - "logs:CreateLogStream" - "logs:PutLogEvents" Resource: - !Sub "arn:${AWS::Partition}:logs:${AWS::Region}:${AWS::AccountId}:log-group:/aws/codebuild/*" - PolicyName: CodeBuildArtifactsBucket PolicyDocument: Version: "2012-10-17" Statement: - Effect: Allow Action: - "s3:GetObject" - "s3:GetObjectVersion" - "s3:PutObject" Resource: - !Sub "arn:${AWS::Partition}:s3:::${PipelineArtifactsBucket}/*" - PolicyName: AssumeStagePipExecutionRoles PolicyDocument: Version: "2012-10-17" Statement: - Action: - sts:AssumeRole Effect: Allow Resource: "*" Condition: StringEquals: aws:ResourceTag/Role: pipeline-execution-role # Uncomment and modify the following step for running the unit-tests # CodeBuildProjectUnitTest: # Type: AWS::CodeBuild::Project # Properties: # Artifacts: # Type: CODEPIPELINE # Environment: # Type: LINUX_CONTAINER # ComputeType: BUILD_GENERAL1_SMALL # Image: aws/codebuild/amazonlinux2-x86_64-standard:3.0 # ServiceRole: !GetAtt CodeBuildServiceRole.Arn # Source: # Type: CODEPIPELINE # BuildSpec: pipeline/buildspec_unit_test.yml CodeBuildProjectBuildAndDeployFeature: Condition: IsFeatureBranchPipeline Type: AWS::CodeBuild::Project Properties: Artifacts: Type: CODEPIPELINE Environment: Type: LINUX_CONTAINER ComputeType: BUILD_GENERAL1_SMALL Image: aws/codebuild/amazonlinux2-x86_64-standard:3.0 PrivilegedMode: true EnvironmentVariables: - Name: SAM_TEMPLATE Value: !Ref SamTemplate - Name: DEPLOYMENT_REGION Value: !Ref DeploymentRegion - Name: TOOLING_PIPELINE_EXECUTION_ROLE Value: !Ref ToolingCodePipelineExecutionRoleArn - Name: TOOLING_CLOUDFORMATION_EXECUTION_ROLE Value: !Ref ToolingCloudFormationExecutionRoleArn - Name: ARTIFACTS_BUCKET Value: !Ref ArtifactsBucket - Name: IMAGE_REPOSITORY Value: !Ref ImageRepositoryURI - Name: FEATURE_BRANCH_NAME Value: !Ref FeatureGitBranch ServiceRole: !GetAtt CodeBuildServiceRole.Arn Source: Type: CODEPIPELINE BuildSpec: pipeline/buildspec_feature.yml CodeBuildProjectBuildAndPackage: Condition: IsMainBranchPipeline Type: AWS::CodeBuild::Project Properties: Artifacts: Type: CODEPIPELINE Environment: Type: LINUX_CONTAINER ComputeType: BUILD_GENERAL1_SMALL Image: aws/codebuild/amazonlinux2-x86_64-standard:3.0 PrivilegedMode: true EnvironmentVariables: - Name: SAM_TEMPLATE Value: !Ref SamTemplate - Name: DEPLOYMENT_REGION Value: !Ref DeploymentRegion - Name: TOOLING_PIPELINE_EXECUTION_ROLE Value: !Ref ToolingCodePipelineExecutionRoleArn - Name: TOOLING_CLOUDFORMATION_EXECUTION_ROLE Value: !Ref ToolingCloudFormationExecutionRoleArn - Name: ARTIFACTS_BUCKET Value: !Ref ArtifactsBucket - Name: IMAGE_REPOSITORY Value: !Ref ImageRepositoryURI ServiceRole: !GetAtt CodeBuildServiceRole.Arn Source: Type: CODEPIPELINE BuildSpec: pipeline/buildspec_build_package.yml # Uncomment and modify the following step for running the integration tests # CodeBuildProjectIntegrationTest: # Condition: IsMainBranchPipeline # Type: AWS::CodeBuild::Project # Properties: # Artifacts: # Type: CODEPIPELINE # Environment: # Type: LINUX_CONTAINER # ComputeType: BUILD_GENERAL1_SMALL # Image: aws/codebuild/amazonlinux2-x86_64-standard:3.0 # ServiceRole: !GetAtt CodeBuildServiceRole.Arn # Source: # Type: CODEPIPELINE # BuildSpec: pipeline/buildspec_integration_test.yml CodeBuildProjectDeploy: Condition: IsMainBranchPipeline Type: AWS::CodeBuild::Project Properties: Artifacts: Type: CODEPIPELINE Environment: Type: LINUX_CONTAINER ComputeType: BUILD_GENERAL1_SMALL Image: aws/codebuild/amazonlinux2-x86_64-standard:3.0 ServiceRole: !GetAtt CodeBuildServiceRole.Arn Source: Type: CODEPIPELINE BuildSpec: pipeline/buildspec_deploy.yml