I recentled needed to setup S3 and CloudFormation to host a static website built with React.
AWSTemplateFormatVersion: "2010-09-09"
Description: Graphboss CI/CD pipeline
Parameters:
GitHubOAuthToken:
Type: String
NoEcho: true
MinLength: 40
MaxLength: 40
AllowedPattern: "[a-z0-9]*"
GitHubOwner:
Type: String
AllowedPattern: "[A-Za-z0-9-]+"
GitHubRepo:
Type: String
AllowedPattern: "[A-Za-z0-9-]+"
GitHubBranch:
Type: String
AllowedPattern: "[A-Za-z0-9-]+"
Resources:
ArtifactStoreBucket:
Type: AWS::S3::Bucket
Properties:
VersioningConfiguration:
Status: Enabled
Pipeline:
Type: AWS::CodePipeline::Pipeline
Properties:
ArtifactStore:
Location: !Ref ArtifactStoreBucket
Type: S3
Name: !Sub "${GitHubRepo}-${GitHubBranch}"
RestartExecutionOnUpdate: true
RoleArn: !GetAtt PipelineRole.Arn
Stages:
- Name: Source
Actions:
- Name: Source
ActionTypeId:
Category: Source
Owner: ThirdParty
Version: "1"
Provider: GitHub
Configuration:
Owner: !Ref GitHubOwner
Repo: !Ref GitHubRepo
Branch: !Ref GitHubBranch
PollForSourceChanges: false
OAuthToken: !Ref GitHubOAuthToken
OutputArtifacts:
- Name: SourceCode
RunOrder: 1
# - Name: CodePipeline
# Actions:
# - Name: Update-Stack
# ActionTypeId:
# Category: Deploy
# Owner: AWS
# Provider: CloudFormation
# Version: "1"
# InputArtifacts:
# - Name: SourceCode
# Configuration:
# ActionMode: CREATE_UPDATE
# Capabilities: CAPABILITY_IAM,CAPABILITY_NAMED_IAM,CAPABILITY_AUTO_EXPAND
# RoleArn: !GetAtt CloudformationRole.Arn
# StackName: !Ref AWS::StackName
# TemplatePath: "SourceCode::template.yaml"
# ParameterOverrides: |
# {
# "GitHubOwner": !Ref GitHubOwner,
# "GitHubBranch": { "Ref": "GitHubBranch" },
# "GitHubOAuthToken": { "Ref": "GitHubOAuthToken" },
# "GitHubRepo": { "Ref": "GitHubRepo" },
# }
# RunOrder: 1
- Name: Build
Actions:
- Name: Website
ActionTypeId:
Category: Build
Owner: AWS
Provider: CodeBuild
Version: "1"
Configuration:
ProjectName: !Ref CodeBuildProject
InputArtifacts:
- Name: SourceCode
OutputArtifacts:
- Name: BuildWebsite
RunOrder: 1
- Name: Deploy
Actions:
- Name: Website
ActionTypeId:
Category: Deploy
Owner: AWS
Provider: S3
Version: "1"
InputArtifacts:
- Name: BuildWebsite
Configuration:
BucketName: !Ref HostingBucket
Extract: true
CannedACL: "private"
CacheControl: "no-cache"
RunOrder: 1
GithubWebhook:
Type: "AWS::CodePipeline::Webhook"
Properties:
Authentication: GITHUB_HMAC
AuthenticationConfiguration:
SecretToken: !Ref GitHubOAuthToken
RegisterWithThirdParty: true
Filters:
- JsonPath: "$.ref"
MatchEquals: refs/heads/{Branch}
TargetPipeline: !Ref Pipeline
TargetAction: Source
TargetPipelineVersion: !GetAtt Pipeline.Version
CodeBuildProject:
Type: AWS::CodeBuild::Project
Properties:
Artifacts:
Type: CODEPIPELINE
Source:
Type: CODEPIPELINE
Environment:
Type: LINUX_CONTAINER
ComputeType: BUILD_GENERAL1_SMALL
Image: aws/codebuild/standard:5.0
EnvironmentVariables:
- Name: ARTIFACT_BUCKET
Value: !Ref ArtifactStoreBucket
- Name: ARTIFACT_BUCKET_PREFIX
Value: PackagedCode
Name: !Sub "${GitHubRepo}-${GitHubBranch}"
ServiceRole:
Fn::GetAtt:
- CodeBuildRole
- Arn
CloudformationRole:
Type: AWS::IAM::Role
Properties:
AssumeRolePolicyDocument:
Statement:
- Action: sts:AssumeRole
Effect: Allow
Principal:
Service: cloudformation.amazonaws.com
Version: "2012-10-17"
ManagedPolicyArns:
- arn:aws:iam::aws:policy/AdministratorAccess
PipelineRole:
Type: AWS::IAM::Role
Properties:
AssumeRolePolicyDocument:
Statement:
- Action: sts:AssumeRole
Effect: Allow
Principal:
Service: codepipeline.amazonaws.com
Version: "2012-10-17"
ManagedPolicyArns:
- arn:aws:iam::aws:policy/AdministratorAccess
CodeBuildRole:
Type: AWS::IAM::Role
Properties:
AssumeRolePolicyDocument:
Version: "2012-10-17"
Statement:
Effect: Allow
Principal:
Service: codebuild.amazonaws.com
Action: sts:AssumeRole
ManagedPolicyArns:
- arn:aws:iam::aws:policy/AdministratorAccess
HostingBucket:
Type: AWS::S3::Bucket
Properties:
AccessControl: Private
HostingBucketPolicy:
Type: AWS::S3::BucketPolicy
Properties:
PolicyDocument:
Id: PolicyForCloudFrontPrivateContent
Version: 2012-10-17
Statement:
- Sid: PublicReadForGetBucketObjects
Effect: Allow
Principal:
CanonicalUser: !GetAtt CloudFrontOAI.S3CanonicalUserId
Action: "s3:GetObject"
Resource: !Join
- ""
- - "arn:aws:s3:::"
- !Ref HostingBucket
- /*
Bucket: !Ref HostingBucket
CloudFrontCertificate:
Type: AWS::CertificateManager::Certificate
Properties:
DomainName: graphboss.com
DomainValidationOptions:
- DomainName: graphboss.com
HostedZoneId: Z1OTIL07BUWDR5
- DomainName: www.graphboss.com
HostedZoneId: Z1OTIL07BUWDR5
SubjectAlternativeNames:
- www.graphboss.com
ValidationMethod: DNS
CloudFrontDistribution:
Type: AWS::CloudFront::Distribution
Properties:
DistributionConfig:
Comment: CDN for website
Aliases:
- graphboss.com
- www.graphboss.com
ViewerCertificate:
AcmCertificateArn: !Ref CloudFrontCertificate
SslSupportMethod: sni-only
Enabled: true
DefaultCacheBehavior:
AllowedMethods:
- GET
- HEAD
- OPTIONS
ForwardedValues:
QueryString: true
TargetOriginId: HostingBucketOrigin
ViewerProtocolPolicy: redirect-to-https
DefaultRootObject: index.html
CustomErrorResponses:
- ErrorCode: 400
ResponseCode: 200
ResponsePagePath: /index.html
- ErrorCode: 403
ResponseCode: 200
ResponsePagePath: /index.html
- ErrorCode: 404
ResponseCode: 200
ResponsePagePath: /index.html
- ErrorCode: 405
ResponseCode: 200
ResponsePagePath: /index.html
- ErrorCode: 414
ResponseCode: 200
ResponsePagePath: /index.html
- ErrorCode: 416
ResponseCode: 200
ResponsePagePath: /index.html
Origins:
- DomainName: !GetAtt HostingBucket.DomainName
Id: HostingBucketOrigin
S3OriginConfig:
OriginAccessIdentity:
Fn::Join:
- "/"
- - origin-access-identity/cloudfront
- !Ref CloudFrontOAI
CloudFrontOAI:
Type: AWS::CloudFront::CloudFrontOriginAccessIdentity
Properties:
CloudFrontOriginAccessIdentityConfig:
Comment: Allow access to the Graphboss S3 bucket from CloudFront
Outputs:
OAI:
Value: !Ref CloudFrontOAI
Description: OAI
S3CanonicalUserId:
Value: !GetAtt CloudFrontOAI.S3CanonicalUserId
Description: S3CanonicalUserId
CloudFrontDistributionURL:
Value: !Join
- ""
- - "https://"
- !GetAtt
- CloudFrontDistribution
- DomainName
Description: CloudFront URL for the website
WebsiteURL:
Value: !GetAtt
- HostingBucket
- WebsiteURL
Description: URL for website hosted on S3
S3BucketSecureURL:
Value: !Join
- ""
- - "https://"
- !GetAtt
- HostingBucket
- DomainName
Description: Name of S3 bucket to hold website content
Want to learn more about serverless applications and devops with AWS?
Sign up for our newsletter.