AWS IAM Policy Generator: Least-privilege IAM, S3 bucket and trust policies — JSON or Terraform.
Runs in your browser — nothing you paste leaves this page. How we prove that
AWS IAM Policy Generator playground
s3:ListBucket acts on the bucket ARN and s3:GetObject on object ARNs (bucket/*), so they need separate resources — granting both on one ARN leaves one of them with no effect.
Selected: s3:ListBucket
Filled from the AWS ARN format of each action's resource type until you edit it. Replace every ${…} placeholder.
Results update as you type — press Enter to run now.
Policy JSON
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "ListBucket",
"Effect": "Allow",
"Action": "s3:ListBucket",
"Resource": "arn:aws:s3:::example-bucket"
},
{
"Sid": "ReadObjects",
"Effect": "Allow",
"Action": "s3:GetObject",
"Resource": "arn:aws:s3:::example-bucket/*"
}
]
}Action data: AWS Service Reference, retrieved 2026-10-04
Pick a service, the actions and the resources they act on, add conditions, and get a valid IAM identity policy, S3 bucket policy or role trust policy as JSON and as a Terraform aws_iam_policy_document — with the size checked against the AWS quota and a warning on every wildcard, all computed in your browser, no signup required.
The Gap
"Action": "*" works. That is the problem.
AWS evaluates three kinds of policy you will write by hand. An identity policy is attached to a user, group or role and says what that principal may do, so it has no Principal element. A resource-based policy — an S3 bucket policy, a KMS key policy, an SQS queue policy — is attached to the resource and must name who it applies to in Principal. A trust policy is the resource-based policy on a role: it decides who may assume the role, typically with sts:AssumeRole or, for GitHub Actions and other OIDC providers, sts:AssumeRoleWithWebIdentity.
Least privilege means granting only the actions a workload calls, on only the resources it touches. A wildcard policy passes every test and fails the audit: requests are denied by default, an explicit Deny beats any Allow, and everything a policy allows is what a leaked credential can do. Scoping is fiddly because actions act on different resource types — s3:ListBucket on the bucket ARN, s3:GetObject on bucket/*.
Policies also have size limits, counted without whitespace: 6,144 characters for a customer managed policy; for inline policies, 2,048 characters across a user, 5,120 across a group and 10,240 across a role; and 20 KB for an S3 bucket policy. A policy that grew one statement at a time fails at deploy, not in review.
The generator checks grammar, quotas and common over-grants; it does not simulate AWS evaluation. Confirm effective access with IAM Access Analyzer or the IAM policy simulator before production.
The Pipeline
How it works.
Four deterministic steps run on every change — all inside your browser tab, against action data taken from the AWS Service Reference.
-
Pick the actions.
Choose a service and filter its actions by access level — List, Read, Write, Permissions management, Tagging. The action list comes from the AWS Service Reference, bundled with the page.
-
Scope the resources.
Each action names the resource types it acts on; the ARN format for that type is filled in, so you replace placeholders instead of typing ARNs from memory.
-
Assemble and check.
Statements become a Version 2012-10-17 document. Sids must be alphanumeric and unique, a bucket policy needs a Principal and an identity policy must not have one, and every condition operator is checked.
-
Measure and warn.
The minified policy is measured against the quota you pick, and wildcard actions, Resource "*" on write actions, permissions-management actions and an unconditioned Principal "*" are flagged. Nothing leaves the tab.
Policy Reference
One bucket, read-only, two formats.
The first preset as the panel generates it: the same two statements as policy JSON and as a Terraform data source.
Identity policy JSON
s3:ListBucket acts on the bucket and s3:GetObject on its objects, so each statement carries its own ARN. Minified, it is 248 of the 6,144 characters a managed policy allows.
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "ListBucket",
"Effect": "Allow",
"Action": "s3:ListBucket",
"Resource": "arn:aws:s3:::example-bucket"
},
{
"Sid": "ReadObjects",
"Effect": "Allow",
"Action": "s3:GetObject",
"Resource": "arn:aws:s3:::example-bucket/*"
}
]
} The same policy in Terraform
Pass data.aws_iam_policy_document.policy.json to an aws_iam_policy or aws_iam_role_policy resource.
data "aws_iam_policy_document" "policy" {
statement {
sid = "ListBucket"
effect = "Allow"
actions = ["s3:ListBucket"]
resources = ["arn:aws:s3:::example-bucket"]
}
statement {
sid = "ReadObjects"
effect = "Allow"
actions = ["s3:GetObject"]
resources = ["arn:aws:s3:::example-bucket/*"]
}
} Next Step
Deploying from GitHub Actions? Drop the access keys.
An OIDC trust policy lets a workflow assume a role with short-lived credentials, pinned to one repository and branch. The guide walks through the identity provider, the trust policy, configure-aws-credentials and the same setup in Terraform.
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Principal": {
"Federated": "arn:aws:iam::123456789012:oidc-provider/token.actions.githubusercontent.com"
},
"Action": "sts:AssumeRoleWithWebIdentity",
"Condition": {
"StringEquals": {
"token.actions.githubusercontent.com:aud": "sts.amazonaws.com"
},
"StringLike": {
"token.actions.githubusercontent.com:sub": "repo:my-org/my-repo:ref:refs/heads/main"
}
}
}
]
} FAQ
Questions, answered.
Tap a question to expand the answer.
What is an IAM policy, and what is the difference between identity-based and resource-based policies?
An IAM policy is a JSON document that lists which actions are allowed or denied on which resources, optionally under conditions. An identity-based policy is attached to a user, group or role and grants that identity its permissions, so it has no Principal element. A resource-based policy is attached to the resource itself — an S3 bucket, an SQS queue, a KMS key — and must name the Principal it applies to. When both apply to a request in the same account, AWS combines them, and an explicit Deny in either one always wins.
What is the difference between an IAM policy and an S3 bucket policy?
The Principal element. An IAM policy is attached to a user, group or role, so the principal is implied and the element is not allowed. A bucket policy is attached to the bucket, so every statement must say who it applies to — another account, a role ARN, a service such as cloudfront.amazonaws.com, or "*" for everyone. The generator enforces this either way: it requires a Principal in bucket mode, rejects one in identity mode, and warns when a bucket statement grants Principal "*" without a Condition.
How do I write a least-privilege IAM policy?
Grant only the actions the workload actually calls, on only the resources it touches: name specific actions instead of s3:* or *, and put real ARNs in Resource instead of "*". Add conditions where they narrow access further, for example aws:SourceVpce, aws:PrincipalOrgID or a resource tag. Then let AWS check the result: IAM Access Analyzer validates a policy against AWS best practices and can generate a policy from the actions a role has actually used, based on its CloudTrail history. The generator flags wildcard actions, Resource "*" on write and permissions-management actions, and Allow with NotAction.
What are the size limits for IAM and bucket policies?
A customer managed policy can be at most 6,144 characters. Inline policies are limited per identity, as the total of all inline policies attached to it: 2,048 characters for a user, 10,240 for a role and 5,120 for a group. IAM does not count white space toward these limits, which is why the size meter measures the minified JSON. An S3 bucket policy is a separate limit of 20 KB, and these character limits cannot be raised through a quota request.
How do I use the generated policy with Terraform?
The Terraform tab writes the same statements as a data "aws_iam_policy_document" block, which Terraform renders to JSON when it plans. Reference its json attribute wherever a policy is expected: policy = data.aws_iam_policy_document.example.json on an aws_iam_policy for a managed policy, on an aws_iam_role_policy for an inline role policy, or on an aws_s3_bucket_policy for a bucket policy. If you prefer to keep the raw JSON, jsonencode() or a heredoc works too, but the data source keeps the policy in HCL where it diffs cleanly.
Where does the list of actions come from?
From the AWS Service Reference, the machine-readable JSON files AWS publishes for each service with its actions, resource types and condition keys. The page states the date the data was retrieved, and the list covers 12 commonly used services: S3, EC2, Lambda, DynamoDB, IAM, CloudWatch Logs, SQS, SNS, KMS, STS, Secrets Manager and ECR. Each action carries its access level — Read, List, Write, Permissions management or Tagging — and the resource types it can be scoped to, which is what drives the ARN templates and the warnings. For any other service, the Service Authorization Reference in the AWS documentation is the authoritative list.
What is a trust policy?
A trust policy is the resource-based policy attached to an IAM role that says who may assume it; the role's permissions policies then say what that principal can do once it has. For GitHub Actions with OIDC, the trust policy allows sts:AssumeRoleWithWebIdentity for the federated principal token.actions.githubusercontent.com, with conditions that require the aud claim to equal sts.amazonaws.com and the sub claim to match your repository, such as repo:my-org/my-repo:ref:refs/heads/main — or, for repositories created after 15 July 2026, the immutable form repo:my-org@<owner-id>/my-repo@<repo-id>:ref:refs/heads/main. Leaving out the sub condition would let any GitHub repository assume the role. A role trust policy is limited to 2,048 characters by default, adjustable up to 8,192.
Does my policy ever leave my browser?
No. The generator runs 100% client-side: the action catalogue ships with the page and every policy is built in your browser tab. Nothing is uploaded to a server, there is no account or signup, and the share link encodes your policy in the URL fragment, which browsers never send to a server.
More free, private DevOps tools.
The AWS IAM Policy Generator is one tool in OpsCanopy — a growing canopy of browser-based validators, converters and testers that never touch a server.
More in Security
New to AWS? Read the AWS guide →
42 free tools, every one offline-capable — opscanopy.com works with no signup and nothing uploaded.
More for securing a pipeline: the JWT Decoder and the Certificate Decoder, or browse the full tools directory.
The generator checks structure, quotas and common over-grants but does not evaluate SCPs, permissions boundaries or session policies — test with IAM Access Analyzer before you deploy. OpsCanopy is free and open.