@kensio/yulin 1.21.7 → 1.21.9
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/README.md +22 -2
- package/dist/service/lambda/cfn/event-source-mapping/sim-cfn-lambda-event-source-mapping-properties.js +2 -0
- package/dist/service/lambda/cfn/event-source-mapping/sim-cfn-lambda-event-source-mapping-property-rules.js +1 -1
- package/dist/service/lambda/command/event-source-mapping/create-event-source-mapping-input.d.ts +2 -0
- package/dist/service/lambda/command/event-source-mapping/create-event-source-mapping-input.js +4 -0
- package/dist/service/lambda/command/event-source-mapping/create-event-source-mapping-refusals.js +0 -5
- package/dist/service/lambda/command/event-source-mapping/create-event-source-mapping.handler.d.ts +2 -0
- package/dist/service/lambda/command/event-source-mapping/create-event-source-mapping.handler.js +2 -0
- package/dist/service/lambda/command/event-source-mapping/sim-lambda-event-source-mapping-commands.d.ts +2 -0
- package/dist/service/lambda/destination/sim-lambda-destination-targets.d.ts +2 -1
- package/dist/service/lambda/event-source/poll/kinesis/sim-lambda-kinesis-shard-poller.d.ts +0 -4
- package/dist/service/lambda/event-source/poll/kinesis/sim-lambda-kinesis-shard-poller.js +10 -15
- package/dist/service/lambda/event-source/poll/sim-lambda-dynamodb-stream-event-source-poller.d.ts +1 -6
- package/dist/service/lambda/event-source/poll/sim-lambda-dynamodb-stream-event-source-poller.js +9 -27
- package/dist/service/lambda/event-source/poll/sim-lambda-dynamodb-stream-polling.d.ts +19 -0
- package/dist/service/lambda/event-source/poll/sim-lambda-dynamodb-stream-polling.js +27 -0
- package/dist/service/lambda/event-source/poll/sim-lambda-event-source-function.d.ts +1 -1
- package/dist/service/lambda/event-source/poll/sim-lambda-event-source-function.js +3 -1
- package/dist/service/lambda/event-source/poll/sim-lambda-stream-batch-age.d.ts +13 -0
- package/dist/service/lambda/event-source/poll/sim-lambda-stream-batch-age.js +27 -0
- package/dist/service/lambda/event-source/poll/sim-lambda-stream-batch-info.d.ts +15 -0
- package/dist/service/lambda/event-source/poll/sim-lambda-stream-batch-info.js +26 -0
- package/dist/service/lambda/event-source/poll/sim-lambda-stream-batch-outcome.d.ts +1 -0
- package/dist/service/lambda/event-source/poll/sim-lambda-stream-batch-outcome.js +7 -1
- package/dist/service/lambda/event-source/poll/sim-lambda-stream-batch-processing.d.ts +17 -0
- package/dist/service/lambda/event-source/poll/sim-lambda-stream-batch-processing.js +12 -0
- package/dist/service/lambda/event-source/poll/sim-lambda-stream-cursor.d.ts +15 -0
- package/dist/service/lambda/event-source/poll/sim-lambda-stream-cursor.js +28 -0
- package/dist/service/lambda/event-source/poll/sim-lambda-stream-expiry.d.ts +19 -0
- package/dist/service/lambda/event-source/poll/sim-lambda-stream-expiry.js +23 -0
- package/dist/service/lambda/event-source/poll/sim-lambda-stream-failure-context.d.ts +3 -0
- package/dist/service/lambda/event-source/poll/sim-lambda-stream-failure-context.js +19 -0
- package/dist/service/lambda/event-source/poll/sim-lambda-stream-failure-destination.d.ts +15 -0
- package/dist/service/lambda/event-source/poll/sim-lambda-stream-failure-destination.js +38 -0
- package/dist/service/lambda/event-source/poll/sim-lambda-stream-failure-record.d.ts +41 -0
- package/dist/service/lambda/event-source/poll/sim-lambda-stream-failure-record.js +17 -0
- package/dist/service/lambda/event-source/poll/sim-lambda-stream-progress-state.d.ts +21 -0
- package/dist/service/lambda/event-source/poll/sim-lambda-stream-progress-state.js +39 -0
- package/dist/service/lambda/event-source/poll/sim-lambda-stream-progress.d.ts +7 -37
- package/dist/service/lambda/event-source/poll/sim-lambda-stream-progress.js +22 -62
- package/dist/service/lambda/event-source/poll/sim-lambda-stream-retry.d.ts +4 -39
- package/dist/service/lambda/event-source/poll/sim-lambda-stream-retry.js +12 -64
- package/dist/service/lambda/event-source/sim-lambda-event-source-mapping.d.ts +10 -3
- package/dist/service/lambda/event-source/sim-lambda-event-source-mapping.js +12 -3
- package/dist/service/lambda/event-source/sim-lambda-stream-destination-config.d.ts +7 -0
- package/dist/service/lambda/event-source/sim-lambda-stream-destination-config.js +38 -0
- package/dist/service/lambda/event-source/stream/kinesis/sim-kinesis-event-source-streams.js +1 -0
- package/dist/service/lambda/event-source/stream/sim-dynamodb-event-source-stream-reader.js +1 -0
- package/dist/service/lambda/event-source/stream/sim-dynamodb-event-source-stream-shard.d.ts +1 -0
- package/dist/service/lambda/event-source/stream/sim-dynamodb-event-source-stream-shard.js +7 -0
- package/dist/service/lambda/event-source/stream/sim-lambda-event-source-streams.d.ts +1 -0
- package/dist/service/lambda/index.d.ts +1 -0
- package/dist/service/lambda/sim-lambda-commands.js +1 -0
- package/dist/service/ses/command/authorize/sim-ses-authorizer.d.ts +9 -0
- package/dist/service/ses/command/authorize/sim-ses-authorizer.js +18 -2
- package/dist/service/ses/command/send/sim-ses-send-email.js +2 -1
- package/docs/README.md +7 -0
- package/docs/ai-skill/README.md +6 -1
- package/docs/sdk/README.md +15 -0
- package/docs/services/acm/README.md +24 -40
- package/docs/services/apigateway/README.md +52 -71
- package/docs/services/apigatewayv2/README.md +55 -74
- package/docs/services/athena/README.md +17 -26
- package/docs/services/backup/README.md +29 -39
- package/docs/services/bedrock/README.md +38 -52
- package/docs/services/cloudformation/README.md +43 -55
- package/docs/services/cloudfront/README.md +69 -95
- package/docs/services/cloudwatch/README.md +40 -54
- package/docs/services/cognito/README.md +30 -45
- package/docs/services/dynamodb/README.md +34 -51
- package/docs/services/ecr/README.md +36 -77
- package/docs/services/ecs/README.md +26 -46
- package/docs/services/elbv2/README.md +19 -29
- package/docs/services/eventbridge/README.md +14 -18
- package/docs/services/firehose/README.md +24 -32
- package/docs/services/glue/README.md +41 -78
- package/docs/services/iam/README.md +13 -15
- package/docs/services/kinesis/README.md +53 -93
- package/docs/services/kms/README.md +22 -32
- package/docs/services/lambda/README.md +112 -85
- package/docs/services/logs/README.md +41 -50
- package/docs/services/organizations/README.md +50 -85
- package/docs/services/personalize/README.md +28 -44
- package/docs/services/rekognition/README.md +26 -38
- package/docs/services/route53/README.md +17 -17
- package/docs/services/s3/README.md +47 -51
- package/docs/services/scheduler/README.md +41 -52
- package/docs/services/secretsmanager/README.md +27 -42
- package/docs/services/ses/README.md +24 -34
- package/docs/services/sns/README.md +18 -26
- package/docs/services/sqs/README.md +14 -14
- package/docs/services/ssm/README.md +13 -17
- package/docs/services/stepfunctions/README.md +18 -20
- package/docs/services/sts/README.md +32 -45
- package/docs/services/wafv2/README.md +12 -17
- package/docs/testing/README.md +228 -0
- package/docs/time/README.md +10 -0
- package/llms.txt +1 -0
- package/package.json +1 -1
|
@@ -1,20 +1,15 @@
|
|
|
1
1
|
# Simulated CloudWatch Logs
|
|
2
2
|
|
|
3
|
-
Yulin
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
account.
|
|
7
|
-
|
|
8
|
-
The point of it is to make log data addressable. Code that writes to CloudWatch Logs is code teams
|
|
9
|
-
already have, and the alternative for a test is capturing process output.
|
|
3
|
+
Yulin simulates CloudWatch Logs in memory. It stores log groups, streams, and events. Application
|
|
4
|
+
code can write events through the normal SDK commands, and tests can read one stream with
|
|
5
|
+
`GetLogEvents` or search a group with `FilterLogEvents`.
|
|
10
6
|
|
|
11
7
|
CloudWatch Logs specific types are imported from the `@kensio/yulin/logs` subpath.
|
|
12
8
|
|
|
13
9
|
## Writing and searching log events
|
|
14
10
|
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
which execution environment wrote the line.
|
|
11
|
+
`FilterLogEvents` searches every stream in a group. A test can find an event without knowing which
|
|
12
|
+
execution environment wrote it.
|
|
18
13
|
|
|
19
14
|
```typescript sim-logs-write-and-search
|
|
20
15
|
/**
|
|
@@ -86,11 +81,9 @@ set of alternatives, and a quoted phrase matches with its spaces intact.
|
|
|
86
81
|
|
|
87
82
|
An omitted or empty pattern matches everything.
|
|
88
83
|
|
|
89
|
-
|
|
84
|
+
Yulin refuses structured pattern syntaxes. A JSON property pattern (`{ $.level = "ERROR" }`), a
|
|
90
85
|
space delimited field pattern (`[level=ERROR, message]`) and a regular expression term
|
|
91
|
-
(`%ERROR|WARN%`) each raise `SimLogsUnsupportedOperationException`.
|
|
92
|
-
worse. A pattern quietly treated as matching everything would turn an assertion about one log line
|
|
93
|
-
into an assertion about any log line at all, and the test would keep passing while testing nothing.
|
|
86
|
+
(`%ERROR|WARN%`) each raise `SimLogsUnsupportedOperationException`.
|
|
94
87
|
|
|
95
88
|
## Reading one stream
|
|
96
89
|
|
|
@@ -166,10 +159,8 @@ console.log(read);
|
|
|
166
159
|
|
|
167
160
|
## Retention
|
|
168
161
|
|
|
169
|
-
Retention is
|
|
170
|
-
|
|
171
|
-
ahead of the deletion that eventually follows from it. A log group with no retention keeps its
|
|
172
|
-
events forever, the AWS default.
|
|
162
|
+
Retention is stored and reported but leaves events in place. A log group without a retention setting
|
|
163
|
+
keeps events forever, matching the AWS default.
|
|
173
164
|
|
|
174
165
|
The accepted values are a fixed set. A reasonable-looking `retentionInDays: 10` is refused here
|
|
175
166
|
exactly as it is by an account.
|
|
@@ -210,9 +201,8 @@ console.log(
|
|
|
210
201
|
|
|
211
202
|
## Lambda handler output
|
|
212
203
|
|
|
213
|
-
A Lambda function
|
|
214
|
-
|
|
215
|
-
by searching its log group.
|
|
204
|
+
A simulated Lambda function writes its output to `/aws/lambda/<function name>`, whether it runs from
|
|
205
|
+
a zip archive or an in-process handler. Search that group to assert on handler output.
|
|
216
206
|
|
|
217
207
|
```typescript sim-logs-lambda-output
|
|
218
208
|
/**
|
|
@@ -256,11 +246,9 @@ const found = await simAws.logs().filterLogEvents(
|
|
|
256
246
|
console.log(found.events?.[0]?.message);
|
|
257
247
|
```
|
|
258
248
|
|
|
259
|
-
|
|
260
|
-
else, but a test tool that swallowed it would make a failing test harder to debug. Recording is a
|
|
261
|
-
tee.
|
|
249
|
+
Output also remains visible in the terminal to help diagnose failing tests.
|
|
262
250
|
|
|
263
|
-
An invocation that ends in an error
|
|
251
|
+
An invocation that ends in an uncaught error leaves an `ERROR Invoke Error` line in the group
|
|
264
252
|
after whatever it printed, carrying the error's type, its message and its stack. The
|
|
265
253
|
[simulated Lambda docs](https://yulinsim.dev/services/lambda/ "Simulated Lambda usage docs") show
|
|
266
254
|
one.
|
|
@@ -272,8 +260,8 @@ shape in a test, and leave the value alone.
|
|
|
272
260
|
|
|
273
261
|
Writing on this path is unconditional. A real function needs `logs:CreateLogGroup` and
|
|
274
262
|
`logs:PutLogEvents` on its execution Role, and one without them produces no logs at all, in silence.
|
|
275
|
-
|
|
276
|
-
|
|
263
|
+
Yulin always captures this output so missing log permissions do not hide diagnostic messages in
|
|
264
|
+
tests.
|
|
277
265
|
|
|
278
266
|
## Declaring a log group in a template
|
|
279
267
|
|
|
@@ -308,12 +296,11 @@ Two divergences to know about:
|
|
|
308
296
|
|
|
309
297
|
## Delivering logs from another service
|
|
310
298
|
|
|
311
|
-
CloudWatch Logs delivery
|
|
312
|
-
v2
|
|
313
|
-
means three CloudWatch Logs resources.
|
|
299
|
+
CloudWatch Logs delivery connects a service's log source to a destination. CloudFront standard
|
|
300
|
+
logging v2 uses a delivery source, a delivery destination, and a delivery.
|
|
314
301
|
|
|
315
|
-
|
|
316
|
-
|
|
302
|
+
The source identifies the resource and log type. The destination identifies where logs would go and
|
|
303
|
+
their output format. The delivery joins them.
|
|
317
304
|
|
|
318
305
|
```typescript sim-logs-delivery
|
|
319
306
|
/**
|
|
@@ -418,7 +405,7 @@ rules from real AWS are modelled here, each of them a deploy that looks fine unt
|
|
|
418
405
|
- **A delivery holds both its ends.** Deleting the source or the destination while a delivery joins
|
|
419
406
|
them fails with `ConflictException`. The delivery goes first, and CloudFormation orders that
|
|
420
407
|
itself when a stack is deleted.
|
|
421
|
-
- **CloudFront
|
|
408
|
+
- **CloudFront supports only `ACCESS_LOGS`.** Any other `logType` over a distribution is
|
|
422
409
|
refused.
|
|
423
410
|
- **CloudFront delivery is set up from `us-east-1`**, whatever region the destination bucket is in.
|
|
424
411
|
A CloudFront delivery source put from anywhere else is refused.
|
|
@@ -441,10 +428,9 @@ bare variables and let delivery name them.
|
|
|
441
428
|
|
|
442
429
|
### Declaring delivery in a template
|
|
443
430
|
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
deploy (see [the rules above](#delivering-logs-from-another-service)).
|
|
431
|
+
A CloudFormation template can declare the same three resources alongside the CloudFront distribution.
|
|
432
|
+
The source's `ResourceArn` can use `Ref` to include the generated distribution ID. A hard-coded ID
|
|
433
|
+
for a missing distribution fails deployment (see [the rules above](#delivering-logs-from-another-service)).
|
|
448
434
|
|
|
449
435
|
```yaml
|
|
450
436
|
SiteDistribution:
|
|
@@ -501,9 +487,9 @@ The template carries the S3 layout as two flat properties, and the API takes the
|
|
|
501
487
|
delivery. CloudWatch Logs issues that ID. A template cannot predict it.
|
|
502
488
|
|
|
503
489
|
`Fn::GetAtt` gives `Arn` on all three. The source also publishes `Service` and `ResourceArns`, and
|
|
504
|
-
the delivery publishes `DeliveryId` and `DeliveryDestinationType`. The destination publishes
|
|
505
|
-
|
|
506
|
-
|
|
490
|
+
the delivery publishes `DeliveryId` and `DeliveryDestinationType`. The destination publishes only
|
|
491
|
+
`Arn`. Read `DeliveryDestinationType` from the delivery rather than the destination. CloudFormation
|
|
492
|
+
refuses attributes outside this set.
|
|
507
493
|
|
|
508
494
|
`Tags` and `DeliveryDestinationPolicy` are recorded as ignored properties, and the stack still
|
|
509
495
|
deploys.
|
|
@@ -732,7 +718,8 @@ function is. `UpdateAlias` moves what the filter reaches, and the filter stays a
|
|
|
732
718
|
|
|
733
719
|
## Metric filters
|
|
734
720
|
|
|
735
|
-
A metric filter
|
|
721
|
+
A metric filter converts matching log events into CloudWatch metric datapoints. An alarm can then
|
|
722
|
+
watch the metric without application code calling `PutMetricData`.
|
|
736
723
|
|
|
737
724
|
```typescript sim-logs-metric-filter
|
|
738
725
|
/**
|
|
@@ -916,7 +903,9 @@ console.log(MetricAlarms?.[0]?.StateValue);
|
|
|
916
903
|
|
|
917
904
|
## Embedded Metric Format
|
|
918
905
|
|
|
919
|
-
A log event
|
|
906
|
+
A log event containing an Embedded Metric Format (EMF) document publishes its declared metrics.
|
|
907
|
+
AWS Lambda Powertools uses this path. It writes EMF to standard output instead of calling the
|
|
908
|
+
CloudWatch API.
|
|
920
909
|
|
|
921
910
|
```typescript sim-logs-embedded-metric-format
|
|
922
911
|
/**
|
|
@@ -997,7 +986,9 @@ A log event is read as a document only where it parses as JSON, comes out as an
|
|
|
997
986
|
|
|
998
987
|
Three things go on `simAws.logs().metricPublicationFailures` rather than passing quietly. A metric the metadata declares and the document body carries no number under, a metric asking for `StorageResolution: 1`, which simulated CloudWatch has no period short enough for, and a directive that asked for dimensions and got no usable set of them.
|
|
999
988
|
|
|
1000
|
-
A dimension set is
|
|
989
|
+
A dimension set is accepted or dropped as a whole. Yulin drops a set when the body lacks one of its
|
|
990
|
+
keys or a value has a type other than string. Publishing only part of the set would create the wrong
|
|
991
|
+
metric identity. A directive without a usable set produces no datapoint.
|
|
1001
992
|
|
|
1002
993
|
Each entry on the ledger names its `source`, which is `{ kind: "metricFilter", filterName }` or `{ kind: "embeddedMetricFormat" }`. The two are told apart by kind rather than by name, because a metric filter may be called anything.
|
|
1003
994
|
|
|
@@ -1132,7 +1123,7 @@ console.log(described.logGroups?.[0]?.logGroupArn);
|
|
|
1132
1123
|
- **Events never expire.** Retention is stored and reported, never acted on.
|
|
1133
1124
|
- **A metric filter reading a field of the log event.** A `metricValue` or a dimension value
|
|
1134
1125
|
beginning `$` is refused where the filter is put. Both need a structured filter pattern, and
|
|
1135
|
-
|
|
1126
|
+
both require a structured syntax, which Yulin refuses.
|
|
1136
1127
|
- **How far back a `defaultValue` looks.** A filter remembers the most recent minute it matched
|
|
1137
1128
|
something in. A later write into that same minute publishes no default over the top, and a write
|
|
1138
1129
|
landing in an earlier minute a match was already seen in does publish one. Events
|
|
@@ -1143,21 +1134,21 @@ console.log(described.logGroups?.[0]?.logGroupArn);
|
|
|
1143
1134
|
read, which is how it reaches CloudWatch in an account.
|
|
1144
1135
|
- **`AWS::Logs::SubscriptionFilter`.** Recorded as a gap. The log group, the metric filter and the
|
|
1145
1136
|
three delivery resource types are what simulated CloudFormation deploys here.
|
|
1146
|
-
- **`ApplyOnTransformedLogs` and `EmitSystemFieldDimensions` on a metric filter.** Recorded
|
|
1147
|
-
|
|
1148
|
-
- **
|
|
1137
|
+
- **`ApplyOnTransformedLogs` and `EmitSystemFieldDimensions` on a metric filter.** Recorded as
|
|
1138
|
+
ignored properties. Log transformers are absent.
|
|
1139
|
+
- **Delivery resources store configuration only.** A delivery records that a source was joined to a destination
|
|
1149
1140
|
and how the records would be written. No access log file ever reaches the bucket.
|
|
1150
1141
|
- **`GetDeliverySource`, `GetDeliveryDestination` and `GetDelivery`.** Absent as SDK operations. The
|
|
1151
1142
|
three `Describe` operations report the same resources. The three action names are authorized where
|
|
1152
1143
|
CloudFormation reads a delivery Resource back.
|
|
1153
1144
|
- **Delivery resource tags and cross-account delivery.** `PutDeliverySource`,
|
|
1154
1145
|
`PutDeliveryDestination` and `CreateDelivery` refuse tags outright. `DeliveryDestinationPolicy` in
|
|
1155
|
-
a template is recorded
|
|
1146
|
+
a template is recorded as an ignored property.
|
|
1156
1147
|
- **An `=` in a suffix path with Hive compatible paths off.** Taken. Whether real CloudWatch Logs
|
|
1157
1148
|
takes one is unverified. A path hand-rolling its own partition keys without the option is left
|
|
1158
1149
|
alone here, and refused with the option on.
|
|
1159
|
-
- **Log types for services other than CloudFront.**
|
|
1160
|
-
|
|
1150
|
+
- **Log types for services other than CloudFront.** Yulin accepts any `logType` for resources other
|
|
1151
|
+
than distributions because the valid set varies by service.
|
|
1161
1152
|
- **Logs Insights, export tasks, tags, encryption and data protection policies.** Absent. Tags and
|
|
1162
1153
|
`kmsKeyId` on `CreateLogGroup` are refused outright. A property cannot look set here and behave
|
|
1163
1154
|
differently in an account.
|
|
@@ -1,18 +1,14 @@
|
|
|
1
1
|
# Simulated Organizations
|
|
2
2
|
|
|
3
|
-
Yulin simulates AWS Organizations service control policies
|
|
4
|
-
organization around an account forbids something before a deployment does.
|
|
3
|
+
Yulin simulates AWS Organizations service control policies (SCPs) and organization structure.
|
|
5
4
|
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
identity and resource policies. An SCP therefore applies to a CloudFormation deployment, an
|
|
10
|
-
intercepted SDK client, and a direct service call alike.
|
|
5
|
+
An SCP limits permissions granted by identity and resource policies. Attach one to the organization
|
|
6
|
+
root, an organizational unit or an account. An account inherits policies from every node on its path
|
|
7
|
+
from the root. Simulated IAM applies them to direct calls, intercepted clients and CloudFormation.
|
|
11
8
|
|
|
12
9
|
## Attach a policy to an organizational unit
|
|
13
10
|
|
|
14
|
-
|
|
15
|
-
under that unit inherits it. Units nest, and the root sits above all of them.
|
|
11
|
+
Create an organizational unit and attach an SCP to it. Accounts below the unit inherit the policy.
|
|
16
12
|
|
|
17
13
|
```typescript sim-organizations-organizational-unit
|
|
18
14
|
/**
|
|
@@ -44,16 +40,13 @@ const decision = simAws.account("123456789012").iam().authorize({
|
|
|
44
40
|
console.log(decision.value); // "ExplicitDeny"
|
|
45
41
|
```
|
|
46
42
|
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
`organizations.root()` is the node above everything, and a policy attached there covers every
|
|
50
|
-
account in the organization.
|
|
43
|
+
Pass a parent as the second argument to `createOrganizationalUnit` to nest units. With no parent, the
|
|
44
|
+
new unit sits below `organizations.root()`.
|
|
51
45
|
|
|
52
46
|
## Every level has to allow the action
|
|
53
47
|
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
able to do neither.
|
|
48
|
+
Every node on the path must allow the action. An allow at one level cannot supply an allow missing
|
|
49
|
+
at another. A deny at any level rejects the request.
|
|
57
50
|
|
|
58
51
|
```typescript sim-organizations-every-level-allows
|
|
59
52
|
/**
|
|
@@ -89,15 +82,12 @@ console.log(decision.value); // "ImplicitDeny"
|
|
|
89
82
|
console.log(decision.serviceControlPolicy.unallowedLevels); // [ "Workloads" ]
|
|
90
83
|
```
|
|
91
84
|
|
|
92
|
-
`unallowedLevels`
|
|
93
|
-
denial that takes longest to track down.
|
|
94
|
-
|
|
95
|
-
A `Deny` at any level ends the request whatever another level allows.
|
|
85
|
+
`unallowedLevels` identifies the nodes with no matching allow.
|
|
96
86
|
|
|
97
87
|
## The management account
|
|
98
88
|
|
|
99
|
-
`setManagementAccount`
|
|
100
|
-
|
|
89
|
+
Use `setManagementAccount` to exempt one account from SCP evaluation. Its identity and resource
|
|
90
|
+
policies still apply.
|
|
101
91
|
|
|
102
92
|
```typescript sim-organizations-management-account
|
|
103
93
|
/**
|
|
@@ -126,9 +116,8 @@ console.log(decision.serviceControlPolicy.isApplied); // false
|
|
|
126
116
|
|
|
127
117
|
## Attach a service control policy to an Account
|
|
128
118
|
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
`simAws.organizations()`, not from an account scope.
|
|
119
|
+
An SCP attached directly to an account applies only to that account. Organization state belongs to
|
|
120
|
+
the whole `SimAws` instance and is available through `simAws.organizations()`.
|
|
132
121
|
|
|
133
122
|
```typescript sim-organizations-attach-scp
|
|
134
123
|
/**
|
|
@@ -159,17 +148,15 @@ console.log(decision.serviceControlPolicy.isDenied); // true
|
|
|
159
148
|
console.log(decision.serviceControlPolicy.denyStatements[0]?.Sid); // "DenyBucketCreation"
|
|
160
149
|
```
|
|
161
150
|
|
|
162
|
-
|
|
163
|
-
|
|
151
|
+
New organization nodes receive the AWS-managed `FullAWSAccess` policy. A deny-list SCP can then
|
|
152
|
+
block one action while leaving other actions allowed.
|
|
164
153
|
|
|
165
|
-
An account
|
|
166
|
-
and resource policies decide its requests as they did before.
|
|
154
|
+
An account outside the organization is unaffected by SCPs.
|
|
167
155
|
|
|
168
156
|
## Catch a deployment the policy denies
|
|
169
157
|
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
applies to a member account's root the same way AWS does.
|
|
158
|
+
CloudFormation creates resources through each service's authorized command path. A deployment with
|
|
159
|
+
no caller runs as the account root, and SCPs apply to that root.
|
|
173
160
|
|
|
174
161
|
```typescript sim-organizations-scp-deployment
|
|
175
162
|
/**
|
|
@@ -213,14 +200,13 @@ const failed = simAws
|
|
|
213
200
|
console.log(failed?.status); // "CREATE_FAILED"
|
|
214
201
|
```
|
|
215
202
|
|
|
216
|
-
|
|
217
|
-
|
|
203
|
+
When an SCP denies creation, the resource enters `CREATE_FAILED` and the deployment rejects. The
|
|
204
|
+
error names the policy.
|
|
218
205
|
|
|
219
206
|
## Name the principal a deployment runs as
|
|
220
207
|
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
statement conditioned on `aws:PrincipalArn` then has a deploy role to match against.
|
|
208
|
+
Pass `caller` when the deployment should run as a role. SCP conditions on `aws:PrincipalArn` then
|
|
209
|
+
evaluate against that role.
|
|
224
210
|
|
|
225
211
|
```typescript sim-organizations-scp-deploy-role
|
|
226
212
|
/**
|
|
@@ -285,17 +271,15 @@ const stack = await simAws.cloudFormation().deployTemplate({
|
|
|
285
271
|
console.log(stack.getResource("ReportsBucket")?.status); // "CREATE_COMPLETE"
|
|
286
272
|
```
|
|
287
273
|
|
|
288
|
-
|
|
289
|
-
denies the root, and the account root is who a bare `createRole` runs as.
|
|
274
|
+
Create the role before attaching a policy that would deny the setup call.
|
|
290
275
|
|
|
291
276
|
## Name the caller the rest of a test reads as
|
|
292
277
|
|
|
293
|
-
A deployment
|
|
294
|
-
the
|
|
295
|
-
on every read.
|
|
278
|
+
A deployment caller applies only to that deployment. Other calls still use the account root unless
|
|
279
|
+
the simulation has a default caller.
|
|
296
280
|
|
|
297
|
-
`defaultCaller` on `SimAws`
|
|
298
|
-
|
|
281
|
+
Set `defaultCaller` on `SimAws` to choose the principal for unattributed calls. An explicit `caller`
|
|
282
|
+
still takes precedence.
|
|
299
283
|
|
|
300
284
|
```typescript sim-organizations-scp-default-caller
|
|
301
285
|
/**
|
|
@@ -369,17 +353,13 @@ console.log(read.Parameter?.Value); // "reports-bucket"
|
|
|
369
353
|
console.log(identity.Arn); // "arn:aws:iam::123456789012:role/Administrator"
|
|
370
354
|
```
|
|
371
355
|
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
Naming a default caller says who an unattributed call comes from, and leaves the root's own identity
|
|
376
|
-
access where it was. A test about root behaviour names `simAws.account().rootPrincipal` and gets the
|
|
377
|
-
root. Under the policy above that call is denied, which is what the statement is written to do.
|
|
356
|
+
Create and configure the default caller before attaching policies that would deny those setup calls.
|
|
357
|
+
Pass `simAws.account().rootPrincipal` explicitly when a test needs to make a request as root.
|
|
378
358
|
|
|
379
359
|
## Write an allow list instead of a deny list
|
|
380
360
|
|
|
381
|
-
`detachFullAwsAccess`
|
|
382
|
-
|
|
361
|
+
Call `detachFullAwsAccess` to use an allow-list SCP. The remaining policies must explicitly allow an
|
|
362
|
+
action.
|
|
383
363
|
|
|
384
364
|
```typescript sim-organizations-scp-allow-list
|
|
385
365
|
/**
|
|
@@ -407,16 +387,13 @@ console.log(decision.denialReason);
|
|
|
407
387
|
// "because no service control policy allows the s3:GetObject action"
|
|
408
388
|
```
|
|
409
389
|
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
Detaching `FullAWSAccess` on its own leaves the account holding no policy, and every action is then
|
|
414
|
-
denied. AWS behaves the same way, and warns about it.
|
|
390
|
+
SCPs still limit an account root. Removing `FullAWSAccess` without adding another allow policy denies
|
|
391
|
+
every action.
|
|
415
392
|
|
|
416
393
|
## Deploy an organization from CloudFormation
|
|
417
394
|
|
|
418
|
-
|
|
419
|
-
|
|
395
|
+
Simulated CloudFormation supports the organization, organizational unit, account and policy
|
|
396
|
+
resource types.
|
|
420
397
|
|
|
421
398
|
```typescript sim-organizations-cloudformation
|
|
422
399
|
/**
|
|
@@ -470,17 +447,13 @@ const decision = simAws.account("123456789012").iam().authorize({
|
|
|
470
447
|
console.log(decision.value); // "ExplicitDeny"
|
|
471
448
|
```
|
|
472
449
|
|
|
473
|
-
`Content`
|
|
474
|
-
|
|
475
|
-
or none of them. A target this organization has never heard of fails the resource before anything is
|
|
476
|
-
attached.
|
|
450
|
+
`Content` accepts an object or JSON text. `TargetIds` accepts one target or a list of roots, units and
|
|
451
|
+
accounts. An unknown target fails the resource before the policy is attached anywhere.
|
|
477
452
|
|
|
478
|
-
A
|
|
479
|
-
|
|
480
|
-
worth declaring for `RootId`, which is what a unit hangs off.
|
|
453
|
+
A `SimAws` instance starts with one organization. `AWS::Organizations::Organization` adopts it and
|
|
454
|
+
exposes its `RootId`.
|
|
481
455
|
|
|
482
|
-
`AWS::Organizations::Account`
|
|
483
|
-
back with `Ref` or `Fn::GetAtt AccountId`.
|
|
456
|
+
`AWS::Organizations::Account` generates an account ID. Read it with `Ref` or `Fn::GetAtt AccountId`.
|
|
484
457
|
|
|
485
458
|
These are the properties read from each resource:
|
|
486
459
|
|
|
@@ -491,10 +464,8 @@ These are the properties read from each resource:
|
|
|
491
464
|
| `AWS::Organizations::Account` | `AccountName`, `Email`, `ParentIds` | `Tags`, `RoleName` |
|
|
492
465
|
| `AWS::Organizations::Policy` | `Name`, `Type`, `Content`, `TargetIds` | `Tags`, `Description` |
|
|
493
466
|
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
policies from more than one stack keeps the others. A unit that still holds something when it goes
|
|
497
|
-
hands what it holds to its parent, so every Account keeps a path to the root.
|
|
467
|
+
Stack teardown removes resources created by that stack. Policies from other stacks remain attached.
|
|
468
|
+
Accounts and child units move to the deleted unit's parent.
|
|
498
469
|
|
|
499
470
|
## Reading a denial
|
|
500
471
|
|
|
@@ -510,21 +481,16 @@ sides, through `decision.serviceControlPolicy`:
|
|
|
510
481
|
| `denyStatements` | The matching `Deny` statements. |
|
|
511
482
|
| `allowStatements` | The matching `Allow` statements. |
|
|
512
483
|
|
|
513
|
-
`decision.denialReason`
|
|
514
|
-
simulated service passes it through to the error it throws.
|
|
484
|
+
`decision.denialReason` contains the text used by service access-denied errors.
|
|
515
485
|
|
|
516
|
-
`
|
|
517
|
-
account, in the order they were evaluated, including `FullAWSAccess` where it is still attached.
|
|
486
|
+
`serviceControlPoliciesFor(accountId)` returns the policies in evaluation order.
|
|
518
487
|
|
|
519
|
-
`serviceControlPolicySetFor(accountId).levels`
|
|
520
|
-
root first. That grouping is what sim IAM evaluates.
|
|
488
|
+
`serviceControlPolicySetFor(accountId).levels` groups policies by node, starting at the root.
|
|
521
489
|
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
`serviceControlPolicySetFor(accountId).applies` tells the two apart, and so does
|
|
527
|
-
`decision.serviceControlPolicy.isApplied`.
|
|
490
|
+
An empty policy list can mean that the account is outside the organization, is the management
|
|
491
|
+
account or has no policies. The first two are exempt. The last is denied every action. Check
|
|
492
|
+
`serviceControlPolicySetFor(accountId).applies` or `decision.serviceControlPolicy.isApplied` to
|
|
493
|
+
distinguish them.
|
|
528
494
|
|
|
529
495
|
## Available functionality
|
|
530
496
|
|
|
@@ -567,7 +533,6 @@ Simulated Organizations supports:
|
|
|
567
533
|
| Service-linked roles | Evaluated like any other principal. AWS exempts a service-linked role from SCPs. |
|
|
568
534
|
| Other policy types | Resource control policies, declarative policies, tag policies, backup policies and AI services opt-out policies are not simulated. |
|
|
569
535
|
| The Organizations SDK | `CreatePolicy`, `AttachPolicy`, `ListAccounts` and the rest of the API are not handled. Policies are attached through the accessor. |
|
|
570
|
-
| CloudFormation | `AWS::Organizations::Organization`, `::OrganizationalUnit`, `::Account` and `::Policy` are not created from a template. |
|
|
571
536
|
| Organization condition keys | `aws:PrincipalOrgID` and `aws:PrincipalOrgPaths` are not populated. A condition naming either fails to match. |
|
|
572
537
|
| Service principals | A request whose caller is a service principal or anonymous belongs to no Account and is subject to no policy. |
|
|
573
538
|
| Condition operator coverage | The operators above are evaluated. Anything else fails closed and the statement holding it matches nothing. |
|