We launched the cloudonaut blog in 2015. Since then, we have published 390 articles, 91 podcast episodes, and 99 videos. Our weekly newsletter keeps you up-to-date. Subscribe now!.
Subscribe
Our weekly newsletter keeps you up-to-date. Subscribe now! It's all free.
This blog can be accessed by anyone with access to the free Internet. It’s a public website. But many websites offer a members-only area. You have to log in to get access to parts of the website. In this blog post, I demonstrate how CloudFront can be used to protect parts of your website from the public.
To serve content only to logged-in users with CloudFront, we have to wire three pieces together:
A private & public key pair.
A signed cookie protected CloudFront origin that uses the public key to verify signed cookies.
A component that generates and returns signed cookies with the private key. We use Lambda@Edge here because CloudFront can trigger it directly.
I wired up the pieces using CloudFormation. Let’s have a look at the template step by step.
First, We define the S3 bucket that we use as origins for our CloudFront distribution. We use a single bucket here and separate the public and private files into folders. You could also use two S3 buckets if you wish, or you could use other origin types such as load balancers or external HTTP endpoints.
Second, we create the public key that CloudFront uses to verify the signature in the cookies. To generate a private/Public key pair, run the following commands:
Managing key rotation in CloudFormation is possible but cumbersome. To add a new public key, duplicate the CloudFrontPublicKey1 resource and reference the new resource in the key group. Please don’t delete the old public key while it is in use. The expiry of your cookies (1 day in this example) defines the minimum wait duration.
Third, it’s time to implement the Lambda@Edge function that generates the signed cookies.
You might want to adjust the following:
MAX_AGE_IN_SECONDS: Expiry of the signed cookie (both the cookie and the content expires)
Private key (from private_key.pem)
The Lambda function checks if the Authorization header contains the value Bearer secret. You likely want to replace this with something different to authenticate the user, e.g., by verifying a JWT.
We use a custom policy here and not a canned policy. Canned policies only grant access to specific files, while custom policies can use the wildcard * character to specify a larger group of files at once.
Last but not least, we define the CloudFront distribution:
To test the demo, create a CloudFormation stack in us-east-1 based on the template. Once the stack is created, upload two files to the created S3 bucket:
To get a private file with the cookies from the previous request:
curl -b cookie.txt https://DOMAIN_NAME/index.html
That’s all you need to run a public and private website behind CloudFront. I hope it helps!
Michael Wittig
I’ve been building on AWS since 2012 together with my brother Andreas. We are sharing our insights into all things AWS on cloudonaut and have written the book AWS in Action. Besides that, we’re currently working on bucketAV, HyperEnv for GitHub Actions, and marbot.
Here are the contact options for feedback and questions.