Skip to main content

aws-why

aws-why runs an AWS CLI command unchanged. If the command fails, it classifies the failure and explains an authorization denial using the strongest evidence AWS made available.

$ aws-why run -- aws s3 cp test.csv s3://prod-data/test.csv
upload failed: ... AccessDenied ...

ACCESS DENIED

Identity
  account: 123456789012
  principal: DataEngineer
  session: example-session

Failed operation
  s3:PutObject

Resource
  arn:aws:s3:::prod-data/test.csv

Cause
  a permissions boundary blocks the action

Evidence
  AWS error response (reported by AWS)

The tool does not treat every AWS failure as IAM. Expired credentials, missing configuration, network errors, and missing resources get distinct results.

Install and use

The normal installation does not require Rust or Cargo. Install the native executable in an isolated environment with pipx:

pipx install aws-why
aws-why run -- aws sts get-caller-identity
aws-why run --json -- aws s3api get-object --bucket example --key report.csv report.csv

Or use uv:

uv tool install aws-why

Release wheels contain the compiled executable; Python is only the distribution mechanism. Wheels are built for macOS on Apple Silicon and Intel, Linux on ARM64 and x86-64, and Windows x86-64.

The command after -- is executed with exactly the supplied argument vector and inherited environment. stdin is inherited and human-mode stdout is streamed. stderr is held in a secure temporary file until the result is classified. On success, aws-why adds no output. It returns the wrapped command's exit code.

In --json mode, successful command output is replayed from secure temporary files. For failures, command output is replaced with one JSON diagnostic object on stdout so CI consumers can parse it reliably. Replay is capped at 64 MiB for stdout and 8 MiB for stderr; analysis retains only the final 1 MiB of stderr.

Each follow-up AWS call has a five-second timeout by default. Change it with --diagnostic-timeout <seconds>.

Evidence hierarchy

aws-why stops at the first useful source:

  1. AWS GetRequestAuthorizationDetails, when the error contains an authorization ID and the API is supported and permitted.
  2. An encoded authorization message decoded through STS.
  3. The AWS service's denial message.
  4. IAM principal-policy simulation when identity, action, and resource are known.
  5. UNKNOWN.

Every action/resource result has its own evidence source and confidence:

  • verified: AWS returned the authorization evaluation for the live request.
  • reported: the live AWS error explicitly named the cause.
  • simulated: IAM simulation produced the result but did not reproduce the request.
  • incomplete: there was not enough evidence for an exact cause.

Simulation is never presented as proof that the live request will succeed. It can omit live request conditions, resource policies, endpoint policies, role chaining, and other enforcement layers.

AWS context and diagnostic permissions

Diagnostic calls use the same credential environment plus the wrapped command's explicit --profile and --region, but they ignore configured custom endpoints and always use the normal AWS endpoint resolver. Follow-up calls are skipped entirely when the original command uses --no-sign-request or an explicit --endpoint-url.

Generated diagnostics redact encoded authorization payloads, common AWS access-key/token formats, and terminal control characters. The wrapped command still runs with its inherited environment and can print any data it chooses—for example, aws sts get-session-token prints credentials by design. Do not use aws-why to run an untrusted executable, and protect captured CI output as you would ordinary AWS CLI output.

AWS may require these permissions for stronger explanations:

  • sts:GetCallerIdentity
  • iam:GetRequestAuthorizationDetails
  • sts:DecodeAuthorizationMessage
  • iam:SimulatePrincipalPolicy

The original command still runs if none of those diagnostic permissions are available; the result simply becomes less specific.

Current scope

The action/resource parser is intentionally optimized for S3, Secrets Manager, KMS, IAM, and STS. AWS authorization IDs are not currently returned by every service or API. Cross-organization details can also be withheld by AWS. In those cases, aws-why reports the known identity/action/resource and says that the exact denial reason is unknown.

aws-why recognizes only a direct aws executable. Shell pipelines and commands such as sh -c 'aws ...' still execute, but follow-up AWS diagnostics are not attempted because their effective AWS context cannot be recovered safely.

Development

cargo fmt --check
cargo test
cargo clippy --all-targets --all-features -- -D warnings
maturin build --release --bindings bin

The end-to-end tests use a temporary fake AWS executable and never contact AWS.

Tagged releases build platform-specific wheels and publish them through PyPI Trusted Publishing. Before the first public release, configure this repository as a trusted publisher for the aws-why PyPI project with environment name pypi, require maintainer approval on that GitHub environment, protect release tags, and push a tag matching the Cargo version, such as v0.1.0. The workflow rejects tags that do not match the Cargo package version, and every third-party action is pinned to an immutable commit.

Metadata

Release files for aws-why 0.1.0

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Built distributions (wheels)

Table of built distributions (wheels) for aws-why 0.1.0
File
aws_why-0.1.0-py3-none-win_amd64.whl Python 3 none Windows x86-64 Details
aws_why-0.1.0-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl Python 3 none Linux glibc 2.17+ x86-64 Details
aws_why-0.1.0-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl Python 3 none Linux glibc 2.17+ ARM64 Details
aws_why-0.1.0-py3-none-macosx_11_0_arm64.whl Python 3 none macOS 11.0+ ARM64 Details
aws_why-0.1.0-py3-none-macosx_10_12_x86_64.whl Python 3 none macOS 10.12+ x86-64 Details

Total release size: 4.8 MB

Release files / aws_why-0.1.0-py3-none-win_amd64.whl

Download URL aws_why-0.1.0-py3-none-win_amd64.whl
Size 970.9 kB
Tags Python 3 Windows x86-64
SHA-256 checksum
How to use checksums
c912dbdb4b22c22a668eefbf50b9d8c877656be51b61325e26b8a7b66f6438f9
BLAKE2b-256 checksum
How to use checksums
b2e8a793e62f225fdf372262b841b02225106dc41fa42ca740517b10b297da22
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Sep 21, 2026.

Transparency log

Release files / aws_why-0.1.0-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl

Download URL aws_why-0.1.0-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl
Size 1.0 MB
Tags Linux glibc 2.17+ x86-64 Python 3
SHA-256 checksum
How to use checksums
23ecb657d453a79a84984b7b9a0fefe8318efe69913e5f794cbc31ead12b2dbd
BLAKE2b-256 checksum
How to use checksums
9623edfe1ccaf89d41bc94d782cf3be911638dacf8029b1fa577b29e498153a3
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Sep 21, 2026.

Transparency log

Release files / aws_why-0.1.0-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl

Download URL aws_why-0.1.0-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl
Size 953.2 kB
Tags Linux glibc 2.17+ ARM64 Python 3
SHA-256 checksum
How to use checksums
f56767a7e69509f16f85ecd5217582606bd6a1f4f040ea7932783377807ef9f6
BLAKE2b-256 checksum
How to use checksums
bb0a80b26248519b70197946a4f65fe9bbdaeb3870a6b5896464aa926767268d
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Sep 21, 2026.

Transparency log

Release files / aws_why-0.1.0-py3-none-macosx_11_0_arm64.whl

Download URL aws_why-0.1.0-py3-none-macosx_11_0_arm64.whl
Size 890.7 kB
Tags Python 3 macOS 11.0+ ARM64
SHA-256 checksum
How to use checksums
2c60ab588e01b941d55a5d02521ba0230e85e803a9b61aad493653ebb8e3f016
BLAKE2b-256 checksum
How to use checksums
5b0f56f0f26588e6060a269b9a8a487d73a917ba06c2d42a44fe1abb8217e114
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Sep 21, 2026.

Transparency log

Release files / aws_why-0.1.0-py3-none-macosx_10_12_x86_64.whl

Download URL aws_why-0.1.0-py3-none-macosx_10_12_x86_64.whl
Size 955.2 kB
Tags Python 3 macOS 10.12+ x86-64
SHA-256 checksum
How to use checksums
74416c2d2ac4bbe0dbcf1ade5253c3004ce841559de0e04ca7d5a7d954e14c22
BLAKE2b-256 checksum
How to use checksums
0b8acf6c408d4bc290cd3cb67272b3deedcbb735d8f27916c1997c69ee974656
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Sep 21, 2026.

Transparency log

Release history Release notifications | RSS feed

0.5.0

5 release files

0.4.0

5 release files

0.3.1

5 release files

0.3.0

5 release files

0.2.1

5 release files

This release

0.1.0 This release

5 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page