We have pipelines that pull the code from a CodeCommit repository and builds and deploys the code.
Between the Source stage and the Build stage, there is a manual approval stage and for random reason this stage sometimes gets skipped and the Pipeline continues directly to the Build stage without getting approved or rejected. Some other times even when it's approved, the manual approval stage would remain pending and waiting for approval. Some other times the Approval stage gets triggered simultaneously with the Source as soon as any code is pushed.
Weirdly enough this only happens to two pipelines that were created using a CloudFormation Template.
In a year or working with aws CodePipeline I never experienced such a thing.
Example of Approval stage getting skipped
Example of Approval stage getting triggered at the same time as the Source stage:
The CloudFormation Template:
AWSTemplateFormatVersion: 2010-09-09
Description: >-
Pipeline for React mobile WebApps. Creates a CodePipeline, along with a Deployment S3 that hosts the static and a CodeBuild Project to build and package the project
Parameters:
RepositoryName:
Type: String
Description: Name of repository to build from
RepositoryBranch:
Type: String
Description: The branch to pull from and build
Default: master
AllowedValues:
- master
- staging
ApiURL:
Type: String
Description: domain of the api to be used by the web app
SocketURL:
Type: String
Description: url of the socket to be used by the web app
SentryURL:
Type: String
Description: url of sentry
CloudfrontURL:
Type: String
Description: url of storage
Resources:
CodeBuildProject:
Type: AWS::CodeBuild::Project
DependsOn: CodeBuildRole
Properties:
Name: !Join
- '-'
- - !Ref RepositoryName
- !Ref RepositoryBranch
- build
- project
ServiceRole: !GetAtt CodeBuildRole.Arn
Environment:
Type: LINUX_CONTAINER
ComputeType: BUILD_GENERAL1_SMALL
Image: aws/codebuild/nodejs:8.11.0
EnvironmentVariables:
- Name: S3_URL
Value: !Join
- '-'
- - !Ref RepositoryName
- !Ref RepositoryBranch
- Name: ENV
Value: !Ref RepositoryBranch
- Name: API_DOMAIN
Value: !Ref ApiURL
- Name: SOCKET_URL
Value: !Ref SocketURL
- Name: SENTRY_URL
Value: !Ref SentryURL
- Name: AWS_CLOUDFRONT_URL
Value: !Ref CloudfrontURL
Source:
Type: CODEPIPELINE
BuildSpec: !Sub |
version: 0.2
phases:
install:
commands:
- echo "installing dependencies"
- npm install
pre_build:
commands:
- echo "building static files"
- npm run build
- echo "static files finished building"
build:
commands:
- echo "build phase started"
- aws s3 sync ./dist s3://${DeploymentBucket}/ --cache-control max-age=0
- echo "build complete"
Artifacts:
Type: CODEPIPELINE
CodeBuildRole:
Type: AWS::IAM::Role
Properties:
AssumeRolePolicyDocument:
Statement:
- Effect: Allow
Principal:
Service:
- codebuild.amazonaws.com
Action:
- sts:AssumeRole
Path: "/"
Policies:
- PolicyName: codebuild-service
PolicyDocument:
Statement:
- Effect: Allow
Action: "*"
Resource: "*"
Version: '2012-10-17'
CodePipeline:
Type: 'AWS::CodePipeline::Pipeline'
DependsOn:
- CodePipelineTrustRole
Properties:
Stages:
- Name: Source
Actions:
- InputArtifacts: []
Name: Source
ActionTypeId:
Category: Source
Owner: AWS
Version: '1'
Provider: CodeCommit
OutputArtifacts:
- Name: MyApp
Configuration:
PollForSourceChanges: false
BranchName: !Ref RepositoryBranch
RepositoryName: !Ref RepositoryName
RunOrder: 1
- Name: Approval
Actions:
- InputArtifacts: []
Name: Approval
ActionTypeId:
Category: Approval
Owner: AWS
Version: '1'
Provider: Manual
OutputArtifacts: []
Configuration:
RunOrder: 1
- Name: BuildAndDeploy
Actions:
- InputArtifacts:
- Name: MyApp
Name: CodeBuild
ActionTypeId:
Category: Build
Owner: AWS
Version: '1'
Provider: CodeBuild
OutputArtifacts:
- Name: MyAppBuild
Configuration:
ProjectName: !Ref CodeBuildProject
RunOrder: 1
- Name: Invalidation
Actions:
- InputArtifacts: []
Name: Invalidate-CloudFront
ActionTypeId:
Category: Invoke
Owner: AWS
Version: '1'
Provider: Lambda
Configuration:
FunctionName: "Cloudfront-Invalidator"
UserParameters: !Sub '{"S3Bucket": "${DeploymentBucket}"}'
OutputArtifacts: []
RunOrder: 1
ArtifactStore:
Type: S3
Location: pipeline-store-bucket
RoleArn: !GetAtt
- CodePipelineTrustRole
- Arn
Name: !Join
- '-'
- - !Ref RepositoryName
- !Ref RepositoryBranch
- pipeline
CodePipelineTrustRole:
Type: 'AWS::IAM::Role'
Description: Creates service role in IAM for AWS CodePipeline
Properties:
AssumeRolePolicyDocument:
Statement:
- Action: 'sts:AssumeRole'
Effect: Allow
Principal:
Service:
- codepipeline.amazonaws.com
Sid: 1
Path: /
Policies:
- PolicyDocument:
Statement:
- Action:
- 's3:GetObject'
- 's3:GetObjectVersion'
- 's3:GetBucketVersioning'
- 's3:PutObject'
Effect: Allow
Resource:
- !Join
- ''
- - 'arn:aws:s3:::'
- 'pipeline-store-bucket'
- '/*'
- !Join
- ''
- - 'arn:aws:s3:::'
- 'pipeline-store-bucket'
- Action:
- 'codecommit:CancelUploadArchive'
- 'codecommit:GetBranch'
- 'codecommit:GetCommit'
- 'codecommit:GetUploadArchiveStatus'
- 'codecommit:UploadArchive'
Effect: Allow
Resource:
- !Join
- ':'
- - arn
- aws
- codecommit
- !Ref 'AWS::Region'
- !Ref 'AWS::AccountId'
- !Ref RepositoryName
- Action:
- 'codebuild:StartBuild'
- 'codebuild:BatchGetBuilds'
- 'codebuild:StopBuild'
Effect: Allow
Resource: '*'
- Action:
- 'cloudformation:DescribeStacks'
- 'cloudformation:DescribeChangeSet'
- 'cloudformation:CreateChangeSet'
- 'cloudformation:DeleteChangeSet'
- 'cloudformation:ExecuteChangeSet'
Effect: Allow
Resource: '*'
- Action:
- 'sns:Publish'
Effect: Allow
Resource: '*'
- Action:
- 'lambda:*'
- 'cloudwatch:*'
- 'events:*'
- 'codepipeline:PutJobSuccessResult'
- 'codepipeline:PutJobFailureResult'
Effect: Allow
Resource: '*'
PolicyName: CodePipelineTrustPolicy
RoleName: !Join
- '-'
- - !Ref AWS::StackName
- CodePipeline
- Role
SourceEvent:
Type: 'AWS::Events::Rule'
Properties:
Description: >-
Rule for Amazon CloudWatch Events to detect changes to the source
repository and trigger pipeline execution
EventPattern:
detail:
event:
- referenceCreated
- referenceUpdated
referenceName:
- !Ref RepositoryBranch
referenceType:
- branch
detail-type:
- CodeCommit Repository State Change
resources:
- !Join
- ':'
- - arn
- aws
- codecommit
- !Ref 'AWS::Region'
- !Ref 'AWS::AccountId'
- !Ref RepositoryName
source:
- aws.codecommit
Name: !Join
- '-'
- - !Ref RepositoryName
- !Ref RepositoryBranch
- SourceEvent
State: ENABLED
Targets:
- Arn: !Join
- ':'
- - arn
- aws
- codepipeline
- !Ref 'AWS::Region'
- !Ref 'AWS::AccountId'
- !Join
- '-'
- - !Ref RepositoryName
- !Ref RepositoryBranch
- pipeline
Id: ProjectPipelineTarget
RoleArn: !GetAtt SourceEventRole.Arn
SourceEventRole:
Type: 'AWS::IAM::Role'
Description: >-
IAM role to allow Amazon CloudWatch Events to trigger AWS CodePipeline
execution
Properties:
AssumeRolePolicyDocument:
Statement:
- Action: 'sts:AssumeRole'
Effect: Allow
Principal:
Service:
- events.amazonaws.com
Sid: 1
Policies:
- PolicyDocument:
Statement:
- Action:
- 'codepipeline:StartPipelineExecution'
Effect: Allow
Resource:
- !Join
- ':'
- - arn
- aws
- codepipeline
- !Ref 'AWS::Region'
- !Ref 'AWS::AccountId'
- !Join
- '-'
- - !Ref RepositoryName
- !Ref RepositoryBranch
- pipeline
PolicyName: CodeStarWorkerCloudWatchEventPolicy
RoleName: !Join
- '-'
- - CodePipeline
- !Ref RepositoryName
- !Ref RepositoryBranch
- CloudWatchEventRule
DeploymentBucket:
Type: 'AWS::S3::Bucket'
Description: >-
S3 Bucket to host the website built from the CodeCommit repository
Properties:
AccessControl: PublicRead
WebsiteConfiguration:
IndexDocument: index.html
ErrorDocument: index.html
BucketName: !Join
- '-'
- - !Ref 'RepositoryName'
- !Ref 'RepositoryBranch'
DeletionPolicy: Delete
DeploymentBucketPolicy:
Type: AWS::S3::BucketPolicy
Description: >-
Policy for the web hosting deployment S3 bucket
Properties:
Bucket: !Ref DeploymentBucket
PolicyDocument:
Statement:
- Sid: PublicReadForGetBucketObjectsxw
Effect: Allow
Principal: '*'
Action: s3:GetObject
Resource: !Join ['', ['arn:aws:s3:::', !Ref 'DeploymentBucket', /*]]
CloudFrontDistribution:
Type: AWS::CloudFront::Distribution
Description: A CloudFront Distribution for the website hosting S3 buckets
DependsOn: DeploymentBucket
Properties:
DistributionConfig:
Origins:
- DomainName: !Join
- '.'
- - !Ref DeploymentBucket
- s3
- amazonaws
- com
Id: !Join
- '-'
- - S3
- !Ref DeploymentBucket
CustomOriginConfig:
HTTPPort: 80
HTTPSPort: 443
OriginProtocolPolicy: https-only
Enabled: true
DefaultCacheBehavior:
AllowedMethods:
- GET
- HEAD
- OPTIONS
- PUT
- POST
- PATCH
- DELETE
ForwardedValues:
QueryString: 'false'
Cookies:
Forward: none
TargetOriginId: !Join
- '-'
- - S3
- !Ref DeploymentBucket
ViewerProtocolPolicy: redirect-to-https
IPV6Enabled: true
DefaultRootObject: index.html
Outputs:
PipelineURL:
Value: !Sub https://console.aws.amazon.com/codepipeline/home?region=${AWS::Region}#/view/${CodePipeline}
Description: URL for the CodePipeline of this stack
SiteUrl:
Value: !GetAtt [DeploymentBucket, WebsiteURL]
Description: URL for the S3 Website
CodeBuildUrl:
Value: !Sub https://eu-west-1.console.aws.amazon.com/codebuild/home?${AWS::Region}#/projects/${CodeBuildProject}/view
Description: URL for the CodeBuild Project of this stack
RepositoryUrl:
Value: !Sub https://eu-west-1.console.aws.amazon.com/codesuite/codecommit/repositories/${RepositoryName}/browse?region=eu-west-1
Description: URL for the repository of this stack
Each CodePipeline stage can have a different version in it so that you can eg. test a new version in beta in parallel with the previous version being deployed to prod. All actions within a stage run the same set of versions (artifacts) though.
CodePipeline will not de-duplicate based on source commit ID because often it's desirable to re-release the same source commit (eg. because the build will pull updated dependencies, or because you want to reset things to a clean state after eg. a rollback).
This means there can be different versions with the same source commit ID in different stages. You go to the "View history" page to verify this.
Example of Approval stage getting skipped
In this print screen I suspect there's 2 changes. C1 was previously approved and is now deployed in "BuildAndDeploy". C2 is the change showing Succeeded in "Source" and waiting for approval in "Approval".
Example of Approval stage getting triggered at the same time as the Source stage:
This is also a case of 2 version. There's one version in Source and another in Approval.
Related
I'm trying to write a template that configures the whole ecs fargate server and its code pipeline.
There is no problem in all other configurations, but the image is empty because it is right after creating the ecr in cloudformation, and the create ecs service refers to the empty image and the process does not end.
So I want to push the server image to ecr with code build and then ecs service create to work, but I don't know how.
Could it be possible to trigger code build or code pipeline inside cloudformation?
If not, is there any way to do docker build & push?
Yes it can be done, I used it before to perform jobs like a database restore as part of stack creation (don't ask). What you need:
A custom resource lambda which kicks off the codebuild job. It will receive the codebuild project to start via a property passed to it in the cloudformation resource definition (assuming that the codebuild is determined at deploy time; else feel free to make the lambda know about which codebuild to run in whatever way makes the most sense to you).
The endpoint to call when the custom resource is complete. A custom resource will stay in CREATE_IN_PROGRESS state until the endpoint is called. It's been a while since I've used custom resources so don't remember where it comes from but I think it's found in the event that the custom resource lambda is invoked with.
Your codebuild job needs that endpoint and needs to be able to send a (GET or POST?) request to it, on both success and failure cases (you pass different params signifying success or failure).
So the overall sequence of steps is:
Define/reference the custom resource in your template, passing in whatever properties the lambda needs.
Deploy stack, custom resource lambda is invoked.
The custom resource status goes into CREATE_IN_PROGRESS
Lambda kicks off codebuild, passing in custom resource endpoint as a param or env var, and returns.
Codebuild starts doing its work.
Until the endpoint is invoked, the custom resource will remain as CREATE_IN_PROGRESS, and the stack create/update process will wait for it, even if it takes hours.
When codebuild has finished its work, it uses curl or similar to invoke that endpoint to signal it's complete.
Custom resource status goes to CREATE_COMPLETE (assuming you've invoked the endpoint with params saying it was successful).
Stack creation completes (or moves on to any resources that were dependent on the custom resource).
Yes, it is possible to trigger the Fargate deployment after pushing the image rather than when the CloudFormation template is run.
The trick is to set the DesiredCount property of AWS::ECS::Service to zero:
Service:
Type: AWS::ECS::Service
Properties:
Cluster: !Ref Cluster
DesiredCount: 0
LaunchType: FARGATE
NetworkConfiguration:
AwsvpcConfiguration:
SecurityGroups:
- !Ref SecG
Subnets: !Ref Subs
ServiceName: !Select [4, !Split ['-', !Select [2, !Split ['/', !Ref AWS::StackId]]]]
TaskDefinition: !Ref TaskDefinition
That said, you can also choose to create a repo with an initial commit that will trigger the build as soon as the template is done executing. This requires you to upload the zipped source code to an S3 bucket and configure the CodeCommit repository like so:
Repo:
Type: AWS::CodeCommit::Repository
Properties:
Code:
BranchName: main
S3:
Bucket: some-bucket
Key: code.zip
RepositoryName: !Select [4, !Split ['-', !Select [2, !Split ['/', !Ref AWS::StackId]]]]
RepositoryDescription: Repository
Triggers:
- Name: Trigger
CustomData: The Code Repository
DestinationArn: !Ref Topic
Branches:
- main
Events: [all]
Note that the some-bucket S3 bucket needs to contain the zipped .Dockerfile and any source code without any .git directory included.
You can see my implementation of this system and the rest of the stack below:
AWSTemplateFormatVersion: '2010-09-09'
Description: CloudFormation Stack to Trigger CodeBuild via CodePipeline
Parameters:
SecG:
Description: Single security group
Type: AWS::EC2::SecurityGroup::Id
Subs:
Description: Comma separated subnet IDs
Type: List<AWS::EC2::Subnet::Id>
ImagesFile:
Type: String
Default: images.json
Resources:
ArtifactBucket:
Type: AWS::S3::Bucket
DeletionPolicy: Retain
Properties:
PublicAccessBlockConfiguration:
BlockPublicAcls: true
BlockPublicPolicy: true
IgnorePublicAcls: true
RestrictPublicBuckets: true
Tags:
- Key: UseWithCodeDeploy
Value: true
CodeBuildServiceRole:
Type: AWS::IAM::Role
Properties:
Path: /
AssumeRolePolicyDocument:
Version: 2012-10-17
Statement:
- Effect: Allow
Principal:
Service: codebuild.amazonaws.com
Action: sts:AssumeRole
Policies:
- PolicyName: !Sub 'ssm-${AWS::Region}-${AWS::StackName}'
PolicyDocument:
Version: '2012-10-17'
Statement:
-
Effect: Allow
Action:
- ssm:GetParameters
- secretsmanager:GetSecretValue
Resource: '*'
- PolicyName: !Sub 'logs-${AWS::Region}-${AWS::StackName}'
PolicyDocument:
Version: "2012-10-17"
Statement:
-
Effect: Allow
Action:
- logs:CreateLogGroup
- logs:CreateLogStream
- logs:PutLogEvents
Resource: '*'
- PolicyName: !Sub 'ecr-${AWS::Region}-${AWS::StackName}'
PolicyDocument:
Version: "2012-10-17"
Statement:
-
Effect: Allow
Action:
- ecr:BatchCheckLayerAvailability
- ecr:CompleteLayerUpload
- ecr:GetAuthorizationToken
- ecr:InitiateLayerUpload
- ecr:PutImage
- ecr:UploadLayerPart
- lightsail:*
Resource: '*'
- PolicyName: !Sub bkt-${ArtifactBucket}-${AWS::Region}
PolicyDocument:
Version: '2012-10-17'
Statement:
-
Effect: Allow
Action:
- s3:ListBucket
- s3:GetBucketLocation
- s3:ListBucketVersions
- s3:GetBucketVersioning
Resource:
- !Sub arn:aws:s3:::${ArtifactBucket}
- arn:aws:s3:::some-bucket
- PolicyName: !Sub obj-${ArtifactBucket}-${AWS::Region}
PolicyDocument:
Version: '2012-10-17'
Statement:
-
Effect: Allow
Action:
- s3:GetObject
- s3:PutObject
- s3:GetObjectAcl
- s3:PutObjectAcl
- s3:GetObjectTagging
- s3:PutObjectTagging
- s3:GetObjectVersion
- s3:GetObjectVersionAcl
- s3:PutObjectVersionAcl
Resource:
- !Sub arn:aws:s3:::${ArtifactBucket}/*
- arn:aws:s3:::some-bucket/*
CodeDeployServiceRole:
Type: AWS::IAM::Role
Properties:
AssumeRolePolicyDocument:
Statement:
- Sid: '1'
Effect: Allow
Principal:
Service:
- codedeploy.us-east-1.amazonaws.com
- codedeploy.eu-west-1.amazonaws.com
Action: sts:AssumeRole
Path: /
ManagedPolicyArns:
- arn:aws:iam::aws:policy/AWSCodeDeployRoleForECS
- arn:aws:iam::aws:policy/service-role/AWSCodeDeployRole
- arn:aws:iam::aws:policy/service-role/AWSCodeDeployRoleForLambda
CodeDeployRolePolicies:
Type: AWS::IAM::Policy
Properties:
PolicyName: !Sub 'CDPolicy-${AWS::Region}-${AWS::StackName}'
PolicyDocument:
Statement:
- Effect: Allow
Resource:
- '*'
Action:
- ec2:Describe*
- Effect: Allow
Resource:
- '*'
Action:
- autoscaling:CompleteLifecycleAction
- autoscaling:DeleteLifecycleHook
- autoscaling:DescribeLifecycleHooks
- autoscaling:DescribeAutoScalingGroups
- autoscaling:PutLifecycleHook
- autoscaling:RecordLifecycleActionHeartbeat
Roles:
- !Ref CodeDeployServiceRole
CodePipelineServiceRole:
Type: AWS::IAM::Role
Properties:
Path: /
AssumeRolePolicyDocument:
Version: '2012-10-17'
Statement:
- Effect: Allow
Principal:
Service: codepipeline.amazonaws.com
Action: sts:AssumeRole
Policies:
- PolicyName: !Sub 'root-${AWS::Region}-${AWS::StackName}'
PolicyDocument:
Version: '2012-10-17'
Statement:
- Resource:
- !Sub 'arn:aws:s3:::${ArtifactBucket}/*'
- !Sub 'arn:aws:s3:::${ArtifactBucket}'
Effect: Allow
Action:
- s3:PutObject
- s3:GetObject
- s3:GetObjectVersion
- s3:GetBucketAcl
- s3:GetBucketLocation
- Resource: "*"
Effect: Allow
Action:
- ecs:*
- Resource: "*"
Effect: Allow
Action:
- iam:PassRole
Condition:
StringLike:
iam:PassedToService:
- ecs-tasks.amazonaws.com
- Resource: !GetAtt Build.Arn
Effect: Allow
Action:
- codebuild:BatchGetBuilds
- codebuild:StartBuild
- codebuild:BatchGetBuildBatches
- codebuild:StartBuildBatch
- Resource: !GetAtt Repo.Arn
Effect: Allow
Action:
- codecommit:CancelUploadArchive
- codecommit:GetBranch
- codecommit:GetCommit
- codecommit:GetRepository
- codecommit:GetUploadArchiveStatus
- codecommit:UploadArchive
AmazonCloudWatchEventRole:
Type: AWS::IAM::Role
Properties:
AssumeRolePolicyDocument:
Version: '2012-10-17'
Statement:
-
Effect: Allow
Principal:
Service:
- events.amazonaws.com
Action: sts:AssumeRole
Path: /
Policies:
-
PolicyName: cwe-pipeline-execution
PolicyDocument:
Version: '2012-10-17'
Statement:
-
Effect: Allow
Action: codepipeline:StartPipelineExecution
Resource: !Sub arn:aws:codepipeline:${AWS::Region}:${AWS::AccountId}:${Pipeline}
AmazonCloudWatchEventRule:
Type: AWS::Events::Rule
Properties:
EventPattern:
source:
- aws.codecommit
detail-type:
- CodeCommit Repository State Change
resources:
- !GetAtt Repo.Arn
detail:
event:
- referenceCreated
- referenceUpdated
referenceType:
- branch
referenceName:
- main
Targets:
-
Arn: !Sub arn:aws:codepipeline:${AWS::Region}:${AWS::AccountId}:${Pipeline}
RoleArn: !GetAtt AmazonCloudWatchEventRole.Arn
Id: codepipeline-Pipeline
Topic:
Type: AWS::SNS::Topic
Properties:
Subscription:
- Endpoint: user#example.com
Protocol: email
TopicPolicy:
Type: AWS::SNS::TopicPolicy
Properties:
PolicyDocument:
Version: '2012-10-17'
Statement:
-
Sid: AllowPublish
Effect: Allow
Principal:
Service:
- 'codestar-notifications.amazonaws.com'
Action:
- 'SNS:Publish'
Resource:
- !Ref Topic
Topics:
- !Ref Topic
Repo:
Type: AWS::CodeCommit::Repository
Properties:
Code:
BranchName: main
S3:
Bucket: some-bucket
Key: code.zip
RepositoryName: !Select [4, !Split ['-', !Select [2, !Split ['/', !Ref AWS::StackId]]]]
RepositoryDescription: Repository
Triggers:
- Name: Trigger
CustomData: The Code Repository
DestinationArn: !Ref Topic
Branches:
- main
Events: [all]
RepoUser:
Type: AWS::IAM::User
Properties:
Path: '/'
ManagedPolicyArns:
- arn:aws:iam::aws:policy/AWSCodeCommitPowerUser
RepoUserKey:
Type: AWS::IAM::AccessKey
Properties:
UserName:
!Ref RepoUser
Registry:
Type: AWS::ECR::Repository
Properties:
RepositoryName: !Select [4, !Split ['-', !Select [2, !Split ['/', !Ref AWS::StackId]]]]
RepositoryPolicyText:
Version: '2012-10-17'
Statement:
- Sid: AllowPushPull
Effect: Allow
Principal:
AWS:
- !GetAtt CodeDeployServiceRole.Arn
Action:
- ecr:GetDownloadUrlForLayer
- ecr:BatchGetImage
- ecr:BatchCheckLayerAvailability
- ecr:PutImage
- ecr:InitiateLayerUpload
- ecr:UploadLayerPart
- ecr:CompleteLayerUpload
Build:
Type: AWS::CodeBuild::Project
Properties:
Artifacts:
Type: CODEPIPELINE
Source:
Type: CODEPIPELINE
BuildSpec: !Sub |
version: 0.2
phases:
pre_build:
commands:
- echo "[`date`] PRE_BUILD"
- echo "Logging in to Amazon ECR..."
- aws ecr get-login-password --region $REGION | docker login --username AWS --password-stdin $ACCOUNT.dkr.ecr.$REGION.amazonaws.com
- IMAGE_URI="$ACCOUNT.dkr.ecr.$REGION.amazonaws.com/$REPO:$TAG"
build:
commands:
- echo "[`date`] BUILD"
- echo "Building Docker Image..."
- docker build -t $REPO:$TAG .
- docker tag $REPO:$TAG $IMAGE_URI
post_build:
commands:
- echo "[`date`] POST_BUILD"
- echo "Pushing Docker Image..."
- docker push $IMAGE_URI
- echo Writing image definitions file...
- printf '[{"name":"svc","imageUri":"%s"}]' $IMAGE_URI > $FILE
artifacts:
files: $FILE
Environment:
ComputeType: BUILD_GENERAL1_SMALL
Image: aws/codebuild/standard:6.0
Type: LINUX_CONTAINER
EnvironmentVariables:
- Name: REGION
Type: PLAINTEXT
Value: !Ref AWS::Region
- Name: ACCOUNT
Type: PLAINTEXT
Value: !Ref AWS::AccountId
- Name: TAG
Type: PLAINTEXT
Value: latest
- Name: REPO
Type: PLAINTEXT
Value: !Ref Registry
- Name: FILE
Type: PLAINTEXT
Value: !Ref ImagesFile
PrivilegedMode: true
Name: !Ref AWS::StackName
ServiceRole: !GetAtt CodeBuildServiceRole.Arn
Pipeline:
Type: AWS::CodePipeline::Pipeline
Properties:
RoleArn: !GetAtt CodePipelineServiceRole.Arn
ArtifactStore:
Type: S3
Location: !Ref ArtifactBucket
Stages:
- Name: Source
Actions:
- Name: Site
ActionTypeId:
Category: Source
Owner: AWS
Version: '1'
Provider: CodeCommit
Configuration:
RepositoryName: !GetAtt Repo.Name
BranchName: main
PollForSourceChanges: 'false'
InputArtifacts: []
OutputArtifacts:
- Name: SourceArtifact
RunOrder: 1
- Name: Build
Actions:
- Name: Docker
ActionTypeId:
Category: Build
Owner: AWS
Version: '1'
Provider: CodeBuild
Configuration:
ProjectName: !Ref Build
InputArtifacts:
- Name: SourceArtifact
OutputArtifacts:
- Name: BuildArtifact
RunOrder: 1
- Name: Deploy
Actions:
- Name: Fargate
ActionTypeId:
Category: Deploy
Owner: AWS
Version: '1'
Provider: ECS
Configuration:
ClusterName: !Ref Cluster
FileName: !Ref ImagesFile
ServiceName: !GetAtt Service.Name
InputArtifacts:
- Name: BuildArtifact
RunOrder: 1
Cluster:
Type: AWS::ECS::Cluster
Properties:
ClusterName: !Select [4, !Split ['-', !Select [2, !Split ['/', !Ref AWS::StackId]]]]
FargateTaskExecutionRole:
Type: AWS::IAM::Role
Properties:
AssumeRolePolicyDocument:
Version: 2012-10-17
Statement:
- Effect: Allow
Principal:
Service:
- ecs-tasks.amazonaws.com
Action:
- sts:AssumeRole
ManagedPolicyArns:
- arn:aws:iam::aws:policy/service-role/AmazonECSTaskExecutionRolePolicy
TaskRole:
Type: AWS::IAM::Role
Properties:
AssumeRolePolicyDocument:
Version: 2012-10-17
Statement:
- Effect: Allow
Principal:
Service:
- ecs-tasks.amazonaws.com
Action:
- sts:AssumeRole
TaskDefinition:
Type: AWS::ECS::TaskDefinition
Properties:
ContainerDefinitions:
-
Name: svc
Image: !Sub ${AWS::AccountId}.dkr.ecr.${AWS::Region}.amazonaws.com/${Registry}:latest
PortMappings:
- ContainerPort: 8080
Cpu: 256
ExecutionRoleArn: !Ref FargateTaskExecutionRole
Memory: 512
NetworkMode: awsvpc
RequiresCompatibilities:
- FARGATE
RuntimePlatform:
CpuArchitecture: ARM64
OperatingSystemFamily: LINUX
TaskRoleArn: !Ref TaskRole
Service:
Type: AWS::ECS::Service
Properties:
Cluster: !Ref Cluster
DesiredCount: 0
LaunchType: FARGATE
NetworkConfiguration:
AwsvpcConfiguration:
SecurityGroups:
- !Ref SecG
Subnets: !Ref Subs
ServiceName: !Select [4, !Split ['-', !Select [2, !Split ['/', !Ref AWS::StackId]]]]
TaskDefinition: !Ref TaskDefinition
Outputs:
ArtifactBucketName:
Description: ArtifactBucket S3 Bucket Name
Value: !Ref ArtifactBucket
ArtifactBucketSecureUrl:
Description: ArtifactBucket S3 Bucket Domain Name
Value: !Sub 'https://${ArtifactBucket.DomainName}'
ClusterName:
Value: !Ref Cluster
ServiceName:
Value: !GetAtt Service.Name
RepoUserAccessKey:
Description: S3 User Access Key
Value: !Ref RepoUserKey
RepoUserSecretKey:
Description: S3 User Secret Key
Value: !GetAtt RepoUserKey.SecretAccessKey
BuildArn:
Description: CodeBuild URL
Value: !GetAtt Build.Arn
RepoArn:
Description: CodeCommit Repository ARN
Value: !GetAtt Repo.Arn
RepoName:
Description: CodeCommit Repository NAme
Value: !GetAtt Repo.Name
RepoCloneUrlHttp:
Description: CodeCommit HTTP Clone URL
Value: !GetAtt Repo.CloneUrlHttp
RepoCloneUrlSsh:
Description: CodeCommit SSH Clone URL
Value: !GetAtt Repo.CloneUrlSsh
PipelineUrl:
Description: CodePipeline URL
Value: !Sub https://console.aws.amazon.com/codepipeline/home?region=${AWS::Region}#/view/${Pipeline}
RegistryUri:
Description: ECR Repository URI
Value: !GetAtt Registry.RepositoryUri
TopicArn:
Description: CodeCommit Notification SNS Topic ARN
Value: !Ref Topic
Hope this helps!
I am trying to create a code pipeline using cloud formation. My cloudformation template gets created successfully. However, the pipeline created gets stuck at the source stage itself saying the provided role does not have permission to access codecommit/s3.
The problem is that I have already given codecommit:* and s3:* policies to the pipeline role. Also I am using user permissions while running the cloud formation template and the user has admin permissions.
When I rerun the pipeline from the dashboard the pipeline runs successfully. Why is it getting failed when run automatically on getting created?
Following is the code where I am facing the problem:
Resources:
CodePipelineRole:
Type: AWS::IAM::Role
Properties:
AssumeRolePolicyDocument:
Version: "2012-10-17"
Statement:
Effect: Allow
Principal:
Service:
- codepipeline.amazonaws.com
- events.amazonaws.com
Action: sts:AssumeRole
Path: /
CodePipelinePolicy:
Type: AWS::IAM::Policy
Properties:
PolicyName: CodePipelinePolicy
PolicyDocument:
Statement:
- Action:
- iam:PassRole
Resource: "*"
Effect: Allow
Condition:
StringEqualsIfExists:
iam:PassedToService:
- cloudformation.amazonaws.com
- elasticbeanstalk.amazonaws.com
- ec2.amazonaws.com
- ecs-tasks.amazonaws.com
- Action:
- s3:*
- cloudwatch:*
- codecommit:*
- opsworks:*
- states:*
- appconfig:*
Resource: "*"
Effect: Allow
Version: '2012-10-17'
Roles:
- Ref: CodePipelineRole
Pipeline:
Type: AWS::CodePipeline::Pipeline
Properties:
ArtifactStore:
Type: S3
Location: !Ref S3Bucket
Name: SamplePipeline
RoleArn: !GetAtt [CodePipelineRole,Arn]
Stages:
- Name: Source
Actions:
- InputArtifacts: []
Name: Template
Region: !Ref AWS::Region
ActionTypeId:
Category: Source
Owner: AWS
Version: '1'
Provider: S3
OutputArtifacts:
- Name: template
Configuration:
S3Bucket: !Ref S3Bucket
PollForSourceChanges: 'false'
S3ObjectKey: !Sub ${NameOfArtifact}.zip
RunOrder: 1
....
Starting with AWS and want to do it right from te beginning. What would be the current state of the art approach to have a complete CI pipeline?
Our idea is to have everything in a local git repository at the company and then we can trigger deployments into the different AWS stages. And with everything we mean everything, so we can automate everything and live completely without the aws web interface.
I went through some tutorials and they all seem to do it differently, tools lile Apex, Amplify, CloudFormation, SAM, etc. came up and some of them seem to be very old and deprecated. So we are trying to get a clear idea, what are the current technologies and which ones should not be used anymore.
Which editors would be good? Are there any that support the deployment with plugins to use directly from the IDE?
Also if there is a sample project out there that does all that or most, it would be a real help!
My personal "state of the art" is as the following:
For each (mirco)service I am creating a separate Git repository in
AWS CodeCommit
Each repository has its own CI/CD pipeline with AWS CodePipeline. The pipeline has the following stages:
Source (AWS CodeCommit)
Build (AWS CodeBuild)
Deploy Staging[*] (AWS CloudFormation)
Approval (Manual Approval)
Deploy Production[*] (AWS CloudFormation)
The whole infrastructure and pipeline is written in CloudFormation (in AWS SAM Syntax) and I highly recommend to do it so as well. This will also help you to tackle your requirement "[...] completely without the aws web interface."
[*]: Both stages are using the same(!) AWS CloudFormation template, I just pass a different Environment parameter into the infrastructure template to be able to make some differences based on the env.
Most of my services are written in TypeScript, to develop it I am using WebStorm with a cool plugin to help me writing AWS CloudFormation templates.
Example of pipeline.yml:
AWSTemplateFormatVersion: 2010-09-09
Parameters:
RepositoryName:
Type: String
ArtifactStoreBucket:
Type: String
Resources:
Pipeline:
Type: AWS::CodePipeline::Pipeline
Properties:
RoleArn: !GetAtt CodePipelineRole.Arn
ArtifactStore:
Location: !Ref ArtifactStoreBucket
Type: S3
Stages:
- Name: Source
Actions:
- Name: CodeCommit
ActionTypeId:
Category: Source
Owner: AWS
Version: 1
Provider: CodeCommit
Configuration:
RepositoryName: !Ref RepositoryName
BranchName: master
InputArtifacts: []
OutputArtifacts:
- Name: SourceOutput
RunOrder: 1
- Name: Build
Actions:
- Name: Build
ActionTypeId:
Category: Build
Owner: AWS
Version: 1
Provider: CodeBuild
Configuration:
ProjectName: !Ref Build
InputArtifacts:
- Name: SourceOutput
OutputArtifacts:
- Name: BuildOutput
RunOrder: 1
- Name: Staging
Actions:
- Name: Deploy
ActionTypeId:
Category: Deploy
Owner: AWS
Version: 1
Provider: CloudFormation
Configuration:
ActionMode: CREATE_UPDATE
Capabilities: CAPABILITY_IAM,CAPABILITY_AUTO_EXPAND
StackName: !Sub ${AWS::StackName}-Infrastructure-Staging
RoleArn: !GetAtt CloudFormationRole.Arn
TemplatePath: BuildOutput::infrastructure-packaged.yml
ParameterOverrides:
!Sub |
{
"Environment": "Staging"
}
InputArtifacts:
- Name: BuildOutput
OutputArtifacts: []
RunOrder: 1
- Name: Approval
Actions:
- Name: Approval
ActionTypeId:
Category: Approval
Owner: AWS
Version: 1
Provider: Manual
InputArtifacts: []
OutputArtifacts: []
RunOrder: 1
- Name: Production
Actions:
- Name: Deploy
ActionTypeId:
Category: Deploy
Owner: AWS
Version: 1
Provider: CloudFormation
Configuration:
ActionMode: CREATE_UPDATE
Capabilities: CAPABILITY_IAM,CAPABILITY_AUTO_EXPAND
StackName: !Sub ${AWS::StackName}-Infrastructure-Production
RoleArn: !GetAtt CloudFormationRole.Arn
TemplatePath: BuildOutput::infrastructure-packaged.yml
ParameterOverrides:
!Sub |
{
"Environment": "Production"
}
InputArtifacts:
- Name: BuildOutput
OutputArtifacts: []
RunOrder: 1
Build:
Type: AWS::CodeBuild::Project
Properties:
Artifacts:
Type: CODEPIPELINE
Environment:
ComputeType: BUILD_GENERAL1_MEDIUM
Image: aws/codebuild/nodejs:10.14.1
Type: LINUX_CONTAINER
Name: !Sub ${AWS::StackName}-Build
ServiceRole: !Ref CodeBuildRole
Source:
Type: CODEPIPELINE
BuildSpec:
!Sub |
version: 0.2
phases:
build:
commands:
- npm install
- npm run lint
- npm run test:unit
- npm run build
- aws cloudformation package --s3-bucket ${ArtifactStoreBucket} --template-file ./infrastructure.yml --output-template-file infrastructure-packaged.yml
artifacts:
files:
- infrastructure-packaged.yml
BuildLogGroup:
Type: AWS::Logs::LogGroup
Properties:
RetentionInDays: 14
LogGroupName: !Sub /aws/codebuild/${Build}
CodePipelineRole:
Type: AWS::IAM::Role
Properties:
AssumeRolePolicyDocument:
Statement:
- Effect: Allow
Principal:
Service: codepipeline.amazonaws.com
Action: sts:AssumeRole
Policies:
- PolicyName: CodePipelineRolePolicy
PolicyDocument:
Statement:
- Effect: Allow
Action:
- iam:PassRole
Resource:
- !GetAtt CloudFormationRole.Arn
- Effect: Allow
Action:
- s3:*
Resource:
- !Sub arn:aws:s3:::${ArtifactStoreBucket}/*
- Effect: Allow
Action:
- codecommit:*
Resource:
- !Sub arn:aws:codecommit:${AWS::Region}:${AWS::AccountId}:${RepositoryName}
- Effect: Allow
Action:
- codebuild:*
Resource:
- !Sub arn:aws:codebuild:${AWS::Region}:${AWS::AccountId}:project/${AWS::StackName}-Build
- Effect: Allow
Action:
- cloudformation:*
Resource:
- !Sub arn:aws:cloudformation:${AWS::Region}:${AWS::AccountId}:stack/${AWS::StackName}-Infrastructure-Staging/*
- !Sub arn:aws:cloudformation:${AWS::Region}:${AWS::AccountId}:stack/${AWS::StackName}-Infrastructure-Production/*
CodeBuildRole:
Type: AWS::IAM::Role
Properties:
AssumeRolePolicyDocument:
Statement:
- Effect: Allow
Principal:
Service: codebuild.amazonaws.com
Action: sts:AssumeRole
Policies:
- PolicyName: CodeBuildRolePolicy
PolicyDocument:
Statement:
- Effect: Allow
Action:
- s3:*
Resource:
- !Sub arn:aws:s3:::${ArtifactStoreBucket}/*
- Effect: Allow
Action:
- codecommit:*
Resource:
- !Sub arn:aws:codecommit:${AWS::Region}:${AWS::AccountId}:${RepositoryName}
- Effect: Allow
Action:
- logs:*
Resource:
- !Sub arn:aws:logs:${AWS::Region}:${AWS::AccountId}:log-group:/aws/codebuild/${AWS::StackName}-Build*
CloudFormationRole:
Type: AWS::IAM::Role
Properties:
AssumeRolePolicyDocument:
Version: 2012-10-17
Statement:
- Effect: Allow
Principal:
Service: cloudformation.amazonaws.com
Action: sts:AssumeRole
ManagedPolicyArns:
- arn:aws:iam::aws:policy/AdministratorAccess
Example of infrastructure.yml:
AWSTemplateFormatVersion: 2010-09-09
Transform: AWS::Serverless-2016-10-31
Parameters:
Environment:
Type: String
AllowedValues:
- Staging
- Production
Resources:
Api:
Type: AWS::Serverless::Function
Properties:
Handler: api.handler
CodeUri: .build
Runtime: nodejs10.x
MemorySize: 128
Timeout: 10
Events:
ProxyApi:
Type: Api
Properties:
Path: /{proxy+}
Method: ANY
Environment:
Variables:
ENVIRONMENT: !Ref Environment
DeploymentPreference:
Enabled: false
ApiLogGroup:
Type: AWS::Logs::LogGroup
Properties:
RetentionInDays: 14
LogGroupName: !Sub /aws/lambda/${Api}
Outputs:
ApiEndpoint:
Value: !Sub https://${ServerlessRestApi}.execute-api.${AWS::Region}.${AWS::URLSuffix}/${ServerlessRestApiProdStage}
I'm trying to use a CloudFormation template to define CodeBuild and CodePipeline to automate the deployment of a static website hosted in an S3 bucket. To give credit where credit's due, I'm largely following the template from https://dzone.com/articles/continuous-delivery-to-s3-via-codepipeline-and-cod.
The problem I can't resolve is that after I add an environment variable for the Hugo version I'd like to use to create the static site files, I get an error from the AWS console that reads: "Template validation error: Template format error: Unresolved resource dependencies [HUGO_VERSION] in the Resources block of the template."
Why isn't it accepting the HUGO_VERSION environment variable that I define under environment_variables? This is version 0.1 of the format, so it's a little different than the current 0.2, but I've read the following link: https://docs.aws.amazon.com/codebuild/latest/userguide/build-spec-ref.html#build-spec-ref-syntax
The thing that really confuses me is that if I remove the lines with ${HUGO_VERSION}, the template is accepted just fine - and then inspection of the CloudWatch logs after building shows (because of the printenv command) HUGO_VERSION=0.49! What gives?
Originally, the template looks like this.
---
AWSTemplateFormatVersion: '2010-09-09'
Description: Pipeline using CodePipeline and CodeBuild for continuous delivery of a single-page application to S3
Parameters:
SiteBucketName:
Type: String
Description: Name of bucket to create to host the website
GitHubUser:
Type: String
Description: GitHub User
Default: "stelligent"
GitHubRepo:
Type: String
Description: GitHub Repo to pull from. Only the Name. not the URL
Default: "devops-essentials"
GitHubBranch:
Type: String
Description: GitHub Branch
Default: "master"
GitHubToken:
NoEcho: true
Type: String
Description: Secret. It might look something like 9b189a1654643522561f7b3ebd44a1531a4287af OAuthToken with access to Repo. Go to https://github.com/settings/tokens
BuildType:
Type: String
Default: "LINUX_CONTAINER"
Description: The build container type to use for building the app
BuildComputeType:
Type: String
Default: "BUILD_GENERAL1_SMALL"
Description: The build compute type to use for building the app
BuildImage:
Type: String
Default: "aws/codebuild/ubuntu-base:14.04"
Description: The build image to use for building the app
Metadata:
AWS::CloudFormation::Interface:
ParameterGroups:
- Label:
default: "Site Configuration"
Parameters:
- SiteBucketName
- Label:
default: "GitHub Configuration"
Parameters:
- GitHubToken
- GitHubUser
- GitHubRepo
- GitHubBranch
- Label:
default: "Build Configuration"
Parameters:
- BuildType
- BuildComputeType
- BuildImage
ParameterLabels:
SiteBucketName:
default: Name of S3 Bucket to create for website hosting
GitHubToken:
default: GitHub OAuth2 Token
GitHubUser:
default: GitHub User/Org Name
GitHubRepo:
default: GitHub Repository Name
GitHubBranch:
default: GitHub Branch Name
BuildType:
default: CodeBuild type
BuildComputeType:
default: CodeBuild instance type
BuildImage:
default: CodeBuild image
Resources:
CodeBuildRole:
Type: AWS::IAM::Role
Properties:
AssumeRolePolicyDocument:
Statement:
- Effect: Allow
Principal:
Service:
- codebuild.amazonaws.com
Action:
- sts:AssumeRole
Path: "/"
Policies:
- PolicyName: codebuild-service
PolicyDocument:
Statement:
- Effect: Allow
Action: "*"
Resource: "*"
Version: '2012-10-17'
CodePipelineRole:
Type: AWS::IAM::Role
Properties:
AssumeRolePolicyDocument:
Statement:
- Effect: Allow
Principal:
Service:
- codepipeline.amazonaws.com
Action:
- sts:AssumeRole
Path: "/"
Policies:
- PolicyName: codepipeline-service
PolicyDocument:
Statement:
- Action:
- codebuild:*
Resource: "*"
Effect: Allow
- Action:
- s3:GetObject
- s3:GetObjectVersion
- s3:GetBucketVersioning
Resource: "*"
Effect: Allow
- Action:
- s3:PutObject
Resource:
- arn:aws:s3:::codepipeline*
Effect: Allow
- Action:
- s3:*
- cloudformation:*
- iam:PassRole
Resource: "*"
Effect: Allow
Version: '2012-10-17'
SiteBucket:
Type: AWS::S3::Bucket
DeletionPolicy: Delete
Properties:
AccessControl: PublicRead
BucketName: !Ref SiteBucketName
WebsiteConfiguration:
IndexDocument: index.html
PipelineBucket:
Type: AWS::S3::Bucket
DeletionPolicy: Delete
CodeBuildDeploySite:
Type: AWS::CodeBuild::Project
DependsOn: CodeBuildRole
Properties:
Name: !Sub ${AWS::StackName}-DeploySite
Description: Deploy site to S3
ServiceRole: !GetAtt CodeBuildRole.Arn
Artifacts:
Type: CODEPIPELINE
Environment:
Type: !Ref BuildType
ComputeType: !Ref BuildComputeType
Image: !Sub ${BuildImage}
Source:
Type: CODEPIPELINE
BuildSpec: !Sub |
version: 0.1
phases:
post_build:
commands:
- aws s3 cp --recursive --acl public-read ./samples s3://${SiteBucketName}/samples
- aws s3 cp --recursive --acl public-read ./html s3://${SiteBucketName}/
artifacts:
type: zip
files:
- ./html/index.html
TimeoutInMinutes: 10
Pipeline:
Type: AWS::CodePipeline::Pipeline
Properties:
RoleArn: !GetAtt CodePipelineRole.Arn
Stages:
- Name: Source
Actions:
- InputArtifacts: []
Name: Source
ActionTypeId:
Category: Source
Owner: ThirdParty
Version: '1'
Provider: GitHub
OutputArtifacts:
- Name: SourceArtifacts
Configuration:
Owner: !Ref GitHubUser
Repo: !Ref GitHubRepo
Branch: !Ref GitHubBranch
OAuthToken: !Ref GitHubToken
RunOrder: 1
- Name: Deploy
Actions:
- Name: Artifact
ActionTypeId:
Category: Build
Owner: AWS
Version: '1'
Provider: CodeBuild
InputArtifacts:
- Name: SourceArtifacts
OutputArtifacts:
- Name: DeploymentArtifacts
Configuration:
ProjectName: !Ref CodeBuildDeploySite
RunOrder: 1
ArtifactStore:
Type: S3
Location: !Ref PipelineBucket
Outputs:
PipelineUrl:
Value: !Sub https://console.aws.amazon.com/codepipeline/home?region=${AWS::Region}#/view/${Pipeline}
Description: CodePipeline URL
SiteUrl:
Value: !GetAtt [SiteBucket, WebsiteURL]
Description: S3 Website URL
Now after I try to add an environment variable to use Hugo in the pipeline, the template looks like this.
---
AWSTemplateFormatVersion: '2010-09-09'
Description: Pipeline using CodePipeline and CodeBuild for continuous delivery of a single-page application to S3
Parameters:
SiteBucketName:
Type: String
Description: Name of bucket to create to host the website
GitHubUser:
Type: String
Description: GitHub User
Default: "stelligent"
GitHubRepo:
Type: String
Description: GitHub Repo to pull from. Only the Name. not the URL
Default: "devops-essentials"
GitHubBranch:
Type: String
Description: GitHub Branch
Default: "master"
GitHubToken:
NoEcho: true
Type: String
Description: Secret. It might look something like 9b189a1654643522561f7b3ebd44a1531a4287af OAuthToken with access to Repo. Go to https://github.com/settings/tokens
BuildType:
Type: String
Default: "LINUX_CONTAINER"
Description: The build container type to use for building the app
BuildComputeType:
Type: String
Default: "BUILD_GENERAL1_SMALL"
Description: The build compute type to use for building the app
BuildImage:
Type: String
Default: "aws/codebuild/ubuntu-base:14.04"
Description: The build image to use for building the app
Metadata:
AWS::CloudFormation::Interface:
ParameterGroups:
- Label:
default: "Site Configuration"
Parameters:
- SiteBucketName
- Label:
default: "GitHub Configuration"
Parameters:
- GitHubToken
- GitHubUser
- GitHubRepo
- GitHubBranch
- Label:
default: "Build Configuration"
Parameters:
- BuildType
- BuildComputeType
- BuildImage
ParameterLabels:
SiteBucketName:
default: Name of S3 Bucket to create for website hosting
GitHubToken:
default: GitHub OAuth2 Token
GitHubUser:
default: GitHub User/Org Name
GitHubRepo:
default: GitHub Repository Name
GitHubBranch:
default: GitHub Branch Name
BuildType:
default: CodeBuild type
BuildComputeType:
default: CodeBuild instance type
BuildImage:
default: CodeBuild image
Resources:
CodeBuildRole:
Type: AWS::IAM::Role
Properties:
AssumeRolePolicyDocument:
Statement:
- Effect: Allow
Principal:
Service:
- codebuild.amazonaws.com
Action:
- sts:AssumeRole
Path: "/"
Policies:
- PolicyName: codebuild-service
PolicyDocument:
Statement:
- Effect: Allow
Action: "*"
Resource: "*"
Version: '2012-10-17'
CodePipelineRole:
Type: AWS::IAM::Role
Properties:
AssumeRolePolicyDocument:
Statement:
- Effect: Allow
Principal:
Service:
- codepipeline.amazonaws.com
Action:
- sts:AssumeRole
Path: "/"
Policies:
- PolicyName: codepipeline-service
PolicyDocument:
Statement:
- Action:
- codebuild:*
Resource: "*"
Effect: Allow
- Action:
- s3:GetObject
- s3:GetObjectVersion
- s3:GetBucketVersioning
Resource: "*"
Effect: Allow
- Action:
- s3:PutObject
Resource:
- arn:aws:s3:::codepipeline*
Effect: Allow
- Action:
- s3:*
- cloudformation:*
- iam:PassRole
Resource: "*"
Effect: Allow
Version: '2012-10-17'
SiteBucket:
Type: AWS::S3::Bucket
DeletionPolicy: Delete
Properties:
AccessControl: PublicRead
BucketName: !Ref SiteBucketName
WebsiteConfiguration:
IndexDocument: index.html
PipelineBucket:
Type: AWS::S3::Bucket
DeletionPolicy: Delete
CodeBuildDeploySite:
Type: AWS::CodeBuild::Project
DependsOn: CodeBuildRole
Properties:
Name: !Sub ${AWS::StackName}-DeploySite
Description: Deploy site to S3
ServiceRole: !GetAtt CodeBuildRole.Arn
Artifacts:
Type: CODEPIPELINE
Environment:
Type: !Ref BuildType
ComputeType: !Ref BuildComputeType
Image: !Sub ${BuildImage}
Source:
Type: CODEPIPELINE
BuildSpec: !Sub |
version: 0.1
environment_variables:
plaintext:
AWS_DEFAULT_REGION: "US-WEST-2"
HUGO_VERSION: "0.49"
phases:
install:
commands:
- printenv
- echo "Install step..."
- curl -Ls https://github.com/gohugoio/hugo/releases/download/v${HUGO_VERSION}/hugo_${HUGO_VERSION}_Linux-64bit.tar.gz -o /tmp/hugo.tar.gz
- tar xf /tmp/hugo.tar.gz -C /tmp
- mv /tmp/hugo_${HUGO_VERSION}_linux_amd64/hugo_${HUGO_VERSION}_linux_amd64 /usr/bin/hugo
- rm -rf /tmp/hugo*
build:
commands:
- hugo
post_build:
commands:
- aws s3 cp --recursive --acl public-read ./public s3://${SiteBucketName}
artifacts:
type: zip
files:
- ./html/index.html
TimeoutInMinutes: 10
Pipeline:
Type: AWS::CodePipeline::Pipeline
Properties:
RoleArn: !GetAtt CodePipelineRole.Arn
Stages:
- Name: Source
Actions:
- InputArtifacts: []
Name: Source
ActionTypeId:
Category: Source
Owner: ThirdParty
Version: '1'
Provider: GitHub
OutputArtifacts:
- Name: SourceArtifacts
Configuration:
Owner: !Ref GitHubUser
Repo: !Ref GitHubRepo
Branch: !Ref GitHubBranch
OAuthToken: !Ref GitHubToken
RunOrder: 1
- Name: Deploy
Actions:
- Name: Artifact
ActionTypeId:
Category: Build
Owner: AWS
Version: '1'
Provider: CodeBuild
InputArtifacts:
- Name: SourceArtifacts
OutputArtifacts:
- Name: DeploymentArtifacts
Configuration:
ProjectName: !Ref CodeBuildDeploySite
RunOrder: 1
ArtifactStore:
Type: S3
Location: !Ref PipelineBucket
Outputs:
PipelineUrl:
Value: !Sub https://console.aws.amazon.com/codepipeline/home?region=${AWS::Region}#/view/${Pipeline}
Description: CodePipeline URL
SiteUrl:
Value: !GetAtt [SiteBucket, WebsiteURL]
Description: S3 Website URL
EDIT 10/20
Still haven't solved this. I tried to follow the advice given below by matsev, but I'm still getting the same validation error. For completeness, the latest template I'm trying is
AWSTemplateFormatVersion: '2010-09-09'
Description: Pipeline using CodePipeline and CodeBuild for continuous delivery of a single-page application to S3
Parameters:
SiteBucketName:
Type: String
Description: Name of bucket to create to host the website
GitHubUser:
Type: String
Description: GitHub User
Default: "stelligent"
GitHubRepo:
Type: String
Description: GitHub Repo to pull from. Only the Name. not the URL
Default: "devops-essentials"
GitHubBranch:
Type: String
Description: GitHub Branch
Default: "master"
GitHubToken:
NoEcho: true
Type: String
Description: Secret. It might look something like 9b189a1654643522561f7b3ebd44a1531a4287af OAuthToken with access to Repo. Go to https://github.com/settings/tokens
BuildType:
Type: String
Default: "LINUX_CONTAINER"
Description: The build container type to use for building the app
BuildComputeType:
Type: String
Default: "BUILD_GENERAL1_SMALL"
Description: The build compute type to use for building the app
BuildImage:
Type: String
Default: "aws/codebuild/ubuntu-base:14.04"
Description: The build image to use for building the app
Metadata:
AWS::CloudFormation::Interface:
ParameterGroups:
- Label:
default: "Site Configuration"
Parameters:
- SiteBucketName
- Label:
default: "GitHub Configuration"
Parameters:
- GitHubToken
- GitHubUser
- GitHubRepo
- GitHubBranch
- Label:
default: "Build Configuration"
Parameters:
- BuildType
- BuildComputeType
- BuildImage
ParameterLabels:
SiteBucketName:
default: Name of S3 Bucket to create for website hosting
GitHubToken:
default: GitHub OAuth2 Token
GitHubUser:
default: GitHub User/Org Name
GitHubRepo:
default: GitHub Repository Name
GitHubBranch:
default: GitHub Branch Name
BuildType:
default: CodeBuild type
BuildComputeType:
default: CodeBuild instance type
BuildImage:
default: CodeBuild image
Resources:
CodeBuildRole:
Type: AWS::IAM::Role
Properties:
AssumeRolePolicyDocument:
Statement:
- Effect: Allow
Principal:
Service:
- codebuild.amazonaws.com
Action:
- sts:AssumeRole
Path: "/"
Policies:
- PolicyName: codebuild-service
PolicyDocument:
Statement:
- Effect: Allow
Action: "*"
Resource: "*"
Version: '2012-10-17'
CodePipelineRole:
Type: AWS::IAM::Role
Properties:
AssumeRolePolicyDocument:
Statement:
- Effect: Allow
Principal:
Service:
- codepipeline.amazonaws.com
Action:
- sts:AssumeRole
Path: "/"
Policies:
- PolicyName: codepipeline-service
PolicyDocument:
Statement:
- Action:
- codebuild:*
Resource: "*"
Effect: Allow
- Action:
- s3:GetObject
- s3:GetObjectVersion
- s3:GetBucketVersioning
Resource: "*"
Effect: Allow
- Action:
- s3:PutObject
Resource:
- arn:aws:s3:::codepipeline*
Effect: Allow
- Action:
- s3:*
- cloudformation:*
- iam:PassRole
Resource: "*"
Effect: Allow
Version: '2012-10-17'
SiteBucket:
Type: AWS::S3::Bucket
DeletionPolicy: Delete
Properties:
AccessControl: PublicRead
BucketName: !Ref SiteBucketName
WebsiteConfiguration:
IndexDocument: index.html
PipelineBucket:
Type: AWS::S3::Bucket
DeletionPolicy: Delete
CodeBuildDeploySite:
Type: AWS::CodeBuild::Project
DependsOn: CodeBuildRole
Properties:
Name: !Sub ${AWS::StackName}-DeploySite
Description: Deploy site to S3
ServiceRole: !GetAtt CodeBuildRole.Arn
Artifacts:
Type: CODEPIPELINE
Environment:
Type: !Ref BuildType
ComputeType: !Ref BuildComputeType
Image: !Sub ${BuildImage}
EnvironmentVariables:
- Name: HUGO_VERSION
Value: '0.49'
Type: PLAINTEXT
Source:
Type: CODEPIPELINE
BuildSpec: !Sub |
version: 0.2
env:
variables:
AWS_DEFAULT_REGION: "US-WEST-2"
phases:
install:
commands:
- printenv
- curl -Ls https://github.com/gohugoio/hugo/releases/download/v${HUGO_VERSION}/hugo_${HUGO_VERSION}_Linux-64bit.tar.gz -o /tmp/hugo.tar.gz
- tar xf /tmp/hugo.tar.gz -C /tmp
- mv /tmp/hugo_${HUGO_VERSION}_linux_amd64/hugo_${HUGO_VERSION}_linux_amd64 /usr/bin/hugo
- rm -rf /tmp/hugo*
build:
commands:
- hugo
post_build:
commands:
- aws s3 cp --recursive --acl public-read ./samples s3://${SiteBucketName}/samples
- aws s3 cp --recursive --acl public-read ./html s3://${SiteBucketName}/
artifacts:
type: zip
files:
- ./html/index.html
TimeoutInMinutes: 10
Pipeline:
Type: AWS::CodePipeline::Pipeline
Properties:
RoleArn: !GetAtt CodePipelineRole.Arn
Stages:
- Name: Source
Actions:
- InputArtifacts: []
Name: Source
ActionTypeId:
Category: Source
Owner: ThirdParty
Version: '1'
Provider: GitHub
OutputArtifacts:
- Name: SourceArtifacts
Configuration:
Owner: !Ref GitHubUser
Repo: !Ref GitHubRepo
Branch: !Ref GitHubBranch
OAuthToken: !Ref GitHubToken
RunOrder: 1
- Name: Deploy
Actions:
- Name: Artifact
ActionTypeId:
Category: Build
Owner: AWS
Version: '1'
Provider: CodeBuild
InputArtifacts:
- Name: SourceArtifacts
OutputArtifacts:
- Name: DeploymentArtifacts
Configuration:
ProjectName: !Ref CodeBuildDeploySite
RunOrder: 1
ArtifactStore:
Type: S3
Location: !Ref PipelineBucket
Outputs:
PipelineUrl:
Value: !Sub https://console.aws.amazon.com/codepipeline/home?region=${AWS::Region}#/view/${Pipeline}
Description: CodePipeline URL
SiteUrl:
Value: !GetAtt [SiteBucket, WebsiteURL]
Description: S3 Website URL
Please check the Environment property of the AWS::CodeBuild::Project in your CloudFormation template. Specifically the EnvironmentVariables allows you to specify environment variables, e.g.
CodeBuildDeploySite:
Type: AWS::CodeBuild::Project
DependsOn: CodeBuildRole
Properties:
Name: !Sub ${AWS::StackName}-DeploySite
Description: Deploy site to S3
ServiceRole: !GetAtt CodeBuildRole.Arn
Artifacts:
Type: CODEPIPELINE
Environment:
Type: !Ref BuildType
ComputeType: !Ref BuildComputeType
Image: !Sub ${BuildImage}
EnvironmentVariables:
- Name: HUGO_VERSION
Value: '0.49'
Type: PLAINTEXT
# More properties...
Now in you can reference the HUGO_VERSION as an environment variable in your buildspec.yml file, e.g.
pre_build:
commands:
- echo HUGO_VERSION $HUGO_VERSION
I believe the following happens:
CloudFormation attempts to resolve ${HUGO_VERSION} as a Parameter of Cloudformation Template as it is within the "!Sub" function.
From AWS documentation on Sub function
To write a dollar sign and curly braces (${}) literally, add an exclamation point (!) after the open curly brace, such as ${!Literal}. AWS CloudFormation resolves this text as ${Literal}.
https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/intrinsic-function-reference-sub.html#w2ab1c21c28c59b7
Therefore your build spec phase should be similar to:
phases:
install:
commands:
- printenv
- echo "Install step..."
- curl -Ls https://github.com/gohugoio/hugo/releases/download/v${!HUGO_VERSION}/hugo_${!HUGO_VERSION}_Linux-64bit.tar.gz -o /tmp/hugo.tar.gz
- tar xf /tmp/hugo.tar.gz -C /tmp
- mv /tmp/hugo_${!HUGO_VERSION}_linux_amd64/hugo_${!HUGO_VERSION}_linux_amd64 /usr/bin/hugo
- rm -rf /tmp/hugo*
Hope this helps!
I have 3 parts to my application
API Server (API Gateway)
Frontend
Lambda
I have setup CodePipeline to build my application stack.
I have CodeBuild to build my API gateway SAM application. And CloudFormation to deploy. This CloudFormation exports a variable ApiEndpoint. This variable is used my my web CodeBuild to use.
The problem now is CloudFormation is saying
No export named skynet-infra-server-ApiEndpoint found. Rollback requested by user.
I understand now that its because the Server build has not complete thus that variable is not exported. But how can I resolve this?
AWSTemplateFormatVersion : '2010-09-09'
Description: 'Skynet stack for Infrastructure. CodePipeline, S3'
Parameters:
PipelineName:
Type: String
Description: Pipeline Name (Lower case only, since S3 bucket names can only have lowercase)
Default: skynet-pipeline
AppName:
Type: String
Description: App Name
Default: skynet
GitHubOwner:
Type: String
Description: GitHub Owner
Default: 2359media
GitHubRepo:
Type: String
Description: GitHub Repo
Default: 'skynet'
GitHubBranch:
Type: String
Description: GitHub Branch
Default: master
GitHubToken:
Type: String
Description: GitHub Token
NoEcho: true
Resources:
S3WebBucket:
Type: AWS::S3::Bucket
Properties:
BucketName: !Sub '${AppName}-web'
WebsiteConfiguration:
IndexDocument: index.html
RoutingRules:
- RedirectRule:
ReplaceKeyPrefixWith: '#'
RoutingRuleCondition:
HttpErrorCodeReturnedEquals: '404'
AccessControl: PublicRead
Tags:
- Key: Cost Center
Value: !Ref AppName
- Key: Owner
Value: Jiew Meng
Pipeline:
Type: AWS::CodePipeline::Pipeline
Properties:
Name: !Ref PipelineName
RoleArn: !GetAtt [PipelineRole, Arn]
ArtifactStore:
Location: !Ref PipelineArtifactStore
Type: S3
DisableInboundStageTransitions: []
Stages:
- Name: GitHubSource
Actions:
- Name: Source
ActionTypeId:
Category: Source
Owner: ThirdParty
Version: 1
Provider: GitHub
Configuration:
Owner: !Ref GitHubOwner
Repo: !Ref GitHubRepo
Branch: !Ref GitHubBranch
OAuthToken: !Ref GitHubToken
OutputArtifacts:
- Name: SourceCode
- Name: Build
Actions:
- Name: Lambda
InputArtifacts:
- Name: SourceCode
OutputArtifacts:
- Name: LambdaPackage
ActionTypeId:
Category: Build
Owner: AWS
Version: 1
Provider: CodeBuild
Configuration:
ProjectName: !Ref CodeBuildLambda
- Name: Server
InputArtifacts:
- Name: SourceCode
OutputArtifacts:
- Name: ServerPackage
ActionTypeId:
Category: Build
Owner: AWS
Version: 1
Provider: CodeBuild
Configuration:
ProjectName: !Ref CodeBuildServer
- Name: CreateChangeSet
Actions:
- Name: Lambda
InputArtifacts:
- Name: LambdaPackage
OutputArtifacts:
- Name: LambdaDeployment
ActionTypeId:
Category: Deploy
Owner: AWS
Version: 1
Provider: CloudFormation
Configuration:
ActionMode: CHANGE_SET_REPLACE
ChangeSetName: !Sub
- '${PipelineName}-lambda'
- {PipelineName: !Ref PipelineName}
RoleArn: !GetAtt [CloudFormationRole, Arn]
StackName: !Sub
- '${PipelineName}-lambda'
- {PipelineName: !Ref PipelineName}
TemplatePath: 'LambdaPackage::SkynetLambdaPackaged.yml'
Capabilities: CAPABILITY_NAMED_IAM
ParameterOverrides: !Sub '{"AppName": "${PipelineName}-lambda"}'
- Name: Server
InputArtifacts:
- Name: ServerPackage
OutputArtifacts:
- Name: ServerDeployment
ActionTypeId:
Category: Deploy
Owner: AWS
Version: 1
Provider: CloudFormation
Configuration:
ActionMode: CHANGE_SET_REPLACE
ChangeSetName: !Sub
- '${PipelineName}-server'
- {PipelineName: !Ref PipelineName}
RoleArn: !GetAtt [CloudFormationRole, Arn]
StackName: !Sub
- '${PipelineName}-server'
- {PipelineName: !Ref PipelineName}
TemplatePath: 'ServerPackage::SkynetServerPackaged.yml'
Capabilities: CAPABILITY_NAMED_IAM
ParameterOverrides: !Sub '{"AppName": "${PipelineName}-server"}'
- Name: Deploy
Actions:
- Name: Lambda
ActionTypeId:
Category: Deploy
Owner: AWS
Version: 1
Provider: CloudFormation
Configuration:
ActionMode: CHANGE_SET_EXECUTE
ChangeSetName: !Sub
- '${PipelineName}-lambda'
- {PipelineName: !Ref PipelineName}
StackName: !Sub
- '${PipelineName}-lambda'
- {PipelineName: !Ref PipelineName}
- Name: Server
ActionTypeId:
Category: Deploy
Owner: AWS
Version: 1
Provider: CloudFormation
Configuration:
ActionMode: CHANGE_SET_EXECUTE
ChangeSetName: !Sub
- '${PipelineName}-server'
- {PipelineName: !Ref PipelineName}
StackName: !Sub
- '${PipelineName}-server'
- {PipelineName: !Ref PipelineName}
- Name: Web
InputArtifacts:
- Name: SourceCode
ActionTypeId:
Category: Build
Owner: AWS
Version: 1
Provider: CodeBuild
Configuration:
ProjectName: !Ref CodeBuildWeb
CodeBuildLambda:
Type: AWS::CodeBuild::Project
Properties:
Name: !Sub '${PipelineName}-lambda'
Artifacts:
Type: CODEPIPELINE
Environment:
ComputeType: BUILD_GENERAL1_SMALL
Image: aws/codebuild/nodejs:7.0.0
Type: LINUX_CONTAINER
EnvironmentVariables:
- Name: S3_BUCKET
Value: !Ref PipelineArtifactStore
ServiceRole: !Ref CodeBuildRole
Source:
BuildSpec: 'lambda/buildspec.yml'
Type: CODEPIPELINE
CodeBuildServer:
Type: AWS::CodeBuild::Project
Properties:
Name: !Sub '${PipelineName}-server'
Artifacts:
Type: CODEPIPELINE
Environment:
ComputeType: BUILD_GENERAL1_SMALL
Image: aws/codebuild/nodejs:7.0.0
Type: LINUX_CONTAINER
EnvironmentVariables:
- Name: S3_BUCKET
Value: !Ref PipelineArtifactStore
ServiceRole: !Ref CodeBuildRole
Source:
BuildSpec: 'server/buildspec.yml'
Type: CODEPIPELINE
CodeBuildWeb:
Type: AWS::CodeBuild::Project
Properties:
Name: !Sub '${PipelineName}-web'
Artifacts:
Type: CODEPIPELINE
Environment:
ComputeType: BUILD_GENERAL1_SMALL
Image: aws/codebuild/nodejs:7.0.0
Type: LINUX_CONTAINER
EnvironmentVariables:
- Name: S3_BUCKET
Value: !Ref S3WebBucket
- Name: API_URL
Value:
Fn::ImportValue:
!Sub '${PipelineName}-server-ApiEndpoint'
ServiceRole: !Ref CodeBuildRole
Source:
BuildSpec: 'web/buildspec.yml'
Type: CODEPIPELINE
PipelineArtifactStore:
Type: AWS::S3::Bucket
Properties:
BucketName: !Sub '${PipelineName}-artifacts'
VersioningConfiguration:
Status: Enabled
CodeBuildRole:
Type: AWS::IAM::Role
Properties:
RoleName: !Sub '${PipelineName}-codebuild'
AssumeRolePolicyDocument:
Version: '2012-10-17'
Statement:
Effect: Allow
Principal:
Service: codebuild.amazonaws.com
Action: sts:AssumeRole
Policies:
- PolicyName: !Sub '${PipelineName}-codebuild'
PolicyDocument:
Version: '2012-10-17'
Statement:
- Effect: Allow
Resource: 'arn:aws:logs:*:*:*'
Action:
- 'logs:CreateLogGroup'
- 'logs:CreateLogStream'
- 'logs:PutLogEvents'
- Effect: Allow
Resource:
- !Sub 'arn:aws:s3:::codepipeline-${AWS::Region}-*/*'
- !Sub
- '${PipelineArtifactStoreArn}/*'
- {PipelineArtifactStoreArn: !GetAtt [PipelineArtifactStore, Arn]}
Action:
- 's3:GetObject'
- 's3:GetObjectVersion'
- 's3:PutObject'
- Effect: Allow
Resource:
- !Sub
- '${S3WebArn}/*'
- {S3WebArn: !GetAtt S3WebBucket.Arn}
Action:
- 's3:*'
CloudFormationRole:
Type: AWS::IAM::Role
Properties:
RoleName: !Sub '${PipelineName}-cloudformation'
AssumeRolePolicyDocument:
Version: '2012-10-17'
Statement:
- Effect: Allow
Principal:
Service: cloudformation.amazonaws.com
Action:
- sts:AssumeRole
ManagedPolicyArns:
- 'arn:aws:iam::aws:policy/AWSLambdaExecute'
Policies:
- PolicyName: !Sub '${PipelineName}-cloudformation'
PolicyDocument:
Version: '2012-10-17'
Statement:
- Effect: Allow
Resource: '*'
Action:
- 's3:GetObject'
- 's3:GetObjectVersion'
- 's3:GetBucketVersioning'
- Effect: Allow
Resource: 'arn:aws:s3:::codepipeline*'
Action:
- 's3:PutObject'
- Effect: Allow
Resource: '*'
Action:
- 'lambda:*'
- Effect: Allow
Resource: !Sub 'arn:aws:apigateway:${AWS::Region}::*'
Action:
- 'apigateway:*'
- Effect: Allow
Resource: '*'
Action:
- 'lambda:CreateEventSourceMapping'
- 'lambda:DeleteEventSourceMapping'
- 'lambda:GetEventSourceMapping'
- Effect: Allow
Resource: '*'
Action:
- 'iam:GetRole'
- 'iam:CreateRole'
- 'iam:DeleteRole'
- 'iam:PassRole'
- 'iam:AttachRolePolicy'
- 'iam:DetachRolePolicy'
- 'iam:DeleteRolePolicy'
- 'iam:PutRolePolicy'
- Effect: Allow
Resource: '*'
Action:
- 'iam:PassRole'
- Effect: Allow
Resource: !Sub 'arn:aws:cloudformation:${AWS::Region}:aws:transform/Serverless-2016-10-31'
Action:
- 'cloudformation:CreateChangeSet'
- Effect: Allow
Resource: '*'
Action:
- 'events:*'
PipelineRole:
Type: AWS::IAM::Role
Properties:
RoleName: !Sub '${PipelineName}-pipeline'
AssumeRolePolicyDocument:
Version: '2012-10-17'
Statement:
- Action: ['sts:AssumeRole']
Effect: Allow
Principal:
Service: [codepipeline.amazonaws.com]
Path: /
Policies:
- PolicyName: SkynetPipeline
PolicyDocument:
Version: '2012-10-17'
Statement:
- Action:
- 's3:GetObject'
- 's3:GetObjectVersion'
- 's3:GetBucketVersioning'
Effect: 'Allow'
Resource: '*'
- Action:
- 's3:PutObject'
Effect: 'Allow'
Resource:
- !GetAtt [PipelineArtifactStore, Arn]
- Action:
- 'codecommit:CancelUploadArchive'
- 'codecommit:GetBranch'
- 'codecommit:GetCommit'
- 'codecommit:GetUploadArchiveStatus'
- 'codecommit:UploadArchive'
Effect: 'Allow'
Resource: '*'
- Action:
- 'codedeploy:CreateDeployment'
- 'codedeploy:GetApplicationRevision'
- 'codedeploy:GetDeployment'
- 'codedeploy:GetDeploymentConfig'
- 'codedeploy:RegisterApplicationRevision'
Effect: 'Allow'
Resource: '*'
- Action:
- 'elasticbeanstalk:*'
- 'ec2:*'
- 'elasticloadbalancing:*'
- 'autoscaling:*'
- 'cloudwatch:*'
- 's3:*'
- 'sns:*'
- 'cloudformation:*'
- 'rds:*'
- 'sqs:*'
- 'ecs:*'
- 'iam:PassRole'
Effect: 'Allow'
Resource: '*'
- Action:
- 'lambda:InvokeFunction'
- 'lambda:ListFunctions'
Effect: 'Allow'
Resource: '*'
- Action:
- 'opsworks:CreateDeployment'
- 'opsworks:DescribeApps'
- 'opsworks:DescribeCommands'
- 'opsworks:DescribeDeployments'
- 'opsworks:DescribeInstances'
- 'opsworks:DescribeStacks'
- 'opsworks:UpdateApp'
- 'opsworks:UpdateStack'
Effect: 'Allow'
Resource: '*'
- Action:
- 'cloudformation:CreateStack'
- 'cloudformation:DeleteStack'
- 'cloudformation:DescribeStacks'
- 'cloudformation:UpdateStack'
- 'cloudformation:CreateChangeSet'
- 'cloudformation:DeleteChangeSet'
- 'cloudformation:DescribeChangeSet'
- 'cloudformation:ExecuteChangeSet'
- 'cloudformation:SetStackPolicy'
- 'cloudformation:ValidateTemplate'
- 'iam:PassRole'
Effect: 'Allow'
Resource: '*'
- Action:
- 'codebuild:BatchGetBuilds'
- 'codebuild:StartBuild'
Effect: 'Allow'
Resource: '*'
Outputs:
WebsiteUrl:
Description: Website URL
Value: !GetAtt S3WebBucket.WebsiteURL
Here's two approaches that should work:
You could put the Web CodeBuild action after the Server CloudFormation update, and then pass the output from the CloudFormation action as input to CodeBuild. Seeing as CodePipeline only allows one input to the CodeBuild action you may need to put all your build logic inside an overridden buildspec rather than having it inside the artifact.
Call the CloudFormation APIs to look up these values as part of the build.