@kensio/yulin 1.23.0 → 1.23.1
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.
- package/dist/service/cloudfront/controller/dependency/sim-cf-controller-dependency.js +6 -3
- package/dist/service/cloudfront/controller/sim-cloudfront-request-pipeline.js +2 -1
- package/dist/service/cloudfront/controller/web-acl/sim-cf-web-acl-guard.d.ts +25 -3
- package/dist/service/cloudfront/controller/web-acl/sim-cf-web-acl-guard.js +35 -6
- package/dist/service/wafv2/evaluate/sim-waf-blocked-response.d.ts +12 -0
- package/dist/service/wafv2/evaluate/sim-waf-blocked-response.js +1 -0
- package/dist/service/wafv2/web-acl/sim-waf-action-input.js +1 -0
- package/docs/services/cloudfront/README.md +17 -1
- package/docs/services/wafv2/README.md +7 -1
- package/package.json +1 -1
|
@@ -29,6 +29,10 @@ export class SimCloudFrontControllerDependenciesFactory {
|
|
|
29
29
|
new DefaultSimCloudFrontBehaviorResolver();
|
|
30
30
|
const originFetcher = properties.originFetcher ?? new SimCloudFrontOriginFetcher();
|
|
31
31
|
const edgeFunctions = new SimAwsCfEdgeFunctions(simAws);
|
|
32
|
+
// A request the web ACL blocks with WAF's default 403 gets the same custom
|
|
33
|
+
// error response an Origin's 403 would, so the one responder serves both.
|
|
34
|
+
const customErrorResponder = properties.customErrorResponder ??
|
|
35
|
+
new SimCfCustomErrorResponder({ behaviourResolver, originFetcher });
|
|
32
36
|
return {
|
|
33
37
|
distroRouter: properties.distroRouter ??
|
|
34
38
|
new DefaultSimCloudFrontDistroRouter({
|
|
@@ -36,14 +40,13 @@ export class SimCloudFrontControllerDependenciesFactory {
|
|
|
36
40
|
cloudFrontRegistry,
|
|
37
41
|
}),
|
|
38
42
|
webAclGuard: properties.webAclGuard ??
|
|
39
|
-
new SimCfWebAclGuard(makeSimCfWebAclResolver(simAws)),
|
|
43
|
+
new SimCfWebAclGuard(makeSimCfWebAclResolver(simAws), customErrorResponder),
|
|
40
44
|
behaviourResolver,
|
|
41
45
|
cffApplicator: properties.cffApplicator ?? new SimCffApplicator(),
|
|
42
46
|
edgeApplicator: properties.edgeApplicator ??
|
|
43
47
|
new SimLambdaEdgeApplicator({ edgeFunctions }),
|
|
44
48
|
contentStage: new SimCfContentStage(new SimCfOriginStage(originFetcher, properties.edgeOriginApplicator ??
|
|
45
|
-
new SimLambdaEdgeOriginApplicator({ edgeFunctions })),
|
|
46
|
-
new SimCfCustomErrorResponder({ behaviourResolver, originFetcher })),
|
|
49
|
+
new SimLambdaEdgeOriginApplicator({ edgeFunctions })), customErrorResponder),
|
|
47
50
|
responseHeadersApplicator: properties.responseHeadersApplicator ??
|
|
48
51
|
new SimCfResponseHeadersApplicator(),
|
|
49
52
|
};
|
|
@@ -44,7 +44,8 @@ export class SimCloudFrontRequestPipeline {
|
|
|
44
44
|
// Put the request through the Distribution's web ACL, if it has one.
|
|
45
45
|
// CloudFront asks WAF before any content handling, so a blocked request is
|
|
46
46
|
// answered at the edge without a Behavior, a CloudFront Function or the
|
|
47
|
-
// Origin ever seeing it.
|
|
47
|
+
// Origin ever seeing it. Its 403 still goes through the Distribution's
|
|
48
|
+
// custom error responses, unless the block action named its own response.
|
|
48
49
|
const webAclResult = await this.stages.webAclGuard.apply(requestReference, distro);
|
|
49
50
|
if (webAclResult instanceof Response) {
|
|
50
51
|
return webAclResult;
|
|
@@ -1,17 +1,26 @@
|
|
|
1
1
|
import type { SimCloudFrontDistribution } from "../../distribution/sim-cloudfront-distribution.js";
|
|
2
2
|
import type { SimCfWebAclResolver } from "../../web-acl/sim-cf-web-acl.js";
|
|
3
|
+
import type { SimCfCustomErrorResponder } from "../error/sim-cf-custom-error-responder.js";
|
|
3
4
|
/**
|
|
4
5
|
* Puts a request through the web ACL a Distribution names, before anything
|
|
5
6
|
* else has a look at it.
|
|
6
7
|
*
|
|
7
8
|
* CloudFront asks WAF ahead of every content-handling stage, so a blocked
|
|
8
9
|
* request never reaches a viewer-request CloudFront Function, a cache
|
|
9
|
-
* Behavior, a response headers policy or the Origin.
|
|
10
|
-
*
|
|
10
|
+
* Behavior, a response headers policy or the Origin.
|
|
11
|
+
*
|
|
12
|
+
* A blocked request is answered with the custom response its block action
|
|
13
|
+
* names, where it names one. Otherwise WAF hands CloudFront its default 403,
|
|
14
|
+
* and CloudFront treats that like a 403 from the Origin: a custom error
|
|
15
|
+
* response the Distribution configures for 403 replaces it. CloudFront cannot
|
|
16
|
+
* tell the two 403s apart, so one rule covers both.
|
|
17
|
+
*
|
|
18
|
+
* https://docs.aws.amazon.com/waf/latest/developerguide/cloudfront-waf-use-cases.html
|
|
11
19
|
*/
|
|
12
20
|
export declare class SimCfWebAclGuard {
|
|
13
21
|
private readonly resolveWebAcl;
|
|
14
|
-
|
|
22
|
+
private readonly customErrorResponder;
|
|
23
|
+
constructor(resolveWebAcl: SimCfWebAclResolver, customErrorResponder: SimCfCustomErrorResponder);
|
|
15
24
|
/**
|
|
16
25
|
* Answer with the request to carry on with, or the response a blocked
|
|
17
26
|
* request gets.
|
|
@@ -21,4 +30,17 @@ export declare class SimCfWebAclGuard {
|
|
|
21
30
|
* request handling is for.
|
|
22
31
|
*/
|
|
23
32
|
apply(request: Request, distribution: SimCloudFrontDistribution): Promise<Request | Response>;
|
|
33
|
+
/**
|
|
34
|
+
* The response a blocked request gets.
|
|
35
|
+
*
|
|
36
|
+
* A custom response from the block action takes precedence over anything
|
|
37
|
+
* the Distribution configures, whatever its status. WAF's default 403 goes
|
|
38
|
+
* through the Distribution's custom error responses instead.
|
|
39
|
+
*
|
|
40
|
+
* The answer is not stored in the Distribution's cache. WAF decides every
|
|
41
|
+
* request before the cache is consulted, so a blocked response stored under
|
|
42
|
+
* the request's cache key would only ever be served to a request WAF had
|
|
43
|
+
* already allowed.
|
|
44
|
+
*/
|
|
45
|
+
private blockedResponse;
|
|
24
46
|
}
|
|
@@ -6,13 +6,22 @@ import { SimCloudFrontInvalidWebAclId } from "../../error/sim-cloudfront.error.j
|
|
|
6
6
|
*
|
|
7
7
|
* CloudFront asks WAF ahead of every content-handling stage, so a blocked
|
|
8
8
|
* request never reaches a viewer-request CloudFront Function, a cache
|
|
9
|
-
* Behavior, a response headers policy or the Origin.
|
|
10
|
-
*
|
|
9
|
+
* Behavior, a response headers policy or the Origin.
|
|
10
|
+
*
|
|
11
|
+
* A blocked request is answered with the custom response its block action
|
|
12
|
+
* names, where it names one. Otherwise WAF hands CloudFront its default 403,
|
|
13
|
+
* and CloudFront treats that like a 403 from the Origin: a custom error
|
|
14
|
+
* response the Distribution configures for 403 replaces it. CloudFront cannot
|
|
15
|
+
* tell the two 403s apart, so one rule covers both.
|
|
16
|
+
*
|
|
17
|
+
* https://docs.aws.amazon.com/waf/latest/developerguide/cloudfront-waf-use-cases.html
|
|
11
18
|
*/
|
|
12
19
|
export class SimCfWebAclGuard {
|
|
13
20
|
resolveWebAcl;
|
|
14
|
-
|
|
21
|
+
customErrorResponder;
|
|
22
|
+
constructor(resolveWebAcl, customErrorResponder) {
|
|
15
23
|
this.resolveWebAcl = resolveWebAcl;
|
|
24
|
+
this.customErrorResponder = customErrorResponder;
|
|
16
25
|
}
|
|
17
26
|
/**
|
|
18
27
|
* Answer with the request to carry on with, or the response a blocked
|
|
@@ -41,9 +50,29 @@ export class SimCfWebAclGuard {
|
|
|
41
50
|
body: await requestBody(request),
|
|
42
51
|
resourceType: "CLOUDFRONT",
|
|
43
52
|
});
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
53
|
+
if (decision.action === "BLOCK") {
|
|
54
|
+
return await this.blockedResponse(request, distribution, decision.blocked ?? simWafDefaultBlockedResponse());
|
|
55
|
+
}
|
|
56
|
+
return allowedRequest(request, decision);
|
|
57
|
+
}
|
|
58
|
+
/**
|
|
59
|
+
* The response a blocked request gets.
|
|
60
|
+
*
|
|
61
|
+
* A custom response from the block action takes precedence over anything
|
|
62
|
+
* the Distribution configures, whatever its status. WAF's default 403 goes
|
|
63
|
+
* through the Distribution's custom error responses instead.
|
|
64
|
+
*
|
|
65
|
+
* The answer is not stored in the Distribution's cache. WAF decides every
|
|
66
|
+
* request before the cache is consulted, so a blocked response stored under
|
|
67
|
+
* the request's cache key would only ever be served to a request WAF had
|
|
68
|
+
* already allowed.
|
|
69
|
+
*/
|
|
70
|
+
async blockedResponse(request, distribution, blocked) {
|
|
71
|
+
const response = simWafBlockedHttpResponse(blocked);
|
|
72
|
+
if (blocked.isCustom) {
|
|
73
|
+
return response;
|
|
74
|
+
}
|
|
75
|
+
return await this.customErrorResponder.apply(request, distribution, response);
|
|
47
76
|
}
|
|
48
77
|
}
|
|
49
78
|
/**
|
|
@@ -7,6 +7,18 @@ export interface SimWafBlockedResponse {
|
|
|
7
7
|
readonly contentType: string;
|
|
8
8
|
readonly body: string;
|
|
9
9
|
readonly headers: readonly SimWafHeader[];
|
|
10
|
+
/**
|
|
11
|
+
* Whether the block action named a `CustomResponse` of its own.
|
|
12
|
+
*
|
|
13
|
+
* A fronting service treats the two differently. A custom response goes to
|
|
14
|
+
* the client exactly as the rule describes it, and the service's own error
|
|
15
|
+
* handling has no say in it. WAF's default 403 is handed to the service as
|
|
16
|
+
* any other 403 would be, so a CloudFront custom error response for 403
|
|
17
|
+
* replaces it.
|
|
18
|
+
*
|
|
19
|
+
* https://docs.aws.amazon.com/waf/latest/developerguide/customizing-the-response-for-blocked-requests.html
|
|
20
|
+
*/
|
|
21
|
+
readonly isCustom: boolean;
|
|
10
22
|
}
|
|
11
23
|
/**
|
|
12
24
|
* The body a block action with no custom response of its own answers with.
|
|
@@ -18,6 +18,7 @@ export function simWafBlockedResponse(customResponse, bodies) {
|
|
|
18
18
|
contentType: body?.contentType ?? fallback.contentType,
|
|
19
19
|
body: body?.content ?? fallback.body,
|
|
20
20
|
headers: simWafResponseHeaders(customResponse.ResponseHeaders),
|
|
21
|
+
isCustom: true,
|
|
21
22
|
};
|
|
22
23
|
}
|
|
23
24
|
/**
|
|
@@ -260,6 +260,11 @@ Origin again. A rule carrying it alone, with no `ResponsePagePath`, configures e
|
|
|
260
260
|
status the Distribution serves no page for. See
|
|
261
261
|
[What a Distribution stores](#what-a-distribution-stores).
|
|
262
262
|
|
|
263
|
+
A request the Distribution's [web ACL](#web-acls) blocks gets the custom error response for 403
|
|
264
|
+
as well. CloudFront cannot tell WAF's 403 from the Origin's, so a site mapping 403 to its not-found
|
|
265
|
+
page serves that page to a blocked request too. A block action with a `CustomResponse` of its own
|
|
266
|
+
is the exception (see [Web ACLs](#web-acls)).
|
|
267
|
+
|
|
263
268
|
## Serve simulated CloudFront on localhost
|
|
264
269
|
|
|
265
270
|
Use `serveSimAws` to send HTTP requests through the simulated distribution on localhost.
|
|
@@ -1846,7 +1851,7 @@ the site serves from the Origin (see [Limitations](#limitations)).
|
|
|
1846
1851
|
|
|
1847
1852
|
A Distribution can put a WAFv2 web ACL in front of everything it serves. Name the web ACL's ARN in
|
|
1848
1853
|
`WebACLId` and the Distribution evaluates it against every request that arrives. A request the web
|
|
1849
|
-
ACL blocks
|
|
1854
|
+
ACL blocks is answered at the edge. A request it allows carries on to the cache Behavior and the
|
|
1850
1855
|
Origin.
|
|
1851
1856
|
|
|
1852
1857
|
CloudFront takes its web ACL this way. WAFv2's `AssociateWebACL` covers the regional resource types.
|
|
@@ -1859,6 +1864,17 @@ simulation never created, is refused with `InvalidWebACLId` at `CreateDistributi
|
|
|
1859
1864
|
The web ACL decides before any other stage sees the request. A blocked request never reaches a
|
|
1860
1865
|
viewer-request CloudFront Function, a cache Behavior, a response headers policy or the Origin.
|
|
1861
1866
|
|
|
1867
|
+
What a blocked request gets depends on the block action. A `CustomResponse` on the action is sent
|
|
1868
|
+
as the rule describes it, whatever its status, and the Distribution's `CustomErrorResponses` have no
|
|
1869
|
+
say. With no `CustomResponse`, WAF answers 403 and the Distribution treats it as it treats a 403
|
|
1870
|
+
from the Origin. A custom error response for 403 with a `ResponsePagePath` replaces it with the
|
|
1871
|
+
response page and its `ResponseCode`. Without one, the viewer gets WAF's 403. The order is the one
|
|
1872
|
+
[AWS documents for blocked requests](https://docs.aws.amazon.com/waf/latest/developerguide/customizing-the-response-for-blocked-requests.html).
|
|
1873
|
+
|
|
1874
|
+
A blocked request's answer is never stored in the Distribution's cache, so `ErrorCachingMinTTL`
|
|
1875
|
+
has no effect on it. The next viewer to ask for the same URL is answered by WAF's decision about
|
|
1876
|
+
their own request.
|
|
1877
|
+
|
|
1862
1878
|
A CloudFormation Distribution naming a web ACL this simulation does not hold deploys without one.
|
|
1863
1879
|
The `WebACLId` lands on `stack.ignoredProperties` and every request is served, including the ones
|
|
1864
1880
|
the web ACL would have decided. A template naming a web ACL from a real account is ordinary, and a
|
|
@@ -1096,9 +1096,15 @@ its assets are outside the simulation.
|
|
|
1096
1096
|
## Protecting a CloudFront distribution
|
|
1097
1097
|
|
|
1098
1098
|
A simulated CloudFront distribution names its web ACL in `WebACLId` on its `DistributionConfig`,
|
|
1099
|
-
and evaluates it against every request that reaches the distribution. A blocked request
|
|
1099
|
+
and evaluates it against every request that reaches the distribution. A blocked request is answered
|
|
1100
1100
|
before a cache behaviour, a viewer-request CloudFront Function or the origin sees it.
|
|
1101
1101
|
|
|
1102
|
+
WAF's default 403 goes through the distribution's custom error responses, as a 403 from the origin
|
|
1103
|
+
would. A distribution mapping 403 to a not-found page serves that page, with its `ResponseCode`, to
|
|
1104
|
+
a request the web ACL blocked. A block action with a `CustomResponse` takes precedence. Its status
|
|
1105
|
+
and body reach the viewer unchanged, even when the distribution has a custom error response for the
|
|
1106
|
+
same status.
|
|
1107
|
+
|
|
1102
1108
|
CloudFront is associated this way and not through `AssociateWebACL`, which real WAF keeps for the
|
|
1103
1109
|
regional resource types. The ARN has to name a `CLOUDFRONT` [scope](#scopes) web ACL. See
|
|
1104
1110
|
[web ACLs in the CloudFront docs](https://yulinsim.dev/services/cloudfront/#web-acls) for the whole example.
|
package/package.json
CHANGED