-
Notifications
You must be signed in to change notification settings - Fork 0
/
template.yaml
282 lines (281 loc) · 8.35 KB
/
template.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
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
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
AWSTemplateFormatVersion: 2010-09-09
Transform: AWS::Serverless-2016-10-31
Parameters:
DomainName:
Description: Name of the domain
Type: String
ConstraintDescription: must be the name of an existing Hosted Zone in Route53.
HostName:
Description: Hostname part of the URL for the website.
Type: String
HostedZoneId:
Description: Hosted Zone ID needed for SSL certificate validation.
Type: String
Subject:
Type: String
Description: Contact us email subject
ToEmailAddress:
Type: String
Description: Email address you want contact form submittions to go to
ReCaptchaClientSecret:
Type: String
Description: Your Google reCAPTCHA client secret
ReCaptchaServerSecret:
Type: String
Description: Your Google reCAPTCHA server secret
EdgeLambdaArn:
Type: String
Description: Edge Lambda ARN for index pages
Default: None
SSLCertificateArn:
Type: String
Description: SSL Certificate ARN
Default: None
DeployWebFiles:
Type: String
Description: Deploy web files to S3
Default: 'true'
AllowedValues:
- true
- false
Conditions:
IsUsEast1: !Equals
- !Ref AWS::Region
- us-east-1
IsDeployWebFiles: !Equals
- !Ref DeployWebFiles
- true
Resources:
ContactUsSNSTopic:
Type: AWS::SNS::Topic
Properties:
DisplayName:
Fn::Join:
- ''
- - Ref: AWS::StackName
- ' Topic'
Subscription:
- Endpoint: !Ref ToEmailAddress
Protocol: email
TopicName:
Fn::Join:
- ''
- - Ref: AWS::StackName
- '-topic'
ContactUsFunctionApi:
Type: AWS::Serverless::Api
Properties:
StageName: Prod
Cors: "'*'"
ContactUsFunction:
Type: AWS::Serverless::Function
Properties:
FunctionName: !Sub ${AWS::StackName}-contactUsFormProcessor
Description: Contact us form processor
Handler: index.handler
CodeUri: src/contactUsFormProcessor
Runtime: nodejs18.x
Timeout: 5
Policies:
- SNSPublishMessagePolicy:
TopicName: !GetAtt ContactUsSNSTopic.TopicName
Events:
PostEvent:
Type: Api
Properties:
RestApiId: !Ref ContactUsFunctionApi
Path: /
Method: post
Environment:
Variables:
ReCaptchaSecret: !Ref ReCaptchaServerSecret
ContactUsSNSTopic: !Ref ContactUsSNSTopic
Subject: !Ref Subject
CloudFrontS3IndexHtml:
Type: AWS::Serverless::Function
Condition: IsUsEast1
Properties:
FunctionName: !Sub ${AWS::StackName}-cloudFrontS3IndexHtml
Description: CloudFront S3 index.html edge lambda
Handler: index.handler
CodeUri: src/cloudFrontS3IndexHtml
Runtime: nodejs18.x
Timeout: 5
AutoPublishAlias: riznob
AssumeRolePolicyDocument:
Version: '2012-10-17'
Statement:
- Effect: Allow
Principal:
Service:
- lambda.amazonaws.com
- edgelambda.amazonaws.com
Action: sts:AssumeRole
DeploymentLayer:
Type: AWS::Serverless::Application
Condition: IsDeployWebFiles
Properties:
Location:
ApplicationId: arn:aws:serverlessrepo:us-east-1:375983427419:applications/deploy-to-s3
SemanticVersion: 2.4.2
SiteSource:
Type: AWS::Serverless::Function
Condition: IsDeployWebFiles
Properties:
Layers:
- !GetAtt DeploymentLayer.Outputs.Arn
CodeUri: web/dist
AutoPublishAlias: live
Runtime: python3.11
Handler: deployer.resource_handler
Timeout: 600
Policies:
- S3FullAccessPolicy:
BucketName: !Ref S3Bucket
DeploymentResource:
Type: AWS::CloudFormation::CustomResource
Condition: IsDeployWebFiles
Properties:
ServiceToken: !GetAtt SiteSource.Arn
Version: !Ref SiteSource.Version
TargetBucket: !Ref S3Bucket
Substitutions:
FilePattern: "*.html"
Values:
CONTACT_API: !Ref ContactUsFunctionApi
REGION: !Ref AWS::Region
CAPTCHA_SITE_KEY: !Ref ReCaptchaClientSecret
CANONICAL_URL: !Sub https://${HostName}.${DomainName}/
Acl: 'private'
CacheControlMaxAge: 600
S3Bucket:
Type: AWS::S3::Bucket
Properties:
WebsiteConfiguration:
IndexDocument: index.html
ErrorDocument: error.html
BucketPolicy:
Type: AWS::S3::BucketPolicy
Properties:
Bucket: !Ref S3Bucket
PolicyDocument:
Statement:
- Action: s3:GetObject
Effect: Allow
Resource: !Sub ${S3Bucket.Arn}/*
Principal:
Service: cloudfront.amazonaws.com
Condition:
StringEquals:
AWS:SourceArn: !Sub arn:aws:cloudfront::${AWS::AccountId}:distribution/${CloudFrontDistribution}
- Effect: Deny
Principal: '*'
Action: 's3:*'
Resource:
- !Sub ${S3Bucket.Arn}/*
- !GetAtt S3Bucket.Arn
Condition:
Bool:
AWS:SecureTransport: false
SSLCertificate:
Type: AWS::CertificateManager::Certificate
Properties:
DomainName: !Sub ${HostName}.${DomainName}
DomainValidationOptions:
- DomainName: !Sub ${HostName}.${DomainName}
HostedZoneId: !Ref HostedZoneId
ValidationMethod: DNS
CloudFrontDistributionOriginAccessControl:
Type: AWS::CloudFront::OriginAccessControl
Properties:
OriginAccessControlConfig:
Description: Access control for CloudFront distribution
Name: !Sub ${AWS::StackName}-access-control
OriginAccessControlOriginType: s3
SigningBehavior: always
SigningProtocol: sigv4
CloudFrontDistribution:
Type: AWS::CloudFront::Distribution
Properties:
DistributionConfig:
Origins:
- DomainName: !GetAtt S3Bucket.DomainName
Id: !Ref S3Bucket
OriginAccessControlId: !GetAtt CloudFrontDistributionOriginAccessControl.Id
S3OriginConfig:
OriginAccessIdentity: ''
Enabled: 'true'
HttpVersion: http2
Aliases:
- !Sub ${HostName}.${DomainName}
DefaultCacheBehavior:
AllowedMethods:
- GET
- HEAD
TargetOriginId: !Ref S3Bucket
ForwardedValues:
QueryString: 'false'
Cookies:
Forward: none
ViewerProtocolPolicy: redirect-to-https
LambdaFunctionAssociations:
- EventType: origin-request
LambdaFunctionARN: !If [IsUsEast1, !Ref CloudFrontS3IndexHtml.Version, !Ref EdgeLambdaArn]
ViewerCertificate:
AcmCertificateArn: !If [IsUsEast1, !Ref SSLCertificate, !Ref SSLCertificateArn]
SslSupportMethod: sni-only
CustomErrorResponses:
- ErrorCode: 403
ResponseCode: 404
ResponsePagePath: /404.html
ErrorCachingMinTTL: 300
DNSRecord:
Type: AWS::Route53::RecordSetGroup
Properties:
HostedZoneId: !Ref HostedZoneId
RecordSets:
- Name: !Sub ${HostName}.${DomainName}.
Type: A
AliasTarget:
HostedZoneId: Z2FDTNDATAQYW2
DNSName: !GetAtt CloudFrontDistribution.DomainName
DeployUser:
Type: AWS::IAM::User
Properties:
UserName: !Sub ${AWS::StackName}-deploy
Path: "/"
Policies:
- PolicyName: cloudfront-s3-readwrite
PolicyDocument:
Version: '2012-10-17'
Statement:
- Effect: Allow
Action:
- cloudfront:CreateInvalidation
Resource:
- "*"
- Effect: Allow
Action:
- s3:ListBucket
Resource: !Sub arn:aws:s3:::${S3Bucket}
- Effect: Allow
Action:
- s3:DeleteObject
- s3:GetObject
- s3:GetObjectAcl
- s3:PutObject
- s3:PutObjectAcl
Resource: !Sub arn:aws:s3:::${S3Bucket}/*
Outputs:
ApiUrl:
Description: URL of your API endpoint
Value: !Sub https://${ContactUsFunctionApi}.execute-api.${AWS::Region}.amazonaws.com/Prod/
CloudFrontDistributionId:
Description: CloudFront Distribution ID
Value: !Ref CloudFrontDistribution
IAMUser:
Description: IAM User with permission to deploy
Value: !Ref DeployUser
S3Bucket:
Description: S3 Bucket
Value: !Ref S3Bucket