Most IAM in production is the wrong shape. The roles were created in the first month under deadline pressure, with permissions chosen by guessing rather than designing. The wildcards (s3:*, Resource: *) were added because something was failing and the wildcard fixed it. The new permissions added since then accumulated without anyone removing the old ones, so each role now has more than it needs and probably more than the team realizes. The result is a set of roles that work but offer almost no protection: a compromised service account has access to most of the account, a misconfigured deploy can rewrite anything, and the security team has stopped trying to audit the policies because the permission graph is too large to reason about.
The principle that prevents this is least privilege: each role gets the minimum permissions needed for its actual workload, and nothing else. The principle is well-known and rarely applied because applying it requires designing the permissions deliberately rather than copying an existing role. Designing them deliberately requires knowing what each service actually does, which API calls it makes, which resources it touches. That information exists in the codebase but is not in any one place; assembling it is the work that gets skipped, which is why the first wildcard wins. The /warden-iam skill is built to do that assembly: it reads the codebase, identifies the actual access patterns per service, and produces the IAM with the right scope from the start.
Why generalist AI produces over-permissioned roles
Ask Cursor or ChatGPT for an IAM role for a service that uses S3. You get a role with s3:* and Resource: "*". The role works for any S3 operation on any bucket. It also fails the principle of least privilege spectacularly: a compromised service account using this role has full S3 access across the account. The model could have produced a scoped role (s3:GetObject, s3:PutObject, on a specific bucket prefix), but doing so requires knowing which bucket and which operations, and the model does not know. The wildcard is the safe answer for the prompt; it is the wrong answer for the production environment.
The other failure mode is the missing explicit denies. Some actions are so dangerous that they warrant an explicit deny on every role except the few that actually need them: deleting backups, rotating root credentials, modifying IAM itself. A generalist tool will not include these because the prompt did not ask for them, and the cost of forgetting them is paid the day someone's access key leaks and an attacker uses the inherited permissions to disable backups before exfiltrating data. /warden-iam includes explicit denies for these high-impact actions by default.
What least-privilege IAM actually requires
Least-privilege design has four parts. First, the actor inventory: every service, every human role, every external integration that needs access. Each actor is a separate IAM identity. Second, the access pattern inventory: what each actor actually needs to do (read this bucket, write that queue, invoke this Lambda, list these tables). The pattern inventory is derived from the codebase, not from imagination. Third, the policies: one per role, with the actions and resources scoped to the actual access pattern, with explicit denies on high-impact actions that the role does not need. Fourth, the documentation: a per-role document that explains what the role can do, why it has those permissions, and what to remove if the role's responsibilities change.
The discipline is to design these together. A role designed without the access pattern inventory ends up with wildcards because there is no list of specific actions to scope to. A policy designed without the explicit denies ends up missing the protections that bound the worst case. Documentation written after the fact misses the reasoning. /warden-iam produces all four together as a single artifact so the team can review the full access model rather than approving roles one at a time.
How /warden-iam works
Step one: identify actors and access patterns
When invoked, /warden-iam reads the codebase to identify the actors (each service, each scheduled job, each human role) and their access patterns (which AWS/GCP/Azure APIs each one calls, with what arguments). The pattern inventory is grounded in the actual code: the s3.GetObject call in media-service becomes a specific permission on the specific bucket prefix; the sqs.SendMessage call in worker becomes a specific permission on the specific queue. The list is the input to the policies.
Step two: produce the policies
Each role gets a policy listing the specific actions and resources it needs. Wildcards on resources are flagged as override candidates; if a wildcard is required (an admin role for break-glass, a logging role that writes to a wildcard prefix), the override is documented with the reason. Explicit denies are added for high-impact actions: deleting backups, modifying IAM, rotating root credentials. The policy is the final artifact; the team reviews it for shape before it is applied.
Step three: trust relationships
The trust policy (who can assume the role) is designed alongside the permission policy. A service role is assumed only by the service that needs it (the EC2 instance profile, the Lambda execution role, the EKS service account). A human role is assumed via SSO with the right group. A cross-account role has the right external ID requirement. Each trust relationship is documented with the assumption flow so the team can audit how the role can actually be used.
Step four: document the access model
The output ends with a per-role document: what the role does, what it can act on, what it explicitly cannot do, what triggers reviewing the role's permissions. The document is the artifact that future engineers read when they want to know whether their service should reuse an existing role or get a new one. Without the document, the default behavior is to copy an over-permissioned role, which is how the original sprawl started.
An IAM role with iam:PassRole and a wildcard on the role it can pass is one of the most dangerous combinations: it lets the principal escalate to any role in the account. /warden-iam refuses this combination by default and requires explicit override with a documented reason.
Tonone's /warden-iam skill designs IAM from scratch using least-privilege principles, with policies grounded in actual code access patterns, explicit denies on high-impact actions, and per-role documentation.
When to use /warden-iam, and when not to
/warden-iam is the right call when setting up cloud permissions for a new system or team, when existing IAM has accumulated permissions and needs cleanup, or when a new team member or service needs access and you want to define it with least privilege rather than copy an over-permissioned role.
Skip the skill for incremental permission additions to an already-well-scoped role (a regular IAM edit). For broader application security work (auth middleware, validation, rate limits), /warden-harden is the right call. For threat modeling that informs which controls matter most, /warden-threat produces the model.
| Capability | Tonone | Generalist chatbot | Cursor / Copilot |
|---|---|---|---|
| Reads codebase for actual access patterns | Yes, derives permissions from API calls | Wildcards as default | Not in scope |
| Per-actor policy design | Yes, one role per actor with scoped actions | Single broad role | Not in scope |
| Explicit denies on high-impact actions | Yes, by default | Not included | Not in scope |
| Trust policy designed alongside permissions | Yes, assumption flow documented | Generic trust | Not in scope |
| Per-role access documentation | Yes, what/why/what triggers review | Not in scope | Not in scope |
A worked example: IAM for a new service
Suppose the brief is: design IAM for a new image-processing service that reads from S3, writes thumbnails back to S3, sends jobs to SQS, and writes metadata to DynamoDB. Run /warden-iam.
// IAM Role: image-processor
// Purpose: process user-uploaded images, generate thumbnails,
// write metadata, queue downstream notifications.
//
// Trust policy: assumed by the image-processor ECS task only.
//
// Permission policy:
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "ReadOriginalUploads",
"Effect": "Allow",
"Action": ["s3:GetObject"],
"Resource": ["arn:aws:s3:::acme-uploads/users/*/originals/*"]
},
{
"Sid": "WriteThumbnails",
"Effect": "Allow",
"Action": ["s3:PutObject", "s3:PutObjectAcl"],
"Resource": ["arn:aws:s3:::acme-uploads/users/*/thumbnails/*"]
},
{
"Sid": "QueueNotifications",
"Effect": "Allow",
"Action": ["sqs:SendMessage"],
"Resource": ["arn:aws:sqs:us-east-1:111122223333:image-processed"]
},
{
"Sid": "WriteImageMetadata",
"Effect": "Allow",
"Action": [
"dynamodb:PutItem",
"dynamodb:UpdateItem",
"dynamodb:GetItem"
],
"Resource": ["arn:aws:dynamodb:us-east-1:111122223333:table/image-metadata"]
},
{
"Sid": "DenyDangerousIam",
"Effect": "Deny",
"Action": [
"iam:*",
"sts:AssumeRole",
"backup:DeleteRecoveryPoint",
"kms:ScheduleKeyDeletion"
],
"Resource": "*"
}
]
}
// Documentation:
// What this role can do:
// - Read user originals from acme-uploads/users/*/originals/*
// - Write thumbnails to acme-uploads/users/*/thumbnails/*
// - Send messages to the image-processed SQS queue
// - Read/write metadata in image-metadata DynamoDB table
//
// What this role explicitly cannot do:
// - Modify any IAM resources
// - Assume any other role
// - Delete backup recovery points
// - Schedule KMS key deletion
//
// Review trigger: whenever image-processor adds a new AWS API call,
// update this policy to include only that specific action and resource.The role is scoped to exactly what the service does. The explicit denies bound the blast radius if the role is compromised. The documentation tells future engineers when to revisit. That is what least-privilege IAM looks like in practice; the alternative is the wildcard role nobody can audit.
Related skills
/warden-iam designs IAM. For broader application hardening (auth middleware, validation, rate limits, security headers), /warden-harden is the right call. For threat modeling that informs the IAM design, /warden-threat is the entry point. For the cloud infrastructure that the IAM applies to, /forge-infra produces the IaC.
Install
/warden-iam ships with the Warden agent in the Tonone for Claude Code package. Install Tonone, invoke /warden-iam from any Claude Code session, and the skill produces least-privilege IAM grounded in the actual code access patterns.
1. Add to marketplace
2. Install Warden
IAM done right on day one is the IAM nobody has to clean up later. The skill is built so least privilege is the default, not the audit response.
Frequently asked questions
- What does /warden-iam do?
- It designs IAM from scratch using least-privilege principles. The output includes per-actor roles with scoped permissions, trust policies, explicit denies on high-impact actions, and documentation per role.
- What clouds does /warden-iam support?
- AWS IAM, GCP IAM, and Azure RBAC. The skill detects which the project uses and produces the equivalent role/policy artifacts in each cloud's native format.
- How is /warden-iam different from copying an existing role?
- Copying inherits the over-permissioning. /warden-iam derives permissions from the actual code access patterns of the new actor, producing a role scoped to that actor's needs.
- When should I use /warden-iam?
- When setting up cloud permissions for a new system, when existing IAM needs cleanup, or when adding a new actor (service or human) and wanting to apply least privilege rather than copying an existing role.
- Does /warden-iam audit existing IAM?
- Yes. Run it against an existing account to produce a cleanup plan: which permissions are unused, which wildcards can be scoped down, which roles can be merged or split for clarity.
- How do I install /warden-iam?
- Install Tonone for Claude Code via the get-started guide at tonone.ai/get-started. /warden-iam ships with the Warden agent and is invoked as a slash command in any Claude Code session. Tonone is free and MIT-licensed.
- Is /warden-iam free?
- Yes. The skill is part of Tonone, which is MIT-licensed. The only cost is Claude Code token usage during the work.
- Does /warden-iam handle cross-account access?
- Yes. Cross-account roles are designed with external ID requirements and the right trust policy, with the assumption flow documented so the team can audit how the role is actually used.