-
Notifications
You must be signed in to change notification settings - Fork 7
/
basic-auth-edge-lambda.yaml
157 lines (144 loc) · 5.25 KB
/
basic-auth-edge-lambda.yaml
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
AWSTemplateFormatVersion: "2010-09-09"
Description: HTTP Basic authentication Lambda@Edge
Parameters:
AuthUsername:
Description: Username for http basic auth
Type: String
AuthPassword:
Description: Password for http basic auth
Type: String
AuthCookieSecret:
Description: Secret used to generate cookie hash
Type: String
AuthCookieMaxAgeSeconds:
Description: Authentication cookie max age in seconds
Type: Number
Domain:
Description: Domain for authentication cookie domain param and redirects. example value, domain.com
Type: String
AuthEnabled:
Description: Require authentication to access the environment. Set false in prod environments
AllowedValues:
- true
- false
Type: String
Resources:
EdgeLambdaRole:
Type: 'AWS::IAM::Role'
Properties:
AssumeRolePolicyDocument:
Version: '2012-10-17'
Statement:
- Action: 'sts:AssumeRole'
Principal:
Service:
- lambda.amazonaws.com
- edgelambda.amazonaws.com
- replicator.lambda.amazonaws.com
Effect: Allow
Policies:
- PolicyName: EdgePoliciesLambdaPolicy
PolicyDocument:
Version: '2012-10-17'
Statement:
- Action:
- 'lambda:GetFunction'
- 'lambda:EnableReplication*'
- 'lambda:InvokeFunction'
- 'logs:CreateLogGroup'
- 'logs:CreateLogStream'
- 'logs:PutLogEvents'
- 'xray:PutTraceSegments'
- 'xray:PutTelemetryRecords'
Effect: Allow
Resource: '*'
AuthEdgeLambda:
Type: 'AWS::Lambda::Function'
Properties:
Handler: 'index.beforeOriginRequest'
Role: !GetAtt EdgeLambdaRole.Arn
Code:
ZipFile: !Sub |
'use strict';
const path = require('path');
exports.beforeOriginRequest = (event, context, callback) => {
const { request } = event.Records[0].cf;
const uri = request.uri;
const headers = request.headers;
const AUTH_COOKIE_NAME = 'dev-auth=';
const authEnabled = ${AuthEnabled};
const authCookieSecret = '${AuthCookieSecret}';
const authUsername = '${AuthUsername}';
const authPassword = '${AuthPassword}';
const authCookieMaxAgeSeconds = ${AuthCookieMaxAgeSeconds};
const domain = '${Domain}';
if(authEnabled) {
const authCookieValue = getCookieValue(headers, AUTH_COOKIE_NAME);
if(authCookieValue !== authCookieSecret) {
const basicAuthString = 'Basic ' + new Buffer(authUsername + ':' + authPassword).toString('base64');
if (headers.authorization && headers.authorization[0].value === basicAuthString) {
const authCookieValue = AUTH_COOKIE_NAME + authCookieSecret + '; Max-Age=' + authCookieMaxAgeSeconds + '; Domain=' + domain +'; HttpOnly; Secure; Path=/';
callback(null, {
status: '307',
statusDescription: 'Authentication success',
headers: {
'Set-Cookie': [{
key: 'Set-Cookie',
value: authCookieValue,
}],
location: [{
key: 'Location',
value: 'https://' + domain + uri,
}]
}
});
} else {
callback(null, {
status: '401',
statusDescription: 'Unauthorized',
body: 'Please authenticate',
headers: {
'www-authenticate': [{key: 'WWW-Authenticate', value:'Basic realm=' + domain}]
}
});
}
}
}
// Optional SPA routing. If requested object doesn't have file name extension it is considered SPA route and responded with index.html
if (path.extname(request.uri) === '') {
request.uri = `/index.html`;
}
callback(null, request);
};
const getCookieValue = (headers, cookieName) => {
if (headers.cookie) {
const foundCookie = headers.cookie
.map(cookie => cookie.value)
.reduce((all, current) => {
return current.split(';').concat(all);
}, [])
.find(cookie => cookie.includes(cookieName));
return foundCookie && foundCookie.split('=').pop();
}
return null;
};
Runtime: 'nodejs12.x'
Timeout: '5'
TracingConfig:
Mode: 'Active'
AuthEdgeLambdaVersion:
Type: 'AWS::Lambda::Version'
Properties:
FunctionName:
Ref: AuthEdgeLambda
Outputs:
AuthEdgeLambdaArn:
Description: Arn of the auth edge lambda
Value: !GetAtt AuthEdgeLambda.Arn
Export:
Name: !Sub ${AWS::StackName}-AuthEdgeLambda-Arn
AuthEdgeLambdaVersion:
Description: Version of the auth edge lambda
Value: !GetAtt AuthEdgeLambdaVersion.Version
Export:
Name: !Sub ${AWS::StackName}-AuthEdgeLambda-Version