magic-pocket-cli 0.2.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- magic_pocket_cli-0.2.0.dist-info/METADATA +14 -0
- magic_pocket_cli-0.2.0.dist-info/RECORD +65 -0
- magic_pocket_cli-0.2.0.dist-info/WHEEL +4 -0
- magic_pocket_cli-0.2.0.dist-info/entry_points.txt +2 -0
- pocket_cli/__init__.py +0 -0
- pocket_cli/cli/__init__.py +0 -0
- pocket_cli/cli/aws_auth.py +48 -0
- pocket_cli/cli/awscontainer_cli.py +328 -0
- pocket_cli/cli/cloudfront_cli.py +116 -0
- pocket_cli/cli/cloudfront_keys_cli.py +68 -0
- pocket_cli/cli/cloudfront_waf_cli.py +68 -0
- pocket_cli/cli/deploy_cli.py +274 -0
- pocket_cli/cli/destroy_cli.py +358 -0
- pocket_cli/cli/dsql_cli.py +60 -0
- pocket_cli/cli/main_cli.py +91 -0
- pocket_cli/cli/migrate_cli.py +148 -0
- pocket_cli/cli/neon_cli.py +97 -0
- pocket_cli/cli/permissions_cli.py +46 -0
- pocket_cli/cli/rds_cli.py +63 -0
- pocket_cli/cli/runtime_config_cli.py +185 -0
- pocket_cli/cli/s3_cli.py +69 -0
- pocket_cli/cli/status_cli.py +56 -0
- pocket_cli/cli/tidb_cli.py +73 -0
- pocket_cli/cli/vpc_cli.py +92 -0
- pocket_cli/cli/waf_cli.py +182 -0
- pocket_cli/django_cli.py +412 -0
- pocket_cli/mediator.py +220 -0
- pocket_cli/resources/__init__.py +0 -0
- pocket_cli/resources/aws/__init__.py +0 -0
- pocket_cli/resources/aws/builders/__init__.py +57 -0
- pocket_cli/resources/aws/builders/codebuild.py +363 -0
- pocket_cli/resources/aws/builders/depot.py +84 -0
- pocket_cli/resources/aws/builders/docker.py +34 -0
- pocket_cli/resources/aws/builders/dockerignore.py +44 -0
- pocket_cli/resources/aws/cloudformation.py +790 -0
- pocket_cli/resources/aws/ecr.py +145 -0
- pocket_cli/resources/aws/efs.py +138 -0
- pocket_cli/resources/aws/lambdahandler.py +182 -0
- pocket_cli/resources/aws/s3_utils.py +58 -0
- pocket_cli/resources/aws/state.py +74 -0
- pocket_cli/resources/awscontainer.py +265 -0
- pocket_cli/resources/cloudfront.py +491 -0
- pocket_cli/resources/cloudfront_acm.py +55 -0
- pocket_cli/resources/cloudfront_keys.py +81 -0
- pocket_cli/resources/cloudfront_waf.py +67 -0
- pocket_cli/resources/dsql.py +142 -0
- pocket_cli/resources/neon.py +353 -0
- pocket_cli/resources/rds.py +680 -0
- pocket_cli/resources/s3.py +307 -0
- pocket_cli/resources/tidb.py +298 -0
- pocket_cli/resources/upstash.py +152 -0
- pocket_cli/resources/vpc.py +67 -0
- pocket_cli/templates/cloudformation/awscontainer.yaml +516 -0
- pocket_cli/templates/cloudformation/cf_function_api_host.js +5 -0
- pocket_cli/templates/cloudformation/cf_function_spa_auth.js +28 -0
- pocket_cli/templates/cloudformation/cf_function_spa_fallback.js +8 -0
- pocket_cli/templates/cloudformation/cloudfront.yaml +309 -0
- pocket_cli/templates/cloudformation/cloudfront_acm.yaml +43 -0
- pocket_cli/templates/cloudformation/cloudfront_keys.yaml +32 -0
- pocket_cli/templates/cloudformation/cloudfront_waf.yaml +97 -0
- pocket_cli/templates/cloudformation/vpc.yaml +213 -0
- pocket_cli/templates/init/django-dotenv.env +3 -0
- pocket_cli/templates/init/django-settings.py +140 -0
- pocket_cli/templates/init/pocket.Dockerfile +26 -0
- pocket_cli/templates/init/pocket_simple.toml +31 -0
|
@@ -0,0 +1,309 @@
|
|
|
1
|
+
AWSTemplateFormatVersion: "2010-09-09"
|
|
2
|
+
Description: spa configuration for webapp
|
|
3
|
+
|
|
4
|
+
Resources:
|
|
5
|
+
OriginAccessControl:
|
|
6
|
+
Type: AWS::CloudFront::OriginAccessControl
|
|
7
|
+
Properties:
|
|
8
|
+
OriginAccessControlConfig:
|
|
9
|
+
Name: "{{ slug }}-oac"
|
|
10
|
+
OriginAccessControlOriginType: s3
|
|
11
|
+
SigningBehavior: always
|
|
12
|
+
SigningProtocol: sigv4
|
|
13
|
+
|
|
14
|
+
# {% if has_token_kvs %}
|
|
15
|
+
TokenKvs:
|
|
16
|
+
Type: AWS::CloudFront::KeyValueStore
|
|
17
|
+
Properties:
|
|
18
|
+
Name: "{{ slug }}-token-kvs"
|
|
19
|
+
Comment: "KVS for SPA token secret"
|
|
20
|
+
# {% endif %}
|
|
21
|
+
|
|
22
|
+
# {% for route in routes %}
|
|
23
|
+
# {% if route.is_spa %}
|
|
24
|
+
UrlFallbackFunction{{ route.yaml_key }}:
|
|
25
|
+
Type: AWS::CloudFront::Function
|
|
26
|
+
Properties:
|
|
27
|
+
Name: "{{ slug }}-{{ route.name }}-fallback"
|
|
28
|
+
AutoPublish: true
|
|
29
|
+
# {% if route.require_token %}
|
|
30
|
+
FunctionCode:
|
|
31
|
+
Fn::Sub:
|
|
32
|
+
- |
|
|
33
|
+
{{ function_codes[route.yaml_key] }}
|
|
34
|
+
- TokenKvs:
|
|
35
|
+
Fn::GetAtt: TokenKvs.Id
|
|
36
|
+
# {% else %}
|
|
37
|
+
FunctionCode: |
|
|
38
|
+
{{ function_codes[route.yaml_key] }}
|
|
39
|
+
# {% endif %}
|
|
40
|
+
FunctionConfig:
|
|
41
|
+
Comment: "CloudFront function for {{ route.name }}"
|
|
42
|
+
Runtime: cloudfront-js-2.0
|
|
43
|
+
# {% if route.require_token %}
|
|
44
|
+
KeyValueStoreAssociations:
|
|
45
|
+
- KeyValueStoreARN:
|
|
46
|
+
Fn::GetAtt: TokenKvs.Arn
|
|
47
|
+
# {% endif %}
|
|
48
|
+
# {% endif %}
|
|
49
|
+
# {% if route.versioning %}
|
|
50
|
+
ResponseHeadersPolicy{{ route.yaml_key }}:
|
|
51
|
+
Type: AWS::CloudFront::ResponseHeadersPolicy
|
|
52
|
+
Properties:
|
|
53
|
+
ResponseHeadersPolicyConfig:
|
|
54
|
+
Name: "{{ slug }}-{{ route.name }}-headers"
|
|
55
|
+
CustomHeadersConfig:
|
|
56
|
+
Items:
|
|
57
|
+
- Header: "cache-control"
|
|
58
|
+
Value: "public, max-age={{ route.versioned_max_age }}, immutable"
|
|
59
|
+
Override: true
|
|
60
|
+
# {% endif %}
|
|
61
|
+
# {% if route.is_deploy_hash %}
|
|
62
|
+
DeployHashStripFunction{{ route.yaml_key }}:
|
|
63
|
+
Type: AWS::CloudFront::Function
|
|
64
|
+
Properties:
|
|
65
|
+
Name: "{{ slug }}-{{ route.name }}-deploy-hash-strip"
|
|
66
|
+
AutoPublish: true
|
|
67
|
+
FunctionCode: |
|
|
68
|
+
{{ deploy_hash_function_codes[route.yaml_key] }}
|
|
69
|
+
FunctionConfig:
|
|
70
|
+
Comment: "Strip deploy hash prefix for {{ route.name }}"
|
|
71
|
+
Runtime: cloudfront-js-2.0
|
|
72
|
+
# {% endif %}
|
|
73
|
+
# {% endfor %}
|
|
74
|
+
|
|
75
|
+
# {% if has_lambda_route %}
|
|
76
|
+
ApiHostFunction:
|
|
77
|
+
Type: AWS::CloudFront::Function
|
|
78
|
+
Properties:
|
|
79
|
+
Name: "{{ slug }}-api-host"
|
|
80
|
+
AutoPublish: true
|
|
81
|
+
FunctionCode: |
|
|
82
|
+
{{ api_host_function_code }}
|
|
83
|
+
FunctionConfig:
|
|
84
|
+
Comment: "Add X-Forwarded-Host for API routes"
|
|
85
|
+
Runtime: cloudfront-js-2.0
|
|
86
|
+
# {% endif %}
|
|
87
|
+
|
|
88
|
+
CloudFrontDistribution:
|
|
89
|
+
Type: AWS::CloudFront::Distribution
|
|
90
|
+
DependsOn:
|
|
91
|
+
- OriginAccessControl
|
|
92
|
+
# {% for route in routes %}
|
|
93
|
+
# {% if route.is_spa %}
|
|
94
|
+
- UrlFallbackFunction{{ route.yaml_key }}
|
|
95
|
+
# {% endif %}
|
|
96
|
+
# {% if route.versioning %}
|
|
97
|
+
- ResponseHeadersPolicy{{ route.yaml_key }}
|
|
98
|
+
# {% endif %}
|
|
99
|
+
# {% if route.is_deploy_hash %}
|
|
100
|
+
- DeployHashStripFunction{{ route.yaml_key }}
|
|
101
|
+
# {% endif %}
|
|
102
|
+
# {% endfor %}
|
|
103
|
+
# {% if has_lambda_route %}
|
|
104
|
+
- ApiHostFunction
|
|
105
|
+
# {% endif %}
|
|
106
|
+
Properties:
|
|
107
|
+
DistributionConfig:
|
|
108
|
+
# {% if domain %}
|
|
109
|
+
Aliases:
|
|
110
|
+
- "{{ domain }}"
|
|
111
|
+
# {% endif %}
|
|
112
|
+
Enabled: true
|
|
113
|
+
Origins:
|
|
114
|
+
# {% for route in routes %}
|
|
115
|
+
# {% if not route.is_lambda %}
|
|
116
|
+
- Id: "{{ resource_prefix }}{{ route.name }}"
|
|
117
|
+
DomainName: "{{ bucket_name }}.s3.{{ s3_region }}.amazonaws.com"
|
|
118
|
+
OriginPath: "{{ route.origin_path }}"
|
|
119
|
+
OriginAccessControlId:
|
|
120
|
+
Fn::GetAtt: OriginAccessControl.Id
|
|
121
|
+
S3OriginConfig:
|
|
122
|
+
OriginAccessIdentity: "" # Leave this blank because we use OAC(Origin Access Control)
|
|
123
|
+
# {% endif %}
|
|
124
|
+
# {% endfor %}
|
|
125
|
+
# {% for handler_key, export_name in api_origins.items() %}
|
|
126
|
+
- Id: "{{ resource_prefix }}api-{{ handler_key }}"
|
|
127
|
+
DomainName:
|
|
128
|
+
Fn::ImportValue: "{{ export_name }}"
|
|
129
|
+
CustomOriginConfig:
|
|
130
|
+
OriginProtocolPolicy: https-only
|
|
131
|
+
HTTPSPort: 443
|
|
132
|
+
# {% endfor %}
|
|
133
|
+
# {% if managed_asset_files %}
|
|
134
|
+
- Id: "{{ resource_prefix }}pocket-managed"
|
|
135
|
+
DomainName: "{{ bucket_name }}.s3.{{ s3_region }}.amazonaws.com"
|
|
136
|
+
OriginPath: "/pocket_managed"
|
|
137
|
+
OriginAccessControlId:
|
|
138
|
+
Fn::GetAtt: OriginAccessControl.Id
|
|
139
|
+
S3OriginConfig:
|
|
140
|
+
OriginAccessIdentity: ""
|
|
141
|
+
# {% endif %}
|
|
142
|
+
# {% if default_route.is_lambda %}
|
|
143
|
+
DefaultCacheBehavior:
|
|
144
|
+
CachePolicyId: "4135ea2d-6df8-44a3-9df3-4b5a84be39ad" # Managed-CachingDisabled
|
|
145
|
+
OriginRequestPolicyId: "b689b0a8-53d0-40ab-baf2-68738e2966ac" # Managed-AllViewerExceptHostHeader
|
|
146
|
+
TargetOriginId: "{{ resource_prefix }}api-{{ default_route.handler }}"
|
|
147
|
+
ViewerProtocolPolicy: "redirect-to-https"
|
|
148
|
+
FunctionAssociations:
|
|
149
|
+
- EventType: viewer-request
|
|
150
|
+
FunctionARN:
|
|
151
|
+
Fn::GetAtt: ApiHostFunction.FunctionMetadata.FunctionARN
|
|
152
|
+
AllowedMethods:
|
|
153
|
+
- GET
|
|
154
|
+
- HEAD
|
|
155
|
+
- OPTIONS
|
|
156
|
+
- PUT
|
|
157
|
+
- PATCH
|
|
158
|
+
- POST
|
|
159
|
+
- DELETE
|
|
160
|
+
# {% else %}
|
|
161
|
+
DefaultCacheBehavior:
|
|
162
|
+
CachePolicyId: "658327ea-f89d-4fab-a63d-7e88639e58f6" # Managed-CachingOptimized
|
|
163
|
+
TargetOriginId: "{{ resource_prefix }}{{ default_route.name }}"
|
|
164
|
+
ViewerProtocolPolicy: "redirect-to-https"
|
|
165
|
+
# {% if default_route.is_spa %}
|
|
166
|
+
FunctionAssociations:
|
|
167
|
+
- EventType: viewer-request
|
|
168
|
+
FunctionARN:
|
|
169
|
+
Fn::GetAtt: UrlFallbackFunction{{ default_route.yaml_key }}.FunctionMetadata.FunctionARN
|
|
170
|
+
# {% endif %}
|
|
171
|
+
# {% if default_route.versioning %}
|
|
172
|
+
ResponseHeadersPolicyId:
|
|
173
|
+
Ref: ResponseHeadersPolicy{{ default_route.yaml_key }}
|
|
174
|
+
# {% endif %}
|
|
175
|
+
# {% if default_route.signed and signing_key %}
|
|
176
|
+
TrustedKeyGroups:
|
|
177
|
+
- Fn::ImportValue: "{{ export.key_group_id }}"
|
|
178
|
+
# {% endif %}
|
|
179
|
+
# {% endif %}
|
|
180
|
+
# {% if extra_s3_routes or extra_lambda_routes or managed_asset_files %}
|
|
181
|
+
CacheBehaviors:
|
|
182
|
+
# {% for route in extra_s3_routes %}
|
|
183
|
+
- CachePolicyId: "658327ea-f89d-4fab-a63d-7e88639e58f6" # Managed-CachingOptimized
|
|
184
|
+
TargetOriginId: "{{ resource_prefix }}{{ route.name }}"
|
|
185
|
+
ViewerProtocolPolicy: "redirect-to-https"
|
|
186
|
+
PathPattern: "{{ route.path_pattern }}"
|
|
187
|
+
# {% if route.is_spa %}
|
|
188
|
+
FunctionAssociations:
|
|
189
|
+
- EventType: viewer-request
|
|
190
|
+
FunctionARN:
|
|
191
|
+
Fn::GetAtt: UrlFallbackFunction{{ route.yaml_key }}.FunctionMetadata.FunctionARN
|
|
192
|
+
# {% endif %}
|
|
193
|
+
# {% if route.is_deploy_hash %}
|
|
194
|
+
FunctionAssociations:
|
|
195
|
+
- EventType: viewer-request
|
|
196
|
+
FunctionARN:
|
|
197
|
+
Fn::GetAtt: DeployHashStripFunction{{ route.yaml_key }}.FunctionMetadata.FunctionARN
|
|
198
|
+
# {% endif %}
|
|
199
|
+
# {% if route.versioning %}
|
|
200
|
+
ResponseHeadersPolicyId:
|
|
201
|
+
Ref: ResponseHeadersPolicy{{ route.yaml_key }}
|
|
202
|
+
# {% endif %}
|
|
203
|
+
# {% if route.signed and signing_key %}
|
|
204
|
+
TrustedKeyGroups:
|
|
205
|
+
- Fn::ImportValue: "{{ export.key_group_id }}"
|
|
206
|
+
# {% endif %}
|
|
207
|
+
# {% endfor %}
|
|
208
|
+
# {% for route in extra_lambda_routes %}
|
|
209
|
+
- CachePolicyId: "4135ea2d-6df8-44a3-9df3-4b5a84be39ad" # Managed-CachingDisabled
|
|
210
|
+
OriginRequestPolicyId: "b689b0a8-53d0-40ab-baf2-68738e2966ac" # Managed-AllViewerExceptHostHeader
|
|
211
|
+
TargetOriginId: "{{ resource_prefix }}api-{{ route.handler }}"
|
|
212
|
+
ViewerProtocolPolicy: "redirect-to-https"
|
|
213
|
+
PathPattern: "{{ route.path_pattern }}"
|
|
214
|
+
FunctionAssociations:
|
|
215
|
+
- EventType: viewer-request
|
|
216
|
+
FunctionARN:
|
|
217
|
+
Fn::GetAtt: ApiHostFunction.FunctionMetadata.FunctionARN
|
|
218
|
+
AllowedMethods:
|
|
219
|
+
- GET
|
|
220
|
+
- HEAD
|
|
221
|
+
- OPTIONS
|
|
222
|
+
- PUT
|
|
223
|
+
- PATCH
|
|
224
|
+
- POST
|
|
225
|
+
- DELETE
|
|
226
|
+
# {% endfor %}
|
|
227
|
+
# {% for filename in managed_asset_files %}
|
|
228
|
+
- CachePolicyId: "658327ea-f89d-4fab-a63d-7e88639e58f6" # Managed-CachingOptimized
|
|
229
|
+
TargetOriginId: "{{ resource_prefix }}pocket-managed"
|
|
230
|
+
ViewerProtocolPolicy: "redirect-to-https"
|
|
231
|
+
PathPattern: "/{{ filename }}"
|
|
232
|
+
# {% endfor %}
|
|
233
|
+
# {% endif %}
|
|
234
|
+
ViewerCertificate:
|
|
235
|
+
# {% if acm_certificate_arn %}
|
|
236
|
+
AcmCertificateArn: "{{ acm_certificate_arn }}"
|
|
237
|
+
SslSupportMethod: sni-only
|
|
238
|
+
# {% else %}
|
|
239
|
+
CloudFrontDefaultCertificate: true
|
|
240
|
+
# {% endif %}
|
|
241
|
+
# {% if waf_acl_arn %}
|
|
242
|
+
WebACLId: "{{ waf_acl_arn }}"
|
|
243
|
+
# {% endif %}
|
|
244
|
+
|
|
245
|
+
# {% if domain %}
|
|
246
|
+
DNSRecord:
|
|
247
|
+
Type: AWS::Route53::RecordSet
|
|
248
|
+
DependsOn:
|
|
249
|
+
- CloudFrontDistribution
|
|
250
|
+
Properties:
|
|
251
|
+
HostedZoneId: "{{ hosted_zone_id }}"
|
|
252
|
+
Name: "{{ domain }}"
|
|
253
|
+
Type: A
|
|
254
|
+
AliasTarget:
|
|
255
|
+
HostedZoneId: Z2FDTNDATAQYW2 # Z2FDTNDATAQYW2 is the fixed hosted zone id for cloudfront
|
|
256
|
+
DNSName:
|
|
257
|
+
Fn::GetAtt: CloudFrontDistribution.DomainName
|
|
258
|
+
# {% endif %}
|
|
259
|
+
|
|
260
|
+
# {% for rf in redirect_from %}
|
|
261
|
+
"CloudFrontDistribution{{ rf.yaml_key }}":
|
|
262
|
+
Type: AWS::CloudFront::Distribution
|
|
263
|
+
Properties:
|
|
264
|
+
DistributionConfig:
|
|
265
|
+
Aliases:
|
|
266
|
+
- "{{ rf.domain }}"
|
|
267
|
+
Enabled: true
|
|
268
|
+
Origins:
|
|
269
|
+
- Id: "redirect-from"
|
|
270
|
+
DomainName:
|
|
271
|
+
Fn::Sub: "{{ rf.bucket_website_domain }}"
|
|
272
|
+
CustomOriginConfig:
|
|
273
|
+
OriginProtocolPolicy: http-only
|
|
274
|
+
DefaultCacheBehavior:
|
|
275
|
+
CachePolicyId: "4135ea2d-6df8-44a3-9df3-4b5a84be39ad" # Managed-CachingDisabled
|
|
276
|
+
TargetOriginId: "redirect-from"
|
|
277
|
+
ViewerProtocolPolicy: "redirect-to-https"
|
|
278
|
+
ViewerCertificate:
|
|
279
|
+
AcmCertificateArn: "{{ acm_redirect_arns[rf.yaml_key] }}"
|
|
280
|
+
SslSupportMethod: sni-only
|
|
281
|
+
|
|
282
|
+
"DNSRecord{{ rf.yaml_key }}":
|
|
283
|
+
Type: AWS::Route53::RecordSet
|
|
284
|
+
DependsOn:
|
|
285
|
+
- "CloudFrontDistribution{{ rf.yaml_key }}"
|
|
286
|
+
Properties:
|
|
287
|
+
HostedZoneId: "{{ hosted_zone_id }}"
|
|
288
|
+
Name: "{{ rf.domain }}"
|
|
289
|
+
Type: A
|
|
290
|
+
AliasTarget:
|
|
291
|
+
HostedZoneId: Z2FDTNDATAQYW2 # Z2FDTNDATAQYW2 is the fixed hosted zone id for cloudfront
|
|
292
|
+
DNSName:
|
|
293
|
+
Fn::GetAtt: "CloudFrontDistribution{{ rf.yaml_key }}.DomainName"
|
|
294
|
+
# {% endfor %}
|
|
295
|
+
|
|
296
|
+
Outputs:
|
|
297
|
+
DistributionId:
|
|
298
|
+
Value:
|
|
299
|
+
Ref: CloudFrontDistribution
|
|
300
|
+
DistributionDomainName:
|
|
301
|
+
Value:
|
|
302
|
+
Fn::GetAtt: CloudFrontDistribution.DomainName
|
|
303
|
+
# {% if has_token_kvs %}
|
|
304
|
+
TokenKvsArn:
|
|
305
|
+
Value:
|
|
306
|
+
Fn::GetAtt: TokenKvs.Arn
|
|
307
|
+
Export:
|
|
308
|
+
Name: "{{ export.kvs_arn }}"
|
|
309
|
+
# {% endif %}
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
AWSTemplateFormatVersion: "2010-09-09"
|
|
2
|
+
Description: ACM certificates for CloudFront (us-east-1)
|
|
3
|
+
|
|
4
|
+
Resources:
|
|
5
|
+
# {% if domain %}
|
|
6
|
+
Certificate:
|
|
7
|
+
Type: AWS::CertificateManager::Certificate
|
|
8
|
+
Properties:
|
|
9
|
+
DomainName: "{{ domain }}"
|
|
10
|
+
DomainValidationOptions:
|
|
11
|
+
- DomainName: "{{ domain }}"
|
|
12
|
+
HostedZoneId: "{{ hosted_zone_id }}"
|
|
13
|
+
Tags:
|
|
14
|
+
- Key: Name
|
|
15
|
+
Value: "{{ resource_prefix }}cloudfront-cert"
|
|
16
|
+
ValidationMethod: DNS
|
|
17
|
+
# {% endif %}
|
|
18
|
+
|
|
19
|
+
# {% for rf in redirect_from %}
|
|
20
|
+
"Certificate{{ rf.yaml_key }}":
|
|
21
|
+
Type: AWS::CertificateManager::Certificate
|
|
22
|
+
Properties:
|
|
23
|
+
DomainName: "{{ rf.domain }}"
|
|
24
|
+
DomainValidationOptions:
|
|
25
|
+
- DomainName: "{{ rf.domain }}"
|
|
26
|
+
HostedZoneId: "{{ rf.hosted_zone_id }}"
|
|
27
|
+
Tags:
|
|
28
|
+
- Key: Name
|
|
29
|
+
Value: "{{ resource_prefix }}spa-cert-{{ rf.yaml_key }}"
|
|
30
|
+
ValidationMethod: DNS
|
|
31
|
+
# {% endfor %}
|
|
32
|
+
|
|
33
|
+
Outputs:
|
|
34
|
+
# {% if domain %}
|
|
35
|
+
CertificateArn:
|
|
36
|
+
Value:
|
|
37
|
+
Ref: Certificate
|
|
38
|
+
# {% endif %}
|
|
39
|
+
# {% for rf in redirect_from %}
|
|
40
|
+
"CertificateArn{{ rf.yaml_key }}":
|
|
41
|
+
Value:
|
|
42
|
+
Ref: "Certificate{{ rf.yaml_key }}"
|
|
43
|
+
# {% endfor %}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
AWSTemplateFormatVersion: "2010-09-09"
|
|
2
|
+
Description: CloudFront signing key resources
|
|
3
|
+
|
|
4
|
+
Resources:
|
|
5
|
+
PublicKey:
|
|
6
|
+
Type: AWS::CloudFront::PublicKey
|
|
7
|
+
Properties:
|
|
8
|
+
PublicKeyConfig:
|
|
9
|
+
Name: "{{ resource_prefix }}publickey"
|
|
10
|
+
CallerReference: "{{ resource_prefix }}publickey"
|
|
11
|
+
EncodedKey: |
|
|
12
|
+
{{ signing_public_key_pem | indent(10, first=False) }}
|
|
13
|
+
|
|
14
|
+
KeyGroup:
|
|
15
|
+
Type: AWS::CloudFront::KeyGroup
|
|
16
|
+
DependsOn:
|
|
17
|
+
- PublicKey
|
|
18
|
+
Properties:
|
|
19
|
+
KeyGroupConfig:
|
|
20
|
+
Name: "{{ resource_prefix }}keygroup"
|
|
21
|
+
Items:
|
|
22
|
+
- !Ref PublicKey
|
|
23
|
+
|
|
24
|
+
Outputs:
|
|
25
|
+
PublicKeyId:
|
|
26
|
+
Value: !Ref PublicKey
|
|
27
|
+
Export:
|
|
28
|
+
Name: "{{ export.public_key_id }}"
|
|
29
|
+
KeyGroupId:
|
|
30
|
+
Value: !Ref KeyGroup
|
|
31
|
+
Export:
|
|
32
|
+
Name: "{{ export.key_group_id }}"
|
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
AWSTemplateFormatVersion: "2010-09-09"
|
|
2
|
+
Description: WAFv2 IPSet + WebACL for CloudFront (us-east-1)
|
|
3
|
+
|
|
4
|
+
# Notes:
|
|
5
|
+
# - Scope=CLOUDFRONT requires us-east-1.
|
|
6
|
+
# - waf.enable_ip_set = true (default):
|
|
7
|
+
# - DefaultAction = Block
|
|
8
|
+
# - IPSet (Addresses=[]) + ip-allow Rule (Allow on IPSet match) を出力
|
|
9
|
+
# - 初回 deploy 直後は deny-all。`pocket waf ip add self ...` で CIDR を投入
|
|
10
|
+
# - IPSet の Addresses は CFn template 上は常に空で、CLI が side-channel
|
|
11
|
+
# 更新する仕様 (CFn 視点では常に drift だが意図的)
|
|
12
|
+
# - waf.enable_ip_set = false:
|
|
13
|
+
# - DefaultAction = Allow
|
|
14
|
+
# - IPSet / ip-allow Rule は出力しない
|
|
15
|
+
# - managed_rule_groups (必須) で「許可ベース + 怪しいリクエストのみ block」
|
|
16
|
+
|
|
17
|
+
Resources:
|
|
18
|
+
# {% if waf.enable_ip_set %}
|
|
19
|
+
IPSet:
|
|
20
|
+
Type: AWS::WAFv2::IPSet
|
|
21
|
+
Properties:
|
|
22
|
+
Name: "{{ slug }}-waf-allow"
|
|
23
|
+
Description: "CloudFront IP allowlist - managed by pocket waf ip CLI"
|
|
24
|
+
Scope: CLOUDFRONT
|
|
25
|
+
IPAddressVersion: IPV4
|
|
26
|
+
Addresses: []
|
|
27
|
+
Tags:
|
|
28
|
+
- Key: Name
|
|
29
|
+
Value: "{{ resource_prefix }}cloudfront-waf-allow"
|
|
30
|
+
# {% endif %}
|
|
31
|
+
|
|
32
|
+
WebACL:
|
|
33
|
+
Type: AWS::WAFv2::WebACL
|
|
34
|
+
Properties:
|
|
35
|
+
Name: "{{ slug }}-waf"
|
|
36
|
+
Description: "CloudFront WAF - IP allowlist plus optional managed rules"
|
|
37
|
+
Scope: CLOUDFRONT
|
|
38
|
+
DefaultAction:
|
|
39
|
+
# {% if waf.enable_ip_set %}
|
|
40
|
+
Block: {}
|
|
41
|
+
# {% else %}
|
|
42
|
+
Allow: {}
|
|
43
|
+
# {% endif %}
|
|
44
|
+
VisibilityConfig:
|
|
45
|
+
SampledRequestsEnabled: true
|
|
46
|
+
CloudWatchMetricsEnabled: true
|
|
47
|
+
MetricName: "{{ slug }}-waf"
|
|
48
|
+
Rules:
|
|
49
|
+
# {% if waf.enable_ip_set %}
|
|
50
|
+
- Name: ip-allow
|
|
51
|
+
Priority: 0
|
|
52
|
+
Action:
|
|
53
|
+
Allow: {}
|
|
54
|
+
Statement:
|
|
55
|
+
IPSetReferenceStatement:
|
|
56
|
+
Arn:
|
|
57
|
+
Fn::GetAtt: IPSet.Arn
|
|
58
|
+
VisibilityConfig:
|
|
59
|
+
SampledRequestsEnabled: true
|
|
60
|
+
CloudWatchMetricsEnabled: true
|
|
61
|
+
MetricName: "{{ slug }}-waf-ip-allow"
|
|
62
|
+
# {% endif %}
|
|
63
|
+
# {% for group_name in waf.managed_rule_groups %}
|
|
64
|
+
- Name: "managed-{{ loop.index0 }}-{{ group_name }}"
|
|
65
|
+
Priority: {{ loop.index if waf.enable_ip_set else loop.index0 }}
|
|
66
|
+
OverrideAction:
|
|
67
|
+
None: {}
|
|
68
|
+
Statement:
|
|
69
|
+
ManagedRuleGroupStatement:
|
|
70
|
+
VendorName: AWS
|
|
71
|
+
Name: "{{ group_name }}"
|
|
72
|
+
VisibilityConfig:
|
|
73
|
+
SampledRequestsEnabled: true
|
|
74
|
+
CloudWatchMetricsEnabled: true
|
|
75
|
+
MetricName: "{{ slug }}-waf-managed-{{ loop.index0 }}"
|
|
76
|
+
# {% endfor %}
|
|
77
|
+
Tags:
|
|
78
|
+
- Key: Name
|
|
79
|
+
Value: "{{ resource_prefix }}cloudfront-waf"
|
|
80
|
+
|
|
81
|
+
Outputs:
|
|
82
|
+
WebACLArn:
|
|
83
|
+
Value:
|
|
84
|
+
Fn::GetAtt: WebACL.Arn
|
|
85
|
+
# {% if waf.enable_ip_set %}
|
|
86
|
+
IPSetArn:
|
|
87
|
+
Value:
|
|
88
|
+
Fn::GetAtt: IPSet.Arn
|
|
89
|
+
# AWS::WAFv2::IPSet の Ref は "<Name>|<UUID>|<Scope>" の合成 string を返す。
|
|
90
|
+
# WAFv2 API (GetIPSet / UpdateIPSet) は UUID 単体 (36 char) を要求するので、
|
|
91
|
+
# ここでは Fn::GetAtt の Id (= UUID) を使う必要がある。
|
|
92
|
+
IPSetId:
|
|
93
|
+
Value:
|
|
94
|
+
Fn::GetAtt: IPSet.Id
|
|
95
|
+
IPSetName:
|
|
96
|
+
Value: "{{ slug }}-waf-allow"
|
|
97
|
+
# {% endif %}
|
|
@@ -0,0 +1,213 @@
|
|
|
1
|
+
AWSTemplateFormatVersion: "2010-09-09"
|
|
2
|
+
Description: vpc stack created by zerode
|
|
3
|
+
|
|
4
|
+
Resources:
|
|
5
|
+
VPC:
|
|
6
|
+
Type: AWS::EC2::VPC
|
|
7
|
+
Properties:
|
|
8
|
+
CidrBlock: 10.0.0.0/16
|
|
9
|
+
EnableDnsHostnames: true
|
|
10
|
+
EnableDnsSupport: true
|
|
11
|
+
Tags:
|
|
12
|
+
- Key: Name
|
|
13
|
+
Value: "{{ name }}"
|
|
14
|
+
|
|
15
|
+
# {% if internet_gateway %}
|
|
16
|
+
InternetGateway:
|
|
17
|
+
Type: AWS::EC2::InternetGateway
|
|
18
|
+
Properties:
|
|
19
|
+
Tags:
|
|
20
|
+
- Key: Name
|
|
21
|
+
Value: "{{ name }}"
|
|
22
|
+
|
|
23
|
+
InternetGatewayAttachment:
|
|
24
|
+
Type: AWS::EC2::VPCGatewayAttachment
|
|
25
|
+
Properties:
|
|
26
|
+
InternetGatewayId:
|
|
27
|
+
Ref: InternetGateway
|
|
28
|
+
VpcId:
|
|
29
|
+
Ref: VPC
|
|
30
|
+
|
|
31
|
+
PublicRouteTable:
|
|
32
|
+
Type: AWS::EC2::RouteTable
|
|
33
|
+
Properties:
|
|
34
|
+
VpcId:
|
|
35
|
+
Ref: VPC
|
|
36
|
+
Tags:
|
|
37
|
+
- Key: Name
|
|
38
|
+
Value: "{{ name }}-public"
|
|
39
|
+
|
|
40
|
+
DefaultPublicRoute:
|
|
41
|
+
Type: AWS::EC2::Route
|
|
42
|
+
DependsOn: InternetGatewayAttachment
|
|
43
|
+
Properties:
|
|
44
|
+
RouteTableId:
|
|
45
|
+
Ref: PublicRouteTable
|
|
46
|
+
DestinationCidrBlock: 0.0.0.0/0
|
|
47
|
+
GatewayId:
|
|
48
|
+
Ref: InternetGateway
|
|
49
|
+
|
|
50
|
+
# {% for zone in zones %}
|
|
51
|
+
PublicSubnet{{ loop.index }}:
|
|
52
|
+
Type: AWS::EC2::Subnet
|
|
53
|
+
Properties:
|
|
54
|
+
VpcId:
|
|
55
|
+
Ref: VPC
|
|
56
|
+
AvailabilityZone: "{{ zone }}"
|
|
57
|
+
CidrBlock: 10.0.1{{ loop.index0 }}.0/24
|
|
58
|
+
MapPublicIpOnLaunch: true
|
|
59
|
+
Tags:
|
|
60
|
+
- Key: Name
|
|
61
|
+
Value: "{{ name }}-public-{{ loop.index }}"
|
|
62
|
+
|
|
63
|
+
PublicSubnetRouteTableAssociation{{ loop.index }}:
|
|
64
|
+
Type: AWS::EC2::SubnetRouteTableAssociation
|
|
65
|
+
Properties:
|
|
66
|
+
RouteTableId:
|
|
67
|
+
Ref: PublicRouteTable
|
|
68
|
+
SubnetId:
|
|
69
|
+
Ref: PublicSubnet{{ loop.index }}
|
|
70
|
+
# {% endfor %}
|
|
71
|
+
# {% endif %}
|
|
72
|
+
|
|
73
|
+
# {% for zone in zones %}
|
|
74
|
+
PrivateSubnet{{ loop.index }}:
|
|
75
|
+
Type: AWS::EC2::Subnet
|
|
76
|
+
Properties:
|
|
77
|
+
VpcId:
|
|
78
|
+
Ref: VPC
|
|
79
|
+
AvailabilityZone: "{{ zone }}"
|
|
80
|
+
CidrBlock: 10.0.2{{ loop.index0 }}.0/24
|
|
81
|
+
MapPublicIpOnLaunch: false
|
|
82
|
+
Tags:
|
|
83
|
+
- Key: Name
|
|
84
|
+
Value: "{{ name }}-private-{{ loop.index }}"
|
|
85
|
+
|
|
86
|
+
# {% if private_route_table %}
|
|
87
|
+
PrivateRouteTable{{ loop.index }}:
|
|
88
|
+
Type: AWS::EC2::RouteTable
|
|
89
|
+
Properties:
|
|
90
|
+
VpcId:
|
|
91
|
+
Ref: VPC
|
|
92
|
+
Tags:
|
|
93
|
+
- Key: Name
|
|
94
|
+
Value: "{{ name }}-private-{{ loop.index }}"
|
|
95
|
+
|
|
96
|
+
PrivateSubnetRouteTableAssociation{{ loop.index }}:
|
|
97
|
+
Type: AWS::EC2::SubnetRouteTableAssociation
|
|
98
|
+
Properties:
|
|
99
|
+
RouteTableId:
|
|
100
|
+
Ref: PrivateRouteTable{{ loop.index }}
|
|
101
|
+
SubnetId:
|
|
102
|
+
Ref: PrivateSubnet{{ loop.index }}
|
|
103
|
+
# {% endif %}
|
|
104
|
+
|
|
105
|
+
# {% if nat_gateway %}
|
|
106
|
+
NATGatewayIP{{ loop.index }}:
|
|
107
|
+
Type: "AWS::EC2::EIP"
|
|
108
|
+
Properties:
|
|
109
|
+
Domain: vpc
|
|
110
|
+
Tags:
|
|
111
|
+
- Key: Name
|
|
112
|
+
Value: "{{ name }}-natgateway-{{ loop.index }}"
|
|
113
|
+
|
|
114
|
+
NATGateway{{ loop.index }}:
|
|
115
|
+
Type: AWS::EC2::NatGateway
|
|
116
|
+
Properties:
|
|
117
|
+
AllocationId:
|
|
118
|
+
Fn::GetAtt:
|
|
119
|
+
- NATGatewayIP{{ loop.index }}
|
|
120
|
+
- AllocationId
|
|
121
|
+
SubnetId:
|
|
122
|
+
Ref: PublicSubnet{{ loop.index }}
|
|
123
|
+
Tags:
|
|
124
|
+
- Key: Name
|
|
125
|
+
Value: "{{ name }}-{{ loop.index }}"
|
|
126
|
+
|
|
127
|
+
PrivateRoute{{ loop.index }}:
|
|
128
|
+
Type: AWS::EC2::Route
|
|
129
|
+
DependsOn: PrivateSubnetRouteTableAssociation{{ loop.index }}
|
|
130
|
+
Properties:
|
|
131
|
+
RouteTableId:
|
|
132
|
+
Ref: PrivateRouteTable{{ loop.index }}
|
|
133
|
+
DestinationCidrBlock: 0.0.0.0/0
|
|
134
|
+
NatGatewayId:
|
|
135
|
+
Ref: NATGateway{{ loop.index }}
|
|
136
|
+
# {% endif %}
|
|
137
|
+
# {% endfor %}
|
|
138
|
+
|
|
139
|
+
# {% if efs %}
|
|
140
|
+
EFSSecurityGroup:
|
|
141
|
+
Type: AWS::EC2::SecurityGroup
|
|
142
|
+
Properties:
|
|
143
|
+
GroupDescription: "{{ name }}-efs"
|
|
144
|
+
GroupName: "{{ name }}-efs"
|
|
145
|
+
SecurityGroupEgress:
|
|
146
|
+
- CidrIp: 0.0.0.0/0
|
|
147
|
+
Description: Allow all outbound traffic by default
|
|
148
|
+
IpProtocol: "-1"
|
|
149
|
+
Tags:
|
|
150
|
+
- Key: Name
|
|
151
|
+
Value: "{{ name }}-efs"
|
|
152
|
+
VpcId:
|
|
153
|
+
Ref: VPC
|
|
154
|
+
|
|
155
|
+
EfsAccessPoint:
|
|
156
|
+
Type: AWS::EFS::AccessPoint
|
|
157
|
+
Properties:
|
|
158
|
+
FileSystemId: "{{ resource.efs.filesystem_id }}"
|
|
159
|
+
PosixUser:
|
|
160
|
+
Uid: "1000"
|
|
161
|
+
Gid: "1000"
|
|
162
|
+
RootDirectory:
|
|
163
|
+
CreationInfo:
|
|
164
|
+
OwnerGid: "1000"
|
|
165
|
+
OwnerUid: "1000"
|
|
166
|
+
Permissions: "0777"
|
|
167
|
+
Path: "{{ efs.access_point_path }}"
|
|
168
|
+
# {% for zone in zones %}
|
|
169
|
+
MountTarget{{ loop.index }}:
|
|
170
|
+
Type: AWS::EFS::MountTarget
|
|
171
|
+
Properties:
|
|
172
|
+
FileSystemId: "{{ resource.efs.filesystem_id }}"
|
|
173
|
+
SubnetId:
|
|
174
|
+
Ref: PrivateSubnet{{ loop.index }}
|
|
175
|
+
SecurityGroups:
|
|
176
|
+
- Ref: EFSSecurityGroup
|
|
177
|
+
# {% endfor %}
|
|
178
|
+
# {% endif %}
|
|
179
|
+
|
|
180
|
+
Outputs:
|
|
181
|
+
VPC:
|
|
182
|
+
Value:
|
|
183
|
+
Ref: VPC
|
|
184
|
+
Export:
|
|
185
|
+
Name: "{{ export.vpc_id }}"
|
|
186
|
+
|
|
187
|
+
# {% for zone in zones %}
|
|
188
|
+
PrivateSubnet{{ loop.index }}:
|
|
189
|
+
Value:
|
|
190
|
+
Ref: PrivateSubnet{{ loop.index }}
|
|
191
|
+
Export:
|
|
192
|
+
Name: "{{ export.private_subnet_ }}{{ loop.index }}"
|
|
193
|
+
|
|
194
|
+
# {% if nat_gateway %}
|
|
195
|
+
NATGatewayIP{{ loop.index }}:
|
|
196
|
+
Value:
|
|
197
|
+
Ref: NATGatewayIP{{ loop.index }}
|
|
198
|
+
# {% endif %}
|
|
199
|
+
# {% endfor %}
|
|
200
|
+
|
|
201
|
+
# {% if efs %}
|
|
202
|
+
EFSAccessPointArn:
|
|
203
|
+
Value:
|
|
204
|
+
Fn::GetAtt: EfsAccessPoint.Arn
|
|
205
|
+
Export:
|
|
206
|
+
Name: "{{ export.efs_access_point_arn }}"
|
|
207
|
+
|
|
208
|
+
EFSSecurityGroup:
|
|
209
|
+
Value:
|
|
210
|
+
Ref: EFSSecurityGroup
|
|
211
|
+
Export:
|
|
212
|
+
Name: "{{ export.efs_security_group }}"
|
|
213
|
+
# {% endif %}
|