AWS IAM Trust Policies - Comprehensive Guide
1. Overview of IAM Trust Policies
AWS IAM Trust Policies are JSON documents that define which principals (users, roles, or services) can assume a specific IAM role. They act as the gatekeeper for role assumption, establishing the trust relationship between the role and the entities that can use it.
graph TB
A[Principal] -->|Requests| B[AssumeRole]
B -->|Evaluates| C[Trust Policy]
C -->|If Trusted| D[Temporary Credentials]
C -->|If Not Trusted| E[Access Denied]
D --> F[Role Permissions Applied]
style A fill:#e1f5fe
style C fill:#fff3e0
style D fill:#e8f5e8
style E fill:#ffebee
style F fill:#f3e5f5
Trust Policy Flow Explanation:
This diagram shows the fundamental flow of trust policy evaluation. When a principal (user, role, or service) attempts to assume a role, AWS evaluates the trust policy attached to that role. If the principal is listed as trusted in the policy, temporary credentials are issued with the role's permissions. If not, access is denied immediately.
2. Key Concepts and Components
Trust Policy Structure
graph LR
A[Trust Policy] --> B[Version]
A --> C[Statement Array]
C --> D[Effect]
C --> E[Principal]
C --> F[Action]
C --> G[Condition]
style A fill:#fff3e0
style B fill:#e8f5e8
style C fill:#e1f5fe
style D fill:#f3e5f5
style E fill:#fff8e1
style F fill:#e8f4fd
style G fill:#fce4ec
Trust Policy Components:
A trust policy consists of a version identifier and one or more statements. Each statement contains an Effect (Allow/Deny), Principal (who can assume), Action (what they can do), and optional Conditions (under what circumstances). The Principal element is what distinguishes trust policies from regular IAM policies.
Principal Types
graph TD
A[Principal Types] --> B[AWS Account]
A --> C[IAM User]
A --> D[IAM Role]
A --> E[AWS Service]
A --> F[Federated User]
A --> G[Anonymous User]
B --> B1["arn:aws:iam::123456789012:root"]
C --> C1["arn:aws:iam::123456789012:user/username"]
D --> D1["arn:aws:iam::123456789012:role/rolename"]
E --> E1["ec2.amazonaws.com"]
F --> F1["arn:aws:iam::123456789012:saml-provider/provider"]
G --> G1["*"]
style A fill:#fff3e0
style B fill:#e8f5e8
style C fill:#e1f5fe
style D fill:#f3e5f5
style E fill:#fff8e1
style F fill:#e8f4fd
style G fill:#fce4ec
Principal Types Explained:
This diagram shows the different types of principals that can be specified in trust policies. AWS Account principals grant access to all users in an account, IAM Users are specific user ARNs, IAM Roles allow role chaining, AWS Services enable service-linked roles, Federated Users work with SAML/OIDC providers, and Anonymous Users (*) should be used with extreme caution.
3. Traffic Flow Diagrams
Cross-Account Role Assumption
sequenceDiagram
participant U as User (Account A)
participant STS as AWS STS
participant R as Role (Account B)
participant S as Service (Account B)
U->>STS: aws sts assume-role
STS->>R: Check Trust Policy
R->>STS: Trust Policy Evaluation
alt Trust Policy Allows
STS->>U: Return Temporary Credentials
U->>S: Access Service with Temp Creds
S->>U: Service Response
else Trust Policy Denies
STS->>U: Access Denied
end
Cross-Account Role Assumption Flow:
This sequence diagram illustrates how cross-account role assumption works. A user in Account A requests to assume a role in Account B through AWS STS. STS checks the role's trust policy, and if the user's account/principal is trusted, temporary credentials are issued. These credentials can then be used to access resources in Account B according to the role's permissions.
Service-Linked Role Flow
sequenceDiagram
participant AWS as AWS Service
participant STS as AWS STS
participant Role as Service Role
participant Resource as AWS Resource
AWS->>STS: Assume Service Role
STS->>Role: Verify Service Trust Policy
Role->>STS: Service Listed in Principal
STS->>AWS: Issue Service Credentials
AWS->>Resource: Access Resource
Resource->>AWS: Grant Access
AWS->>Resource: Perform Operation
Service-Linked Role Flow:
This diagram shows how AWS services assume roles to perform operations on your behalf. Services like EC2, Lambda, or RDS assume roles with trust policies that explicitly trust the service. This is fundamental to AWS's security model, ensuring services only get the minimum permissions needed.
Federated Access Flow
sequenceDiagram
participant User as External User
participant IDP as Identity Provider
participant STS as AWS STS
participant Role as Federated Role
participant AWS as AWS Services
User->>IDP: Authenticate
IDP->>User: Return SAML/OIDC Token
User->>STS: AssumeRoleWithSAML/WebIdentity
STS->>Role: Verify Trust Policy & Token
Role->>STS: Trust Policy Allows IDP
STS->>User: Return AWS Credentials
User->>AWS: Access AWS Services
Federated Access Flow:
This sequence demonstrates federated access where external users authenticate with their identity provider (like Active Directory or Google) and then assume AWS roles. The trust policy must explicitly trust the identity provider, and the SAML/OIDC token is validated before credentials are issued.
Role Chaining Flow
graph TD
A[Initial User] --> B[Assume Role 1]
B --> C[Role 1 Trust Policy]
C --> D[Temporary Creds 1]
D --> E[Assume Role 2]
E --> F[Role 2 Trust Policy]
F --> G[Temporary Creds 2]
G --> H[Access Final Resource]
I[Trust Chain Validation]
C --> I
F --> I
I --> J[Chain Length Check]
J --> K[Max 1 Hour Session]
style A fill:#e1f5fe
style C fill:#fff3e0
style F fill:#fff3e0
style I fill:#ffebee
style J fill:#ffebee
style K fill:#ffebee
Role Chaining Flow:
This diagram illustrates role chaining, where one role assumes another role. Each role in the chain must have a trust policy that allows the previous role to assume it. AWS limits role chaining to prevent infinite loops and security issues. The maximum session duration decreases with each hop in the chain.
4. Setup Sequence and Commands
Command Execution Flow
graph TD
A[Start Setup] --> B[1. Create Trust Policy Document]
B --> C[2. Create IAM Role]
C --> D[3. Attach Permission Policies]
D --> E[4. Test Role Assumption]
E --> F[5. Configure External Access]
F --> G[6. Validate and Monitor]
B --> B1[trust-policy.json]
C --> C1[aws iam create-role]
D --> D1[aws iam attach-role-policy]
E --> E1[aws sts assume-role]
F --> F1[Cross-account/Service config]
G --> G1[CloudTrail monitoring]
style A fill:#e8f5e8
style B fill:#e1f5fe
style C fill:#fff3e0
style D fill:#f3e5f5
style E fill:#fff8e1
style F fill:#e8f4fd
style G fill:#fce4ec
Setup Sequence Explanation:
This diagram shows the logical order for setting up IAM roles with trust policies. Each step builds upon the previous one, starting with creating the trust policy document, then the role itself, attaching permissions, testing functionality, configuring external access, and finally implementing monitoring. The sequence ensures a systematic approach to role creation.
Detailed Command Sequence
1
Create Trust Policy Document
cat > trust-policy.json << 'EOF'
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Principal": {
"AWS": "arn:aws:iam::123456789012:root"
},
"Action": "sts:AssumeRole"
}
]
}
EOF
2
Create IAM Role with Trust Policy
aws iam create-role \
--role-name CrossAccountAccessRole \
--assume-role-policy-document file://trust-policy.json \
--description "Role for cross-account access with trust policy"
3
Attach Permission Policies to Role
aws iam attach-role-policy \
--role-name CrossAccountAccessRole \
--policy-arn arn:aws:iam::aws:policy/ReadOnlyAccess
4
Test Role Assumption
aws sts assume-role \
--role-arn arn:aws:iam::987654321098:role/CrossAccountAccessRole \
--role-session-name TestSession \
--duration-seconds 3600
5
Verify Role Configuration
aws iam get-role --role-name CrossAccountAccessRole
6
List Attached Policies
aws iam list-attached-role-policies --role-name CrossAccountAccessRole
5. Detailed Configurations
Basic Trust Policy Configuration
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Principal": {
"AWS": "arn:aws:iam::123456789012:root"
},
"Action": "sts:AssumeRole"
}
]
}
Basic Trust Policy Parameters:
- Version: Policy language version. Always use "2012-10-17" for current syntax
- Effect: "Allow" or "Deny". Use "Allow" to grant trust, "Deny" to explicitly block
- Principal: The AWS account root that can assume this role
- Action: "sts:AssumeRole" is the standard action for role assumption
Usage: This is the foundation trust policy that allows an entire AWS account to assume the role. Any user in account 123456789012 with appropriate permissions can assume this role.
Service Trust Policy Configuration
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Principal": {
"Service": "ec2.amazonaws.com"
},
"Action": "sts:AssumeRole"
}
]
}
Service Trust Policy Parameters:
- Service Principal: Specifies which AWS service can assume the role
- Common Services: ec2.amazonaws.com, lambda.amazonaws.com, ecs-tasks.amazonaws.com
- Regional Services: Some services are regional (e.g., elasticbeanstalk.region.amazonaws.com)
Usage: This trust policy enables EC2 instances to assume the role. Create this for EC2 instance profiles or when EC2 needs to access other AWS services on your behalf.
Multi-Principal Trust Policy
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Principal": {
"AWS": [
"arn:aws:iam::123456789012:user/AdminUser",
"arn:aws:iam::123456789012:role/CrossAccountRole"
],
"Service": "lambda.amazonaws.com"
},
"Action": "sts:AssumeRole"
}
]
}
Multi-Principal Parameters:
- Multiple AWS Principals: Array of specific users and roles
- Mixed Principal Types: Can combine AWS principals and service principals
- Specific Users: More restrictive than account-level trust
Usage: This configuration allows specific users, roles, and services to assume the role. Use when you need granular control over who can assume the role rather than trusting an entire account.
Conditional Trust Policy
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Principal": {
"AWS": "arn:aws:iam::123456789012:root"
},
"Action": "sts:AssumeRole",
"Condition": {
"StringEquals": {
"sts:ExternalId": "UniqueExternalId123"
},
"IpAddress": {
"aws:SourceIp": "203.0.113.0/24"
},
"DateGreaterThan": {
"aws:CurrentTime": "2024-01-01T00:00:00Z"
}
}
}
]
}
Conditional Trust Policy Parameters:
- ExternalId: Prevents confused deputy attacks in cross-account scenarios
- SourceIp: Restricts access to specific IP addresses or ranges
- CurrentTime: Time-based access controls
- Other Conditions: MFA, user agent, request timestamp
Usage: Conditional trust policies add extra security layers. ExternalId is crucial for third-party access, IP restrictions limit geographic access, and time conditions enable temporary access windows.
Federated Trust Policy (SAML)
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Principal": {
"Federated": "arn:aws:iam::123456789012:saml-provider/CompanySAML"
},
"Action": "sts:AssumeRoleWithSAML",
"Condition": {
"StringEquals": {
"SAML:aud": "https://signin.aws.amazon.com/saml"
}
}
}
]
}
SAML Trust Policy Parameters:
- Federated Principal: ARN of the SAML identity provider
- AssumeRoleWithSAML: Specific action for SAML-based authentication
- SAML:aud: Audience condition to validate SAML assertions
- Other SAML Conditions: SAML:sub, SAML:cn, SAML:eduPersonAffiliation
Usage: This enables Single Sign-On (SSO) integration with corporate identity providers. Users authenticate with their corporate credentials and receive temporary AWS access based on their SAML attributes.
Web Identity Trust Policy (OIDC)
{
"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:sub": "repo:myorg/myrepo:ref:refs/heads/main",
"token.actions.githubusercontent.com:aud": "sts.amazonaws.com"
}
}
}
]
}
OIDC Trust Policy Parameters:
- OIDC Provider: ARN of the OpenID Connect identity provider
- AssumeRoleWithWebIdentity: Action for web identity federation
- Subject (sub): Specific identity within the OIDC provider
- Audience (aud): Intended audience for the token
Usage: This example shows GitHub Actions integration where specific repositories can assume roles for CI/CD operations. The subject condition ensures only the specified repository and branch can assume the role.
Creating the Role with Trust Policy
aws iam create-role \
--role-name MyTrustedRole \
--assume-role-policy-document file://trust-policy.json \
--description "Role with comprehensive trust policy" \
--max-session-duration 43200 \
--tags Key=Purpose,Value=CrossAccountAccess Key=Environment,Value=Production
Create Role Parameters:
- --role-name: Unique name for the role (required)
- --assume-role-policy-document: Trust policy file path
- --description: Human-readable description
- --max-session-duration: Maximum session length (1-12 hours)
- --tags: Key-value pairs for organization and billing
Sequence: This command must be run after creating the trust policy JSON file. It creates the role and establishes the trust relationship. The role exists but has no permissions until you attach policies.
Updating Trust Policy
aws iam update-assume-role-policy \
--role-name MyTrustedRole \
--policy-document file://updated-trust-policy.json
Update Trust Policy Parameters:
- --role-name: Name of existing role to update
- --policy-document: New trust policy document
Sequence: Use this command to modify an existing role's trust policy. Changes take effect immediately. Be careful as this can break existing access if principals are removed.
Attaching Permission Policies
aws iam attach-role-policy \
--role-name MyTrustedRole \
--policy-arn arn:aws:iam::aws:policy/ReadOnlyAccess
aws iam put-role-policy \
--role-name MyTrustedRole \
--policy-name CustomInlinePolicy \
--policy-document file://custom-permissions.json
Permission Policy Parameters:
- attach-role-policy: Attaches AWS managed or customer managed policies
- put-role-policy: Creates inline policies directly on the role
- --policy-arn: ARN of managed policy to attach
- --policy-name: Name for inline policy
Sequence: Permission policies are attached after creating the role. They define what actions the role can perform, while trust policies define who can assume the role. You can attach multiple policies to a single role.
6. Advanced Scenarios
Cross-Account Access with External ID
sequenceDiagram
participant C as Client (Account A)
participant T as Third Party Service
participant STS as AWS STS
participant R as Role (Account B)
C->>T: Request service with ExternalId
T->>STS: AssumeRole with ExternalId
STS->>R: Validate Trust Policy + ExternalId
R->>STS: ExternalId matches
STS->>T: Return temporary credentials
T->>C: Perform service using credentials
External ID Flow:
This diagram shows how External IDs prevent confused deputy attacks in cross-account scenarios. When a third-party service needs access to your AWS account, you provide a unique External ID. The service must present this ID when assuming the role, ensuring only authorized parties can access your resources.
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Principal": {
"AWS": "arn:aws:iam::THIRD-PARTY-ACCOUNT:root"
},
"Action": "sts:AssumeRole",
"Condition": {
"StringEquals": {
"sts:ExternalId": "MyUniqueExternalId-2024-7f8e9d"
}
}
}
]
}
External ID Best Practices:
- Uniqueness: Use UUIDs or long random strings
- Rotation: Change External IDs periodically
- Documentation: Keep track of which External IDs are used where
- Validation: Third-party services must provide the exact External ID
MFA-Required Trust Policy
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Principal": {
"AWS": "arn:aws:iam::123456789012:root"
},
"Action": "sts:AssumeRole",
"Condition": {
"Bool": {
"aws:MultiFactorAuthPresent": "true"
},
"NumericLessThan": {
"aws:MultiFactorAuthAge": "3600"
}
}
}
]
}
MFA Trust Policy Parameters:
- MultiFactorAuthPresent: Requires MFA to be used
- MultiFactorAuthAge: Maximum age of MFA token in seconds
- Security Benefit: Prevents compromised credentials from accessing sensitive roles
Time-Limited Access Trust Policy
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Principal": {
"AWS": "arn:aws:iam::123456789012:user/TemporaryUser"
},
"Action": "sts:AssumeRole",
"Condition": {
"DateGreaterThan": {
"aws:CurrentTime": "2024-07-01T00:00:00Z"
},
"DateLessThan": {
"aws:CurrentTime": "2024-12-31T23:59:59Z"
}
}
}
]
}
Time-Limited Trust Policy:
- DateGreaterThan: Access becomes available after this date
- DateLessThan: Access expires after this date
- Use Cases: Temporary contractors, project-based access, compliance requirements
Advanced Cross-Account Setup Commands
# Create trust policy for cross-account access with conditions
cat > cross-account-trust.json << 'EOF'
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Principal": {
"AWS": "arn:aws:iam::123456789012:root"
},
"Action": "sts:AssumeRole",
"Condition": {
"StringEquals": {
"sts:ExternalId": "MyExternalId123"
},
"Bool": {
"aws:MultiFactorAuthPresent": "true"
}
}
}
]
}
EOF
# Create the cross-account role
aws iam create-role \
--role-name SecureCrossAccountRole \
--assume-role-policy-document file://cross-account-trust.json \
--description "Secure cross-account role with MFA and External ID"
# Create and attach custom permission policy
cat > cross-account-permissions.json << 'EOF'
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": [
"s3:GetObject",
"s3:PutObject"
],
"Resource": "arn:aws:s3:::my-shared-bucket/*"
}
]
}
EOF
aws iam put-role-policy \
--role-name SecureCrossAccountRole \
--policy-name S3AccessPolicy \
--policy-document file://cross-account-permissions.json
# Test the role assumption from the trusted account
aws sts assume-role \
--role-arn arn:aws:iam::TARGET-ACCOUNT:role/SecureCrossAccountRole \
--role-session-name CrossAccountSession \
--external-id MyExternalId123 \
--duration-seconds 3600
7. Troubleshooting
Common Trust Policy Issues
flowchart TD
A[AssumeRole Failed] --> B{Check Trust Policy}
B -->|Principal Missing| C[Add Principal to Trust Policy]
B -->|Principal Incorrect| D[Verify Principal ARN]
B -->|Condition Failed| E[Review Condition Logic]
B -->|Action Missing| F[Add sts:AssumeRole]
C --> G[Update Trust Policy]
D --> G
E --> G
F --> G
G --> H[Test Role Assumption]
H -->|Success| I[Access Granted]
H -->|Failure| J[Check Permissions Policy]
style A fill:#ffebee
style I fill:#e8f5e8
style J fill:#fff3e0
Troubleshooting Flow:
This flowchart shows the systematic approach to troubleshooting trust policy issues. Start by checking if the principal is correctly specified in the trust policy, then verify conditions are met, and finally ensure the correct action is allowed. If trust policy is correct but access still fails, check the permissions policies attached to the role.
Diagnostic Commands
# Check current user identity
aws sts get-caller-identity
# View trust policy for a role
aws iam get-role --role-name MyTrustedRole --query 'Role.AssumeRolePolicyDocument'
# List all policies attached to a role
aws iam list-attached-role-policies --role-name MyTrustedRole
# Check inline policies
aws iam list-role-policies --role-name MyTrustedRole
# Get specific inline policy
aws iam get-role-policy --role-name MyTrustedRole --policy-name PolicyName
# Test role assumption with verbose output
aws sts assume-role \
--role-arn arn:aws:iam::123456789012:role/MyTrustedRole \
--role-session-name TestSession \
--debug
Common Pitfalls:
- Forgetting to specify the correct principal ARN
- Using outdated policy syntax (wrong Version)
- Circular trust relationships between roles
- Overly restrictive conditions that prevent legitimate access
- Not understanding the difference between trust policies and permission policies
Best Practices Summary
Practice |
Description |
Benefit |
Least Privilege |
Only grant minimum required trust |
Reduces attack surface |
External ID |
Use for third-party access |
Prevents confused deputy attacks |
MFA Requirements |
Require MFA for sensitive roles |
Adds authentication layer |
Time Restrictions |
Limit access to specific time windows |
Temporary access control |
IP Restrictions |
Limit access to specific networks |
Geographic/network security |
Regular Auditing |
Review trust policies periodically |
Maintains security posture |
Conclusion
AWS IAM Trust Policies are the foundation of secure cross-account access, service integration, and federated identity management. By understanding the components, flows, and proper configuration techniques outlined in this guide, you can implement robust trust relationships that follow security best practices.
Remember that trust policies work in conjunction with permission policies - trust policies determine who can assume a role, while permission policies determine what that role can do. Both are essential for a complete security model.
Always test trust policies in a non-production environment before implementing them in production. Use CloudTrail to monitor role assumption activities and regularly audit your trust relationships for security compliance.