Subchapter 34.1
references/aws-iam-policy-generation.mdMarkdown29 KBView on GitHub
If the user provides source code in Python, Go, TypeScript, JavaScript, or Java:
You MUST propose the uvx iam-policy-autopilot@latest generate-policies command. You MUST NOT manually analyze the code and construct a policy yourself. The Autopilot tool does deterministic static analysis — your job is to construct the correct command with the right flags, NOT to replicate what the tool does.
If no source code is provided, or the language is unsupported (Rust, C#, PHP, Ruby, etc.): Use the Service Authorization Reference path to produce the policy directly.
Generates baseline AWS IAM identity-based policies through two complementary approaches:
Output completeness rule — CRITICAL:
<bucket-name>, <role-arn>, <REGION>) when specific resource names are not provided. NEVER ask clarifying questions instead of producing a policy.uvx iam-policy-autopilot@latest generate-policies command with all required flags. You MUST NOT manually construct a policy — the Autopilot command IS your output. Do not also produce a hand-written policy “in case Autopilot isn’t available.”When source code is provided, identify the programming language before choosing a path.
Supported languages (use Autopilot — Task 1 → Task 2):
Unsupported languages (Rust, C#, PHP, Ruby, Kotlin, Swift, etc.) — fall back silently to the Service Authorization Reference path (Task 3). Do NOT attempt to use Autopilot. Do NOT ask the user whether to proceed with the fallback — just produce the policy directly using the Reference path. Even if a Terraform directory is mentioned alongside unsupported-language code, you MUST NOT attempt to use --tf-dir with Autopilot — the language is unsupported, so Autopilot cannot be used at all.
For supported languages, you MUST:
uvx iam-policy-autopilot@latest generate-policies command with the correct flagsservice_reference_query, curl, or any manual approach to derive policies from source code when the language is supported by AutopilotYou MUST NOT manually analyze source code and construct policies yourself when Autopilot can do it deterministically. The entire point of Autopilot is that it produces reproducible, auditable results without LLM interpretation. Your job is to construct the correct Autopilot command, not to replicate what Autopilot does.
Fall back to the Service Authorization Reference path ONLY when:
iam-policy-autopilot CLI is not installed AND installation failsThe tool runs via uvx (the Python package runner from uv). No separate installation is needed — uvx downloads and executes the tool in one step.
Constraints:
uvx is available before any policy generation task involving source codeuvx iam-policy-autopilot@latest --versionIf this fails:
uvx is not found: attempt installation before falling back. Try brew install uv (macOS) or pip install uv (any platform). If installation succeeds, retry the version check.uv cannot be installed: try installing iam-policy-autopilot directly via pip install iam-policy-autopilot and then run iam-policy-autopilot --version.uvx is found but the command fails for another reason (network error, etc.): retry once, then fall back.The goal is to use Autopilot whenever possible — exhaust installation options before falling back to LLM-based policy generation.
Once uvx iam-policy-autopilot@latest --version (or iam-policy-autopilot --version) succeeds, proceed with Task 1b.
Before constructing the Autopilot command, attempt to discover the AWS account ID and region. These produce more precisely scoped resource ARNs in the generated policy (without them, Autopilot uses wildcards).
Discovery methods (try in order):
User-provided values — If the user specified an account ID or region in their prompt, use those directly.
Environment variables — Check for AWS_ACCOUNT_ID, AWS_DEFAULT_REGION, or AWS_REGION:
echo "Account: ${AWS_ACCOUNT_ID:-not set}" && echo "Region: ${AWS_REGION:-${AWS_DEFAULT_REGION:-not set}}"AWS CLI / STS — If AWS credentials are configured, query STS:
aws sts get-caller-identity --query Account --output text
aws configure get regionProject configuration files — Look for account/region in common locations:
terraform.tfvars, *.tf files (look for region or account_id variables)cdk.json or cdk.context.jsonsamconfig.toml (look for region parameter).env files (look for AWS_REGION, AWS_ACCOUNT_ID)serverless.yml (look for provider.region)Constraints:
--account and --region (Autopilot will use wildcards in ARNs)--account and --region flags entirely. A missing flag (producing wildcard ARNs) is always better than a fabricated value (producing incorrect ARNs that won’t match real resources).--account and --region flags in the Autopilot commandAnalyzes source files using deterministic static analysis to produce minimal IAM identity-based policies.
When to use: User has application source code that makes AWS SDK calls and wants IAM policies generated from it.
uvx iam-policy-autopilot@latest generate-policies \
/home/user/project/src/app.py /home/user/project/src/handler.py \
--region us-east-1 \
--account 123456789012 \
--service-hints s3 dynamodb \
--prettyRequired parameters:
<source_files> — One or more absolute paths to source filesOptional parameters:
--region <REGION> — AWS region for resource ARNs--account <ACCOUNT> — AWS account ID for resource ARNs--service-hints <SERVICES> — Space-separated AWS service names to scope analysis--pretty — Pretty-print JSON output--upload-policies <PREFIX> — Upload generated policies to IAM with given prefix--tf-dir <DIR> — Terraform project directory for more precise ARNs--tfstate <FILES> — terraform.tfstate files for deployed resource ARNs (highest precision)--explain <PATTERN> — Explain why specific actions were includedConstraints:
--service-hints to reduce false positives from ambiguous method names--region and --account if values were discovered in Task 1b or provided by the user — these produce scoped ARNs instead of wildcards--upload-policies, recommend enabling CloudTrail logging and CloudWatch alarms for IAM changes (see Security Considerations)service_reference_query or manually construct the policy — delegate to AutopilotTerraform integration — MANDATORY:
--tf-dir <absolute_path> (or --tfstate <file>) in the Autopilot command. This is NOT optional.--tf-dir produces more precise ARNs than manual construction.When to use: Autopilot is unavailable, the task does not involve source code, or the user names specific API operations/IAM actions directly.
Constraints:
service_reference_query tool is availablecurl and jq fallback automatically — do NOT ask the user for permission to proceedCollect the information needed to generate the policy.
Required parameters:
operations — The AWS API operations the user wants to perform (e.g., CopyObject — note: this is an API operation, not an IAM action. CopyObject requires s3:GetObject + s3:PutObject; there is no s3:CopyObject IAM action). API operation names and IAM action names frequently differ.Optional parameters:
account_id — AWS account ID for ARN construction (default: placeholder 123456789012)region — AWS region (default: us-east-1)resource_scope — Specific resource ARNs or patterns (default: derived from service reference)policy_type — identity or resource (default: identity)Constraints:
Look up the correct IAM actions for each requested API operation.
The reference lives at https://servicereference.us-east-1.amazonaws.com/v1/<service>/<service>.json. These files are large. Use the service_reference_query tool or curl with jq to extract only what you need.
See service authorization reference details for all query patterns and the reference structure.
Tool call example:
service_reference_query(service="lambda", operation="CreateFunction")CLI fallback (when the tool is unavailable):
curl -s "https://servicereference.us-east-1.amazonaws.com/v1/lambda/lambda.json" | \
jq '.Operations[] | select(.Name == "CreateFunction")'Constraints:
AuthorizedActions for each operation, including cross-service actions (e.g., iam:PassRole for lambda:CreateFunction) and prerequisite actions (e.g., lambda:GetLayerVersion for lambda:CreateFunction — required to attach layers during creation). Do NOT omit actions from the AuthorizedActions list based on your own judgment about whether they seem “optional” — if the service reference lists them, include them.s3-object-lambda:*, s3:GetObjectVersion, s3:GetObjectTagging) unless the user explicitly mentions Object Lambda, versioning, tagging, access points, or similar featuresBuild the IAM policy document from the queried actions.
Pre-flight check — BEFORE writing any action name into a policy, verify it is not in the hallucinated-actions table (see Troubleshooting section). Common mistakes: writing s3:SelectObjectContent instead of s3:GetObject, s3:HeadObject instead of s3:GetObject, s3:CreateMultipartUpload instead of s3:PutObject, s3:DeleteBucketEncryption instead of s3:PutEncryptionConfiguration. If you are about to write any S3 action that looks like an API operation name rather than a permission name, STOP and check the table.
Constraints:
*iam:PassRole) into their own statement with appropriate conditionsResource-based policy requirements:
When constructing resource-based policies (i.e., policy_type is resource), you MUST include condition keys to prevent confused deputy attacks where applicable:
aws:SourceArn — to restrict which resource ARN can invoke the cross-service callaws:SourceAccount — to restrict which account ID can make the requestaws:PrincipalOrgID — to restrict access to principals within a specific AWS OrganizationInclude whichever condition keys are supported by the service and relevant to the use case. Omit only when the service does not support the key or the user explicitly requests unrestricted access.
Condition operator safety rules (CRITICAL):
ForAnyValue in a Deny statement, you MUST add a separate Deny statement with a Null condition ("Null": {"<key>": "true"}) to handle the case where the context key is absent. Without this, requests missing the key bypass the deny entirely.ForAllValues in an Allow statement, you MUST add a Null condition ("Null": {"<key>": "false"}) in the same statement to require the key to exist. Without this, requests missing the key are silently allowed.ForAnyValue and ForAllValues MUST only be used with array-typed condition keys (ArrayOfString, ArrayOfARN, etc.) — never with scalar types.aws:TagKeys, aws:VpceOrgPaths) MUST use a set operator (ForAnyValue: or ForAllValues:) — plain StringNotLike or StringEquals without a set operator is INCORRECT for these keys.Worked example — ForAnyValue:StringNotLike in Deny (MANDATORY pattern):
When restricting access based on a multi-valued key like aws:VpceOrgPaths, you MUST produce TWO Deny statements:
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "DenyNonMatchingVpceOrgPath",
"Effect": "Deny",
"Principal": "*",
"Action": "s3:*",
"Resource": ["arn:aws:s3:::my-bucket", "arn:aws:s3:::my-bucket/*"],
"Condition": {
"ForAnyValue:StringNotLike": {
"aws:VpceOrgPaths": "o-orgid/r-rootid/ou-ouid/*"
}
}
},
{
"Sid": "DenyMissingVpceOrgPath",
"Effect": "Deny",
"Principal": "*",
"Action": "s3:*",
"Resource": ["arn:aws:s3:::my-bucket", "arn:aws:s3:::my-bucket/*"],
"Condition": {
"Null": { "aws:VpceOrgPaths": "true" }
}
}
]
}Key rules for this pattern:
ForAnyValue:StringNotLike (NOT plain StringNotLike) because aws:VpceOrgPaths is a multi-valued/array keyNull check MUST reference the SAME condition key (aws:VpceOrgPaths), not a different key like aws:VpcEndpointIdSee common pitfalls for additional examples.
| Situation | Path | Command/Approach |
|---|---|---|
| Source code using AWS SDKs | Autopilot | generate-policies with source files |
| Policy seems too broad from Autopilot | Autopilot | Re-run with --service-hints |
| Need to understand a specific action | Autopilot | Use --explain with an action pattern |
| Using Terraform and want precise ARNs | Autopilot | Add --tf-dir or --tfstate flags |
| Autopilot unavailable or install failed | Reference | Query service authorization reference |
| User names specific API operations (no source code) | Reference | Query service authorization reference |
| Unsupported language | Reference | Query service authorization reference |
| Need resource-based policies | Reference | Autopilot only supports identity-based |
--service-hints are omitted, Autopilot may match ambiguous method names across multiple services, producing broader policies than intended. When using the Reference path, incomplete operation lists or missing cross-service actions can result in either over- or under-permissive policies. Always review generated policies before deployment..env, terraform.tfvars) to discover account IDs and regions. Ensure these files do not contain secrets beyond what is needed, and be aware that STS calls appear in CloudTrail logs.--upload-policies flag creates and attaches IAM policies directly. You MUST NOT use this flag without explicit user confirmation. When using --upload-policies, recommend that users:
CreatePolicy, AttachRolePolicy events)iam:SimulateCustomPolicy or the IAM Policy Simulator to validate that the policy grants only the intended access.aws:SourceArn — restricts access to a specific resource ARN making the cross-service callaws:SourceAccount — restricts access to a specific account IDaws:PrincipalOrgID — restricts access to principals within a specific AWS OrganizationIf uvx is not installed, the user needs to install uv first: https://docs.astral.sh/uv/getting-started/installation/ (opens in a new tab) (or brew install uv on macOS, pip install uv elsewhere). Once uv is installed, uvx is available and no further setup is needed. If uvx cannot be installed, fall back to the Service Authorization Reference path.
Use --service-hints to restrict analysis. Without hints, ambiguous method names may match multiple AWS services.
Ensure source files contain actual AWS SDK client calls (e.g., s3_client.get_object(), new S3Client().send()). Wrapper functions without direct SDK usage won’t be detected.
API names and IAM actions frequently differ. Query the service authorization reference — do not guess. For example, dynamodb:BatchExecuteStatement does not exist as an IAM action — the operation requires dynamodb:PartiQLDelete, PartiQLInsert, PartiQLSelect, and PartiQLUpdate.
These are API operation names that models incorrectly use as IAM actions. The left column shows what you MUST NOT write; the right column shows what you MUST write instead:
| ❌ WRONG (not a real IAM action) | ✅ CORRECT IAM action(s) |
|---|---|
s3:UploadPartCopy | s3:PutObject (destination) + s3:GetObject (source) |
s3:CopyObject | s3:PutObject (destination) + s3:GetObject (source) |
s3:SelectObjectContent | s3:GetObject |
s3:HeadObject | s3:GetObject |
s3:HeadBucket | s3:ListBucket |
s3:ListBuckets | s3:ListAllMyBuckets |
s3:ListObjectVersions | s3:ListBucketVersions |
s3:DeleteBucketEncryption | s3:PutEncryptionConfiguration |
s3:GetObjectLockConfiguration | s3:GetBucketObjectLockConfiguration |
s3:CreateMultipartUpload | s3:PutObject |
dynamodb:BatchExecuteStatement | dynamodb:PartiQL* actions |
apigateway:CreateRestApi | apigateway:POST + apigateway:PUT on /restapis |
apigateway:CreateApi | apigateway:POST on /apis |
apigatewayv2:CreateApi | apigateway:POST on /apis |
apigateway:UpdateStage | apigateway:PATCH on /restapis/*/stages/* |
apigateway:DeleteRestApi | apigateway:DELETE on /restapis/<api-id> |
How to read this table: If you find yourself about to write an action from the left column, STOP and use the right column instead. The left column contains API operation names that do NOT exist as IAM actions.
When in doubt, ALWAYS query the service authorization reference. Never guess action names from API operation names.
API Gateway uses HTTP-verb-based actions (POST, GET, PUT, PATCH, DELETE). Always scope to the specific resource path — do NOT use "Resource": "*":
| Operation | Action(s) | Resource ARN |
|---|---|---|
| Create REST API | apigateway:POST, apigateway:PUT | arn:aws:apigateway:*::/restapis |
| Create HTTP API (v2) | apigateway:POST | arn:aws:apigateway:*::/apis |
| Create authorizer | apigateway:POST | arn:aws:apigateway:*::/restapis/*/authorizers |
| Create domain name | apigateway:POST | arn:aws:apigateway:*::/domainnames |
| Update stage | apigateway:PATCH | arn:aws:apigateway:*::/restapis/*/stages/* |
| Delete REST API | apigateway:DELETE | arn:aws:apigateway:*::/restapis/<api-id> |
| Invoke (data plane) | execute-api:Invoke | arn:aws:execute-api:*:*:<api-id>/<stage>/*/* |
IMPORTANT — API Gateway v2 (HTTP APIs) ARN format:
/apis in the IAM resource ARN — NOT /v2/apis/v2/ prefix is an API endpoint URL path, NOT part of the IAM ARN format/restapis) and HTTP APIs (/apis) use the same apigateway: service prefix in IAMIMPORTANT — CreateRestApi requires both POST and PUT:
CreateRestApi operation requires apigateway:POST for the core creation, plus apigateway:PUT for import/clone operations that occur during creation (e.g., importing an OpenAPI definition)apigateway:POST and apigateway:PUT when generating policies for REST API creationSome operations require actions in other services (e.g., lambda:CreateFunction requires iam:PassRole). Always check the full AuthorizedActions list including entries where Service differs from the queried service.
Lambda CreateFunction — complete action list (commonly incomplete):
The CreateFunction operation requires ALL of the following:
lambda:CreateFunction (core action)lambda:GetLayerVersion (required to attach layers during creation)lambda:TagResource (required if tags are applied at creation)iam:PassRole with iam:PassedToService condition for lambda.amazonaws.com (cross-service, separate statement)Do NOT omit lambda:GetLayerVersion — it is listed in AuthorizedActions and is required for the operation to succeed when layers are involved.
These operators have critical edge cases with missing context keys. See common pitfalls for the Null-check patterns required to use them safely.
Verify the resource ARN format matches what the service expects. Use query pattern 3 from the service authorization reference to look up the correct ARN format.
| Language | SDK |
|---|---|
| Python | boto3, botocore |
| Go | AWS SDK for Go v2 |
| TypeScript | AWS SDK for JavaScript v3 |
| JavaScript | AWS SDK for JavaScript v3 |
| Java | AWS SDK for Java v2 |
--tfstate for deployed resource ARNs