- Published on
AWS Identity Management: Understanding Users, Groups, Roles, and Policies
- Authors
- Name
- Nguyen Phuc Cuong
When building applications on AWS, managing who can access what resources is critical for security and compliance. AWS Identity and Access Management (IAM) provides the foundation for access control in your AWS environment. Understanding these core IAM components - Users, Groups, Roles, and Policies - is essential for any cloud developer or administrator.
The Building Blocks of AWS Identity Management
"AWS IAM is the control center for managing access to AWS resources. It's where you define who can do what in your AWS environment, enabling you to implement the principle of least privilege."
Let's break down each component and understand how they work together to create a secure and manageable environment.
IAM Users: Individual Identities
IAM Users are individual identities that represent people or services that interact with your AWS resources. Each user has:
- A unique name within your AWS account
- Credentials for authentication (password and/or access keys)
- Permissions granted through direct policy attachments or group memberships
When to Create IAM Users
✅ Create IAM Users for
- Individual team members requiring AWS console access
- Services that need programmatic access to AWS resources
- Providing limited access to contractors
- Audit tracking of individual actions
❌ Don't Create IAM Users for
- Applications running on EC2 instances (use Roles instead)
- Cross-account access (use Roles)
- Temporary access needs (use Roles with STS)
- Anonymous or unauthenticated access (use other mechanisms)
Creating and Managing IAM Users
Here's a basic AWS CLI example to create a new IAM user:
# Create a new user
aws iam create-user --user-name developer-jane
# Attach a policy directly to the user
aws iam attach-user-policy --user-name developer-jane --policy-arn arn:aws:iam::aws:policy/AmazonS3ReadOnlyAccess
# Create access keys for programmatic access
aws iam create-access-key --user-name developer-jane
Security Best Practice: Limit the number of IAM users with programmatic access keys, and rotate access keys regularly. For users who only need console access, don't create access keys at all.
IAM Groups: Organizing Users
IAM Groups are collections of IAM users. Instead of managing permissions for each user individually, you can assign permissions to groups and then add users to those groups. This makes permission management more scalable and less error-prone.
Benefits of Using IAM Groups
- Simplified permission management: Update permissions once for multiple users
- Organizational clarity: Create groups that mirror your organizational structure
- Reduced administrative overhead: Onboard new users quickly by adding them to existing groups
- Consistent permissions: Ensure users with similar roles have identical access levels
Common Group Structure Examples
├── Administrators
│ ├── Full AWS access
│ └── Members: senior admins, CTO
├── Developers
│ ├── EC2, S3, RDS access
│ ├── Limited to development environments
│ └── Members: development team
├── DataScientists
│ ├── S3, Athena, SageMaker access
│ └── Members: data science team
└── ReadOnlyUsers
├── Read-only access to specified services
└── Members: junior team members, auditors
Managing IAM Groups with AWS CLI
# Create a new group
aws iam create-group --group-name Developers
# Attach a policy to the group
aws iam attach-group-policy --group-name Developers --policy-arn arn:aws:iam::aws:policy/AmazonS3FullAccess
# Add a user to the group
aws iam add-user-to-group --user-name developer-jane --group-name Developers
IAM Roles: Temporary Access
IAM Roles are similar to users but are not associated with a specific person. Instead, roles are assumable by anyone or any service that needs them temporarily. This makes roles perfect for:
- Granting AWS services permission to act on your behalf
- Providing cross-account access
- Enabling federated identity access (e.g., Active Directory or web identity federation)
- Implementing temporary access for applications running on EC2
The Trust Relationship
What makes roles unique is their trust relationship, which defines who can assume the role. A trust relationship is a policy document that specifies:
- Which entities can assume the role
- Under what conditions they can assume it
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Principal": {
"Service": "ec2.amazonaws.com"
},
"Action": "sts:AssumeRole"
}
]
}
Common Use Cases for IAM Roles
🖥️ EC2 Instance Roles
Allow applications running on EC2 instances to make API requests without storing access keys. Credentials are automatically rotated and delivered through the instance metadata service.
🔄 Cross-Account Access
Enable users from one AWS account to access resources in another AWS account securely, without needing to create users in multiple accounts.
🔐 Federated Access
Allow users from your corporate directory or web identity providers (Google, Facebook, etc.) to access AWS resources securely without creating IAM users.
⚙️ Service Roles
Permit AWS services like Lambda or CloudFormation to perform actions on your behalf, such as creating resources or accessing other AWS services.
Creating and Assuming Roles
Here's how to create a role for EC2 instances using AWS CLI:
# Create a role trust policy file first (trust-policy.json)
# Then create the role
aws iam create-role \
--role-name S3AccessRole \
--assume-role-policy-document file://trust-policy.json
# Attach policy to the role
aws iam attach-role-policy \
--role-name S3AccessRole \
--policy-arn arn:aws:iam::aws:policy/AmazonS3ReadOnlyAccess
To assume a role programmatically:
import boto3
# Create an STS client
sts_client = boto3.client('sts')
# Assume role
assumed_role = sts_client.assume_role(
RoleArn="arn:aws:iam::123456789012:role/CrossAccountRole",
RoleSessionName="AssumeRoleSession"
)
# Get temporary credentials
credentials = assumed_role['Credentials']
# Use these credentials to create a new session
s3_client = boto3.client(
's3',
aws_access_key_id=credentials['AccessKeyId'],
aws_secret_access_key=credentials['SecretAccessKey'],
aws_session_token=credentials['SessionToken']
)
# Now use s3_client with the assumed role permissions
IAM Policies: The Permission Language
IAM Policies are JSON documents that define permissions. They specify what actions are allowed or denied on which AWS resources and under what conditions. Policies can be attached to users, groups, or roles.
Types of IAM Policies
- Identity-based policies: Attached directly to IAM identities (users, groups, roles)
- Resource-based policies: Attached to resources like S3 buckets or SQS queues
- Service control policies (SCPs): Used in AWS Organizations to set permission boundaries
- Permission boundaries: Set the maximum permissions an IAM entity can have
Anatomy of an IAM Policy
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "AllowS3ListBuckets",
"Effect": "Allow",
"Action": "s3:ListAllMyBuckets",
"Resource": "*"
},
{
"Sid": "AllowS3AccessToSpecificBucket",
"Effect": "Allow",
"Action": [
"s3:GetObject",
"s3:PutObject"
],
"Resource": "arn:aws:s3:::my-bucket/*",
"Condition": {
"IpAddress": {
"aws:SourceIp": "203.0.113.0/24"
}
}
}
]
}
Policy Elements Explained
- Version: Policy language version (always "2012-10-17" for current policies)
- Statement: Array of individual permission statements
- Sid: Optional identifier for the statement
- Effect: Whether to "Allow" or "Deny" access
- Action: The specific API operations allowed or denied
- Resource: The AWS resources to which the actions apply
- Condition: Optional conditions for when the policy is in effect
AWS Managed vs. Customer Managed Policies
Feature | AWS Managed | Customer Managed |
---|---|---|
Created by | AWS | You |
Maintenance | AWS updates automatically | You must update manually |
Customization | No modifications allowed | Fully customizable |
Common use case | Standard job functions | Custom requirements |
Putting It All Together: IAM Best Practices
Implementing Least Privilege
The principle of least privilege is the foundation of secure IAM management. Grant only the permissions required for specific tasks, and nothing more. Here's a practical approach:
- Start with minimum permissions
- Analyze AWS CloudTrail logs to identify additional required permissions
- Gradually add permissions as needed
- Use AWS Access Analyzer to identify unused permissions
IAM Security Checklist
Essential IAM Security Best Practices:
- Secure the root account with MFA and minimal usage
- Implement MFA for all IAM users
- Rotate credentials regularly
- Remove unused users and permissions
- Use roles for EC2 instances instead of embedding credentials
- Use groups to assign permissions to users
- Establish a strong password policy
- Use conditions in policies to restrict access further
- Monitor and audit IAM usage with CloudTrail
Real-World IAM Architecture Example
Let's look at a typical IAM structure for a mid-sized development team:
├── IAM Users
│ ├── Individual team members
│ └── Service accounts
├── IAM Groups
│ ├── Administrators
│ ├── Developers
│ ├── DataTeam
│ └── ReadOnly
├── IAM Roles
│ ├── EC2-App-Role
│ ├── Lambda-Execution-Role
│ ├── Cross-Account-Access
│ └── Federated-User-Role
└── IAM Policies
├── AWS Managed Policies
└── Customer Managed Policies
├── Dev-Environment-Access
├── Prod-ReadOnly-Access
└── Database-Management
Implementation with Infrastructure as Code
Here's a Terraform example to create this IAM structure:
# Create IAM groups
resource "aws_iam_group" "developers" {
name = "Developers"
}
resource "aws_iam_group" "admins" {
name = "Administrators"
}
# Create IAM policies
resource "aws_iam_policy" "dev_environment_access" {
name = "DevelopmentEnvironmentAccess"
description = "Permissions for development environment resources"
policy = jsonencode({
Version = "2012-10-17"
Statement = [
{
Effect = "Allow"
Action = [
"ec2:Describe*",
"s3:Get*",
"s3:List*",
"rds:Describe*"
]
Resource = "*"
Condition = {
StringEquals = {
"aws:RequestedRegion": "us-west-2"
}
StringLike = {
"aws:ResourceTag/Environment": "Dev"
}
}
}
]
})
}
# Attach policy to group
resource "aws_iam_group_policy_attachment" "dev_policy" {
group = aws_iam_group.developers.name
policy_arn = aws_iam_policy.dev_environment_access.arn
}
# Create IAM role for EC2
resource "aws_iam_role" "app_role" {
name = "EC2-App-Role"
assume_role_policy = jsonencode({
Version = "2012-10-17"
Statement = [
{
Effect = "Allow"
Principal = {
Service = "ec2.amazonaws.com"
}
Action = "sts:AssumeRole"
}
]
})
}
# Attach policy to role
resource "aws_iam_role_policy_attachment" "app_s3_access" {
role = aws_iam_role.app_role.name
policy_arn = "arn:aws:iam::aws:policy/AmazonS3ReadOnlyAccess"
}
Advanced IAM Topics
Permission Boundaries
Permission boundaries are an advanced feature that set the maximum permissions an IAM entity can have. They're useful for delegating IAM administration while maintaining control over maximum access levels.
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": [
"s3:*",
"cloudwatch:*",
"ec2:*"
],
"Resource": "*"
},
{
"Effect": "Deny",
"Action": [
"iam:*",
"organizations:*"
],
"Resource": "*"
}
]
}
Resource-Based Policies
In addition to identity-based policies, some AWS services support resource-based policies. These are attached directly to resources rather than IAM identities. S3 bucket policies are a common example:
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Principal": {
"AWS": "arn:aws:iam::123456789012:user/developer-jane"
},
"Action": [
"s3:GetObject",
"s3:PutObject"
],
"Resource": "arn:aws:s3:::my-bucket/*"
}
]
}
Conclusion
AWS IAM provides a robust framework for managing access to your AWS resources. By understanding and properly implementing Users, Groups, Roles, and Policies, you can create a secure yet flexible environment that follows the principle of least privilege.
Remember that IAM is not a set-it-and-forget-it service. Regular reviews, ongoing adjustments, and continuous monitoring are essential parts of maintaining a secure AWS environment as your applications and organization evolve.