AWS IAM CLI Commands: Manage Users, Roles, and Policies
After reading this page you will be able to create, inspect, update, and delete IAM users, groups, roles, and policies entirely from your terminal. The AWS CLI is the fastest tool for repeatable admin work, audits, and scripting. For most workloads and human access, roles and temporary credentials are the safer default over long-lived IAM user credentials.
Simple explanation
IAM controls who can do what inside your AWS account. Every API call to AWS gets checked against IAM policies before it is allowed or denied.
The AWS CLI is a terminal interface that lets you create, inspect, and update IAM resources (users, groups, roles, and policies) without opening the AWS Console. It shines when you need repeatable, scriptable, auditable changes: adding the same role across ten accounts, checking every policy on a role, or generating a credential report to find stale access keys.
Think of IAM as the security desk in an office building. The security desk decides who gets a badge (users), which floors each badge opens (policies), and which teams share the same access level (groups). Roles are like visitor passes: they are temporary, expire on their own, and get handed to whoever has a valid reason to enter. The AWS CLI is the radio the security team uses to issue commands quickly instead of walking to every door in person.
For human access and most application workloads, short-lived credentials obtained through role assumption are the safer default. IAM users with permanent access keys still have valid use cases, but they should not be your starting point.
Before you start
- AWS CLI installed and configured. If you have not set it up yet, follow Installing the AWS CLI and then configuring the AWS CLI.
- Correct account and profile. If you manage multiple AWS accounts, always pass
—profile your-profile-nameor setAWS_PROFILEto avoid running commands against the wrong account. - CloudShell as an alternative. If you do not want to install anything locally, AWS CloudShell gives you a browser-based terminal with the CLI pre-installed and authenticated.
- IAM management permissions. You need permissions like
iam:CreateRole,iam:AttachRolePolicy,iam:ListUsers, and related actions. A dedicated IAM-management role scoped to the actions you need is better than using full admin. - Never use root credentials for day-to-day work. The root account should be locked behind MFA and used only for account-level tasks that no other principal can perform.
- Prefer role-based or federated access. Where possible, use IAM Identity Center (SSO) or federated access with an identity provider instead of creating standalone IAM users. See IAM Users vs Roles for guidance on which to choose.
Before running any IAM command, confirm you are in the right account by running aws sts get-caller-identity. This takes one second and can save you from accidentally modifying production IAM resources.
How IAM management works from the CLI
IAM has four core resource types, and the CLI gives you commands for all of them:
- Users are identities with permanent credentials (password, access keys). Best reserved for specific integration use cases, not as the default access model.
- Groups are collections of users. Attach policies to a group and every user in that group inherits those permissions. Groups simplify permission management when you do need IAM users.
- Roles are identities with no permanent credentials. A trusted entity (an EC2 instance, a Lambda function, a human using SSO) assumes the role and receives temporary credentials. Roles are the recommended way to grant access in most scenarios.
- Policies are JSON documents that define what actions are allowed or denied on which resources. Managed policies are standalone and reusable — AWS provides pre-built ones and you can write your own. Inline policies are embedded directly on a single user, group, or role. See managed vs customer managed policies.
Roles have two policy dimensions that are easy to confuse:
- Trust policy defines who can assume the role (the “who can open this door?” question).
- Permissions policy defines what the role can do once assumed (the “what can you touch inside the room?” question).
A trust policy is the lock on a door: it decides who is allowed to turn the handle. A permissions policy is what is inside the room: it controls what you can touch once you are inside. Many IAM debugging headaches come from fixing the wrong one of these two.
“Attach” means linking a managed policy to a user, group, or role. “Assume” means a principal is temporarily taking on a role’s identity and permissions. For a deeper explanation of how assumption works, see Role Assumption in AWS.
The CLI is effective for both one-off operations (quickly check what policies a role has) and audit workflows (generate a credential report, list all entities with AdministratorAccess). For long-lived infrastructure, version-controlled tools like Terraform are usually a better fit.
When to use this
Good use cases for the CLI
- Auditing IAM resources. List all roles with a specific policy attached, generate credential reports, check for overly broad permissions.
- Scripting repeatable changes. Create the same role structure in multiple accounts, rotate credentials, bulk-update policy attachments.
- Checking policy attachments. Quickly see what policies are attached to a role, user, or group without navigating the console.
- Creating or updating roles for workloads. Set up a Lambda execution role, an EC2 instance role, or a cross-account role.
- Generating credential reports. Find stale access keys, users without MFA, or unused accounts.
- Quick operational fixes. Attach a missing policy, remove an over-permissive attachment, or clean up a test user.
Many teams start with the CLI for quick wins, then graduate to Terraform once the IAM setup stabilizes. You do not have to pick one forever. Use the CLI to prototype, then codify the result.
When the CLI is not the best fit
- Broad declarative infrastructure management. If you are defining IAM for an entire application stack across multiple environments, Terraform gives you version control, plan previews, and drift detection.
- Long-term versioned IAM at scale. When dozens of roles and policies need to evolve together, managing them as code in a repository with review workflows is safer than ad-hoc CLI commands.
- First-time exploration. If you are learning what IAM resources exist in an account you have never seen before, the console’s visual layout can be faster for discovery.
Working with IAM users
IAM users have permanent credentials. They are appropriate for specific integration use cases, such as a third-party service that cannot assume a role, but for most human and application access, roles are preferred. If you do need IAM users, organize them into groups and apply least-privilege policies.
List all IAM users
Returns every IAM user in the account with creation date and ARN.
aws iam list-usersFor a cleaner view, filter to just usernames and ARNs:
aws iam list-users --query 'Users[*].[UserName,Arn]' --output tableCreate a new IAM user
aws iam create-user --user-name aliceCreate a console login profile
This gives the user a password for AWS Console access. The —password-reset-required flag forces them to change it on first login.
aws iam create-login-profile \
--user-name alice \
--password 'Temp@Password123!' \
--password-reset-requiredCreate access keys for a user
Access keys give the user programmatic access. Before creating them, ask whether a role would work instead. See AWS Access Keys Explained and why long-lived access keys are dangerous.
aws iam create-access-key --user-name aliceThis command returns the secret access key exactly once. It is never shown again. Store it securely immediately. For applications running inside AWS, do not create access keys at all. Use IAM roles with temporary credentials instead.
Delete a user
You cannot delete a user that still has policies, access keys, or group memberships attached. The CLI will reject the request. Follow the cleanup order below exactly, or you will get DeleteConflict errors.
# 1. Detach managed policies
aws iam detach-user-policy \
--user-name alice \
--policy-arn arn:aws:iam::aws:policy/AmazonS3ReadOnlyAccess
# 2. Remove from groups
aws iam remove-user-from-group \
--user-name alice \
--group-name Developers
# 3. Delete access keys
aws iam delete-access-key \
--user-name alice \
--access-key-id AKIAIOSFODNN7EXAMPLE
# 4. Delete the user
aws iam delete-user --user-name aliceWorking with IAM groups
Groups let you manage permissions for multiple IAM users at once. Instead of attaching policies to each user individually, attach them to a group and add users to it. When someone leaves a team, remove them from the group and the permissions go away instantly.
A group is like a department mailing list at a company. Instead of giving each person in marketing their own copy of every announcement, you add them to the “marketing” list and send once. When someone transfers to engineering, you remove them from the marketing list and add them to the engineering one. Their access changes immediately without touching individual permissions.
Groups are for IAM users only. You cannot add roles to groups, and groups cannot be referenced as principals in trust policies. If you are using IAM Identity Center (SSO), permission sets serve a similar organizational purpose for federated users.
List all groups
aws iam list-groups --query 'Groups[*].[GroupName,Arn]' --output tableCreate a group
aws iam create-group --group-name DevelopersAdd a user to a group
aws iam add-user-to-group \
--user-name alice \
--group-name DevelopersList users in a group
aws iam get-group --group-name Developers \
--query 'Users[*].[UserName]' --output tableAttach a managed policy to a group
Every user in the group inherits this policy immediately.
aws iam attach-group-policy \
--group-name Developers \
--policy-arn arn:aws:iam::aws:policy/PowerUserAccessDetach a policy from a group
aws iam detach-group-policy \
--group-name Developers \
--policy-arn arn:aws:iam::aws:policy/PowerUserAccessList policies attached to a group
aws iam list-attached-group-policies --group-name DevelopersName your groups after job functions (Developers, Auditors, BillingAdmins), not after individuals. This makes it obvious what access each group grants when you review IAM later.
Working with IAM roles
Roles are the preferred way to grant access in AWS. They issue temporary credentials through AWS STS, which eliminates the risk of permanent credential leaks. You attach a trust policy (who can assume the role) and one or more permissions policies (what the role can do). For a full explanation, see IAM Roles Explained.
List all roles
aws iam list-roles --query 'Roles[*].[RoleName,Arn]' --output tableCreate a role with a trust policy
Write the trust policy to a file first. This example creates a role that AWS Lambda can assume:
cat > trust-policy.json << 'EOF'
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Principal": { "Service": "lambda.amazonaws.com" },
"Action": "sts:AssumeRole"
}
]
}
EOF
aws iam create-role \
--role-name MyLambdaExecutionRole \
--assume-role-policy-document file://trust-policy.json \
--description "Execution role for order-processing Lambda"The trust policy controls who can assume the role. This is separate from the permissions policies that control what the role can do. For more on trust policy structure, see IAM Policy Structure.
Get details for a specific role
Returns the role’s ARN, creation date, trust policy, and description.
aws iam get-role --role-name MyLambdaExecutionRoleList policies attached to a role
aws iam list-attached-role-policies --role-name MyLambdaExecutionRoleAttach a managed policy to a role
aws iam attach-role-policy \
--role-name MyLambdaExecutionRole \
--policy-arn arn:aws:iam::aws:policy/service-role/AWSLambdaBasicExecutionRoleDetach a policy from a role
aws iam detach-role-policy \
--role-name MyLambdaExecutionRole \
--policy-arn arn:aws:iam::aws:policy/service-role/AWSLambdaBasicExecutionRoleDelete a role
You must detach all managed policies and delete all inline policies before deleting a role. If any policies remain attached, the CLI returns a DeleteConflict error. Check with list-attached-role-policies and list-role-policies first.
# 1. Detach all managed policies (repeat for each attached policy)
aws iam detach-role-policy \
--role-name MyLambdaExecutionRole \
--policy-arn arn:aws:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole
# 2. Delete all inline policies (repeat for each)
aws iam delete-role-policy \
--role-name MyLambdaExecutionRole \
--policy-name InlineDynamoDBAccess
# 3. Delete the role
aws iam delete-role --role-name MyLambdaExecutionRoleWorking with managed policies
Create a customer managed policy
Write the policy document to a file, then create the policy. This example grants read-only access to a specific S3 bucket:
cat > s3-read-policy.json << 'EOF'
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": ["s3:GetObject", "s3:ListBucket"],
"Resource": [
"arn:aws:s3:::my-app-bucket",
"arn:aws:s3:::my-app-bucket/*"
]
}
]
}
EOF
aws iam create-policy \
--policy-name MyAppS3ReadPolicy \
--policy-document file://s3-read-policy.jsonFor guidance on writing well-scoped policies, see IAM Policy Structure and Principle of Least Privilege.
List customer managed policies
Use —scope Local to filter out the hundreds of AWS-managed policies and see only your own:
aws iam list-policies --scope Local \
--query 'Policies[*].[PolicyName,Arn]' --output tableWithout —scope Local, list-policies returns every AWS-managed policy too (hundreds of them). Always filter when you are looking for your own policies. Use —scope AWS if you specifically want to browse the built-in ones.
Attach a managed policy to a user
aws iam attach-user-policy \
--user-name alice \
--policy-arn arn:aws:iam::123456789012:policy/MyAppS3ReadPolicyRetrieve the JSON for an existing policy
This is a two-step process because IAM policies can have multiple versions:
# Step 1: get the default version ID
aws iam get-policy \
--policy-arn arn:aws:iam::123456789012:policy/MyAppS3ReadPolicy{
"Policy": {
"PolicyName": "MyAppS3ReadPolicy",
"DefaultVersionId": "v1",
"...": "..."
}
}# Step 2: get the actual JSON document using that version ID
aws iam get-policy-version \
--policy-arn arn:aws:iam::123456789012:policy/MyAppS3ReadPolicy \
--version-id v1You can combine these two steps into one command using —query and shell substitution, but for learning purposes, running them separately makes it clearer what each step returns.
Create a new policy version and set it as default
Updating a customer managed policy means creating a new version. The —set-as-default flag makes the new version active immediately.
aws iam create-policy-version \
--policy-arn arn:aws:iam::123456789012:policy/MyAppS3ReadPolicy \
--policy-document file://updated-policy.json \
--set-as-defaultIAM retains up to 5 policy versions. If you have reached the limit, delete an old version first with aws iam delete-policy-version. For production environments, consider managing policies with Terraform so changes go through version control and code review.
If you omit —set-as-default, the new version is stored but not active. Use aws iam set-default-policy-version to promote it later.
Working with inline policies
Inline policies are embedded directly on a single user, group, or role. They are useful for tightly scoped, one-off permissions that you do not want reused elsewhere. For reusable permissions, prefer managed policies. See managed vs customer managed policies for guidance on when each type fits.
A managed policy is like a company-wide dress code posted on the wall: it applies to everyone it is attached to, and you update it in one place. An inline policy is like a sticky note on one person’s desk with a specific exception: “You are allowed to wear sneakers on Fridays.” It only applies to that one person, and if they leave, the sticky note goes with them.
Add an inline policy to a role
aws iam put-role-policy \
--role-name MyLambdaExecutionRole \
--policy-name InlineDynamoDBAccess \
--policy-document file://dynamo-policy.jsonList inline policies on a role
This returns only the policy names. Use get-role-policy to retrieve the actual JSON.
aws iam list-role-policies --role-name MyLambdaExecutionRoleGet an inline policy document
aws iam get-role-policy \
--role-name MyLambdaExecutionRole \
--policy-name InlineDynamoDBAccessDelete an inline policy
aws iam delete-role-policy \
--role-name MyLambdaExecutionRole \
--policy-name InlineDynamoDBAccessInline policies on users and groups
The same pattern applies with different command prefixes:
# Add inline policy to a user
aws iam put-user-policy \
--user-name alice \
--policy-name InlineS3Access \
--policy-document file://s3-policy.json
# List inline policies on a group
aws iam list-group-policies --group-name Developers
# Delete inline policy from a group
aws iam delete-group-policy \
--group-name Developers \
--policy-name InlineS3AccessSimulating and auditing permissions
Simulate a principal’s policy
Test whether a specific IAM entity is allowed to perform an action, without actually performing it. This is useful for debugging AccessDenied errors.
aws iam simulate-principal-policy \
--policy-source-arn arn:aws:iam::123456789012:role/MyLambdaExecutionRole \
--action-names s3:GetObject \
--resource-arns arn:aws:s3:::my-app-bucket/data.jsonPolicy simulation is a non-destructive way to answer “would this principal be allowed to do X?” before you deploy. It evaluates all attached policies, including any permission boundaries or SCPs, and tells you the result without making the actual API call.
Find all roles with AdministratorAccess attached
aws iam list-entities-for-policy \
--policy-arn arn:aws:iam::aws:policy/AdministratorAccessGenerate and retrieve the IAM credential report
The credential report is a CSV listing every IAM user, their password and access key status, MFA configuration, and last-used dates. It is the fastest way to find stale credentials.
# Generate the report (may take a few seconds)
aws iam generate-credential-report
# Download and decode it
aws iam get-credential-report \
--query 'Content' --output text | base64 --decodeLook for users with access keys unused for 90+ days, users without MFA enabled, and access keys that were never rotated. Stale credentials are one of the most common entry points in AWS account compromises. For guidance on what to act on, see the account monitoring guide.
Safer credential guidance
The commands on this page include creating IAM users and access keys because those operations are sometimes necessary. But they should not be your default approach.
Long-lived access keys are the most common source of AWS credential leaks. They get committed to Git, shared in chat, or left on decommissioned machines. Wherever possible, use roles and temporary credentials instead.
Preferred access patterns, ranked from safest to riskiest:
- IAM roles for workloads. EC2 instances, Lambda functions, ECS tasks, and other AWS services should use roles. The service handles credential rotation automatically.
- IAM Identity Center (SSO) for humans. Federated access through an identity provider gives humans short-lived credentials tied to their corporate identity.
- Role assumption with STS for cross-account or elevated access. Use
aws sts assume-roleto get temporary credentials scoped to a specific role. See AWS STS and Temporary Credentials. - IAM users with access keys (last resort). Only when the above options are not possible, such as third-party integrations that require static credentials. Rotate keys regularly, enforce MFA, and scope permissions tightly with least-privilege policies.
A long-lived access key is like a physical house key. Lose it once and anyone who picks it up has full access until you change the locks. A temporary credential from STS is like a hotel key card that expires at checkout. Even if someone finds it on the sidewalk, it stops working on its own.
Quick reference table
| Task | Command |
|---|---|
| List users | aws iam list-users |
| List groups | aws iam list-groups |
| Create user | aws iam create-user --user-name NAME |
| Create group | aws iam create-group --group-name NAME |
| Add user to group | aws iam add-user-to-group --user-name NAME --group-name GROUP |
| Create access key | aws iam create-access-key --user-name NAME |
| List roles | aws iam list-roles |
| Create role | aws iam create-role --role-name NAME --assume-role-policy-document file://trust.json |
| Get role details | aws iam get-role --role-name NAME |
| Attach policy to role | aws iam attach-role-policy --role-name NAME --policy-arn ARN |
| Detach policy from role | aws iam detach-role-policy --role-name NAME --policy-arn ARN |
| List attached role policies | aws iam list-attached-role-policies --role-name NAME |
| Create managed policy | aws iam create-policy --policy-name NAME --policy-document file://policy.json |
| List customer managed policies | aws iam list-policies --scope Local |
| Get policy JSON | aws iam get-policy-version --policy-arn ARN --version-id v1 |
| Simulate permissions | aws iam simulate-principal-policy --policy-source-arn ARN --action-names ACTION |
| Generate credential report | aws iam generate-credential-report |
AWS CLI vs Console vs Terraform
Each tool has a sweet spot for IAM management. Choosing the right one depends on whether you are exploring, scripting, or building long-lived infrastructure.
| AWS Console | AWS CLI | Terraform | |
|---|---|---|---|
| Best for | Discovery, one-off manual changes, visual exploration | Scripting, auditing, repeatable commands, quick fixes | Version-controlled desired-state management across environments |
| Repeatability | Low. Manual clicks are hard to reproduce exactly | High. Commands can be saved in scripts and rerun | Highest. Infrastructure is declared in code and tracked in Git |
| Auditability | Limited to CloudTrail logs | Commands can be logged and reviewed | Full change history in version control with plan previews |
| Scale | Gets tedious across many accounts or resources | Scales well with shell loops and scripts | Designed for multi-account, multi-environment management |
| Learning curve | Low | Medium | Higher |
| When to avoid | Bulk changes, anything that needs to be repeatable | Long-lived infrastructure that should be version-controlled | One-off investigations, quick audits |
A common pattern: use the Console to explore and understand what exists, the CLI for one-off fixes and auditing scripts, and Terraform for any IAM resources that are part of your application’s infrastructure. See Managing IAM with Terraform for the Terraform approach.
Common mistakes
- Running commands against the wrong profile/account. If you manage multiple AWS accounts, always check
aws sts get-caller-identitybefore making changes. Use—profileexplicitly rather than relying on defaults. - Using long-lived access keys when a role would work. Creating an IAM user with access keys is often a habit from tutorials. For EC2, Lambda, ECS, and other AWS services, use roles instead. They handle credential rotation automatically.
- Confusing trust policies with permissions policies. The trust policy controls who can assume the role. The permissions policy controls what the role can do. A role with the right permissions but the wrong trust policy will produce AccessDenied errors on the
sts:AssumeRolecall itself. - Forgetting cleanup order before deletion. You cannot delete a user, group, or role that still has policies attached, inline policies, access keys, or group memberships. Detach and delete dependencies first, then delete the resource.
- Copy/pasting broken flags from web pages. Many websites render
—as a typographic em-dash. If a CLI command fails with an unrecognized argument, check that all flags use literal ASCII double hyphens. - Listing all policies without filtering.
aws iam list-policieswithout—scope Localreturns hundreds of AWS-managed policies. Use—scope Localwhen you want only your customer managed policies. - Not saving the secret access key on creation.
create-access-keyshows the secret exactly once. If you do not capture it, you must delete the key and create a new one. - Not using —query and —output for readability. Raw JSON output from IAM commands can be hundreds of lines. Use
—querywith—output tableto extract what you need.
Summary
- The AWS CLI supports every IAM operation: users, groups, roles, managed policies, inline policies, and auditing.
- Prefer roles and temporary credentials over IAM users with long-lived access keys for both workloads and human access.
- Use groups to manage permissions for multiple IAM users. Attach policies to the group, not individual users.
- Create roles with a trust policy file (who can assume it) and attach permissions policies separately (what it can do).
- Retrieve policy JSON in two steps: get the policy (for the version ID), then get-policy-version (for the document).
- Use the credential report to audit user credentials and find stale access keys.
- For long-lived IAM infrastructure, use Terraform for version control and review workflows.
Frequently asked questions
Can I manage IAM entirely from the AWS CLI?
Yes. Every IAM operation available in the AWS Console has an equivalent CLI command. The CLI is especially effective for scripting bulk changes, auditing resources across accounts, and building repeatable workflows.
Should I use IAM users or roles?
Prefer roles wherever possible. Roles issue temporary credentials that expire automatically, which eliminates the risk of leaked long-lived keys. IAM users with access keys are appropriate only for narrow use cases like third-party integrations that cannot assume roles.
How do I inspect an existing policy JSON document?
Run aws iam get-policy to retrieve the policy metadata and its default version ID, then run aws iam get-policy-version with that version ID to get the actual JSON document.
How do I audit stale credentials?
Generate the IAM credential report with aws iam generate-credential-report, then download it with aws iam get-credential-report. The CSV includes password and access key last-used dates, making it easy to spot unused or stale credentials.
When should I switch from CLI changes to Terraform?
When you need version-controlled, reviewable, repeatable IAM management across multiple environments or accounts, Terraform is a better fit. The CLI is ideal for one-off operations, auditing, and quick fixes. Terraform is better for long-lived infrastructure that should be declared and tracked in source control.