diff --git a/src/content/docs/aws/developer-tools/running-localstack/lstk.mdx b/src/content/docs/aws/developer-tools/running-localstack/lstk.mdx index 6f971dae..e99e1ab7 100644 --- a/src/content/docs/aws/developer-tools/running-localstack/lstk.mdx +++ b/src/content/docs/aws/developer-tools/running-localstack/lstk.mdx @@ -1055,6 +1055,8 @@ The port comes from your AWS emulator's configured `port` (default `4566`); if n If the `localstack` profile is already configured correctly, `lstk` reports `LocalStack AWS profile is already configured.` and makes no changes. +On an interactive terminal, `setup aws` prompts (Y/n) before writing. Overwriting an existing `localstack` profile whose values differ requires `--force` (which also skips the prompt); writing a fresh profile, completing a partial one, or leaving an already-correct profile unchanged never needs it. + :::note The former `lstk config profile` command has been removed; use `lstk setup aws`. ::: @@ -1075,6 +1077,19 @@ It requires the `az` CLI to be installed and a running LocalStack Azure emulator To instead redirect your **global** `az` (so existing scripts run unmodified against LocalStack), see [`lstk az start-interception`](#az). +#### `setup azure` + +Prepare an isolated Azure CLI config directory (under the `lstk` config dir, via `AZURE_CONFIG_DIR`) that routes [`lstk az`](#az) commands to the LocalStack Azure emulator. +It registers a custom Azure cloud (`LocalStack`) pointing at LocalStack's Azure endpoints, activates it, disables Azure CLI instance discovery and telemetry, and performs a one-time dummy service-principal login. +Your global `~/.azure` configuration is left untouched. + +```bash +lstk setup azure +``` + +Requires the `az` CLI on your `PATH` and a running LocalStack Azure emulator. +Run this once; afterwards use `lstk az ` to run Azure CLI commands against LocalStack. + ### `config` Manage CLI configuration. diff --git a/src/content/docs/aws/developer-tools/security-testing/explainable-iam.md b/src/content/docs/aws/developer-tools/security-testing/explainable-iam.md index cc2509a7..d3502795 100644 --- a/src/content/docs/aws/developer-tools/security-testing/explainable-iam.md +++ b/src/content/docs/aws/developer-tools/security-testing/explainable-iam.md @@ -9,8 +9,10 @@ sidebar: ## Introduction -The IAM Policy Engine logs output related to failed policy evaluation directly to the LocalStack logs. -You can enable `DEBUG=1` to gain visibility into these log messages, allowing you to identify the additional policies required for your request to succeed. +When IAM enforcement denies a request, the IAM Policy Engine returns a descriptive denial message in the API response and records the same information in the LocalStack logs. +These messages identify the action that was denied, the policy type responsible (identity-based policy, resource-based policy, permissions boundary, or service control policy), the specific policy document involved, and whether the denial was explicit or implicit. +This helps you pinpoint the additional policies required for your request to succeed. +Enable `DEBUG=1` to surface the full log output. ## Getting started @@ -91,22 +93,21 @@ awslocal lambda create-function \ --zip-file fileb://function.zip ``` +The request is denied, and the error response names the exact action that was missing: + ```bash -An error occurred (AccessDeniedException) when calling the CreateFunction operation: Access to the specified resource is denied +An error occurred (AccessDeniedException) when calling the CreateFunction operation: User: arn:aws:iam::000000000000:user/test-user is not authorized to perform: iam:PassRole on resource: arn:aws:iam::000000000000:role/lambda-role because no identity-based policy allows the iam:PassRole action ``` -You can inspect the LocalStack logs, to observe the presence of five log entries directly related to the denied request: +The same information is written to the LocalStack logs. +Inspect the logs to see the corresponding Policy Engine entry: ```bash -INFO:localstack_ext.services.iam.policy_engine.handler: Request for service lambda for operation CreateFunction denied. -DEBUG:localstack_ext.services.iam.policy_engine.handler: Necessary permissions for this action: ["Action 'lambda:CreateFunction' for 'arn:aws:lambda:us-east-1:000000000000:function:test-function'", "Action 'iam:PassRole' for 'arn:aws:iam::000000000000:role/lambda-role'"] -DEBUG:localstack_ext.services.iam.policy_engine.handler: 0 permissions have been explicitly denied: [] -DEBUG:localstack_ext.services.iam.policy_engine.handler: 1 permissions have been explicitly allowed: ["Action 'lambda:CreateFunction' for 'arn:aws:lambda:us-east-1:000000000000:function:test-function'"] -DEBUG:localstack_ext.services.iam.policy_engine.handler: 1 permissions have been implicitly denied: ["Action 'iam:PassRole' for 'arn:aws:iam::000000000000:role/lambda-role'"] +2026-06-23T15:48:09.650 INFO --- [PoolThread-twisted.internet.reactor-2] localstack.pro.core.services.iam.policy_engine.handler : User: arn:aws:iam::000000000000:user/test-user is not authorized to perform: iam:PassRole on resource: arn:aws:iam::000000000000:role/lambda-role because no identity-based policy allows the iam:PassRole action ``` -Upon examination, it becomes apparent that the action `iam:PassRole` is not allowed; rather, it is implicitly denied for your user concerning the resource `arn:aws:iam::000000000000:role/lambda-role`. -This implies that there is no explicit deny statement in the relevant policies, but there is also no allow statement, resulting in the implicit denial of the action. +The message tells you that `iam:PassRole` is *implicitly* denied for your user on the resource `arn:aws:iam::000000000000:role/lambda-role`. +This means there is no explicit deny statement in the relevant policies, but there is also no allow statement, so the action is denied by default. You can incorporate this action into the policy. ### Incorporate the action into the policy @@ -131,6 +132,28 @@ Edit the `policy_1.json` file to include the `iam:PassRole` action: Re-run the Lambda [`CreateFunction`](https://docs.aws.amazon.com/lambda/latest/dg/API_CreateFunction.html) API. You will notice that the request is now successful, and the function is created. +## Reading denial messages + +Every denial message follows the same structure: the **principal** that made the request, the **action** it attempted, the **resource** it targeted, and the **cause** of the denial. +The cause tells you both the policy type and whether the denial was explicit or implicit: + +- An **explicit deny** names the policy type and the specific policy document, for example `with an explicit deny in a service control policy: arn:aws:organizations::000000000000:policy/p-abc123`. +- An **implicit deny** indicates that no policy allowed the action, for example `because no identity-based policy allows the s3:ListBucket action`. + +The Policy Engine evaluates identity-based policies, resource-based policies, permissions boundaries, and service control policies, and the denial message identifies whichever one is responsible. + +### Inline policies + +The logs go one step further for inline policies. +On AWS, inline policies are reported anonymously, which makes denials caused by them difficult to trace. +LocalStack instead names the specific inline policy responsible for the denial: + +```bash +2026-06-23T15:57:15.197 INFO --- [PoolThread-twisted.internet.reactor-2] localstack.pro.core.services.iam.policy_engine.handler : User: arn:aws:sts::000000000000:assumed-role/role-881f9fff/TestSession is not authorized to perform: kms:DescribeKey on resource: arn:aws:kms:us-east-1:000000000000:key/ad764663-5e3d-4325-81de-c7e0964f7b7f with an explicit deny in a role inline policy: policy-fc33c780 +``` + +Here, the request was blocked by an explicit deny in the inline policy `policy-fc33c780` attached to the assumed role, letting you go straight to the policy that needs changing. + ## Soft Mode Enabling `IAM_SOFT_MODE=1` allows you to review the logs and assess whether your requests would have been denied or granted while executing your entire stack without disruptions. diff --git a/src/content/docs/aws/developer-tools/security-testing/iam-policy-enforcement.md b/src/content/docs/aws/developer-tools/security-testing/iam-policy-enforcement.md index 17e21d24..e1369079 100644 --- a/src/content/docs/aws/developer-tools/security-testing/iam-policy-enforcement.md +++ b/src/content/docs/aws/developer-tools/security-testing/iam-policy-enforcement.md @@ -13,6 +13,10 @@ IAM Policy Enforcement feature can be used to test your security policies and cr The environment configuration `ENFORCE_IAM=1` is required while starting LocalStack to enable this feature. Per default, IAM enforcement is disabled, and all APIs can be accessed without authentication. +When enabled, LocalStack evaluates identity-based policies, resource-based policies, permissions boundaries, and [service control policies](#service-control-policies) together to decide whether a request is allowed. +When a request is denied, LocalStack returns a descriptive error that identifies the denied action and the policy responsible for the denial. +See [Explainable IAM](/aws/developer-tools/security-testing/explainable-iam/) for a detailed look at these messages. + ## Getting started This guide is designed for users new to IAM Policy Enforcement and assumes basic knowledge of the AWS CLI and our [`awslocal`](https://github.com/localstack/awscli-local) wrapper script. @@ -78,14 +82,15 @@ awslocal s3 mb s3://mybucket ``` ```bash -make_bucket failed: s3://mybucket An error occurred (AccessDeniedException) when calling the CreateBucket operation: Access to the specified resource is denied +make_bucket failed: s3://mybucket An error occurred (AccessDeniedException) when calling the CreateBucket operation: User: arn:aws:iam::000000000000:user/test is not authorized to perform: s3:CreateBucket on resource: arn:aws:s3:::mybucket because no identity-based policy allows the s3:CreateBucket action ``` As anticipated, the attempt to create the bucket fails with an `AccessDeniedException` error, confirming that user `test` lacks the necessary permissions for this action. +The error message names the denied action (`s3:CreateBucket`) and explains that no identity-based policy allows it. You can view the LocalStack logs to validate the policy enforcement: ```bash -2023-11-03T12:21:10.971 INFO --- [ asgi_gw_1] l.s.i.p.handler : Request for service 's3' by principal 'arn:aws:iam::000000000000:user/test' for operation 'CreateBucket' denied. +2023-11-03T12:21:10.971 INFO --- [ asgi_gw_1] localstack.pro.core.services.iam.policy_engine.handler : User: arn:aws:iam::000000000000:user/test is not authorized to perform: s3:CreateBucket on resource: arn:aws:s3:::mybucket because no identity-based policy allows the s3:CreateBucket action 2023-11-03T12:21:10.972 INFO --- [ asgi_gw_1] localstack.request.aws : AWS s3.CreateBucket => 403 (AccessDenied) ``` @@ -122,6 +127,62 @@ You can view the LocalStack logs to validate the policy enforcement: You can further use the IAM Policy Enforcement feature to test your Infrastructure as Code (IaC) deployments and ensure that your policies are correctly enforced. If the IAM policies are not correctly enforced, you will get an unsuccessful response from the API call, and the LocalStack logs will provide you with the necessary information to debug the issue. +## Service Control Policies + +Service Control Policies (SCPs) are a policy type managed by [AWS Organizations](https://docs.aws.amazon.com/organizations/latest/userguide/orgs_manage_policies_scps.html). +Unlike identity-based and resource-based policies, SCPs do not grant permissions on their own — they act as guardrails that define the maximum permissions available to the accounts they apply to. +If an SCP does not allow an action (or explicitly denies it), no `Allow` in an identity-based policy can override that result. + +With `ENFORCE_IAM=1`, LocalStack evaluates SCPs alongside identity-based policies, resource-based policies, and permissions boundaries. +This applies both to single-account access and to cross-account access, where a principal in one account acts on a resource owned by another. + +The steps below extend the walkthrough above: user `test` already has an identity-based policy that allows `s3:CreateBucket`. +We will add an SCP that denies the action and confirm that the request is blocked despite the identity-based `Allow`. + +In **Terminal 1**, create an organization and a service control policy that denies `s3:CreateBucket`: + +```bash +awslocal organizations create-organization --feature-set ALL +``` + + +```bash +awslocal organizations create-policy \ + --name deny-create-bucket \ + --type SERVICE_CONTROL_POLICY \ + --description "Deny S3 bucket creation" \ + --content '{"Version":"2012-10-17","Statement":[{"Effect":"Deny","Action":"s3:CreateBucket","Resource":"*"}]}' +``` + +Attach the SCP to the target account: + +```bash +awslocal organizations attach-policy \ + --policy-id \ + --target-id +``` + +Back in **Terminal 2**, attempt to create the bucket again as user `test`: + +```bash +awslocal s3 mb s3://mybucket +``` + +Even though the user's identity-based policy allows `s3:CreateBucket`, the SCP guardrail blocks the request, and the denial message names the responsible SCP: + +```bash +make_bucket failed: s3://mybucket An error occurred (AccessDeniedException) when calling the CreateBucket operation: User: arn:aws:iam::000000000000:user/test is not authorized to perform: s3:CreateBucket on resource: arn:aws:s3:::mybucket with an explicit deny in a service control policy: arn:aws:organizations::000000000000:policy/ +``` + +The LocalStack logs record the same information: + +```bash +2023-11-03T12:30:44.512 INFO --- [ asgi_gw_1] localstack.pro.core.services.iam.policy_engine.handler : User: arn:aws:iam::000000000000:user/test is not authorized to perform: s3:CreateBucket on resource: arn:aws:s3:::mybucket with an explicit deny in a service control policy: arn:aws:organizations::000000000000:policy/ +2023-11-03T12:30:44.513 INFO --- [ asgi_gw_1] localstack.request.aws : AWS s3.CreateBucket => 403 (AccessDenied) +``` + +This confirms that the SCP overrides the identity-based `Allow`, matching the AWS evaluation order in which an SCP guardrail takes precedence. + ## Feature coverage The feature coverage is documented in the [IAM coverage documentation](/aws/developer-tools/security-testing/iam-coverage/).