Skip to content

Instantly share code, notes, and snippets.

@haranjackson
Last active April 5, 2020 00:33
Show Gist options
  • Save haranjackson/f16e837f33e1ddb6df8a521d06607977 to your computer and use it in GitHub Desktop.
Save haranjackson/f16e837f33e1ddb6df8a521d06607977 to your computer and use it in GitHub Desktop.
CloudFormation template for quickly creating a password-protected website. Put your website's source in folder "src" next to authAtEdge.yml and deploy.sh. Based on: github.com/aws-samples/cloudfront-authorization-at-edge.
AWSTemplateFormatVersion: 2010-09-09
Transform: AWS::Serverless-2016-10-31
Parameters:
DomainName:
Type: String
Description: Domain name of the website
HostedZone:
Type: String
Description: Hosted zone within which the domain name lies
Resources:
################################
# S3
################################
Bucket:
Type: AWS::S3::Bucket
Properties:
AccessControl: Private
BucketName: !Ref DomainName
BucketPolicy:
Type: AWS::S3::BucketPolicy
Properties:
Bucket: !Ref Bucket
PolicyDocument:
Statement:
- Action:
- s3:PutObject
Effect: Deny
Resource: !Sub "arn:aws:s3:::${Bucket}/*"
Principal: "*"
Condition:
StringNotEquals:
s3:x-amz-server-side-encryption: AES256
- Action:
- s3:PutObject
Effect: Deny
Resource: !Sub "arn:aws:s3:::${Bucket}/*"
Principal: "*"
Condition:
"Null":
s3:x-amz-server-side-encryption: true
- Action:
- s3:GetObject
Effect: Allow
Resource: !Sub "arn:aws:s3:::${Bucket}/*"
Principal:
AWS: !Sub "arn:aws:iam::cloudfront:user/CloudFront Origin Access Identity ${CloudFrontOriginAccessIdentity}"
################################
# CLOUDFRONT
################################
CloudFrontOriginAccessIdentity:
Type: AWS::CloudFront::CloudFrontOriginAccessIdentity
Properties:
CloudFrontOriginAccessIdentityConfig:
Comment: Origin Access Identity for Serverless Static with Basic Auth
Distribution:
Type: AWS::CloudFront::Distribution
Properties:
DistributionConfig:
Aliases:
- !Ref DomainName
CacheBehaviors:
- PathPattern: /parseauth
Compress: true
ForwardedValues:
QueryString: true
LambdaFunctionAssociations:
- EventType: viewer-request
LambdaFunctionARN: !GetAtt LambdaEdgeProtection.Outputs.ParseAuthHandler
TargetOriginId: dummy-origin
ViewerProtocolPolicy: redirect-to-https
- PathPattern: /refreshauth
Compress: true
ForwardedValues:
QueryString: true
LambdaFunctionAssociations:
- EventType: viewer-request
LambdaFunctionARN: !GetAtt LambdaEdgeProtection.Outputs.RefreshAuthHandler
TargetOriginId: dummy-origin
ViewerProtocolPolicy: redirect-to-https
- PathPattern: /signout
Compress: true
ForwardedValues:
QueryString: true
LambdaFunctionAssociations:
- EventType: viewer-request
LambdaFunctionARN: !GetAtt LambdaEdgeProtection.Outputs.SignOutHandler
TargetOriginId: dummy-origin
ViewerProtocolPolicy: redirect-to-https
DefaultCacheBehavior:
Compress: true
ForwardedValues:
QueryString: true
LambdaFunctionAssociations:
- EventType: viewer-request
LambdaFunctionARN: !GetAtt LambdaEdgeProtection.Outputs.CheckAuthHandler
- EventType: origin-response
LambdaFunctionARN: !GetAtt LambdaEdgeProtection.Outputs.HttpHeadersHandler
TargetOriginId: protected-origin
ViewerProtocolPolicy: redirect-to-https
Enabled: true
DefaultRootObject: index.html
Origins:
- DomainName: example.org # Dummy origin is used for Lambda@Edge functions, keep this as-is
Id: dummy-origin
CustomOriginConfig:
OriginProtocolPolicy: match-viewer
- DomainName: !GetAtt Bucket.DomainName
Id: protected-origin
S3OriginConfig:
OriginAccessIdentity: !Sub origin-access-identity/cloudfront/${CloudFrontOriginAccessIdentity}
ViewerCertificate:
AcmCertificateArn: !Ref Certificate
SslSupportMethod: sni-only
LambdaEdgeProtection:
Type: AWS::Serverless::Application
Properties:
Location:
ApplicationId: arn:aws:serverlessrepo:us-east-1:520945424137:applications/cloudfront-authorization-at-edge
SemanticVersion: 1.0.6
Parameters:
CreateCloudFrontDistribution: false
AlternateDomainNames: !Ref DomainName
HttpHeaders: !Sub |-
{
"Content-Security-Policy": "script-src 'self'; object-src 'none'; connect-src 'self'",
"Strict-Transport-Security": "max-age=31536000; includeSubdomains; preload",
"Referrer-Policy": "same-origin",
"X-XSS-Protection": "1; mode=block",
"X-Frame-Options": "DENY",
"X-Content-Type-Options": "nosniff"
}
################################
# DNS
################################
RecordSet:
Type: AWS::Route53::RecordSet
Properties:
AliasTarget:
DNSName: !GetAtt Distribution.DomainName
HostedZoneId: Z2FDTNDATAQYW2 # required
HostedZoneName: !Sub ${HostedZone}.
Name: !Ref DomainName
Type: A
Certificate:
Type: AWS::CertificateManager::Certificate
Properties:
DomainName: !Ref DomainName
ValidationMethod: DNS
BUCKET=
DOMAIN_NAME=
HOSTED_ZONE=
STACK_NAME=
################################
aws cloudformation package \
--template-file authAtEdge.yml \
--output-template-file pkg.yml \
--s3-bucket $BUCKET \
>/dev/null
aws cloudformation deploy \
--template-file pkg.yml \
--stack-name $STACK_NAME \
--region us-east-1 \
--capabilities CAPABILITY_NAMED_IAM CAPABILITY_AUTO_EXPAND \
--parameter-overrides DomainName=$DOMAIN_NAME HostedZone=$HOSTED_ZONE
rm pkg.yml
aws s3 sync src/ s3://$DOMAIN_NAME --delete --sse AES256
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment