Cross-Account Access

Earn 25 points (50 with Pro) in two steps

  1. ① Read through the lesson — each section gets a ✓ as you scroll through it.
  2. ② When every section has a ✓, tap Complete lesson.

0 of 11 read · keep scrolling

✦ See fewer ads and earn double points — 50 a lesson instead of 25 — with Pro

Lesson: Mastering Cross-Account Access in Secure Architectures

Introduction: The Necessity of Cross-Account Access

In modern cloud computing environments, organizations rarely rely on a single, monolithic account to manage their entire infrastructure. Instead, they distribute workloads across multiple accounts to isolate environments (such as development, staging, and production), segregate sensitive data, or comply with regulatory requirements. While this multi-account strategy is excellent for limiting the blast radius of a security incident, it introduces a significant engineering challenge: how do you allow authorized users or services in one account to interact with resources in another account securely?

Cross-account access is the architectural practice of granting permission for an identity in one account (the "source" or "trusting" account) to perform actions on resources located in another account (the "target" or "trusted" account). If implemented poorly, this practice can become the single greatest vulnerability in your cloud perimeter. If implemented correctly, it provides a granular, auditable, and temporary way to manage resources without the need for static credentials or shared account passwords.

This lesson explores the mechanics of cross-account access, the security principles that govern it, and the practical implementation strategies you need to build a hardened, multi-account architecture. By the end of this module, you will understand how to move away from long-lived credentials and toward a model of identity-based, temporary authorization.


Not read yet

The Core Concept: Trust Relationships

At the heart of cross-account access lies the concept of a "Trust Relationship." In most cloud environments, an identity (like a user or a role) exists only within the boundaries of a specific account. To grant access to someone from outside that boundary, you must explicitly tell your account to trust the external entity.

Think of it like a physical building. If you have an office in Building A, your badge works there. If you need to enter Building B, you don't just walk in; the security team at Building B must create a record that says, "We recognize the badge system of Building A, and specifically, we allow this individual to enter our lobby."

The Two-Part Authentication Dance

Cross-account access always requires two distinct steps to be successful:

  1. The Target Account (Trusting): You must define a policy that allows the external entity to assume a role within your account. This is known as a Trust Policy or an Identity-based Policy that permits sts:AssumeRole.
  2. The Source Account (Trusted): You must define a policy that allows your local identity (user or role) to perform the sts:AssumeRole action on the target account’s role.

Without both sides of this configuration, access will be denied. This two-way validation is a critical security feature because it prevents a malicious actor from simply "pointing" to a role they don't own.

Callout: The Principle of Least Privilege in Cross-Account Access Cross-account access is often treated as a "blank check." Engineers sometimes create a cross-account role with AdministratorAccess to make things "easier." This is a fundamental error. When designing cross-account roles, you must scope the permissions to the specific resources and actions required for the task. If a service in Account A only needs to read from an S3 bucket in Account B, the cross-account role must only have s3:GetObject permissions for that specific bucket.


Not read yet

Practical Implementation: Role-Based Access

The standard way to implement cross-account access is through Role Assumption. An identity in the source account requests temporary credentials from the Security Token Service (STS) by assuming a role in the target account.

Step-by-Step: Configuring the Target Account

First, you must create a role in the target account that specifies which external accounts are allowed to assume it.

  1. Navigate to the IAM console in the target account.
  2. Create a new role and select "Another AWS Account" (or the equivalent identity provider option).
  3. Enter the ID of the source account.
  4. Optionally, require an "External ID." This is a secret string that acts as a password for the role assumption process, which is critical when using third-party services to access your account.
  5. Attach the specific permissions policy required for the task.

Step-by-Step: Configuring the Source Account

Once the target role exists, you must authorize your local user or service to request those credentials.

  1. Locate the user or service role in the source account.
  2. Add an inline policy or managed policy that allows the sts:AssumeRole action.
  3. Specify the Amazon Resource Name (ARN) of the target role you created in the previous step.
{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Effect": "Allow",
            "Action": "sts:AssumeRole",
            "Resource": "arn:aws:iam::TARGET_ACCOUNT_ID:role/CrossAccountAccessRole"
        }
    ]
}

Note: The Resource field in the policy above must point to the specific role ARN in the target account. If you use a wildcard (*), you are potentially allowing your users to assume any role in that target account, which is a significant security risk.


Not read yet

Common Pitfalls and Security Risks

Even experienced architects often make mistakes when implementing cross-account access. Understanding these pitfalls is the first step toward building a robust architecture.

The "Wildcard" Trap

The most common mistake is using wildcards in the Resource or Principal fields. If you configure a trust policy to allow Principal: "*", you are essentially opening your role to every account in the cloud provider’s ecosystem. Always explicitly define the account ID or the specific ARN.

Ignoring the External ID

The External ID is a mechanism designed to prevent the "Confused Deputy" problem. If you are using a third-party SaaS tool to manage your resources, they might ask you to grant them access to your account. If you use a generic role, they might be able to access your account using the same role they use for other customers. By requiring an External ID, you ensure that the role can only be assumed if the requester provides the unique secret you shared with that specific vendor.

Lack of Auditing

Cross-account access can become a "black box." If you don't enable CloudTrail logging in both the source and target accounts, you will have no way of knowing who assumed the role or what actions they performed. Always ensure that AssumeRole events are captured in your logs and forwarded to a centralized security account for analysis.

Feature Best Practice Risk of Ignoring
Account IDs Use exact IDs in Trust Policies Unauthorized access from other accounts
External ID Use for 3rd-party integrations Confused Deputy attacks
Permissions Least privilege (specific actions) Escalation of privilege
Logging Enable CloudTrail in both accounts Lack of forensic visibility
Session Duration Set to minimum required time Longer window for potential misuse

Not read yet

Advanced Architecture: Using IAM Roles for Service Accounts (IRSA)

In containerized environments like Kubernetes, cross-account access takes on a different form. Instead of users manually assuming roles, the infrastructure handles it automatically. This is often implemented using OIDC (OpenID Connect) providers.

When a pod in a Kubernetes cluster in Account A needs to access a database in Account B, you configure the Kubernetes cluster to act as an OIDC provider. You then create an IAM role in Account B that trusts the OIDC provider (the cluster) rather than a specific account.

Why this is superior:

  • Granularity: You can grant access to individual pods rather than an entire node.
  • Automatic Rotation: The OIDC tokens are short-lived and automatically rotated by the orchestration layer.
  • No Static Credentials: There are no access keys stored in environment variables or configuration files.

Warning: Never store access keys or secret keys in your code, container images, or CI/CD pipelines. Even with cross-account access, the temptation to "hardcode" credentials for convenience is high. Always use the native identity provider mechanisms (like IAM Roles or OIDC) to facilitate access.


Not read yet

Establishing a Secure Workflow: Step-by-Step

To implement cross-account access properly, follow this structured workflow. This approach ensures that you maintain control, visibility, and security at every stage.

Phase 1: Planning and Scoping

Before touching any configuration, identify exactly what needs to be accessed. Ask yourself:

  • Who (or what service) needs access?
  • What specific resources do they need to interact with?
  • What is the minimum set of permissions (actions) required?
  • How long does this access need to last?

Phase 2: Building the Target Role

In the target account, create a role that follows the naming convention of your organization (e.g., CrossAccount-Readonly-S3). Set the Trust Policy to only allow the specific account ID of the source account.

{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Effect": "Allow",
      "Principal": {
        "AWS": "arn:aws:iam::SOURCE_ACCOUNT_ID:root"
      },
      "Action": "sts:AssumeRole",
      "Condition": {
        "StringEquals": {
          "sts:ExternalId": "SecretUniqueString"
        }
      }
    }
  ]
}

Phase 3: Granting Permission in the Source Account

In the source account, apply a policy to the entity (user, group, or role) that allows them to assume the target role. Test this using the Command Line Interface (CLI) to ensure the handshake is successful.

# Example command to assume the role
aws sts assume-role \
    --role-arn arn:aws:iam::TARGET_ACCOUNT_ID:role/CrossAccount-Readonly-S3 \
    --role-session-name MySessionName

Phase 4: Verification and Monitoring

Once configured, use the target account’s CloudTrail logs to verify that the AssumeRole call was successful. Check the userIdentity section of the log to confirm the correct source account and user performed the action.


Not read yet

Handling the "Confused Deputy" Problem

The "Confused Deputy" problem is a classic security vulnerability where an entity with higher privileges (the deputy) is tricked by an entity with lower privileges into performing an action that the lower-privileged entity should not be able to perform.

In the context of cross-account access, imagine a scenario where a third-party backup service has a role in your account. If you don't use an External ID, the backup service might be tricked into backing up data from one of their other customers into your account, or vice versa, because they don't know which customer "owns" the request.

By implementing the sts:ExternalId condition, you provide a unique, non-guessable secret that acts as a cryptographic proof of ownership. The service must present this ID when assuming the role. Since only you and the service know this ID, the risk of a confused deputy attack is effectively neutralized.

Callout: Why Not Use Access Keys? Many beginners ask, "Why not just create an IAM user in the target account and give the source account the Access Key ID and Secret Access Key?" This is a dangerous practice. Long-lived credentials are easily leaked, difficult to rotate, and impossible to revoke without potentially breaking services. Role assumption uses temporary security tokens that automatically expire, significantly reducing the window of opportunity for an attacker if a credential is compromised.


Not read yet

Best Practices for Enterprise Environments

1. Centralized Identity Management

Ideally, you should have a single "Identity Account" where all your users reside. You then grant these users permissions to assume roles in other accounts. This avoids the need to create individual IAM users in every single account, which is an administrative nightmare and a security risk.

2. Standardized Naming Conventions

Use a consistent naming convention for your cross-account roles. For example, use CrossAccount-Admin, CrossAccount-ReadOnly, or CrossAccount-SecurityAuditor. This makes it easy to identify the purpose of a role at a glance and simplifies the process of auditing permissions across the organization.

3. Automated Auditing

Use automated tools to scan your IAM policies for over-privileged roles. Many cloud providers offer tools that can detect if a role has more permissions than it actually uses based on access patterns. Regularly prune unused roles and tighten policies that are too broad.

4. Enforce MFA for Sensitive Roles

For roles that grant broad administrative access, enforce Multi-Factor Authentication (MFA) in the trust policy. You can add a condition that requires the session to be authenticated with an MFA device before the AssumeRole action is permitted.

"Condition": {
    "Bool": {
        "aws:MultiFactorAuthPresent": "true"
    }
}

5. Use Service Control Policies (SCPs)

If you are using an organization-level hierarchy, use Service Control Policies (SCPs) to set guardrails. For example, you can create an SCP that prevents any account in your organization from assuming a role that doesn't belong to your organization. This prevents data exfiltration to accounts you don't control.


Not read yet

Troubleshooting Common Issues

When setting up cross-account access, you will inevitably run into "Access Denied" errors. Here is a systematic way to troubleshoot:

  • Check the Trust Policy: Does the target role's trust policy explicitly list the source account ID?
  • Check the Permissions Policy: Does the source user/role have an explicit Allow for the sts:AssumeRole action?
  • Check the Resource ARN: Is the ARN in the source policy exactly correct? A single typo in the account ID will cause the request to fail.
  • Check for Deny Policies: Remember that in most cloud IAM systems, an explicit Deny overrides any Allow. Check for any SCPs or boundary policies that might be blocking the action.
  • Check External ID: If the target role requires an External ID, ensure it is being passed in the API call or CLI command.
  • Check Time Skew: If using OIDC or other time-sensitive tokens, ensure the system clocks on your servers are synchronized.

Not read yet

Summary and Key Takeaways

Cross-account access is the foundation of secure, scalable multi-account architectures. By moving away from static credentials and embracing temporary, role-based access, you drastically reduce your attack surface and simplify identity management.

Key Takeaways:

  1. Trust is Bidirectional: Cross-account access requires configuration in both the source (trusted) and target (trusting) accounts. Neither side can grant access without the other.
  2. Avoid Long-Lived Credentials: Always prefer IAM roles and temporary security tokens over static access keys. Roles provide the necessary isolation and automatic credential rotation.
  3. The Power of Least Privilege: Never use AdministratorAccess for cross-account roles. Define the exact actions and resources required for the specific task at hand.
  4. Use External IDs: When working with third-party vendors, always use the External ID feature to prevent confused deputy attacks and ensure that your roles are not misused by other customers of that vendor.
  5. Visibility is Mandatory: Enable logging (such as CloudTrail) in both the source and target accounts. Without logs, you cannot audit access or perform forensics if a security incident occurs.
  6. Standardize and Automate: Use naming conventions and infrastructure-as-code (IaC) to manage your roles. This ensures consistency and makes it easier to audit your architecture as it grows.
  7. Implement Guardrails: Use organization-level policies (like SCPs) to prevent unauthorized cross-account access and enforce security standards across your entire environment.

By adhering to these principles, you create an environment where access is controlled, transparent, and aligned with modern security best practices. As you move forward in your architecture design, always evaluate whether a cross-account role can solve a problem before resorting to more complex or less secure alternatives.


Not read yet

Frequently Asked Questions (FAQ)

Q: Can I use cross-account access for users who don't have an IAM account? A: Yes, if you use an identity provider (IdP) like Okta or Azure AD, you can federate those identities into your cloud environment. The federation process acts similarly to role assumption, where the IdP provides a token that the cloud environment validates before granting access.

Q: How often should I rotate my cross-account roles? A: Because roles use temporary credentials generated by STS, you don't need to "rotate" the role itself in the same way you rotate a password. However, you should periodically audit the trust policies and permission policies of your roles to ensure they are still necessary and correctly scoped.

Q: What if I need to access a resource in a different region? A: Cross-account access is independent of regions. You can assume a role in an account in the us-east-1 region even if you are originating the request from eu-west-1. The IAM service is global, meaning your trust policies and roles are available across all regions.

Q: Can I limit cross-account access to specific IP addresses? A: Yes, you can add a Condition block to your trust policy that restricts the sts:AssumeRole action to a specific range of IP addresses (the aws:SourceIp condition). This adds an extra layer of defense, ensuring that the role can only be assumed from your corporate network or VPN.

Q: What happens if the target account is deleted? A: If the target account is deleted, any roles within it are also deleted. Any ongoing sessions will be terminated, and no further AssumeRole calls will succeed. It is important to have a lifecycle management process for your accounts to ensure that cross-account dependencies are cleaned up appropriately.

Not read yet

Each section gets a ✓ as you scroll through it. Tap the button to jump to the next one.