Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -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`.
:::
Expand All @@ -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 <args>` to run Azure CLI commands against LocalStack.

### `config`

Manage CLI configuration.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand Down Expand Up @@ -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
Expand All @@ -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.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down Expand Up @@ -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)
```

Expand Down Expand Up @@ -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 <POLICY_ID> \
--target-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/<POLICY_ID>
```

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/<POLICY_ID>
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/).