Home > Categories > Aws cdk > Basic auth to password protect s3 static site with lambda@edge

Home > Basic auth to password protect s3 static site with lambda@edge

Basic auth to password protect s3 static site with lambda@edge


5 Mar 2021


2 Mar 2021

S3 or simple storage service is really great in inexpensive way to host static websites. And in combination with cloudfront its gets even better.

When your website doesn't have much traffic then you can directly deploy changes to live website without worry.

But as your website starts to get large traffic and any of your changes breaks the website then it will upset large number of visitors/customers.

So its better to create preview website to preview changes before updating live version.

And you want to hide this preview website from general population so they don't get confused with duplicate website.

You don't need full featured authentication system like cognito but basic username and password authentication will be sufficient.

So we are going to add basic authentication with lambda executing at edge location.

If you really wanted cognito then you can just replace basic authentication with cognito code inside lambda.

And we are going to deploy all of this using aws cdk which is infrastructure as code. So process is repeatable by just doing copy paste.

To read rest of the article please Purchase Subscription

View complete source code on github

Before we get started I would recommend to develop CDK project inside development docker container.

So we no longer have the issue of "this works on my computer". And it will not mess with your existing workflow.

So checkout my blog post for detailed video explanation.

Then checkout CDK development container settings on github.

So create new folder and initialize CDK project as follows

mkdir password-protect-s3-static-site && cd $_
cdk init app --language typescript

First we are going to create bucket to store preview website and SSL certificate for preview subdomain as follows.

So first we get access to our main domain's route53 hosted zone. And create ssl certificate for preview.example.com subdomain.

Then I am simply creating new s3 bucket and making it serve website from index.html. Then printing out our website url.

Before moving forward I would highly recommend you deploy this stack and test if its working upto this point.

You will have to set publicReadAccess: true on the bucket just for testing. Because by default all public access is blocked.

Then add index.html to this bucket from console or aws cli and go to the bucket url to verify that its serving website properly.

The homepage will work without issue because we have set the path in the bucket but test for other paths and make sure it doesn't redirect to 404 not found.

Also put invalid path on purpose and check if it serves 404 page properly.

If everything is working properly then remove public access and add 2nd part as follows

This is a trick I use to distribute static site only via cloudfront and block direct s3 access.

Without this trick you have to specify full path e.g. example.com/my-page/index.html and by adding this trick you can access same page at path example.com/my-page/.

The trick is to block access to s3 website who doesn't have the specified secret key in the header.

After this if you try to access the s3 website with website url printed in previous step then you will get access denied.

Then I have created cache policy for cloudfront distribution.

Because this is a preview website you don't want to cache it for long time. So you can deploy new version of preview and don't have to invalidate the cache to see the update.

Default cache time is 24 hours I have reduced to 30 minutes. You can change to any size that suits your need.

Most important thing is make sure you add headerBehavior: CacheHeaderBehavior.allowList('authorization') in the cache policy.

By default none of the headers are passed to the lambda function.

Because we are serving static content nothing is passed to the s3 website.

E.g. query string parameter, headers, cookies are not forwarded to s3 website or lambda@edge.

Then using the experimental method I am deploying lambda function at edge.

At the time of writing this article max version of Nodejs is 12.x and maximum memory allowed at edge is 128.

These limits are only applicable for lambda running at edge location.

The actual lambda code is as follows

I have hardcoded the username and password inside the lambda function. You cannot have multiple users.

If you want multiple users then you can implement cognito here.

So if the username password doesn't match then access to this website is denied.

Then you need to deploy lambda with cloudfront distribution as follows

I am creating cloudfront distribution with http origin and passing in the url that we printed before.

The printed url will include http:// that we need to remove before adding in cloudfront.

S3 website cannot be accessed over HTTPS. So connection between cloudfront and s3 website is over HTTP.

Here we pass the the secret key to give cloudfront access to s3 website. This doesn't give user access to website.

To give user access we need to intercept request from cloudfront to s3 and add edge lambda here.

Use the reference to same edge lambda and cache policy that we created in earlier step.

Important thing to notice is you need to provide lambda version to cloudfront.

Each time you deploy lambda with or without changes then a new version is created.

You may face issue of lambda not intercepting request before forwarding. In this case just make some change like adding space and redeploy lambda. This will update the version number and fix the issue.

Deploying cloudfront distribution will take 5min to 45 min so be patient.

So by default cloudfront deploys at something.cloudfront.net domain.

But you want to use your custom domain so you forward your requests from your custom domain to cloudfront domain with alias.

And that's it!! You can password protect your preview website and run your tests.

View complete source code on github


It is bit complicated to password protect static website but its worth it for verifying changes with clients before deploying to live version.

Also using lambda edge you can run A/B tests and all kinds of experiments.

Free users cannot comment below so if you have questions then tweet me @apoorvmote. I would really like to hear your brutally honest feedback.

If you like this article please consider purchasing paid