
AWS Identity and Access Management (IAM) is a core service for managing access to AWS resources securely. As a developer, understanding IAM is important for deploying applications securely while following the principle of least privilege. This guide covers IAM fundamentals, best practices, and practical examples to help developers implement secure access control in their AWS environments.
Contents
Why IAM Matters for Developers
Developers should have a strong understanding of AWS Identity and Access Management (IAM) because it is foundational to building secure, scalable applications in the cloud. IAM controls who can access AWS resources and what actions they can perform, directly impacting the security posture of any application. Whether deploying a Lambda function, configuring an EC2 instance, or integrating with services like S3, DynamoDB, or SNS, developers must ensure that the right permissions are in place — not too broad to risk exposure, and not too restrictive to block functionality. Mastery of IAM empowers developers to implement the principle of least privilege, reduce the attack surface, automate deployments securely, and confidently manage resource access in complex, multi-user environments.
AWS IAM Fundamentals
Core Components
Users
IAM users represent individual identities associated with people or applications that need to interact with AWS services. Each IAM user has a unique name and can be assigned credentials such as passwords for AWS Management Console access or access keys for API and CLI interactions. For developers, creating separate users for different team members or applications ensures fine-grained access control and easy auditing of activity.
Groups
IAM groups are collections of IAM users that simplify permission management. Instead of assigning policies to individual users, developers can group users based on roles (e.g., “DevOps”, “FrontendTeam”) and assign policies to the group. This makes it easier to enforce least-privilege access across teams and manage permissions consistently as users are added or removed.
Roles
IAM roles are temporary identities used by AWS services, applications, or users from other AWS accounts. Unlike users, roles don’t have long-term credentials. Developers commonly use roles for cross-account access, federated identity, or allowing EC2 instances and Lambda functions to interact securely with other AWS services without embedding access keys in code.
Policies
IAM policies are JSON documents that define permissions. They specify what actions are allowed or denied on which AWS resources, under what conditions. Developers can attach policies to users, groups, or roles to control access. AWS provides managed policies for common use cases, but developers can also create custom policies to meet specific application security requirements.
Identity Providers (IdPs)
Identity providers allow users from external systems (like corporate directories or third-party identity services such as Google, Facebook, or Active Directory) to access AWS resources via IAM roles. This is crucial for developers building web or mobile apps that authenticate users via these services, enabling secure, scalable identity federation without managing separate IAM users.
Core Concepts
Principle of Least Privilege
The Principle of Least Privilege is a security concept that recommends giving a user, application, or process only the minimum level of access — or permissions — necessary to perform its function, and nothing more.
Temporary Credentials (Roles)
Temporary credentials in AWS are short-lived security credentials that allow users or applications to access AWS resources without needing long-term access keys or passwords. These credentials are primarily issued by the AWS Security Token Service (STS) and are commonly used to enhance security and flexibility in cloud environments.
IAM Policies Deep Dive
In AWS IAM, there are several types of policies that you can use to define and manage permissions. Each serves a different purpose and is used in various scenarios to secure access to AWS resources. Here’s a breakdown of the main policy types:
1. Identity-Based Policies
These are permissions policies attached to IAM identities — users, groups, or roles.
- Managed Policies:
- AWS Managed Policies: Predefined and maintained by AWS (e.g.,
AmazonS3ReadOnlyAccess
). - Customer Managed Policies: Created and managed by your organization to meet custom requirements.
- AWS Managed Policies: Predefined and maintained by AWS (e.g.,
- Inline Policies:
- Policies embedded directly into a single user, group, or role.
- Not reusable and tightly coupled with the IAM identity they are attached to.
- Useful for one-off, tightly scoped permissions.
2. Resource-Based Policies
These are policies attached directly to AWS resources, such as S3 buckets, SNS topics, or SQS queues.
- Allow cross-account access without requiring the target identity to assume a role.
- Example: An S3 bucket policy allowing another AWS account to read objects from it.
3. Permissions Boundaries
- Set the maximum permissions an IAM user or role can be granted.
- Even if identity-based policies allow a permission, it must also be allowed by the boundary.
- Useful for delegating permission creation while enforcing strict limits.
4. Service Control Policies (SCPs)
- Part of AWS Organizations.
- Define maximum available permissions for accounts in an organizational unit (OU).
- Cannot grant permissions — only restrict what’s possible across the organization.
- Useful for centralized control in multi-account environments.
5. Session Policies
- Temporary policies passed during a session when assuming a role or federating access.
- Further restrict the permissions granted by the role or federated identity.
- Valid only for the duration of the session.
Structure of a Policy
An AWS IAM policy is a JSON document that defines permissions using a structured set of elements. These elements work together to control access to AWS resources. Understanding these components is crucial for writing clear, secure, and effective policies.
Here are the core elements of an IAM policy:
Element | Description |
---|---|
Version | Specifies the policy language version. The current version is "2012-10-17" and should always be used. |
Statement | The main container for the permission rules. A policy can have one or more Statement blocks. |
Effect | Specifies whether the rule allows or denies access. Possible values: "Allow" or "Deny" . |
Action | Lists the specific AWS actions (API operations) being allowed or denied (e.g., "s3:GetObject" ). |
Resource | Specifies the AWS resources the actions apply to, using Amazon Resource Names (ARNs). |
Condition | (Optional) Adds conditional logic to the policy using keys, operators, and values. |
Principal | (Only in resource-based policies) — specifies who the policy applies to (user, role, service, etc.). |
Example:
{ "Version": "2012-10-17", "Statement": [ { "Effect": "Allow", "Action": "s3:GetObject", "Resource": "arn:aws:s3:::my-bucket/*" } ] }
In this example:
- The policy allows
s3:GetObject
action, - On all objects (
*
) inside themy-bucket
, - For the IAM entity the policy is attached to.
Each element plays a critical role in shaping how access is granted or denied. Developers should be careful with wildcards (*
) and always aim to follow the Principle of Least Privilege (PLP) when crafting policies.
Creating and Managing IAM Users & Roles
Creating an IAM User (AWS CLI)
aws iam create-user --user-name dev-user
Attaching a Policy to a User
aws iam attach-user-policy \ --user-name dev-user \ --policy-arn arn:aws:iam::aws:policy/AmazonS3ReadOnlyAccess
Creating an IAM Role for EC2
{ "Version": "2012-10-17", "Statement": [ { "Effect": "Allow", "Principal": { "Service": "ec2.amazonaws.com" }, "Action": "sts:AssumeRole" } ] }
Save this as ec2-trust-policy.json
and run:
aws iam create-role \ --role-name EC2S3AccessRole \ --assume-role-policy-document file://ec2-trust-policy.json
Attaching a Policy to a Role
aws iam attach-role-policy \ --role-name EC2S3AccessRole \ --policy-arn arn:aws:iam::aws:policy/AmazonS3ReadOnlyAccess
Using IAM Roles for Applications
Instead of hardcoding credentials, applications should use IAM roles.
Example: EC2 Instance with an IAM Role
Create an instance profile
aws iam create-instance-profile \ --instance-profile-name EC2S3AccessProfile aws iam add-role-to-instance-profile \ --instance-profile-name EC2S3AccessProfile \ --role-name EC2S3AccessRole
Launch EC2 with the role
aws ec2 run-instances \ --image-id ami-0abcdef1234567890 \ --instance-type t2.micro \ --iam-instance-profile Name=EC2S3AccessProfile
Example: Assuming a Role in Code (Python)
sts_client = boto3.client('sts') assumed_role = sts_client.assume_role( RoleArn="arn:aws:iam::123456789012:role/EC2S3AccessRole", RoleSessionName="AssumeRoleSession" ) credentials = assumed_role['Credentials'] s3_client = boto3.client( 's3', aws_access_key_id=credentials['AccessKeyId'], aws_secret_access_key=credentials['SecretAccessKey'], aws_session_token=credentials['SessionToken'] ) response = s3_client.list_buckets() print(response)
Best Practices for Developers
Follow these proven strategies to secure your AWS applications while maintaining flexibility and scalability:
Avoid Root Account Usage
- Why: The root account has unrestricted access—a single breach compromises everything.
- How:
- Create individual IAM users for team members.Enable MFA (Multi-Factor Authentication) for the root account and store credentials offline.
aws iam enable-mfa-device --user-name root --serial-number arn:aws:iam::123456789012:mfa/root-account-mfa --authentication-code-1 123456 --authentication-code-2 654321
Use IAM Roles Instead of Long-Term Access Keys
- Why: Access keys (stored in
~/.aws/credentials
) are permanent and risky if leaked. - How:
- Assign roles to AWS services (e.g., EC2, Lambda).For local development, use temporary credentials via
aws sts assume-role
.
- Assign roles to AWS services (e.g., EC2, Lambda).For local development, use temporary credentials via
# Python example: Assume a role sts_client = boto3.client('sts') response = sts_client.assume_role( RoleArn="arn:aws:iam::123456789012:role/DevRole", RoleSessionName="DevSession" )
Apply the Principle of Least Privilege (PoLP)
- Why: Over-permissioning leads to security risks (e.g., a compromised S3 write role could delete data).
- How:
- Start with minimum permissions and expand as needed.Use AWS’s Access Advisor to audit unused permissions.
// Example: Restrictive S3 policy { "Version": "2012-10-17", "Statement": [ { "Effect": "Allow", "Action": ["s3:GetObject"], "Resource": ["arn:aws:s3:::production-bucket/read-only/*"] } ] }
Enable MFA for Sensitive Operations
- Why: Adds a second layer of protection for high-risk actions (e.g., terminating EC2 instances).
- How:
- Enforce MFA for users via IAM policies:
{ "Version": "2012-10-17", "Statement": [ { "Effect": "Deny", "Action": ["ec2:TerminateInstances"], "Resource": "*", "Condition": { "BoolIfExists": { "aws:MultiFactorAuthPresent": "false" } } } ] }
Rotate Credentials Regularly
- Why: Compromised keys are a common attack vector.
- How:
- Rotate access keys every 90 days (automate with AWS Secrets Manager or a cron job).
- Use IAM access key age alerts via AWS CloudTrail + EventBridge.
Use IAM Conditions for Fine-Grained Control
Why: Restrict access by IP, time, or request context.
How:
Allow access only from corporate IPs:
"Condition": { "IpAddress": { "aws:SourceIp": ["192.0.2.0/24"] } }
Restrict session duration for assumed roles:
aws iam update-role --role-name DevRole --max-session-duration 3600 # 1 hour
Monitor and Audit with AWS Tools
- Why: Detect anomalies or unauthorized access early.
- How:
- Enable AWS CloudTrail to log all IAM API calls.
- Use IAM Access Analyzer to identify unused permissions or public resources.
- Set up GuardDuty for threat detection.
Avoid Hardcoding Credentials in Code
- Why: GitHub leaks of AWS keys are shockingly common.
- How:
- Use AWS Secrets Manager or Parameter Store for credentials.
- For CI/CD pipelines, leverage OIDC identity providers (e.g., GitHub Actions to AWS).
Tag IAM Resources for Better Governance
- Why: Track costs and access by project/environment.
- How:
aws iam tag-user --user-name dev-user --tags Key=Project,Value=APIv2
Regularly Review and Clean Up Permissions
- Why: Employees change roles; permissions accumulate.
- How:
- Schedule quarterly IAM permission reviews.
- Use AWS IAM Access Analyzer to generate permission reports.
Advanced IAM Features
Permissions Boundaries
Permission Boundaries are an advanced IAM feature that define the maximum permissions an IAM entity (user or role) can have, regardless of what policies are attached to them. They act as a security guardrail, ensuring that even if a user or role is granted overly permissive policies, their effective permissions never exceed the boundary.
CLI method:
aws iam put-user-permissions-boundary \ --user-name dev-user \ --permissions-boundary arn:aws:iam::aws:policy/AmazonS3ReadOnlyAccess
JSON version:
{ "Version": "2012-10-17", "Statement": [ { "Effect": "Allow", "Action": ["s3:*"], "Resource": "*" } ] }
This boundary would allow only S3 access, even if the user has AdministratorAccess
attached.
Service Control Policies (SCPs)
AWS Service Control Policies (SCPs) are a powerful security feature within AWS Organizations that act as guardrails for your entire AWS environment. These JSON-based policies allow you to centrally establish maximum permissions boundaries across all accounts in your organization, preventing any account – even the root user – from exceeding defined limits. SCPs work alongside IAM policies to implement organization-wide security policies, such as restricting access to specific AWS regions, blocking certain services, or enforcing mandatory tagging practices.
Unlike IAM policies that grant permissions, SCPs function as deny lists or allow lists to control which services and actions are available to member accounts. When properly configured, SCPs help maintain consistent compliance standards, reduce attack surfaces, and prevent accidental misconfigurations across all your AWS accounts while still allowing individual teams the flexibility to manage their own IAM permissions within these boundaries.
Permission Boundaries vs. Service Control Policies
Feature | Permission Boundaries | SCPs (Service Control Policies) |
---|---|---|
Scope | Applies to individual IAM users/roles | Applies to entire AWS accounts (via AWS Organizations) |
Granularity | Per-user/role restrictions | Account-wide guardrails |
Policy Type | Allow-based (defines max permissions) | Deny-based (blocks actions) |
Use Case | Controlling individual identities | Enforcing organization-wide security policies |
Tools Every Developer Should Know
IAM Policy Simulator
This tool allows you test policies before applying them.
AWS Policy Simulator
Monitoring IAM Activity
Use AWS CloudTrail and IAM Access Analyzer to:
- Track who used which credentials.
- Detect risky permissions or unused roles.
- Audit changes to IAM entities.
Enable logging for better visibility and security compliance.
CloudTrail
AWS IAM integrates seamlessly with AWS CloudTrail, which logs every action performed by IAM users and roles. CloudTrail tracks all API activity, whether initiated through the AWS Management Console or programmatic API calls, capturing detailed event records.
You have two options for managing these logs:
- Continuous Logging: Configure a trail to automatically deliver CloudTrail events to an Amazon S3 bucket for long-term storage and analysis.
- On-Demand Access: Without a trail, you can still review recent activity (up to 90 days) in the CloudTrail console’s Event History.
CloudTrail provides comprehensive visibility into IAM/STS requests, including:
✔ Source IP addresses
✔ Requester identity
✔ Timestamps
✔ Full request details
This audit capability helps you monitor access patterns, troubleshoot issues, and strengthen security posture.
Checkout Logging IAM and AWS STS API calls with AWS CloudTrail for more information.
IAM Access Analyzer
IAM Access Analyzer is a security feature in AWS that helps you identify and understand who has access to your AWS resources from outside your AWS account. It analyzes policies attached to your IAM roles, users, S3 buckets, KMS keys, Lambda functions, and other supported resources to detect potential unintended access.
Troubleshooting Tips
This table lists common errors, their possible causes and potential solutions.
Error Message | Possible Cause | Solution |
---|---|---|
AccessDenied / AccessDeniedException | Missing permissions for the IAM user or role. | Check IAM policies for required Action and Resource . Use IAM Policy Simulator to debug and test. |
InvalidClientTokenId | Incorrect, expired, or deleted access key or secret. | Reissue access keys and configure credentials using aws configure . |
NotAuthorizedException | Role or identity doesn’t have permission (common with Cognito, Lambda, etc.). | Verify IAM role attached to the service or identity. Update the role policy to include needed permissions. |
EntityAlreadyExists | Trying to create a user, group, or role that already exists. | Use a different name or delete the existing entity before recreating. |
MalformedPolicyDocument | IAM policy JSON is incorrectly formatted or has syntax errors. | Validate the JSON format using the AWS Policy Validator or JSON linters. |
ThrottlingException | Too many requests made to the IAM service in a short time. | Implement retry logic with exponential backoff in SDK or CLI scripts. |
UnrecognizedClientException | Signature mismatch due to wrong credentials or incorrect region. | Verify credentials and make sure the correct AWS region is being used. |
PolicyLengthExceeded | Custom policy exceeds the maximum allowed size (6,144 characters). | Split into multiple policies or refactor to reduce redundancy. |
Code Samples
All code samples in this article can be found in this GitHub location: AWS_IAM_Developers_Guide
Conclusion
AWS IAM is a powerful tool for securing your applications. By following best practices—using roles, applying least privilege, and avoiding hardcoded credentials—you can build and deploy applications securely. By mastering IAM, you ensure your AWS deployments remain secure and scalable.
Next Steps
- Explore AWS IAM Documentation.
- Experiment with custom policies in a sandbox AWS account.
- Implement automated credential rotation.
Got questions or insights to share? Join the conversation in the comments below.