AWSTemplateFormatVersion: 2010-09-09 Description: > This template generates a generic 3-environment CI/CD Pipeline for Serverless Apps that use SAM (Serverless Application Model). Charges may apply for AWS Services utilized - Below are a summary for your convenience: {% if cookiecutter.source_code_repo == "CodeCommit" %}AWS CodeCommit{% else %}GitHub{% endif %}: Manages and Stores your service source code (Git repository) Amazon S3: Manages CodeBuild Artifacts as well as Cache for subsequent runs when defined in the build spec AWS CodeBuild: Manages and Runs builds specified under buildspec.yaml AWS CodePipeline: Manages and Runs the Continuous Integration and Continuous Deployment pipeline AWS CloudFormation: Manages SAM templates and creates the Infrastructure necessary for each environment AWS IAM: Manages Identity and Access across Services outlined above {%- if cookiecutter.source_code_repo == "Github" %} Parameters: GithubRepo: Description: Gitub Repository name Type: AWS::SSM::Parameter::Value Default: /service/{{cookiecutter.project_name.lower().replace(' ', '-')}}/github/repo GithubToken: Description: Github OAuth Token with full permissions on admin:repo_hook and repo Type: AWS::SSM::Parameter::Value NoEcho: true Default: /service/{{cookiecutter.project_name.lower().replace(' ', '-')}}/github/token GithubUser: Description: Github user where the repository lives Type: AWS::SSM::Parameter::Value Default: /service/{{cookiecutter.project_name.lower().replace(' ', '-')}}/github/user {%- endif%} Resources: ###### ####### ## ## ######## ###### ######## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ###### ## ## ## ## ######## ## ###### ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ###### ####### ####### ## ## ###### ######## {%- if cookiecutter.source_code_repo == "CodeCommit" %} CodeRepository: Type: AWS::CodeCommit::Repository Properties: RepositoryName: {{cookiecutter.project_name.lower().replace(' ', '-')}} RepositoryDescription: {{cookiecutter.project_name}} service repository {%- endif %} # CodeBuild project and resources (S3 Bucket for build artifacts, Role, Project) BuildArtifactsBucket: Type: AWS::S3::Bucket Properties: BucketEncryption: ServerSideEncryptionConfiguration: - ServerSideEncryptionByDefault: SSEAlgorithm: AES256 Tags: - Key: "Stack" Value: !Ref AWS::StackName - Key: "Project" Value: {{cookiecutter.project_name}} DeletionPolicy: Retain UpdateReplacePolicy: Retain ######## ## ## #### ## ######## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ######## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ######## ####### #### ######## ######## CodeBuildProject: Type: AWS::CodeBuild::Project Properties: Name: {{cookiecutter.project_name.lower().replace(' ', '-')}} Description: Build project for the {{cookiecutter.project_name}} Artifacts: Type: CODEPIPELINE Environment: Type: LINUX_CONTAINER ComputeType: BUILD_GENERAL1_SMALL Image: aws/codebuild/amazonlinux2-x86_64-standard:2.0 # More info on Images: https://docs.aws.amazon.com/codebuild/latest/userguide/build-env-ref-available.html EnvironmentVariables: - Name: BUILD_OUTPUT_BUCKET Value: !Ref BuildArtifactsBucket Cache: Type: S3 Location: !Sub ${BuildArtifactsBucket}/codebuild-cache ServiceRole: !GetAtt CodeBuildServiceRole.Arn Source: Type: CODEPIPELINE Tags: - Key: "Stack" Value: !Ref AWS::StackName - Key: "Project" Value: {{cookiecutter.project_name}} ######## #### ######## ######## ## #### ## ## ######## ## ## ## ## ## ## ## ## ### ## ## ## ## ## ## ## ## ## ## #### ## ## ######## ## ######## ###### ## ## ## ## ## ###### ## ## ## ## ## ## ## #### ## ## ## ## ## ## ## ## ### ## ## #### ## ######## ######## #### ## ## ######## Pipeline: Type: AWS::CodePipeline::Pipeline Properties: ArtifactStore: Location: !Ref BuildArtifactsBucket Type: S3 Name: {{cookiecutter.project_name.lower().replace(' ', '-')}} RoleArn: !GetAtt CodePipelineExecutionRole.Arn Stages: - Name: Source Actions: - Name: SourceCodeRepo ActionTypeId: # More info on Possible Values: https://docs.aws.amazon.com/codepipeline/latest/userguide/reference-pipeline-structure.html#action-requirements {%- if cookiecutter.source_code_repo == "Github" %} Category: Source Owner: ThirdParty Provider: GitHub Version: "1" Configuration: Owner: !Ref GithubUser Repo: !Ref GithubRepo Branch: main OAuthToken: !Ref GithubToken OutputArtifacts: - Name: SourceCodeAsZip RunOrder: 1 {%- else %} Category: Source Owner: AWS Provider: CodeCommit Version: "1" Configuration: RepositoryName: !GetAtt CodeRepository.Name BranchName: main OutputArtifacts: - Name: SourceCodeAsZip RunOrder: 1 {%- endif %} - Name: Build Actions: - Name: CodeBuild ActionTypeId: Category: Build Owner: AWS Provider: CodeBuild Version: "1" Configuration: ProjectName: !Ref CodeBuildProject InputArtifacts: - Name: SourceCodeAsZip OutputArtifacts: - Name: BuildArtifactAsZip - Name: Beta Actions: - Name: CreateChangeSet ActionTypeId: Category: Deploy Owner: AWS Provider: CloudFormation Version: "1" Configuration: # More info on Possible Values for Cloudformation: https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/continuous-delivery-codepipeline-action-reference.html#w2ab2c13c13b9 ActionMode: CHANGE_SET_REPLACE RoleArn: !GetAtt CloudFormationExecutionRole.Arn StackName: {{cookiecutter.project_name.lower().replace(' ', '-')}}-Beta ChangeSetName: {{cookiecutter.project_name.lower().replace(' ', '-')}}-ChangeSet-Beta TemplatePath: BuildArtifactAsZip::packaged.yaml Capabilities: CAPABILITY_IAM InputArtifacts: - Name: BuildArtifactAsZip RunOrder: 1 - Name: ExecuteChangeSet ActionTypeId: Category: Deploy Owner: AWS Provider: CloudFormation Version: "1" Configuration: ActionMode: CHANGE_SET_EXECUTE RoleArn: !GetAtt CloudFormationExecutionRole.Arn StackName: {{cookiecutter.project_name.lower().replace(' ', '-')}}-Beta ChangeSetName: {{cookiecutter.project_name.lower().replace(' ', '-')}}-ChangeSet-Beta OutputArtifacts: - Name: {{cookiecutter.project_name.lower().replace(' ', '-')}}BetaChangeSet RunOrder: 2 - Name: Gamma Actions: - Name: CreateChangeSet ActionTypeId: Category: Deploy Owner: AWS Provider: CloudFormation Version: "1" Configuration: ActionMode: CHANGE_SET_REPLACE RoleArn: !GetAtt CloudFormationExecutionRole.Arn StackName: {{cookiecutter.project_name.lower().replace(' ', '-')}}-Gamma ChangeSetName: {{cookiecutter.project_name.lower().replace(' ', '-')}}-ChangeSet-Gamma TemplatePath: BuildArtifactAsZip::packaged.yaml Capabilities: CAPABILITY_IAM InputArtifacts: - Name: BuildArtifactAsZip RunOrder: 1 - Name: ExecuteChangeSet ActionTypeId: Category: Deploy Owner: AWS Provider: CloudFormation Version: "1" Configuration: ActionMode: CHANGE_SET_EXECUTE RoleArn: !GetAtt CloudFormationExecutionRole.Arn StackName: {{cookiecutter.project_name.lower().replace(' ', '-')}}-Gamma ChangeSetName: {{cookiecutter.project_name.lower().replace(' ', '-')}}-ChangeSet-Gamma OutputArtifacts: - Name: {{cookiecutter.project_name.lower().replace(' ', '-')}}GammaChangeSet RunOrder: 2 - Name: Prod Actions: - Name: DeploymentApproval ActionTypeId: Category: Approval Owner: AWS Provider: Manual Version: "1" RunOrder: 1 - Name: CreateChangeSet ActionTypeId: Category: Deploy Owner: AWS Provider: CloudFormation Version: "1" Configuration: ActionMode: CHANGE_SET_REPLACE RoleArn: !GetAtt CloudFormationExecutionRole.Arn StackName: {{cookiecutter.project_name.lower().replace(' ', '-')}}-Prod ChangeSetName: {{cookiecutter.project_name.lower().replace(' ', '-')}}-ChangeSet-Prod TemplatePath: BuildArtifactAsZip::packaged.yaml Capabilities: CAPABILITY_IAM InputArtifacts: - Name: BuildArtifactAsZip RunOrder: 2 - Name: ExecuteChangeSet ActionTypeId: Category: Deploy Owner: AWS Provider: CloudFormation Version: "1" Configuration: ActionMode: CHANGE_SET_EXECUTE RoleArn: !GetAtt CloudFormationExecutionRole.Arn StackName: {{cookiecutter.project_name.lower().replace(' ', '-')}}-Prod ChangeSetName: {{cookiecutter.project_name.lower().replace(' ', '-')}}-ChangeSet-Prod OutputArtifacts: - Name: {{cookiecutter.project_name.lower().replace(' ', '-')}}ProdChangeSet RunOrder: 3 #### ### ## ## ## ## ## ### ### ## ## ## #### #### ## ## ## ## ### ## ## ######### ## ## ## ## ## ## ## #### ## ## ## ## CodeBuildServiceRole: Type: AWS::IAM::Role Properties: AssumeRolePolicyDocument: Version: '2012-10-17' Statement: - Action: - 'sts:AssumeRole' Effect: Allow Principal: Service: - codebuild.amazonaws.com Path: / Policies: - PolicyName: CodeBuildLogs PolicyDocument: Version: '2012-10-17' Statement: - Effect: Allow Action: - 'logs:CreateLogGroup' - 'logs:CreateLogStream' - 'logs:PutLogEvents' Resource: - !Sub 'arn:aws:logs:${AWS::Region}:${AWS::AccountId}:log-group:/aws/codebuild/{{cookiecutter.project_name.lower().replace(' ', '-')}}' - !Sub 'arn:aws:logs:${AWS::Region}:${AWS::AccountId}:log-group:/aws/codebuild/{{cookiecutter.project_name.lower().replace(' ', '-')}}:*' - PolicyName: CodeBuildArtifactsBucket PolicyDocument: Version: '2012-10-17' Statement: - Effect: Allow Action: - 's3:GetObject' - 's3:GetObjectVersion' - 's3:PutObject' Resource: - !Sub 'arn:aws:s3:::${BuildArtifactsBucket}/*' - PolicyName: CodeBuildParameterStore PolicyDocument: Version: '2012-10-17' Statement: - Effect: Allow Action: 'ssm:GetParameters' Resource: '*' CloudFormationExecutionRole: Type: AWS::IAM::Role Properties: AssumeRolePolicyDocument: Version: '2012-10-17' Statement: Action: 'sts:AssumeRole' Effect: Allow Principal: Service: cloudformation.amazonaws.com Path: / ManagedPolicyArns: - 'arn:aws:iam::aws:policy/AdministratorAccess' CodePipelineExecutionRole: Type: AWS::IAM::Role Properties: AssumeRolePolicyDocument: Version: '2012-10-17' Statement: - Action: - 'sts:AssumeRole' Effect: Allow Principal: Service: - codepipeline.amazonaws.com Path: / Policies: - PolicyName: CodePipelineAccess PolicyDocument: Version: '2012-10-17' Statement: - Effect: Allow Action: - 'iam:PassRole' - 'lambda:InvokeFunction' - 'lambda:ListFunctions' - 'lambda:InvokeAsyc' Resource: '*' - PolicyName: CodePipelineCodeAndArtifactsS3Bucket PolicyDocument: Version: '2012-10-17' Statement: - Effect: Allow Action: 's3:*' Resource: !Sub 'arn:aws:s3:::${BuildArtifactsBucket}/*' {%- if cookiecutter.source_code_repo == "CodeCommit" %} - Effect: Allow Action: 'codecommit:*' Resource: !Sub 'arn:aws:codecommit:${AWS::Region}:${AWS::AccountId}:${CodeRepository.Name}' {% endif %} - PolicyName: CodePipelineCodeBuildAndCloudformationAccess PolicyDocument: Version: '2012-10-17' Statement: - Effect: Allow Action: - 'codebuild:StartBuild' - 'codebuild:BatchGetBuilds' Resource: - !Sub 'arn:aws:codebuild:${AWS::Region}:${AWS::AccountId}:project/${CodeBuildProject}' - 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:cloudformation:${AWS::Region}:${AWS::AccountId}:stack/{{cookiecutter.project_name.lower().replace(' ', '-')}}*/*' - !Sub 'arn:aws:cloudformation:${AWS::Region}:aws:transform/Serverless-2016-10-31' Outputs: {% if cookiecutter.source_code_repo == "Github" %} GitHubRepositoryHttpUrl: Description: GitHub Git repository Value: !Sub https://github.com/${GithubUser}/${GithubRepo}.git GitHubRepositorySshUrl: Description: GitHub Git repository Value: !Sub git@github.com:${GithubUser}/${GithubRepo}.git {%- else %} CodeCommitRepositoryHttpUrl: Description: AWS CodeCommit Git repository Value: !GetAtt CodeRepository.CloneUrlHttp CodeCommitRepositorySshUrl: Description: AWS CodeCommit Git repository Value: !GetAtt CodeRepository.CloneUrlSsh {%- endif %} BuildArtifactS3Bucket: Description: Amazon S3 Bucket for Pipeline and Build artifacts Value: !Ref BuildArtifactsBucket CodeBuildProject: Description: CodeBuild Project name Value: !Ref CodeBuildProject CodePipeline: Description: AWS CodePipeline pipeline name Value: !Ref Pipeline CodeBuildIAMRole: Description: CodeBuild IAM Role Value: !GetAtt CodeBuildServiceRole.Arn CloudformationIAMRole: Description: Cloudformation IAM Role Value: !GetAtt CloudFormationExecutionRole.Arn CodePipelineIAMRole: Description: CodePipeline IAM Role Value: !GetAtt CodePipelineExecutionRole.Arn