-
Notifications
You must be signed in to change notification settings - Fork 0
/
cloudfront-static.yml
221 lines (210 loc) · 7.15 KB
/
cloudfront-static.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
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
---
AWSTemplateFormatVersion: "2010-09-09"
Description: "Public Read Anonymous via CloudFront from S3"
Parameters:
StackSuffix:
Type: String
AllowedPattern: '.*'
Default: ''
CFFQDN:
Type: String
AllowedPattern: '^[A-Za-z0-9-]+\.[A-Za-z0-9-\.]+$'
Default: ""
Description: "FQDN that this site will actually run on"
R53ZoneId:
Type: String
AllowedPattern: '[A-Za-z][A-Za-z0-9-]{0,127}'
Default: ''
Description: "ZONE ID of the Route 53 Zone to update the FQDN of your site in"
R53ZoneName:
Type: String
AllowedPattern: '^[A-Za-z0-9-]+\.[A-Za-z0-9-\.]+$'
Default: ''
Description: "ZONE Name (Domain Name) of the Route 53 Zone to update the FQDN of your site in"
LoggingBucketName:
Type: String
Default: ''
Description: "S3 Bucket name for S3 and cloudFront logs"
ContentBucketName:
Type: String
Default: ''
Description: "The Bucket containing the content to serve out, anything in this bucket will be available via CF"
DefaultObjectName:
Type: String
Default: 'index.html'
Description: "Default Object in your website"
Resources:
ACMCertificate:
Type: "AWS::CertificateManager::Certificate"
Properties:
DomainName: !Sub "${CFFQDN}"
CertificateTransparencyLoggingPreference: ENABLED
DomainValidationOptions:
- DomainName: !Sub "${R53ZoneName}"
HostedZoneId: !Sub "${R53ZoneId}"
ValidationMethod: DNS
StorageBucket:
Type: AWS::S3::Bucket
Properties:
BucketName: !Sub "${ContentBucketName}${StackSuffix}"
AccessControl: LogDeliveryWrite
LoggingConfiguration:
DestinationBucketName: !Ref 'LoggingStorageBucket'
LogFilePrefix: 'S3/'
PublicAccessBlockConfiguration:
BlockPublicAcls: true
IgnorePublicAcls: true
BlockPublicPolicy: true
RestrictPublicBuckets: true
StorageBucketPolicy:
Type: "AWS::S3::BucketPolicy"
Properties:
Bucket: !Ref StorageBucket
PolicyDocument:
Statement:
-
Action:
- 's3:GetObject'
Effect: Allow
Resource: !Sub 'arn:aws:s3:::${StorageBucket}/*'
Principal:
CanonicalUser: !GetAtt CloudFrontAccessIdentity.S3CanonicalUserId
LoggingStorageBucket:
Type: AWS::S3::Bucket
Properties:
BucketName: !Sub "${LoggingBucketName}${StackSuffix}"
AccessControl: LogDeliveryWrite
PublicAccessBlockConfiguration:
BlockPublicAcls: true
IgnorePublicAcls: true
BlockPublicPolicy: true
RestrictPublicBuckets: true
LifecycleConfiguration:
Rules:
- Id: DeleteContentAfter90Days
Prefix: ''
Status: Enabled
ExpirationInDays: '90'
R53Record:
Type: "AWS::Route53::RecordSet"
Properties:
HostedZoneId: !Sub "${R53ZoneId}"
Type: A
Name: !Sub "${CFFQDN}"
AliasTarget:
DNSName: !GetAtt CloudFrontDistribution.DomainName
HostedZoneId: Z2FDTNDATAQYW2 # CloudFront distribution Route 53 zone ID do not change
CloudFrontAccessIdentity:
Type: AWS::CloudFront::CloudFrontOriginAccessIdentity
Properties:
CloudFrontOriginAccessIdentityConfig:
Comment: !Ref StorageBucket
CloudFrontDistribution:
Type: "AWS::CloudFront::Distribution"
Properties:
DistributionConfig:
Enabled: true
HttpVersion: http2
Aliases:
- !Ref CFFQDN
Comment: !Sub ${AWS::StackName}
DefaultCacheBehavior:
AllowedMethods:
- GET
- HEAD
- OPTIONS
Compress: true
TargetOriginId: s3origin
ViewerProtocolPolicy: "redirect-to-https"
ForwardedValues:
QueryString: 'false'
Cookies:
Forward: none
DefaultTTL: 300
MaxTTL: 3600
MinTTL: 60
LambdaFunctionAssociations:
- EventType: origin-request
LambdaFunctionARN: !Ref SubdirRootObjectFunctionVersion
Logging:
# yamllint disable-line rule:line-length
Bucket: !GetAtt 'LoggingStorageBucket.DomainName' #
IncludeCookies: false
Prefix: 'CloudFront'
Origins:
# yamllint disable-line rule:line-length
- DomainName: !GetAtt 'StorageBucket.DomainName'
Id: s3origin
S3OriginConfig:
OriginAccessIdentity: !Sub 'origin-access-identity/cloudfront/${CloudFrontAccessIdentity}'
DefaultRootObject: !Sub '${DefaultObjectName}'
CustomErrorResponses:
- ErrorCode: '404'
ResponsePagePath: "/404.html"
ResponseCode: '404'
ErrorCachingMinTTL: '60'
PriceClass: PriceClass_100
ViewerCertificate:
SslSupportMethod: sni-only
AcmCertificateArn: !Ref ACMCertificate
MinimumProtocolVersion: TLSv1.2_2019
# CF Requires a versioned Lambda ARN - lets get that
SubdirRootObjectFunctionVersion:
Type: "AWS::Lambda::Version"
Properties:
FunctionName:
Ref: SubdirRootObjectFunction
# Lambda@Edge Function to add default document to URI's ending with /
SubdirRootObjectFunction:
DeletionPolicy: Retain
Type: AWS::Lambda::Function
Properties:
Handler: index.handler
Runtime: nodejs12.x
Timeout: 5
MemorySize: 128
Role: !GetAtt SubdirRootObjectFunctionRole.Arn
Code:
ZipFile:
Fn::Sub: |
'use strict';
exports.handler = (event, context, callback) => {
// Extract the request from the CloudFront event that is sent to Lambda@Edge
var request = event.Records[0].cf.request;
// Extract the URI from the request
var olduri = request.uri;
// Match any '/' that occurs at the end of a URI. Replace it with a default index
var newuri = olduri.replace(/\/$/, '\/${DefaultObjectName}');
// Log the URI as received by CloudFront and the new URI to be used to fetch from origin
console.log("Old URI: " + olduri);
console.log("New URI: " + newuri);
// Replace the received URI with the URI that includes the index page
request.uri = newuri;
// Return to CloudFront
return callback(null, request);
};
# Lambda@Edge Role for Log Writing
SubdirRootObjectFunctionRole:
Type: AWS::IAM::Role
Properties:
AssumeRolePolicyDocument:
Version: 2012-10-17
Statement:
- Action: sts:AssumeRole
Effect: Allow
Principal:
Service:
- lambda.amazonaws.com
- edgelambda.amazonaws.com
Policies:
- PolicyName: DoTheNeedful
PolicyDocument:
Version: 2012-10-17
Statement:
- Sid: AllowWriteLogs
Effect: Allow
Resource: '*'
Action:
- logs:CreateLogGroup
- logs:CreateLogStream
- logs:PutLogEvents