-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathcloudformation.yml
175 lines (159 loc) · 5.62 KB
/
cloudformation.yml
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
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
AWSTemplateFormatVersion: "2010-09-09"
Description: CloudFront for static website
Parameters:
DomainName:
Description: User-facing DNS records
Type: String
CertificateArn:
Description: ARN of ACM certificate in us-east-1
Type: String
OaiId:
Description: ID of pre-created Origin Access Identity
Type: String
AllowedPattern: '[A-Z1-9]{14}'
Resources:
S3Bucket:
Type: AWS::S3::Bucket
Properties:
BucketName: !Ref DomainName
S3BucketPolicy:
Type: AWS::S3::BucketPolicy
Properties:
Bucket: !Ref 'S3Bucket'
PolicyDocument:
Statement:
- Sid: !Sub "${AWS::StackName}-oai-allow"
Action: s3:GetObject
Effect: Allow
Principal:
AWS: !Sub "arn:aws:iam::cloudfront:user/CloudFront Origin Access Identity ${OaiId}"
Resource: !Sub
- "${BucketArn}/*"
- { "BucketArn": !GetAtt S3Bucket.Arn }
CloudFrontDistribution:
Type: AWS::CloudFront::Distribution
Properties:
DistributionConfig:
Enabled: true
Origins:
- DomainName: !GetAtt S3Bucket.DomainName
Id: S3BucketOrigin
S3OriginConfig:
OriginAccessIdentity: !Sub "origin-access-identity/cloudfront/${OaiId}"
Comment: !Ref DomainName
Aliases:
- !Ref DomainName
IPV6Enabled: true
DefaultRootObject: 'index.html'
DefaultCacheBehavior:
TargetOriginId: S3BucketOrigin
Compress: true
AllowedMethods:
- HEAD
- GET
ForwardedValues:
QueryString: false
ViewerProtocolPolicy: redirect-to-https
LambdaFunctionAssociations:
- EventType: origin-request
LambdaFunctionARN: !Ref TheOriginRequestLambdaFunctionVersionV2
PriceClass: PriceClass_All
ViewerCertificate:
AcmCertificateArn: !Ref CertificateArn
SslSupportMethod: sni-only
HttpVersion: http2
CustomErrorResponses:
- ErrorCode: 404
ResponsePagePath: '/404.html'
ResponseCode: 404
- ErrorCode: 403
ResponsePagePath: '/404.html'
ResponseCode: 404
# combination of https://github.com/CloudUnder/lambda-edge-nice-urls and https://github.com/lroguet/amzn-cloudformation/blob/master/storage-content-delivery/static-website-with-cloudfront-lambda-edge.yml
TheOriginRequestLambdaFunction:
Type: AWS::Lambda::Function
Properties:
Description: >
Lambda function performing request URI rewriting.
Code:
ZipFile: !Sub |
/* Public domain project by Cloud Under (https://cloudunder.io).
* Repository: https://github.com/CloudUnder/lambda-edge-nice-urls
*/
const config = {
suffix: '.html',
appendToDirs: 'index.html',
removeTrailingSlash: false,
};
const regexSuffixless = /\/[^/.]+$/; // e.g. "/some/page" but not "/", "/some/" or "/some.jpg"
const regexTrailingSlash = /.+\/$/; // e.g. "/some/" or "/some/page/" but not root "/"
exports.handler = function handler(event, context, callback) {
const { request } = event.Records[0].cf;
const { uri } = request;
const { suffix, appendToDirs, removeTrailingSlash } = config;
// Append ".html" to origin request
if (suffix && uri.match(regexSuffixless)) {
request.uri = uri + suffix;
callback(null, request);
return;
}
// Append "index.html" to origin request
if (appendToDirs && uri.match(regexTrailingSlash)) {
request.uri = uri + appendToDirs;
callback(null, request);
return;
}
// Redirect (301) non-root requests ending in "/" to URI without trailing slash
if (removeTrailingSlash && uri.match(/.+\/$/)) {
const response = {
// body: '',
// bodyEncoding: 'text',
headers: {
'location': [{
key: 'Location',
value: uri.slice(0, -1)
}]
},
status: '301',
statusDescription: 'Moved Permanently'
};
callback(null, response);
return;
}
// If nothing matches, return request unchanged
callback(null, request);
};
Handler: index.handler
MemorySize: 128
Role: !Sub ${TheOriginRequestLambdaFunctionExecutionRole.Arn}
Runtime: nodejs6.10
TheOriginRequestLambdaFunctionVersionV2:
Type: AWS::Lambda::Version
Properties:
FunctionName: !Ref TheOriginRequestLambdaFunction
Description: !Sub "URL rewriting for ${DomainName}"
TheOriginRequestLambdaFunctionExecutionRole:
Type: AWS::IAM::Role
Properties:
AssumeRolePolicyDocument:
Version: 2012-10-17
Statement:
- Effect: Allow
Principal:
Service:
- edgelambda.amazonaws.com
- lambda.amazonaws.com
Action:
- sts:AssumeRole
ManagedPolicyArns:
- arn:aws:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole
Outputs:
CloudFrontDistributionId:
Description: CloudFront ID
Value: !Ref CloudFrontDistribution
CloudFrontDistributionDomainName:
Description: CloudFront Domain Name
Value: !GetAtt CloudFrontDistribution.DomainName
URL:
Description: User-facing URL
Value: !Sub "https://${DomainName}"