Search code examples
amazon-web-servicesaws-cloudformationaws-codepipelineaws-codecommit

How to connect to CodeCommit repository in Cloudformation stack/pipeline


I am very new to Cloudformation and I have a (maybe) stupid question. Here goes.

I want to describe my pipelines with cloudformation templates, which i commit to a repository (just for cloudformation templates).

Then i create a pipeline, that deploys the templates, and with that create the pipelines for the different apps.

This is currently working, but I have one issue: I can't connect to an existing repository. I can only figure out how to create a new repository within the stack, and use that repository in the pipeline. Se below template.

I have seen examples of people connection to github, doing something like this, and I would like to know if this is possible also with Codecommit. The issue is of course, that if you delete your cloudformation stack, you also delete your repository. And if you have an existing repository with your app, it gets gritty.

So is this possible, or have I misunderstood something (remember, I am new to this).

AWSTemplateFormatVersion: 2010-09-09
Resources:
  CodePipeline:
    Type: 'AWS::CodePipeline::Pipeline'
    Properties:
      RoleArn: !GetAtt CodePipeLineRole.Arn
      ArtifactStore:
        Location: !Ref PipelineBucket
        Type: S3
      Stages:
        - 
          Name: Source
          Actions:
            - Name: CheckoutSourceTemplate
              ActionTypeId:
                Category: Source
                Owner: AWS
                Version: 1
                Provider: CodeCommit
              Configuration:
                PollForSourceChanges: true
                RepositoryName: !GetAtt 
                  - PipelineRepo
                  - Name
                BranchName: master
              OutputArtifacts:
                - Name: MyApp
              RunOrder: 1
        - 
          Name: Build
          Actions: 
            - 
              Name: BuildAction
              ActionTypeId: 
                Category: Build
                Owner: AWS
                Version: 1
                Provider: CodeBuild
              InputArtifacts: 
                - 
                  Name: MyApp
              OutputArtifacts: 
                - 
                  Name: MyAppBuild
              Configuration:
                ProjectName: !Ref CodeBuild
  PipelineRepo:
    Type: 'AWS::CodeCommit::Repository'
    Properties:
      RepositoryName: evenz-react-app
      RepositoryDescription: Pipeline repository                
  CodeBuildRole:
    Type: AWS::IAM::Role
    Properties:
      AssumeRolePolicyDocument:
        Version: "2012-10-17"
        Statement:
          - 
            Effect: Allow
            Principal:
              Service:
                - "codebuild.amazonaws.com"
            Action:
              - "sts:AssumeRole"
      Path: /service-role/
      Policies:
        - PolicyName: root
          PolicyDocument:
            Version: "2012-10-17"
            Statement: 
              - 
                Effect: Allow
                Action:
                  - "s3:GetObject"
                  - "s3:GetObjectVersion"
                  - "s3:GetBucketVersioning"
                  - "s3:PutObject"
                Resource: 
                  - !GetAtt PipelineBucket.Arn
                  - !Join ['', [!GetAtt PipelineBucket.Arn, "/*"]]
              - 
                Effect: Allow
                Action:
                  - "s3:GetObject"
                  - "s3:GetObjectVersion"
                  - "s3:GetBucketVersioning"
                  - "s3:PutObject"
                  - "s3:PutObjectAcl"
                Resource: 
                  - !GetAtt DeployBucket.Arn
                  - !Join ['', [!GetAtt DeployBucket.Arn, "/*"]]
              -
                Effect: Allow
                Action:
                  - "logs:CreateLogGroup"
                  - "logs:CreateLogStream"
                  - "logs:PutLogEvents"
                  - "cloudfront:CreateInvalidation"
                Resource:
                  - "*"
  CodePipeLineRole:
    Type: AWS::IAM::Role
    Properties:
      AssumeRolePolicyDocument:
        Version: "2012-10-17"
        Statement:
          - 
            Effect: Allow
            Principal:
              Service:
                - "codepipeline.amazonaws.com"
            Action:
              - "sts:AssumeRole"
      Policies:
        - PolicyName: root
          PolicyDocument:
            Version: "2012-10-17"
            Statement: 
              - 
                Effect: Allow
                Action:
                  - "s3:GetObject"
                  - "s3:GetObjectVersion"
                  - "s3:GetBucketVersioning"
                  - "s3:PutObject"
                Resource: 
                  - !GetAtt PipelineBucket.Arn
                  - !Join ['', [!GetAtt PipelineBucket.Arn, "/*"]]
              - 
                Effect: Allow  
                Action:
                  - "codebuild:BatchGetBuilds"
                  - "codebuild:StartBuild"
                Resource: "*"
              - 
                Effect: Allow  
                Action:
                  - "codecommit:GetRepository"
                  - "codecommit:ListRepositories"
                  - "codecommit:GetBranch"
                  - "codecommit:GetCommit"
                  - "codecommit:UploadArchive"
                  - "codecommit:GetUploadArchiveStatus" 
                Resource: "*"              
  CodeBuild:
    Type: 'AWS::CodeBuild::Project'
    Properties:
      Name: !Sub ${AWS::StackName}-CodeBuild
      ServiceRole: !GetAtt CodeBuildRole.Arn
      Artifacts:
        Type: CODEPIPELINE
        Name: MyProject
      Source: 
        Type: CODEPIPELINE
      Environment:
        ComputeType: BUILD_GENERAL1_SMALL
        Type: LINUX_CONTAINER
        Image: "aws/codebuild/nodejs:8.11.0"
      Source:
        Type: CODEPIPELINE
        BuildSpec: !Sub |
          version: 0.1
          phases:
            pre_build:
              commands:
                - echo Installing source NPM dependencies...
                - npm install
            build:
              commands:
                - echo Build started on `date`
                - npm run build
            post_build:
              commands:
                - aws s3 cp --recursive --acl public-read ./build s3://${DeployBucket}/ 
                - aws s3 cp --acl public-read --cache-control="max-age=0, no-cache, no-store, must-revalidate" ./build/service-worker.js s3://${DeployBucket}/
                - aws s3 cp --acl public-read --cache-control="max-age=0, no-cache, no-store, must-revalidate" ./build/index.html s3://${DeployBucket}/
                - aws cloudfront create-invalidation --distribution-id ${Distribution} --paths /index.html /service-worker.js
          artifacts:
            files:
              - '**/*'
            base-directory: build
  PipelineBucket: 
    Type: 'AWS::S3::Bucket'
    Properties: {}
  DeployBucket:
    Type: 'AWS::S3::Bucket'
    Properties:
      WebsiteConfiguration:
        IndexDocument: index.html
  Distribution:
    Type: "AWS::CloudFront::Distribution"
    Properties:
      DistributionConfig:
        Origins:
          - 
            DomainName: !GetAtt DeployBucket.DomainName
            Id: !Ref DeployBucket
            S3OriginConfig:
              OriginAccessIdentity: ''
        DefaultRootObject: index.html
        Enabled: true
        DefaultCacheBehavior: 
          MinTTL: 86400
          MaxTTL: 31536000
          ForwardedValues: 
            QueryString: true
          TargetOriginId: !Ref DeployBucket
          ViewerProtocolPolicy: "redirect-to-https"

UPDATE:

Thanks to the answer from Marcin below, I changed the reference to the repository to a parameter instead of AWS::CodeCommit::Repository, which works perfectly like I was looking for. The full template now looks like this:

AWSTemplateFormatVersion: 2010-09-09

Parameters: 
  PipelineRepo:
    Type: String
    Default: evenz-react-app
    Description: "Codecommit repo name"

Resources:
  CodePipeline:
    Type: 'AWS::CodePipeline::Pipeline'
    Properties:
      RoleArn: !GetAtt CodePipeLineRole.Arn
      ArtifactStore:
        Location: !Ref PipelineBucket
        Type: S3
      Stages:
        - 
          Name: Source
          Actions:
            - Name: CheckoutSourceTemplate
              ActionTypeId:
                Category: Source
                Owner: AWS
                Version: 1
                Provider: CodeCommit
              Configuration:
                PollForSourceChanges: true
                RepositoryName: !Ref PipelineRepo
                BranchName: master
              OutputArtifacts:
                - Name: MyApp
              RunOrder: 1
        - 
          Name: Build
          Actions: 
            - 
              Name: BuildAction
              ActionTypeId: 
                Category: Build
                Owner: AWS
                Version: 1
                Provider: CodeBuild
              InputArtifacts: 
                - 
                  Name: MyApp
              OutputArtifacts: 
                - 
                  Name: MyAppBuild
              Configuration:
                ProjectName: !Ref CodeBuild            
  CodeBuildRole:
    Type: AWS::IAM::Role
    Properties:
      AssumeRolePolicyDocument:
        Version: "2012-10-17"
        Statement:
          - 
            Effect: Allow
            Principal:
              Service:
                - "codebuild.amazonaws.com"
            Action:
              - "sts:AssumeRole"
      Path: /service-role/
      Policies:
        - PolicyName: root
          PolicyDocument:
            Version: "2012-10-17"
            Statement: 
              - 
                Effect: Allow
                Action:
                  - "s3:GetObject"
                  - "s3:GetObjectVersion"
                  - "s3:GetBucketVersioning"
                  - "s3:PutObject"
                Resource: 
                  - !GetAtt PipelineBucket.Arn
                  - !Join ['', [!GetAtt PipelineBucket.Arn, "/*"]]
              - 
                Effect: Allow
                Action:
                  - "s3:GetObject"
                  - "s3:GetObjectVersion"
                  - "s3:GetBucketVersioning"
                  - "s3:PutObject"
                  - "s3:PutObjectAcl"
                Resource: 
                  - !GetAtt DeployBucket.Arn
                  - !Join ['', [!GetAtt DeployBucket.Arn, "/*"]]
              -
                Effect: Allow
                Action:
                  - "logs:CreateLogGroup"
                  - "logs:CreateLogStream"
                  - "logs:PutLogEvents"
                  - "cloudfront:CreateInvalidation"
                Resource:
                  - "*"
  CodePipeLineRole:
    Type: AWS::IAM::Role
    Properties:
      AssumeRolePolicyDocument:
        Version: "2012-10-17"
        Statement:
          - 
            Effect: Allow
            Principal:
              Service:
                - "codepipeline.amazonaws.com"
            Action:
              - "sts:AssumeRole"
      Policies:
        - PolicyName: root
          PolicyDocument:
            Version: "2012-10-17"
            Statement: 
              - 
                Effect: Allow
                Action:
                  - "s3:GetObject"
                  - "s3:GetObjectVersion"
                  - "s3:GetBucketVersioning"
                  - "s3:PutObject"
                Resource: 
                  - !GetAtt PipelineBucket.Arn
                  - !Join ['', [!GetAtt PipelineBucket.Arn, "/*"]]
              - 
                Effect: Allow  
                Action:
                  - "codebuild:BatchGetBuilds"
                  - "codebuild:StartBuild"
                Resource: "*"
              - 
                Effect: Allow  
                Action:
                  - "codecommit:GetRepository"
                  - "codecommit:ListRepositories"
                  - "codecommit:GetBranch"
                  - "codecommit:GetCommit"
                  - "codecommit:UploadArchive"
                  - "codecommit:GetUploadArchiveStatus" 
                Resource: "*"              
  CodeBuild:
    Type: 'AWS::CodeBuild::Project'
    Properties:
      Name: !Sub ${AWS::StackName}-CodeBuild
      ServiceRole: !GetAtt CodeBuildRole.Arn
      Artifacts:
        Type: CODEPIPELINE
        Name: MyProject
      Source: 
        Type: CODEPIPELINE
      Environment:
        ComputeType: BUILD_GENERAL1_SMALL
        Type: LINUX_CONTAINER
        Image: "aws/codebuild/nodejs:8.11.0"
      Source:
        Type: CODEPIPELINE
        BuildSpec: !Sub |
          version: 0.1
          phases:
            pre_build:
              commands:
                - echo Installing source NPM dependencies...
                - npm install
            build:
              commands:
                - echo Build started on `date`
                - npm run build
            post_build:
              commands:
                - aws s3 cp --recursive --acl public-read ./build s3://${DeployBucket}/ 
                - aws s3 cp --acl public-read --cache-control="max-age=0, no-cache, no-store, must-revalidate" ./build/service-worker.js s3://${DeployBucket}/
                - aws s3 cp --acl public-read --cache-control="max-age=0, no-cache, no-store, must-revalidate" ./build/index.html s3://${DeployBucket}/
                - aws cloudfront create-invalidation --distribution-id ${Distribution} --paths /index.html /service-worker.js
          artifacts:
            files:
              - '**/*'
            base-directory: build
  PipelineBucket: 
    Type: 'AWS::S3::Bucket'
    Properties: {}
  DeployBucket:
    Type: 'AWS::S3::Bucket'
    Properties:
      WebsiteConfiguration:
        IndexDocument: index.html
  Distribution:
    Type: "AWS::CloudFront::Distribution"
    Properties:
      DistributionConfig:
        Origins:
          - 
            DomainName: !GetAtt DeployBucket.DomainName
            Id: !Ref DeployBucket
            S3OriginConfig:
              OriginAccessIdentity: ''
        DefaultRootObject: index.html
        Enabled: true
        DefaultCacheBehavior: 
          MinTTL: 86400
          MaxTTL: 31536000
          ForwardedValues: 
            QueryString: true
          TargetOriginId: !Ref DeployBucket
          ViewerProtocolPolicy: "redirect-to-https"

Solution

  • Maybe I misunderstood the issue, but I think that the separation of your PipelineRepo into its own template and stack would be helpful.

    You could create a simple template for only the PipelineRepo which exports the RepoName e.g.

    Resources:
    
      PipelineRepo:
        Type: 'AWS::CodeCommit::Repository'
        Properties:
          RepositoryName: evenz-react-app
          RepositoryDescription: Pipeline repository
    
    Outputs:
    
      RepoName:
        Value: !GetAtt PipelineRepo.Name
        Export: 
          Name: RepoName
    

    Then you would use ImportValue to import it:

                  Configuration:
                    PollForSourceChanges: true
                    RepositoryName: !ImportValue RepoName
    

    Subsequently, the lifecycle of your PipelineRepo is not tided with the stack of your CodePipeline. CodePipeline stack can be deleted and re-created at anytime, without affecting the PipelineRepo.

    p.s.

    You may hear about importing existing resources into CloudFormation. Normally, this could be considered in a similar case to yours, but AWS::CodeCommit::Repository is not supported for such imports.