Skip to content

Commit 0a6a420

Browse files
committed
Initial commit
0 parents  commit 0a6a420

File tree

7 files changed

+203
-0
lines changed

7 files changed

+203
-0
lines changed

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
node_modules

README.md

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
# Serverless boilerplate for Static website hosting with Basic authentication
2+
3+
## Architecture
4+
5+
```
6+
[CloudFront (with Lambda@Edge)] - Restrict Bucket Access -> [S3 Origin Bucket]
7+
```
8+
9+
## Usage
10+
11+
### Config
12+
13+
Set Basic authentication config ( `handler.js` )
14+
15+
### Deploy
16+
17+
```
18+
$ npm install
19+
$ AWS_PROFILE=XxxxxXXX WEBSITE_S3_BUCKET_NAME=sls-static-basic npm run deploy
20+
```
21+
22+
### Synchronize src/* and Website
23+
24+
```
25+
$ AWS_PROFILE=XxxxxXXX WEBSITE_S3_BUCKET_NAME=sls-static-basic npm run sync
26+
```
27+
28+
### Remove
29+
30+
```
31+
$ AWS_PROFILE=XxxxxXXX WEBSITE_S3_BUCKET_NAME=sls-static-basic npm run remove
32+
```

handler.js

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
'use strict';
2+
3+
const BASIC_AUTH_USERS = {
4+
'user': 'pass'
5+
};
6+
7+
module.exports.basicAuth = (event, context, callback) => {
8+
const request = event.Records[0].cf.request;
9+
const headers = request.headers;
10+
const authorization = headers.authorization || headers.Authorization;
11+
12+
if (authorization) {
13+
const encoded = authorization[0].value.split(' ')[1];
14+
const userAndPassword = new Buffer(encoded, 'base64').toString();
15+
for (let user in BASIC_AUTH_USERS) {
16+
const password = BASIC_AUTH_USERS[user];
17+
if (`${user}:${password}` === userAndPassword) {
18+
callback(null, request);
19+
return;
20+
}
21+
}
22+
}
23+
24+
const response = {
25+
status: '401',
26+
statusDescription: 'Authorization Required',
27+
headers: {
28+
'www-authenticate': [{key: 'WWW-Authenticate', value: 'Basic'}],
29+
'content-type': [{key: 'Content-Type', value: 'text/plain; charset=utf-8'}]
30+
},
31+
body: '401 Authorization Required'
32+
};
33+
34+
callback(null, response);
35+
};

package.json

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
{
2+
"name": "serverless-static-hosting-with-basic-auth",
3+
"version": "0.1.0",
4+
"description": "Serverless boilerplate for Static website hosting with Basic authentication",
5+
"main": "index.js",
6+
"scripts": {
7+
"deploy": "sls deploy -v",
8+
"remove": "sls remove",
9+
"sync": "sls sync",
10+
"test": "echo \"Error: no test specified\" && exit 1"
11+
},
12+
"keywords": [
13+
"serverless"
14+
],
15+
"author": "k1LoW <[email protected]> (https://github.com/k1LoW)",
16+
"license": "MIT",
17+
"devDependencies": {
18+
"serverless": "^1.25.0",
19+
"serverless-plugin-cloudfront-lambda-edge": "^1.0.0",
20+
"serverless-s3-sync": "^1.3.0"
21+
}
22+
}

serverless.yml

Lines changed: 111 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,111 @@
1+
service: ${self:provider.environment.WEBSITE_S3_BUCKET_NAME}
2+
3+
provider:
4+
name: aws
5+
runtime: nodejs6.10
6+
7+
stage: dev
8+
region: us-east-1 # Lambda@Edge function must be us-east-1
9+
10+
environment:
11+
WEBSITE_S3_BUCKET_NAME: ${env:WEBSITE_S3_BUCKET_NAME, 'sls-static-basic'}
12+
13+
plugins:
14+
- serverless-s3-sync
15+
- serverless-plugin-cloudfront-lambda-edge
16+
17+
custom:
18+
s3Sync:
19+
- bucketName: ${self:provider.environment.WEBSITE_S3_BUCKET_NAME}
20+
localDir: src
21+
22+
functions:
23+
basicAuth:
24+
name: '${self:provider.environment.WEBSITE_S3_BUCKET_NAME}-viewer-request'
25+
handler: handler.basicAuth
26+
memorySize: 128
27+
timeout: 1
28+
lambdaAtEdge:
29+
distribution: WebsiteDistribution
30+
eventType: 'viewer-request'
31+
32+
resources:
33+
Resources:
34+
WebsiteBucket:
35+
Type: AWS::S3::Bucket
36+
Properties:
37+
BucketName: ${self:provider.environment.WEBSITE_S3_BUCKET_NAME}
38+
AccessControl: Private
39+
WebsiteConfiguration:
40+
IndexDocument: index.html
41+
ErrorDocument: error.html
42+
WebsiteBucketPolicy:
43+
Type: AWS::S3::BucketPolicy
44+
Properties:
45+
Bucket: { Ref: WebsiteBucket }
46+
PolicyDocument:
47+
Statement:
48+
-
49+
Action:
50+
- "s3:GetObject"
51+
Effect: Allow
52+
Resource: { "Fn::Join" : ["", ["arn:aws:s3:::", { Ref : WebsiteBucket }, "/*" ] ] }
53+
Principal:
54+
AWS: { "Fn::Join" : [" ", ["arn:aws:iam::cloudfront:user/CloudFront Origin Access Identity", { Ref: WebsiteOriginAccessIdentity } ] ] }
55+
WebsiteOriginAccessIdentity:
56+
Type: AWS::CloudFront::CloudFrontOriginAccessIdentity
57+
Properties:
58+
CloudFrontOriginAccessIdentityConfig:
59+
Comment: "CloudFrontOriginAccessIdentity for ${self:service}-${self:provider.stage}"
60+
WebsiteDistribution:
61+
Type: AWS::CloudFront::Distribution
62+
Properties:
63+
DistributionConfig:
64+
DefaultCacheBehavior:
65+
AllowedMethods: [ "DELETE", "GET", "HEAD", "OPTIONS", "PATCH", "POST", "PUT" ]
66+
CachedMethods: [ "GET", "HEAD", "OPTIONS" ]
67+
TargetOriginId: WebsiteBucketOrigin
68+
ViewerProtocolPolicy: redirect-to-https
69+
DefaultTTL: 0
70+
MaxTTL: 0
71+
MinTTL: 0
72+
Compress: true
73+
ForwardedValues:
74+
QueryString: true
75+
Cookies:
76+
Forward: 'all'
77+
CustomErrorResponses:
78+
-
79+
ErrorCode: '403'
80+
ErrorCachingMinTTL: 1
81+
-
82+
ErrorCode: '404'
83+
ErrorCachingMinTTL: 1
84+
-
85+
ErrorCode: '500'
86+
ErrorCachingMinTTL: 1
87+
-
88+
ErrorCode: '502'
89+
ErrorCachingMinTTL: 1
90+
-
91+
ErrorCode: '503'
92+
ErrorCachingMinTTL: 1
93+
-
94+
ErrorCode: '504'
95+
ErrorCachingMinTTL: 1
96+
DefaultRootObject: 'index.html'
97+
Enabled: true
98+
PriceClass: 'PriceClass_100'
99+
HttpVersion: 'http2'
100+
ViewerCertificate:
101+
CloudFrontDefaultCertificate: true
102+
Origins:
103+
-
104+
Id: 'WebsiteBucketOrigin'
105+
DomainName: { 'Fn::GetAtt': [ WebsiteBucket, DomainName ] }
106+
S3OriginConfig:
107+
OriginAccessIdentity: { "Fn::Join" : ["", ["origin-access-identity/cloudfront/", { Ref: WebsiteOriginAccessIdentity } ] ] }
108+
Outputs:
109+
WebsiteURL:
110+
Value: { "Fn::Join" : ["", ["https://", { "Fn::GetAtt" : [ WebsiteDistribution, DomainName ] } ] ] }
111+
Description: "URL for website via CloudFront"

src/error.html

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Error

src/index.html

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Authenticated Access!!!

0 commit comments

Comments
 (0)