Private (Cloud) Fronts demonstrates a method for restricting access to CloudFront distributions by requiring visitors to first authenticate against AWS Cognito. This repository contains the source code for the accompanying blog post (which covers this topic in more detail):
- Clone this repository
- In your IDE of choice, perform a global search-and-replace on the following:
Key | Example | Description |
---|---|---|
@@AWS_PROFILE@@ | default | AWS CLI profile to use to deploy the Lambda functions |
@@AWS_ACCOUNT_ID@@ | 1111222233333 | AWS Account ID, used below to upload the private key to Secrets Manager |
@@AWS_REGION@@ | ap-southeast-2 | AWS CLI region to deploy the Lambda functions into |
@@NAME_CAMEL_CASE@@ | PrivateCloudFronts | Used to name things where the name can be mixed-case. |
@@NAME_KEBAB_CASE@@ | private-cloud-fronts | Used in naming resources like Parameter Store keys, S3 buckets, etc where the name has to be lower case |
High level steps to follow are:
- Generate a public and private key for CloudFront
- Deploy Lambda functions
- Deploy CloudFormation stack
- Upload the private key to AWS Secrets Manager
- Copy website files to S3
- Launch the website in your browser
# Generate a public and private key for CloudFront
openssl genrsa -out private_key.pem 2048
openssl rsa -pubout -in private_key.pem -out public_key.pem
# Lambda Functions
cd lambdas
npm i
sls deploy
# Deploy CloudFormation stack
cd ..
PUBLIC_KEY=$(<public_key.pem)
aws --profile @@AWS_PROFILE@@ --region @@AWS_REGION@@ cloudformation deploy \
--template-file infrastructure/infrastructure.yml \
--stack-name "@@NAME_CAMEL_CASE@@" \
--no-fail-on-empty-changeset \
--parameter-overrides \
"ParamBucketName=@@NAME_KEBAB_CASE@@" \
"ParamCognitoDomainName=@@NAME_KEBAB_CASE@@" \
"ParamCognitoUserPoolName=@@NAME_CAMEL_CASE@@" \
"ParamEncodedPublicKey=${PUBLIC_KEY}"
# Upload the private key to AWS Security Manager
PRIVATE_KEY=$(<private_key.pem)
aws --profile @@AWS_PROFILE@@ --region @@AWS_REGION@@ secretsmanager put-secret-value \
--secret-id "arn:aws:secretsmanager:@@AWS_REGION@@:@@AWS_ACCOUNT_ID@@:secret:/@@NAME_KEBAB_CASE@@/cloudfront/private-key" \
--secret-string "${PRIVATE_KEY}"
# Copy website files to S3
aws --profile @@AWS_PROFILE@@ --region @@AWS_REGION@@ s3 cp website/ s3://@@NAME_KEBAB_CASE@@-website --recursive
# Launch the website
DISTRIBUTION_URL=$(aws --profile @@AWS_PROFILE@@ --region @@AWS_REGION@@ cloudformation describe-stacks --stack-name "@@NAME_CAMEL_CASE@@" --output text --query "Stacks[0].Outputs[?OutputKey=='DistributionUrl'].OutputValue")
# Linux
#xdg-open $DISTRIBUTION_URL
# OSX
#open $DISTRIBUTION_URL
# Windows
#start $DISTRIBUTION_URL
-
Remove the S3 buckets:
aws --profile @@AWS_PROFILE@@ --region @@AWS_REGION@@ s3 rb s3://@@NAME_KEBAB_CASE@@-website --force aws --profile @@AWS_PROFILE@@ --region @@AWS_REGION@@ s3 rb s3://@@NAME_KEBAB_CASE@@-logs --force
-
Remove the CloudFormation stacks
aws --profile @@AWS_PROFILE@@ --region @@AWS_REGION@@ cloudformation delete-stack --stack-name "@@NAME_CAMEL_CASE@@" aws --profile @@AWS_PROFILE@@ --region @@AWS_REGION@@ cloudformation wait stack-delete-complete --stack-name "@@NAME_CAMEL_CASE@@"
-
Remove the Lambda functions
cd lambdas sls remove