@kensio/yulin 1.22.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/serve/controller/sim-service-controller.d.ts +6 -0
- package/dist/serve/controller/sim-service-controller.js +7 -0
- package/dist/serve/http/request/sim-aws-request-authenticator.js +3 -0
- package/dist/service/apigateway/serve/sim-api-gateway-controller.js +1 -0
- package/dist/service/apigateway/serve/sim-rest-api-web-acl-inspection.d.ts +2 -0
- package/dist/service/apigateway/serve/sim-rest-api-web-acl-inspection.js +1 -0
- 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/cognito/serve/sim-cognito-controller.js +4 -3
- package/dist/service/cognito/serve/sim-cognito-domain-controller.js +2 -0
- package/dist/service/cognito/serve/sim-cognito-web-acl-inspection.d.ts +2 -0
- package/dist/service/cognito/serve/sim-cognito-web-acl-inspection.js +1 -0
- package/dist/service/iam/index.d.ts +1 -0
- package/dist/service/iam/index.js +1 -0
- package/dist/service/iam/request/error/sim-aws-request-auth.error.d.ts +1 -1
- package/dist/service/iam/request/error/sim-aws-request-auth.error.js +1 -1
- package/dist/service/iam/request/sim-aws-control-headers.d.ts +2 -1
- package/dist/service/iam/request/sim-aws-control-headers.js +4 -1
- package/dist/service/iam/request/sim-aws-source-ip-header.d.ts +19 -0
- package/dist/service/iam/request/sim-aws-source-ip-header.js +32 -0
- package/dist/service/wafv2/association/sim-waf-associations.js +1 -1
- package/dist/service/wafv2/association/sim-waf-protection.d.ts +5 -0
- package/dist/service/wafv2/association/sim-waf-request-inspection.d.ts +2 -0
- package/dist/service/wafv2/association/sim-waf-request-inspection.js +7 -2
- 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/evaluate/sim-waf-evaluation-request.d.ts +5 -0
- package/dist/service/wafv2/evaluate/sim-waf-inspected-request.d.ts +12 -1
- package/dist/service/wafv2/evaluate/sim-waf-inspected-request.js +12 -1
- package/dist/service/wafv2/index.d.ts +2 -1
- package/dist/service/wafv2/index.js +1 -0
- package/dist/service/wafv2/managed/group/sim-waf-ip-reputation.d.ts +8 -5
- package/dist/service/wafv2/managed/group/sim-waf-ip-reputation.js +10 -5
- package/dist/service/wafv2/managed/sim-waf-managed-address-declaration.d.ts +32 -0
- package/dist/service/wafv2/managed/sim-waf-managed-address-declaration.js +52 -0
- package/dist/service/wafv2/managed/sim-waf-managed-address-range.d.ts +21 -0
- package/dist/service/wafv2/managed/sim-waf-managed-address-range.js +73 -0
- package/dist/service/wafv2/managed/sim-waf-managed-rule-groups.d.ts +7 -0
- package/dist/service/wafv2/managed/sim-waf-managed-rule-groups.js +15 -0
- package/dist/service/wafv2/managed/sim-waf-managed-rule.type.d.ts +5 -0
- package/dist/service/wafv2/managed/sim-waf-managed-rules.d.ts +27 -1
- package/dist/service/wafv2/managed/sim-waf-managed-rules.js +33 -13
- package/dist/service/wafv2/sim-wafv2.js +2 -1
- package/dist/service/wafv2/statement/sim-waf-rate-based-input.d.ts +5 -4
- package/dist/service/wafv2/statement/sim-waf-rate-based-input.js +6 -6
- package/dist/service/wafv2/web-acl/sim-waf-action-input.js +1 -0
- package/docs/services/cloudfront/README.md +17 -1
- package/docs/services/iam/README.md +6 -0
- package/docs/services/wafv2/README.md +112 -15
- package/package.json +3 -3
|
@@ -282,10 +282,11 @@ lets evaluation continue, the way it does for every other statement kind.
|
|
|
282
282
|
window is measured against [simulated time](https://yulinsim.dev/time/), so `advanceBy` past it drops
|
|
283
283
|
what the rule counted.
|
|
284
284
|
|
|
285
|
-
`AggregateKeyType` is `IP` or `CONSTANT`. `IP` counts each client address on its own.
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
285
|
+
`AggregateKeyType` is `IP` or `CONSTANT`. `IP` counts each client address on its own. A request
|
|
286
|
+
comes from `127.0.0.1` unless it names another address (see
|
|
287
|
+
[Where a request comes from](#where-a-request-comes-from)). A test that names none has one client for
|
|
288
|
+
the whole simulation. That is the case a rate limiting test is usually written about (one client,
|
|
289
|
+
sending until the rule trips). `CONSTANT` counts every request the statement sees
|
|
289
290
|
together, and AWS requires a `ScopeDownStatement` alongside it to say which requests those are.
|
|
290
291
|
|
|
291
292
|
A `ScopeDownStatement` narrows what the rule counts. Every statement kind in
|
|
@@ -463,17 +464,103 @@ are.
|
|
|
463
464
|
|
|
464
465
|
### Groups that read the caller
|
|
465
466
|
|
|
466
|
-
The IP reputation, anonymous IP and Bot Control groups decide by who sent a request
|
|
467
|
-
|
|
468
|
-
labels the request, takes the rule's documented
|
|
469
|
-
read the request do.
|
|
467
|
+
The IP reputation, anonymous IP and Bot Control groups decide by who sent a request. AWS publishes
|
|
468
|
+
their rule names, actions and labels, and none of the address lists or bot signatures behind them.
|
|
469
|
+
Each of their rules is declared-only. The group labels the request, takes the rule's documented
|
|
470
|
+
action and honours overrides, as the groups that read the request do.
|
|
470
471
|
|
|
471
472
|
`AWSManagedRulesAmazonIpReputationList` holds `AWSManagedIPReputationList` and
|
|
472
473
|
`AWSManagedReconnaissanceList`, which block, and `AWSManagedIPDDoSList`, which counts as AWS ships
|
|
473
474
|
it. `AWSManagedRulesAnonymousIpList` holds `AnonymousIPList` (VPNs, proxies and Tor) and
|
|
474
475
|
`HostingProviderIPList` (hosting and cloud providers other than AWS), which both block. A test
|
|
475
|
-
declares
|
|
476
|
-
|
|
476
|
+
declares which addresses those five rules flag, and sends requests from them.
|
|
477
|
+
|
|
478
|
+
#### Where a request comes from
|
|
479
|
+
|
|
480
|
+
A request reaches this simulation in process or over loopback, and comes from `127.0.0.1`. The
|
|
481
|
+
`x-sim-aws-source-ip` header names another client address (one IPv4 or IPv6 address). It works
|
|
482
|
+
through `SimAwsHttp` and `serveSimAws` alike, and it is stripped before the request reaches the
|
|
483
|
+
simulated service, as `x-sim-aws-caller` is. A value that is no address is refused with a 400 and
|
|
484
|
+
`InvalidRequestCaller`. `evaluateRequest` takes the address as `sourceIp`.
|
|
485
|
+
|
|
486
|
+
The address reaches the web ACL in front of a Cognito user pool or a REST API stage. The IP
|
|
487
|
+
reputation and anonymous IP rules read it, and so does a rate limit aggregating on `IP`.
|
|
488
|
+
|
|
489
|
+
`managedRules().onAddress` says which of those rules flag one address or a CIDR range. Only the
|
|
490
|
+
rules of the IP reputation and anonymous IP groups can be declared by address, and a rule of any
|
|
491
|
+
other group is refused. Declaring the same range again replaces it. An address inside two declared
|
|
492
|
+
ranges is flagged by the rules of both, and a match declared for the request's path with
|
|
493
|
+
`onRequest` applies beside them.
|
|
494
|
+
|
|
495
|
+
```typescript sim-wafv2-anonymous-ip-list
|
|
496
|
+
/**
|
|
497
|
+
* Blocking sign-ups from a Tor exit range with the anonymous IP list.
|
|
498
|
+
*/
|
|
499
|
+
|
|
500
|
+
import { CreateWebACLCommand } from "@aws-sdk/client-wafv2";
|
|
501
|
+
|
|
502
|
+
import { SimAws } from "@kensio/yulin";
|
|
503
|
+
|
|
504
|
+
const waf = new SimAws().wafV2();
|
|
505
|
+
|
|
506
|
+
const visibility = {
|
|
507
|
+
SampledRequestsEnabled: false,
|
|
508
|
+
CloudWatchMetricsEnabled: false,
|
|
509
|
+
MetricName: "pool",
|
|
510
|
+
};
|
|
511
|
+
|
|
512
|
+
const created = await waf.createWebAcl(
|
|
513
|
+
new CreateWebACLCommand({
|
|
514
|
+
Name: "pool-acl",
|
|
515
|
+
Scope: "REGIONAL",
|
|
516
|
+
DefaultAction: { Allow: {} },
|
|
517
|
+
VisibilityConfig: visibility,
|
|
518
|
+
Rules: [
|
|
519
|
+
{
|
|
520
|
+
Name: "anonymous-ip",
|
|
521
|
+
Priority: 0,
|
|
522
|
+
OverrideAction: { None: {} },
|
|
523
|
+
Statement: {
|
|
524
|
+
ManagedRuleGroupStatement: {
|
|
525
|
+
VendorName: "AWS",
|
|
526
|
+
Name: "AWSManagedRulesAnonymousIpList",
|
|
527
|
+
},
|
|
528
|
+
},
|
|
529
|
+
VisibilityConfig: { ...visibility, MetricName: "anonymous-ip" },
|
|
530
|
+
},
|
|
531
|
+
],
|
|
532
|
+
}),
|
|
533
|
+
);
|
|
534
|
+
|
|
535
|
+
waf.managedRules().onAddress("185.220.101.0/24", {
|
|
536
|
+
matches: ["AnonymousIPList"],
|
|
537
|
+
});
|
|
538
|
+
|
|
539
|
+
const signUp = (sourceIp: string): string =>
|
|
540
|
+
waf.evaluateRequest({
|
|
541
|
+
webAclArn: created.Summary!.ARN,
|
|
542
|
+
request: new Request("https://myapp-login.example.com/signup", {
|
|
543
|
+
headers: { "user-agent": "Mozilla/5.0" },
|
|
544
|
+
}),
|
|
545
|
+
sourceIp,
|
|
546
|
+
}).action;
|
|
547
|
+
|
|
548
|
+
// "BLOCK"
|
|
549
|
+
console.log(signUp("185.220.101.7"));
|
|
550
|
+
|
|
551
|
+
// "ALLOW"
|
|
552
|
+
console.log(signUp("203.0.113.9"));
|
|
553
|
+
```
|
|
554
|
+
|
|
555
|
+
A request over HTTP names its address in the header instead:
|
|
556
|
+
|
|
557
|
+
```text
|
|
558
|
+
POST /signup HTTP/1.1
|
|
559
|
+
Host: myapp-login.auth.eu-west-2.amazoncognito.com
|
|
560
|
+
x-sim-aws-source-ip: 185.220.101.7
|
|
561
|
+
```
|
|
562
|
+
|
|
563
|
+
The other kinds of statement that read the address are still held (see [Held input](#held-input)).
|
|
477
564
|
|
|
478
565
|
Bot Control labels a request by the bot that sent it, and a verified bot is labelled and matches no
|
|
479
566
|
rule. A test declares the bot.
|
|
@@ -865,6 +952,9 @@ and records no message.
|
|
|
865
952
|
|
|
866
953
|
The pages are usually the point. `/signup`, `/confirm` and `/forgotPassword` are the ones that
|
|
867
954
|
create an account or send an email, and a real web ACL on a user pool is usually written for them.
|
|
955
|
+
A request to them can name the client it comes from in the `x-sim-aws-source-ip` header, for the
|
|
956
|
+
anonymous IP list and the IP reputation list to decide on (see
|
|
957
|
+
[Where a request comes from](#where-a-request-comes-from)).
|
|
868
958
|
|
|
869
959
|
```typescript sim-wafv2-cognito-user-pool
|
|
870
960
|
/**
|
|
@@ -1006,9 +1096,15 @@ its assets are outside the simulation.
|
|
|
1006
1096
|
## Protecting a CloudFront distribution
|
|
1007
1097
|
|
|
1008
1098
|
A simulated CloudFront distribution names its web ACL in `WebACLId` on its `DistributionConfig`,
|
|
1009
|
-
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
|
|
1010
1100
|
before a cache behaviour, a viewer-request CloudFront Function or the origin sees it.
|
|
1011
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
|
+
|
|
1012
1108
|
CloudFront is associated this way and not through `AssociateWebACL`, which real WAF keeps for the
|
|
1013
1109
|
regional resource types. The ARN has to name a `CLOUDFRONT` [scope](#scopes) web ACL. See
|
|
1014
1110
|
[web ACLs in the CloudFront docs](https://yulinsim.dev/services/cloudfront/#web-acls) for the whole example.
|
|
@@ -1537,9 +1633,10 @@ where AWS blocks every address outside the list and the simulation blocks none.
|
|
|
1537
1633
|
|
|
1538
1634
|
A rule is held for any of these statement kinds:
|
|
1539
1635
|
|
|
1540
|
-
- `IPSetReferenceStatement`, `GeoMatchStatement` and `AsnMatchStatement`.
|
|
1541
|
-
|
|
1542
|
-
|
|
1636
|
+
- `IPSetReferenceStatement`, `GeoMatchStatement` and `AsnMatchStatement`. A request has a client
|
|
1637
|
+
address (see [Where a request comes from](#where-a-request-comes-from)), and these statements are
|
|
1638
|
+
not yet written to read it. A country or an ASN would also need an address database the simulation
|
|
1639
|
+
does not have.
|
|
1543
1640
|
- `SqliMatchStatement` and `XssMatchStatement`. AWS publishes no description of the detection they
|
|
1544
1641
|
run.
|
|
1545
1642
|
- `RuleGroupReferenceStatement`. A rule group of your own is a resource in its own right, and none
|
|
@@ -1551,7 +1648,7 @@ A rule is held for any of these statement kinds:
|
|
|
1551
1648
|
|
|
1552
1649
|
A `RateBasedStatement` is evaluated (see [Rate limiting](#rate-limiting)). A rule using two of its
|
|
1553
1650
|
aggregation key types is held. `FORWARDED_IP` and `ForwardedIPConfig` read the address from a
|
|
1554
|
-
forwarding header,
|
|
1651
|
+
forwarding header, and are held along with the IP set statement. `CUSTOM_KEYS` and
|
|
1555
1652
|
`CustomKeys` aggregate on headers, cookies and query arguments, and are feasible and not part of
|
|
1556
1653
|
this yet. `GetRateBasedStatementManagedKeys` is not simulated.
|
|
1557
1654
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@kensio/yulin",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.23.1",
|
|
4
4
|
"description": "AWS system behaviour simulation for isolated unit testing",
|
|
5
5
|
"repository": "https://github.com/KensioSoftware/yulin",
|
|
6
6
|
"homepage": "https://yulinsim.dev/",
|
|
@@ -298,9 +298,9 @@
|
|
|
298
298
|
"execa": "^10.0.0",
|
|
299
299
|
"fta-cli": "^3.0.0",
|
|
300
300
|
"hyparquet": "^1.29.2",
|
|
301
|
-
"hyparquet-writer": "^0.
|
|
301
|
+
"hyparquet-writer": "^0.18.0",
|
|
302
302
|
"node-sql-parser": "^5.4.0",
|
|
303
|
-
"oxfmt": "^0.
|
|
303
|
+
"oxfmt": "^0.75.0",
|
|
304
304
|
"oxlint": "^1.77.0",
|
|
305
305
|
"oxlint-tsgolint": "^7.0.2001",
|
|
306
306
|
"semantic-release": "25.0.9",
|