diff --git a/src/content/docs/aws/configuration/config/configuration.md b/src/content/docs/aws/configuration/config/configuration.md index ea336676..9ad76f33 100644 --- a/src/content/docs/aws/configuration/config/configuration.md +++ b/src/content/docs/aws/configuration/config/configuration.md @@ -246,7 +246,7 @@ Also see [OpenSearch configuration variables](#opensearch) which are used to man | `KINESIS_SHARD_LIMIT` | `100` (default), `Infinity` (to disable) | Integer value , causing the Kinesis API to start throwing exceptions to mimic the default shard limit. | | `KINESIS_ON_DEMAND_STREAM_COUNT_LIMIT` | `10` (default), `Infinity` (to disable) | Integer value , causing the Kinesis API to start throwing exceptions to mimic the default on demand stream count limit. | | `KINESIS_LATENCY` | `500` (default), `0` (to disable)| Integer value of milliseconds, causing the Kinesis API to delay returning a response in order to mimic latency from a live AWS call. | -| `KINESIS_MOCK_PROVIDER_ENGINE` | `node` (default) \| `scala` \| `rust` | String value of `node` (default), `scala`, or `rust` that determines the underlying build of Kinesis Mock. See [Performance Tuning](/aws/services/kinesis#performance-tuning) for guidance on choosing an engine. | +| `KINESIS_MOCK_PROVIDER_ENGINE` | `node` (default) \| `scala` | String value of `node` (default) or `scala` that determines the underlying build of Kinesis Mock. | | `KINESIS_MOCK_MAXIMUM_HEAP_SIZE` | `512m` (default) | JVM memory format string that sets the maximum memory size for the Kinesis Mock Scala server, corresponds to the JVM `-Xmx` flag. | | `KINESIS_MOCK_INITIAL_HEAP_SIZE` | `256m` (default) | JVM memory format string that sets the initial memory size for the Kinesis Mock Scala server, corresponds to the JVM `-Xms` flag. | diff --git a/src/content/docs/aws/developer-tools/security-testing/iam-coverage.md b/src/content/docs/aws/developer-tools/security-testing/iam-coverage.md index ae6a05d8..6da10156 100644 --- a/src/content/docs/aws/developer-tools/security-testing/iam-coverage.md +++ b/src/content/docs/aws/developer-tools/security-testing/iam-coverage.md @@ -123,6 +123,10 @@ It only includes operations performed with a principal, not as root, so test set | **Permission Boundaries** | | | | - Roles | | | - Users | +| **Service Control Policies (SCPs)** | | +| | - Enforced across the organization hierarchy (root, OU, account) | +| | - Enforced for cross-account access | +| | - Evaluated by the IAM Policy Simulator | ## Supported Policy Features diff --git a/src/content/docs/aws/services/kinesis.mdx b/src/content/docs/aws/services/kinesis.mdx index 778f0798..29792d4e 100644 --- a/src/content/docs/aws/services/kinesis.mdx +++ b/src/content/docs/aws/services/kinesis.mdx @@ -170,44 +170,21 @@ You can fetch the CloudWatch logs for your Lambda function reading records from ### Performance Tuning -By default, Kinesis Mock runs on the Node.js engine (`KINESIS_MOCK_PROVIDER_ENGINE=node`). -For high-volume workloads, large payloads, or long-running setups, you can switch to a different engine using the `KINESIS_MOCK_PROVIDER_ENGINE` flag. +For high-volume workloads or large payloads, we recommend switching to the Scala engine via the `KINESIS_MOCK_PROVIDER_ENGINE=scala` flag, delivering up to 10x better performance compared to the default Node.js engine. -#### Scala engine - -The Scala engine (`KINESIS_MOCK_PROVIDER_ENGINE=scala`) delivers up to 10x better performance compared to the default Node.js engine. -The following parameters can be tuned for the Scala engine: +Additionally, the following parameters can be tuned: - Increase `KINESIS_MOCK_MAXIMUM_HEAP_SIZE` beyond the default `512m` to reduce JVM memory pressure. - Increase `KINESIS_MOCK_INITIAL_HEAP_SIZE` beyond the default `256m` to pre-allocate more JVM heap memory. +- Reduce `KINESIS_LATENCY` artificial response delays from the default `500` milliseconds (or disable entirely with `0`). + +Refer to our [Kinesis configuration documentation](https://docs.localstack.cloud/references/configuration/#kinesis) for more details on these parameters. :::note `KINESIS_MOCK_MAXIMUM_HEAP_SIZE` and `KINESIS_MOCK_INITIAL_HEAP_SIZE` are only applicable when using the Scala engine. +Future versions of LocalStack will likely default to using the `scala` engine over the less-performant `node` version currently in use. ::: -#### Rust engine - -The Rust engine (`KINESIS_MOCK_PROVIDER_ENGINE=rust`), introduced in LocalStack 2026.07, is a LocalStack-native rebuild of Kinesis Mock and is the recommended choice for any demanding or long-lived workload. -It provides: - -- **Native multi-account and multi-region support** from a single binary, regardless of how many accounts you use — this removes the per-account instance overhead described under [Limitations](#limitations). -- **Faithful enforcement of all AWS API limits**, including per-shard rate ingress/egress limits. -- **An improved persistence model** that replaces the legacy unbounded in-memory queue, allowing the mock to run under sustained load for long periods without the risk of running out of memory. - -:::caution -This is the first release of the Rust engine and it should be considered experimental for anyone opting in. - -Persistence is **not compatible** between the Rust engine and the Node.js or Scala engines, in either direction. -Any existing Kinesis persistence (including Cloud Pods and state created with the `node` or `scala` engines) will not carry over when you switch to `rust` — and vice versa. -Switching engines effectively starts from a fresh state. -::: - -#### All engines - -Regardless of the selected engine, you can reduce `KINESIS_LATENCY` artificial response delays from the default `500` milliseconds (or disable them entirely with `0`). - -Refer to our [Kinesis configuration documentation](https://docs.localstack.cloud/aws/configuration/config/configuration/#kinesis) for more details on these parameters. - ## Resource Browser The LocalStack Web Application provides a Resource Browser for managing Kinesis Streams & Kafka Clusters. @@ -232,10 +209,8 @@ The following code snippets and sample applications provide practical examples o ## Limitations -When using the default Node.js or the Scala engine, each AWS account launches a separate instance of Kinesis Mock in multi-account setups, which is very resource intensive when a large number of AWS accounts are used. -[This Kinesis Mock issue](https://github.com/etspaceman/kinesis-mock/issues/377) is being used to keep track of this feature for the upstream engines. - -The [Rust engine](#performance-tuning) (`KINESIS_MOCK_PROVIDER_ENGINE=rust`) is not affected by this limitation, as it natively supports any number of accounts and regions from a single binary. +In multi-account setups, each AWS account launches a separate instance of Kinesis Mock, which is very resource intensive when a large number of AWS accounts are used. +[This Kinesis Mock issue](https://github.com/etspaceman/kinesis-mock/issues/377) is being used to keep track of this feature. ## API Coverage diff --git a/src/content/docs/aws/services/organizations.mdx b/src/content/docs/aws/services/organizations.mdx index cf7d0837..5ed57a76 100644 --- a/src/content/docs/aws/services/organizations.mdx +++ b/src/content/docs/aws/services/organizations.mdx @@ -88,6 +88,113 @@ To get started, start your LocalStack instance using your preferred method: awslocal organizations delete-organization ``` +## Service Control Policy enforcement + +[Service Control Policies (SCPs)](https://docs.aws.amazon.com/organizations/latest/userguide/orgs_manage_policies_scps.html) set the maximum permissions for accounts in your organization. +When IAM enforcement is enabled, LocalStack checks SCPs together with other applicable policies. +A request goes through only if both the principal's policies, resource's policies and the SCPs covering its account allow the action on the resource. + +To turn on SCP enforcement, start LocalStack with [`ENFORCE_IAM=1`](/aws/developer-tools/security-testing/iam-policy-enforcement) and enable the `SERVICE_CONTROL_POLICY` policy type on your organization root (see the [getting started](#getting-started) steps above). + +LocalStack evaluates SCPs at each level of the organization hierarchy: root, organizational unit, and account. +An action must be allowed by an SCP at every level between the root and the account. +If any level lacks an `Allow`, the result is an implicit deny, and an explicit `Deny` overrides any `Allow`. + +:::note +The organization's management (master) account is exempt from SCPs. +Principals in the management account are never restricted by SCPs, even with an explicit `Deny` SCP attached. +::: + +### Cross-account access + +LocalStack enforces SCPs for [cross-account access](https://docs.aws.amazon.com/IAM/latest/UserGuide/reference_policies_evaluation-logic-cross-account.html), where a principal in one account uses a resource owned by another account. + +For a cross-account request, LocalStack checks the SCPs of the source account (the account making the request). +A deny in those SCPs blocks the request even when the target resource's policy grants access. + +Consider a member account that lists the objects of an S3 bucket in another account of the same organization, with a bucket policy that grants the member account access: + +```bash +# Run as the member (source) account +awslocal s3api list-objects-v2 --bucket cross-account-bucket +``` + +The default `FullAWSAccess` SCP lets the request succeed on the bucket policy. +Attach an SCP that denies `s3:ListBucket` to the member account, and the request fails: + +```bash title="Output" +An error occurred (AccessDenied) when calling the ListObjectsV2 operation: User: arn:aws:iam::111111111111:user/test is not authorized to perform: s3:ListBucket on resource: "arn:aws:s3:::cross-account-bucket" with an explicit deny in a service control policy +``` + +An SCP that allows only unrelated actions (for example, an `ec2:*`-only SCP) produces an implicit deny, since no SCP allows `s3:ListBucket`: + +```bash title="Output" +An error occurred (AccessDenied) when calling the ListObjectsV2 operation: User: arn:aws:iam::111111111111:user/test is not authorized to perform: s3:ListBucket on resource: "arn:aws:s3:::cross-account-bucket" because no service control policy allows the s3:ListBucket action +``` + +The management account stays exempt from SCPs for cross-account requests too. + +### Testing SCPs with the IAM Policy Simulator + +You can use the [IAM Policy Simulator](https://docs.aws.amazon.com/IAM/latest/UserGuide/access_policies_testing-policies.html) to check whether a principal's request would be allowed or denied without running it against your resources. +LocalStack evaluates SCPs during policy simulation, so you can validate SCP behavior with [`SimulatePrincipalPolicy`](https://docs.aws.amazon.com/IAM/latest/APIReference/API_SimulatePrincipalPolicy.html) before making live requests. + +```bash +awslocal iam simulate-principal-policy \ + --policy-source-arn arn:aws:iam::111111111111:user/test \ + --action-names s3:ListBucket \ + --resource-arns arn:aws:s3:::cross-account-bucket +``` + +When SCPs affect the decision, LocalStack populates the `OrganizationsDecisionDetail` field of the [`EvaluationResult`](https://docs.aws.amazon.com/IAM/latest/APIReference/API_EvaluationResult.html), so you can see whether an SCP allowed the action. + +:::note +LocalStack's Policy Simulator and its IAM enforcement engine share the same underlying evaluation logic. +As a result, the simulator reflects the real AWS IAM behavior rather than the behavior of the AWS Policy Simulator, which differs in a few ways: + +- AWS ignores SCPs that contain conditions during simulation. LocalStack evaluates SCPs with conditions. +- AWS applies SCPs to the organization's management account during simulation. LocalStack does not apply SCPs to the management account, matching the real behavior of AWS Organizations. +- AWS reports an explicit `Deny` from an SCP as an implicit deny. LocalStack reports it as an explicit deny, which is the expected outcome. +::: + +## Service Control Policy validation + +When you create or update a Service Control Policy (SCP) with `CreatePolicy` or `UpdatePolicy`, LocalStack validates the policy document against the syntax rules that SCPs must follow. +A policy that violates any of these rules is rejected with a `MalformedPolicyDocumentException` or a `ConstraintViolationException`, matching the behavior you would see on AWS. + +The following constraints are enforced for SCPs: + +- **No `Principal` or `NotPrincipal` elements**: unlike identity-based or resource-based IAM policies, SCPs cannot specify a `Principal` or `NotPrincipal` key inside a `Statement`. A policy that includes either key is rejected with a `MalformedPolicyDocumentException`. +- **Maximum policy size of 10,240 characters**: a policy document larger than 10,240 characters is rejected with a `ConstraintViolationException` (reason `POLICY_CONTENT_LIMIT_EXCEEDED`). This matches the limit enforced by AWS in practice. +- **A single policy object**: the document must be a single JSON object. Passing a JSON array of policy objects is rejected. +- **A single `Statement` key**: the document may contain only one `Statement` key. Duplicate `Statement` keys (or any other duplicate keys) cause the policy to be rejected as malformed. +- **Resources must be present**: each statement must contain a `Resource` element. Specific resource ARNs (not just the `*` wildcard) are accepted. + +:::note +The AWS documentation states that the [maximum SCP size is 5,120 characters](https://docs.aws.amazon.com/organizations/latest/userguide/orgs_reference_limits.html) and that SCPs [only support the `*` wildcard for resources](https://docs.aws.amazon.com/organizations/latest/userguide/orgs_manage_policies_scps_syntax.html#scp-syntax-resource). +LocalStack instead mirrors the behavior observed against real AWS: the enforced size limit is 10,240 characters, and specific resource ARNs are accepted. +::: + +For example, the following policy is rejected because it includes a `Principal` element, which is not permitted in an SCP: + +```bash +awslocal organizations create-policy \ + --name "InvalidSCP" \ + --description "SCP with a Principal element" \ + --type SERVICE_CONTROL_POLICY \ + --content '{ + "Version": "2012-10-17", + "Statement": [ + { + "Effect": "Deny", + "Principal": "*", + "Action": "s3:*", + "Resource": "*" + } + ] + }' +``` + ## API Coverage