Skip to content

Instantly share code, notes, and snippets.

@lmakarov
Created August 30, 2017 19:15
Show Gist options
  • Save lmakarov/e5984ec16a76548ff2b278c06027f1a4 to your computer and use it in GitHub Desktop.
Save lmakarov/e5984ec16a76548ff2b278c06027f1a4 to your computer and use it in GitHub Desktop.
Basic HTTP Authentication for CloudFront with Lambda@Edge
'use strict';
exports.handler = (event, context, callback) => {
// Get request and request headers
const request = event.Records[0].cf.request;
const headers = request.headers;
// Configure authentication
const authUser = 'user';
const authPass = 'pass';
// Construct the Basic Auth string
const authString = 'Basic ' + new Buffer(authUser + ':' + authPass).toString('base64');
// Require Basic authentication
if (typeof headers.authorization == 'undefined' || headers.authorization[0].value != authString) {
const body = 'Unauthorized';
const response = {
status: '401',
statusDescription: 'Unauthorized',
body: body,
headers: {
'www-authenticate': [{key: 'WWW-Authenticate', value:'Basic'}]
},
};
callback(null, response);
}
// Continue request processing if authentication passed
callback(null, request);
};
@lmakarov
Copy link
Author

lmakarov commented Aug 30, 2017

See my article on Medium for details.

@homaily
Copy link

homaily commented Jan 16, 2018

Thanks Leonid for sharing this.

Lines 8 to 13 if moved before the function (before line 2) it will be parsed just once and cached in memory for next executions.

@mikcox
Copy link

mikcox commented Mar 27, 2018

This should be in the official AWS docs. Extremely useful; thanks for sharing!

@pmcdowell-okta
Copy link

Agreed ! There is little documentation on Lambda Edge. Thank you for sharing the code

@trinath-k
Copy link

Imakarov did you finish full doc on how to setup this? I am having hard time implementing this getting errors when assigning role to lambda. Which role should i use and which policies i have to add that role?

@pmcdowell-okta
Copy link

pmcdowell-okta commented Apr 13, 2018

@trinath-k

I had the same problem. Your Lambda has to be in N. Virginia (althought that might have changed).

Find the role you assigned to the Lambda Function, and edit the policy "Trust Relationship" to something like this:

{ "Version": "2012-10-17", "Statement": [ { "Effect": "Allow", "Principal": { "Service": [ "edgelambda.amazonaws.com", "lambda.amazonaws.com" ] }, "Action": "sts:AssumeRole" } ] }

This worked for me. AWS Documentation does not explain that very well.

Good Luck !

@trinath-k
Copy link

trinath-k commented Apr 13, 2018

Hi, I have configured everything. But i still can't access file in my s3 bucket. I am trying to access a file in this s3 bucket. it's only listing the object. I wanted it be able to download or read.

This XML file does not appear to have any style information associated with it. The document tree is shown below.

inventory-endpoints


1000
false

inventory-endpoints-04.06.2018.yaml
2018-04-13T20:40:38.000Z
"b18f7a425f4be500caf2fc7f3107e77c"
10308
STANDARD

@iamwalker
Copy link

Is there a way to set this up on specific directories in the s3 bucket? i.e. domain.com allowed, domain.com/dir triggers auth

Copy link

ghost commented Jun 13, 2018

@iamwalker In CloudFront, under "Origin Settings", you can set the Origin Path. For example, I'm running an S3 bucket with dev, stage and prod folders. I have one CloudFront distribution for each one.

@mathieug
Copy link

mathieug commented Jul 2, 2018

You should return the callback or wrap the second call to it into a else case.

@Spaideri
Copy link

Hi!

Inspired from this I made my own version which is using a shared cookie secret to allow application to use Authorization header for JWT Bearer tokens. See webscale-oy/aws-cloudfront-basic-auth for Cloudformation templates and documentation.

@BenPortner
Copy link

Super helpful. Thank you very much!

@ivictbor
Copy link

ivictbor commented Jun 11, 2020

@sreejithps303
Copy link

Can we pick the credentials from secret manager? can anyone help with the code?

@iothack
Copy link

iothack commented Sep 11, 2020

@SunnyVZ777
Copy link

Do anyone get a problem that in phone (ios) it just popup password panel serveral times when loading the website?

@rkz
Copy link

rkz commented Sep 28, 2020

Similar problem here.

It seems the Authorization header is no longer read by Lambda or some other part of the chain?

I replaced line 17 with:

const body = 'Unauthorized, headers are ' + JSON.stringify(headers);

Test case (with some sensitive data replaced by [...]):

$ curl --user xxx:yyy https://my_endpoint
[...]
> GET / HTTP/2
> Host: [...]
> Authorization: Basic eHh4Onl5eQ==
< HTTP/2 401
< content-length: 341
< server: CloudFront
< date: Mon, 28 Sep 2020 16:40:50 GMT
* Authentication problem. Ignoring this.
< www-authenticate: Basic
[...]

Unauthorized, headers is {"host":[{"key":"Host","value":"[...]"}],"x-forwarded-for":[{"key":"X-Forwarded-For","value":"[...]"}],"user-agent":[{"key":"User-Agent","value":"Amazon CloudFront"}],"via":[{"key":"Via","value":"[...]"}]}* Closing connection 0

The headers variable has no key authorization.

@nachmore
Copy link

@rkz - make sure that your trigger CloudFront Event is Viewer Request and not Origin Request. The auth headers are stripped out of Origin.

@rkz
Copy link

rkz commented Sep 29, 2020

@nachmore that was it :) Thank you

@Habbie
Copy link

Habbie commented Dec 15, 2020

Line 23 is broken - the realm parameter is mandatory! This is documented in RFC7617 section 2 and I found out because Python's urllib's AuthHandler classes do not recognise the header without realm=.

@jeroenvollenbrock
Copy link

This is now also possible, cheaper and faster with the newly launched CloudFront Functions (https://gist.github.com/jeroenvollenbrock/94edbbc62adc986d6d6a9a3076e66f5b)

@malcolmm83
Copy link

@rkz - make sure that your trigger CloudFront Event is Viewer Request and not Origin Request. The auth headers are stripped out of Origin.

I added the 'Authorization' header to the cache key and it now comes through to the 'Origin Request'. My issue is that I need both this header as well as the origin domain for my lambda, and I can't determine the domain from the 'Viewer Request' . Wish this stuff was documented better.

@maheshglm
Copy link

maheshglm commented Aug 22, 2022

Can we pick the credentials from secret manager? can anyone help with the code?

Tried adding aws-cdk to lamda@edge function that is attached to viewer request but size limitation of 1MB for Viewer Request is blocking me. Because with the inclusion of aws-cdk package, the zip file size is increasing more than 4 MB (even with ssm package). Any other workaround for this problem ??

@AlexBorsody
Copy link

AlexBorsody commented Nov 25, 2022

It looks like Amazon has no official documentation on how to do this, Authorizers are only documented to use token auth with APIs, not basic auth.

What is a better alternative to securing a dev or staging site from prying eyes such as dev.mysite.com Firewall with IP restrictions can be unreliable with changing IPs and hinder developer productivity?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment