Cross-Account Access Patterns
Complete the full lesson to earn 25 points
Work through each section, then tap “Mark as Complete” on the last one.
Module: Identity and Access Management
Section: Identity Federation
Lesson: Cross-Account Access Patterns
Introduction: The Necessity of Cross-Account Access
In modern cloud computing, organizations rarely operate within a single, isolated environment. As systems scale, architects move away from monolithic account structures toward multi-account setups to isolate workloads, manage billing, and enforce security boundaries. However, this architectural shift introduces a significant challenge: how do we allow users or services in one environment to securely access resources in another? This is where cross-account access patterns become the bedrock of identity management.
Cross-account access is the practice of granting permissions to an entity (a user, a role, or an application) located in one identity provider or cloud account to interact with assets residing in a completely different cloud account. Without a structured approach to this, administrators often resort to dangerous shortcuts, such as creating duplicate user credentials across multiple accounts or sharing static long-term keys. These methods violate the principle of least privilege and create massive security blind spots that are difficult to audit.
Understanding these patterns is not just about connecting two points; it is about establishing a chain of trust. When we master cross-account access, we move from a state of fragmented identity management to a centralized, governed, and scalable architecture. This lesson will guide you through the mechanics of identity federation, the specific patterns used to establish trust between accounts, and the best practices required to keep your infrastructure secure.
The Fundamentals of Identity Federation
To understand cross-account access, we must first define identity federation. Federation is the process of linking a user’s identity across multiple identity management systems. Instead of maintaining a local user database in every single account, we designate one account as the "Identity Provider" (IdP) and others as "Service Providers" or "Resource Accounts."
When a user attempts to access a resource in a target account, they do not present their original credentials to that target. Instead, they present a token or a temporary security credential issued by their trusted identity source. This avoids the need for password synchronization and allows for centralized de-provisioning. If an employee leaves the company, you disable their access in the central IdP, and their access to all federated accounts is revoked instantly.
The Role of Trust Policies
In most cloud environments, cross-account access relies on a two-part trust relationship. First, the resource account must explicitly permit an external entity to assume a role. Second, the identity account must grant its local user or service permission to perform the "AssumeRole" action. If either side of this handshake is missing or misconfigured, the access request will be denied.
Callout: Trust Policies vs. Permission Policies It is common to confuse these two. A Trust Policy (often called an "AssumeRolePolicy") is attached to the target role and defines who is allowed to assume that role. A Permission Policy (often called an "Identity-based Policy") is attached to the user or service in the source account and defines what that user is allowed to do, including the authority to call the assume-role API. You need both to function correctly.
Pattern 1: The Role-Based Delegation Pattern
The most common and recommended way to handle cross-account access is through role-based delegation. In this pattern, you create a dedicated "Cross-Account Role" in the resource account. This role acts as a gateway; it has specific permissions attached to it that dictate exactly what the caller can do once they assume the identity of that role.
Step-by-Step Implementation
- Identify the Source: Determine the Account ID of the identity account (Account A) where the user or service resides.
- Create the Role in the Target: In the resource account (Account B), create a new IAM role.
- Define the Trust Policy: Configure the role's trust relationship to allow Account A to assume it.
- Attach Permissions: Attach the necessary policies to this role in Account B, granting access to the specific resources (e.g., an S3 bucket or a database).
- Grant Permission in Account A: Update the user's policy in Account A to allow the
sts:AssumeRoleaction for the specific ARN of the role created in Step 2.
Code Example: The Trust Policy (Account B)
The following JSON snippet represents the trust policy for a role in the target account. This policy explicitly trusts the identity account to request access.
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Principal": {
"AWS": "arn:aws:iam::123456789012:root"
},
"Action": "sts:AssumeRole",
"Condition": {
"StringEquals": {
"sts:ExternalId": "UniqueProjectID123"
}
}
}
]
}
Explanation: The Principal field specifies the source account ID. The sts:ExternalId condition is a security best practice that prevents the "confused deputy" problem, which we will discuss in detail later in this lesson.
Pattern 2: Identity Federation via SAML 2.0
While role-based delegation works well for machine-to-machine or user-to-account access, SAML (Security Assertion Markup Language) 2.0 is the industry standard for federating enterprise identity providers (like Active Directory or Okta) into cloud environments. This is often used when you want your corporate employees to log into the cloud console without creating individual IAM users for them.
How SAML Federation Works
When a user logs into your corporate portal, the IdP generates a SAML assertion—a signed XML document containing the user's identity and group attributes. The user's browser posts this assertion to the cloud provider's sign-in endpoint. The cloud provider validates the signature, maps the user's groups to specific IAM roles, and grants the user a session token.
- Mapping Groups to Roles: You can configure the IdP to send a "Role" attribute. If an employee is in the "Developers" group, the IdP sends that attribute, and the cloud provider maps it to a "Developer-Role" that has read-only access to production.
- Benefits: You get single sign-on (SSO) and centralized audit logs. You don't have to manage user lifecycles within the cloud platform itself.
Callout: Why SAML over Local IAM Users? Local IAM users are "static" entities. They require password rotations, MFA management, and manual deletion when an employee leaves. SAML federation uses "just-in-time" access. The user exists in your corporate directory, and the cloud account only sees a temporary session. This reduces the attack surface significantly.
Pattern 3: Resource-Based Policies (The "Direct Access" Model)
In some cases, you do not need to assume a role. Certain cloud resources (such as S3 buckets, SQS queues, or KMS keys) support resource-based policies. These policies allow you to define access directly on the resource itself, specifying an external account as a principal.
Practical Example: Cross-Account S3 Access
If you have a bucket in Account B and you want a service in Account A to upload files to it, you can attach a bucket policy directly to the S3 bucket in Account B:
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Principal": {
"AWS": "arn:aws:iam::123456789012:root"
},
"Action": [
"s3:PutObject",
"s3:GetObject"
],
"Resource": "arn:aws:s3:::my-shared-data-bucket/*"
}
]
}
Warning: Be very careful with resource-based policies. If you accidentally grant access to * (the entire world) in the principal field, your resource will be publicly accessible. Always restrict the principal to a specific account ID or a specific IAM role ARN.
Best Practices for Secure Cross-Account Access
Implementing these patterns is only half the battle. Maintaining them requires a disciplined approach to security. Follow these industry-standard best practices to ensure your cross-account connections do not become liabilities.
1. Implement the Principle of Least Privilege
Never grant AdministratorAccess to a cross-account role. Only provide the specific actions needed for the task. If a service only needs to read logs from a bucket, create a role that only has s3:GetObject and s3:ListBucket permissions.
2. Use External IDs to Prevent Confused Deputy Attacks
The "Confused Deputy" problem occurs when a malicious party convinces a service (the deputy) to perform an action on their behalf using the service's authority. By requiring an ExternalId in your role trust policy, you ensure that only the specific application you intended can assume the role. The application must provide this unique, secret ID during the assume-role request.
3. Monitor Access with Logging
Enable cloud-native logging (such as CloudTrail) in both the source and the target accounts. You should be able to trace a request from the source account all the way to the resource in the target account. Set up alerts for any failed sts:AssumeRole attempts, as these are often indicators of unauthorized probing.
4. Use Short-Lived Credentials
Never store long-term access keys in code or configuration files. When assuming a role, the cloud provider issues temporary security tokens that typically expire within one hour (though this can be configured). These tokens are the safest way to handle cross-account interactions.
5. Automate Role Provisioning
Do not create roles manually in the console. Use Infrastructure as Code (IaC) tools like Terraform or CloudFormation. This ensures that your trust policies are consistent across all accounts and that you have a version-controlled history of who changed what and when.
Comparison: Access Methods
| Method | Use Case | Complexity | Security Level |
|---|---|---|---|
| Role Assumption | Cross-account API calls | Medium | High |
| SAML Federation | User console access | High | Very High |
| Resource Policies | Direct resource sharing | Low | Medium |
| Static Credentials | Legacy/Non-cloud apps | Very High | Low (Avoid) |
Note: Static credentials are the leading cause of data breaches. They are long-lived, often stored in plaintext in code repositories, and extremely difficult to rotate. If you are currently using static credentials for cross-account access, prioritize migrating to role assumption immediately.
Common Pitfalls and How to Avoid Them
Even with the best intentions, engineers often run into "Access Denied" errors that are difficult to debug. Here are the most frequent mistakes and how to resolve them.
The "Missing Permissions" Trap
Users often remember to update the trust policy on the target role but forget to update the permission policy for the user in the source account. Remember: the source user must have explicit permission to call sts:AssumeRole on the target role's ARN.
The "Resource Policy" Conflict
If you have a resource-based policy that denies access, it will override any allow policy. If you find that a user has the correct role permissions but is still getting an "Access Denied" error, check the resource-based policy on the target asset (like an S3 bucket or KMS key) to ensure there isn't an explicit Deny statement blocking that user.
Clock Skew Issues
When using SAML federation, the time on the identity provider's server must be synchronized with the cloud provider's servers. If the system clocks are out of sync, the SAML assertion will be considered expired or invalid, and the login will fail. Always ensure your servers use NTP (Network Time Protocol).
Over-Permissioning the "Root" Account
A common mistake is granting access to the entire account root (arn:aws:iam::ACCOUNT_ID:root). While this is convenient, it effectively grants access to any user within that account who has the AssumeRole permission. Instead, scope your trust policy to a specific role ARN within the source account:
"AWS": "arn:aws:iam::123456789012:role/MyApplicationRole"
Implementing a Secure Pattern: A Practical Scenario
Imagine you have a "Logging Account" where you aggregate all your CloudTrail logs, and you have several "Workload Accounts" that generate these logs. You want to allow a centralized Security Analytics tool residing in the Logging Account to read logs from the S3 buckets in all the Workload Accounts.
Step 1: Configure the Workload Account (The Resource) Create an S3 bucket policy in each Workload Account.
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Principal": {
"AWS": "arn:aws:iam::LOGGING_ACCOUNT_ID:role/SecurityAnalyticsRole"
},
"Action": ["s3:GetObject", "s3:ListBucket"],
"Resource": [
"arn:aws:s3:::workload-logs-bucket",
"arn:aws:s3:::workload-logs-bucket/*"
]
}
]
}
Step 2: Configure the Logging Account (The Identity)
In the Logging Account, the SecurityAnalyticsRole needs to be able to perform the read operations. Because we used a resource-based policy on the S3 bucket, the role in the Logging Account only needs the permissions to read S3.
Step 3: Verification
Test the access using the command line interface from the Logging Account:
aws s3 ls s3://workload-logs-bucket --profile security-analytics-role
If you receive an "Access Denied," use the CloudTrail event history in the Workload Account. Look for the AccessDenied event. It will tell you the exact ARN of the user/role that attempted the call, which helps you verify if your policies are pointing to the correct identity.
Advanced Concepts: Chaining Roles and Transitive Trust
Sometimes, you may need to access a resource that requires passing through multiple accounts. This is called "Role Chaining." While possible, it introduces complexity. If you assume Role A, and then use that identity to assume Role B, you are essentially creating a chain of trust.
- The Limitation: When you assume a role, you are limited to the permissions of the role you just assumed. You cannot "add" permissions from the previous role to the new one.
- The Risk: Role chaining makes auditing difficult. If an incident occurs, you have to trace the identity through multiple assume-role events across different accounts.
- Best Practice: Try to avoid long chains. If you find yourself chaining more than two roles, reconsider your account architecture. Perhaps the resource should be moved, or the service should be deployed in a more central location.
Summary and Key Takeaways
Cross-account access is the architectural glue that holds multi-account cloud environments together. By mastering these patterns, you enable your organization to scale securely without compromising on governance.
Key Takeaways:
- Avoid Long-Term Credentials: Never share access keys between accounts. Always use temporary security tokens generated by assuming roles.
- Trust Policies are Essential: Understand that every cross-account interaction requires a handshake: the source must have permission to request, and the target must have permission to grant.
- The Confused Deputy Problem is Real: Always use
ExternalIdwhen assuming roles to ensure that your application is the only one capable of accessing the target role. - Centralize Identity: Use SAML or OIDC federation to link your corporate identity provider to your cloud accounts. This allows for unified user management and faster offboarding.
- Audit Everything: Use cloud-native logging to monitor
AssumeRoleevents. If you don't log it, you don't know who is accessing your resources. - Use Infrastructure as Code (IaC): Manually configured IAM policies are prone to human error and configuration drift. Use Terraform, CloudFormation, or Pulumi to manage your cross-account trust relationships.
- Least Privilege is Non-Negotiable: Regularly review your role permissions. If a role has permissions it hasn't used in 90 days, remove them.
By following these principles, you turn identity and access management from a source of friction into a competitive advantage. You provide your developers with the access they need to build, while ensuring that the security team has the visibility and control required to protect the organization's most sensitive assets. Remember, identity is the new perimeter—treat it with the same rigor you would apply to your network firewalls.
Enjoying the courses?
Everything stays free. Pro shows fewer ads, doubles your daily points limit so you progress twice as fast, and lets you read each lesson on one page.
- ✓ Fewer advertisements
- ✓ 2× daily points limit
- ✓ Distraction-free lessons