Introduction
This CloudFormation template will create a stack for a full deployment pipeline for your React app with AWS CodePipeline and AWS Codedeploy.
The pipeline will react to git push performed to a branch on a Github repository and it will build the React project and upload it to an S3 static website.
The template contains everything you need to setup this deployment pipeline:
- 2 S3 buckets (one for codepipeline artifacts and one for the static site – configured with static website hosting and the necessary bucket policy)
- An AWS CodePipeline preconfigured with everything needed to run the pipeline
- An AWS CodeDeploy build project that will build your React app (if you want just a static html site this can be skipped)
- 2 IAM Roles (one for AWS CodePipeline and one for AWS CodeBuild) configured with the necessary permissions
If you need to configure this with a custom domain name, with an SSL certificate and CloudFront CDN then check out this template which contains that setup.
Configuration
When you upload the template to CloudFormation and try to create the stack you will be prompted to add the following information:
- Branch. This is the branch from your github repo that you want to deploy
- Repository owner. This your github user name and the second part of the repo url (bold underlined): https://github.com/majestic-cloud/docs
- Repository. This is the project name. This is the last part of your github repo url (bold underlined): https://github.com/majestic-cloud/docs
- GithubOAuthToken. This is your github personal access token. To get this sign in to your Github account then click on your user’s icon in the top right part of the screen, then go to Settings -> Developer settings -> Personal access tokens (or you can go directly to this link: https://github.com/settings/tokens) and then click on Generate new token. After you configure the permissions (check the first checkbox named repo that gives access to all the “repo” permissions) paste the obtained token into the CloudFormation console.
Deployment
You deploy this stack with CloudFormation and once your stack is created you can find in the Outputs section the URL of your static website where the React app is being deployed.
The template
AWSTemplateFormatVersion: 2010-09-09
Parameters:
Branch:
Type: String
Default: "Type here your branch name (usually master or main)"
RepoOwner:
Type: String
Default: "type the github user name"
Repository:
Type: String
Default: "type the github project name"
GithubOAuthToken:
Type: String
Description: "Github access token"
Default: "type your github access token here"
Resources:
ReactToS3CodePipeline:
Type: 'AWS::CodePipeline::Pipeline'
Properties:
RoleArn: !GetAtt CodePipeLineRole.Arn
ArtifactStore:
Location: !Ref PipelineBucket
Type: S3
Stages:
-
Name: Source
Actions:
-
Name: SourceAction
ActionTypeId:
Category: Source
Owner: ThirdParty
Provider: GitHub
Version: 1
OutputArtifacts:
-
Name: TheApp
Configuration:
Owner: !Ref RepoOwner
Repo: !Ref Repository
Branch: main
OAuthToken: !Ref GithubOAuthToken
-
Name: Build
Actions:
-
Name: BuildAction
ActionTypeId:
Category: Build
Owner: AWS
Version: 1
Provider: CodeBuild
InputArtifacts:
-
Name: TheApp
OutputArtifacts:
-
Name: TheBuiltApp
Configuration:
ProjectName: !Ref CodeBuild
-
Name: Deploy
Actions:
-
Name: DeployAction
ActionTypeId:
Category: Deploy
Owner: AWS
Version: 1
Provider: S3
InputArtifacts:
-
Name: TheBuiltApp
RunOrder: 1
Configuration:
BucketName: !Ref DeployBucket
Extract: true
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"
- "s3:PutObjectAcl"
- "s3:PutObjectVersionAcl"
- "s3:DeleteObject"
Resource:
- !GetAtt PipelineBucket.Arn
- !Join ['', [!GetAtt PipelineBucket.Arn, "/*"]]
-
Effect: Allow
Action:
- "s3:GetObject"
- "s3:GetObjectVersion"
- "s3:GetBucketVersioning"
- "s3:PutObject"
- "s3:PutObjectAcl"
- "s3:PutObjectVersionAcl"
- "s3:DeleteObject"
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"
- "s3:PutObjectAcl"
- "s3:PutObjectVersionAcl"
- "s3:DeleteObject"
Resource:
- !GetAtt PipelineBucket.Arn
- !Join ['', [!GetAtt PipelineBucket.Arn, "/*"]]
-
Effect: Allow
Action:
- "s3:GetObject"
- "s3:GetObjectVersion"
- "s3:GetBucketVersioning"
- "s3:PutObject"
- "s3:PutObjectAcl"
- "s3:PutObjectVersionAcl"
- "s3:DeleteObject"
Resource:
- !GetAtt DeployBucket.Arn
- !Join ['', [!GetAtt DeployBucket.Arn, "/*"]]
-
Effect: Allow
Action:
- "codebuild:BatchGetBuilds"
- "codebuild:StartBuild"
Resource: "*"
CodeBuild:
Type: 'AWS::CodeBuild::Project'
Properties:
Name: !Sub ${AWS::StackName}-CodeBuild
ServiceRole: !GetAtt CodeBuildRole.Arn
Artifacts:
Type: CODEPIPELINE
Name: MyProject
Environment:
ComputeType: BUILD_GENERAL1_SMALL
Type: LINUX_CONTAINER
Image: "aws/codebuild/amazonlinux2-x86_64-standard:2.0"
Source:
Type: CODEPIPELINE
BuildSpec: !Sub |
version: 0.1
phases:
pre_build:
commands:
- echo This will run npm install to install the dependencies...
- npm install
build:
commands:
- echo Actually run the build process
- npm run build
artifacts:
files:
- '**/*'
base-directory: build
PipelineBucket:
Type: 'AWS::S3::Bucket'
Properties: {}
DeletionPolicy: Retain
DeployBucket:
Type: 'AWS::S3::Bucket'
Properties:
AccessControl: PublicRead
WebsiteConfiguration:
IndexDocument: index.html
ErrorDocument: error.html
DeletionPolicy: Retain
DeployBucketPolicy:
Type: AWS::S3::BucketPolicy
Properties:
PolicyDocument:
Id: MyPolicy
Version: 2012-10-17
Statement:
- Sid: PublicReadForGetBucketObjects
Effect: Allow
Principal: '*'
Action: 's3:GetObject'
Resource: !Join
- ''
- - 'arn:aws:s3:::'
- !Ref DeployBucket
- /*
Bucket: !Ref DeployBucket
Outputs:
Bucket:
Description: 'Deploy Bucket Name'
Value: !Ref DeployBucket
BucketURL:
Description: 'Deploy bucket (Static website) URL'
Value: !GetAtt 'DeployBucket.WebsiteURL'
Find the above template on Github: https://github.com/majestic-cloud/react-deployment-pipeline/blob/main/cfn-templates/reactToS3v3_noCloudFront.yaml