Reading30 min read·Module 1High exam weight

Cross-Account Access & Resource Sharing

Key concepts

  • Cross-account IAM roles

  • Resource-based policies

  • AWS Resource Access Manager (RAM)

  • Trust policies and trust relationships

  • External ID for third-party access

The Second Account

Eighteen months after the bucket incident, Theo asks Dana for permission to break things again. His new photo pipeline needs load tests, chaos experiments, and a lot of deliberate failure, and none of that belongs anywhere near production. Dana gives him something better than a bigger sandbox role: a whole second AWS account. An account is the strongest isolation boundary AWS offers. By default, no identity in trailbase-dev can see, touch, or delete anything in trailbase-prod, no matter how spectacularly a test goes wrong.

The wall works perfectly for about two weeks. Then Theo needs a sample of real hiker photos to test his thumbnailer. Peakline Media, the marketing agency Trailbase just hired, needs the brand assets sitting in a production S3 bucket. And Mara points out that with a third account coming for her data work, every account is about to rebuild the same VPC from scratch. The isolation that made everyone safe now needs doorways, and cutting those doorways deliberately is what this lesson is about.

AWS gives you three ways through an account wall. An identity can assume an IAM role in the other account and borrow temporary credentials, exactly the way Priya the auditor has done since lesson 1. A resource can carry a resource-based policy that names outside accounts as welcome guests. And for infrastructure that many accounts need to use in place, AWS Resource Access Manager (RAM) shares the resource itself so nobody has to duplicate it.

The Key Decision

IAM roles are the answer for temporary access, API calls, and fine-grained permission control across accounts. AWS RAM is the answer for long-term sharing of supported resources (VPC subnets, Transit Gateways, Resolver rules) without duplicating them. Resource-based policies sit in between: a standing, per-resource grant on the services that support them.

Exam Tip

SAA-C03 loves to make you pick between an IAM role, a resource-based policy, and RAM. When the scenario shares VPC subnets, Transit Gateways, or Route 53 Resolver rules across accounts in an organization, the answer is RAM. When the access is temporary, programmatic, or for a third party, it is a role.

Cross-Account Access Methods
Figure 1: The two main doorways through an account boundary, role assumption versus RAM resource sharing.

Doorway One: Assume a Role Next Door

Theo needing production photos and Peakline needing campaign data share a shape: an identity in one account must make API calls against resources in another account, for a while, with tightly scoped permissions. That shape is cross-account role assumption, and you already know the machinery. A role is defined by a trust policy that says who may assume it and a permissions policy that says what the role can do. Cross-account access changes exactly one thing: the Principal in the trust policy now names another AWS account instead of an AWS service.

Peakline runs a reporting tool that pulls campaign metrics from shared-bucket, where Mara publishes nightly exports. Wiring that up takes three steps, and the exam expects you to know which account performs each one.

IAM Cross-Account Flow
Figure 2: The full handshake. The target account defines trust and permissions, the source account permits the AssumeRole call, and STS issues temporary credentials.

First, the target account (Trailbase production, the account that owns the data) creates the role and its trust policy:

JSONStep 1: Trust Policy in the Target Account
{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Effect": "Allow",
      "Principal": {
        "AWS": "arn:aws:iam::SOURCE-ACCOUNT-ID:root"
      },
      "Action": "sts:AssumeRole",
      "Condition": {
        "StringEquals": {
          "sts:ExternalId": "unique-external-id"
        }
      }
    }
  ]
}

Read the Principal carefully: SOURCE-ACCOUNT-ID is Peakline's account, and the :root suffix means Trailbase trusts the account as a whole, delegating to Peakline's own admins the decision of which of their identities may actually assume the role. The Condition block demands a secret called an external ID on every assumption. Hold that thought; it is the subject of the next section.

Second, the target account attaches a permissions policy to the role, scoped as narrowly as the job allows. Peakline reads exports, so Peakline gets read:

JSONStep 2: Permissions Policy on the Role
{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Effect": "Allow",
      "Action": [
        "s3:GetObject",
        "s3:ListBucket"
      ],
      "Resource": [
        "arn:aws:s3:::shared-bucket",
        "arn:aws:s3:::shared-bucket/*"
      ]
    }
  ]
}

Third, the source account grants its own identities permission to make the sts:AssumeRole call. Trusting an account opens the door from one side; the source account still has to let its people walk through it:

JSONStep 3: IAM Policy in the Source Account
{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Effect": "Allow",
      "Action": "sts:AssumeRole",
      "Resource": "arn:aws:iam::TARGET-ACCOUNT-ID:role/CrossAccountRole"
    }
  ]
}

When Peakline's tool assumes the role, STS hands back temporary credentials that expire on their own, and for the lifetime of that session the caller acts as the role and only the role. Whatever permissions it holds back home stay at the door, which is exactly what keeps the blast radius predictable.

Dana repeats the same three steps to give Theo's dev account read-only access to a snapshot prefix in the production photo bucket. Internal accounts skip the external ID condition, because that condition exists to solve a problem only third parties have.


The Confused Deputy Comes for Peakline

During her quarterly review, Priya stops on the Peakline trust policy draft and asks one question: where is your external ID? The draft Dana wrote trusted Peakline's account and nothing more, and that is enough to expose Trailbase to a classic attack called the confused deputy problem: a trusted service with legitimate privileges gets tricked by a third party into using those privileges against the wrong target.

Here is how it plays out. Peakline's reporting tool is multi-tenant: one product, dozens of client companies, and each client hands Peakline a role ARN to assume. Role ARNs are predictable (account ID plus role name) and are treated as public information. So a malicious company signs up as a Peakline customer and registers Trailbase's role ARN as its own. Peakline's tool, holding Peakline credentials that Trailbase genuinely trusts, assumes the role and dutifully delivers Trailbase's campaign data to the attacker's dashboard. Peakline did nothing malicious. Its software was simply confused about which customer it was acting for.

The external ID closes the hole. Dana generates a unique, unguessable value, places it in the trust policy condition you saw in Step 1, and shares it with Peakline through a secure channel. Peakline stores that value on the Trailbase tenant record and passes it as sts:ExternalId on every AssumeRole call made on Trailbase's behalf. When the attacker registers Trailbase's ARN under their own tenant, the tool sends the attacker's external ID with the call, the condition fails, and STS refuses the assumption. The external ID works as a shared secret that binds the role to one specific relationship, generated by the account owner and unique per partner.

Q

What is the purpose of the External ID in a cross-account role trust policy?

ATo identify the AWS region
BTo encrypt credentials
CTo prevent the confused deputy problem
DTo enable MFA

Doorway Two: The Bucket Invites You In

Peakline's designers have a much smaller need: every few weeks, someone downloads a logo pack from the trailbase-brand-assets bucket. Standing up role assumption for that feels heavy. The designers would have to switch roles, and their session would lose access to their own account mid-task. Some AWS services offer a lighter doorway: a resource-based policy, a policy attached to the resource itself that uses the Principal element you met in lesson 1 to name who may come in, including identities from other accounts.

JSONS3 Bucket Policy for Cross-Account Access
{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Sid": "CrossAccountAccess",
      "Effect": "Allow",
      "Principal": {
        "AWS": "arn:aws:iam::OTHER-ACCOUNT-ID:root"
      },
      "Action": [
        "s3:GetObject",
        "s3:ListBucket"
      ],
      "Resource": [
        "arn:aws:s3:::my-bucket",
        "arn:aws:s3:::my-bucket/*"
      ]
    }
  ]
}

The policy uses generic names; at Trailbase, my-bucket is trailbase-brand-assets and OTHER-ACCOUNT-ID is Peakline's account. Two behavioral differences separate this doorway from role assumption, and both show up on the exam. With a resource-based policy the callers keep their own identity and credentials, so a Peakline designer can read from a Peakline bucket and Trailbase's bucket in the same session, something an assumed role cannot do because assumption swaps identity entirely. And the grant is permanent standing access rather than an expiring session. Both sides still have to agree: the bucket policy admits Peakline, and Peakline's own identity policies must allow those S3 actions too.

Only some services support this doorway, and the exam expects you to recognize the big ones:

Services Supporting Resource-Based Policies

ServiceResourcePolicy Name
Amazon S3BucketsBucket Policy
Amazon SQSQueuesQueue Policy
Amazon SNSTopicsTopic Policy
AWS KMSKeysKey Policy
AWS LambdaFunctionsFunction Policy
Amazon ECRRepositoriesRepository Policy
AWS Secrets ManagerSecretsResource Policy

Doorway Three: Share the Thing Itself with AWS RAM

The third account arrives on schedule: trailbase-data, where Mara builds her analytics stack. And with it comes the problem she predicted. Three accounts means three hand-built VPCs, three NAT gateway bills, and three CIDR ranges that will collide the day the accounts need to talk to each other. Copying infrastructure into every account scales badly, and roles do not help here, because nobody wants to make API calls into another account. The accounts need to launch resources inside networking that lives somewhere else.

That is the job of AWS Resource Access Manager (RAM): a service that shares supported AWS resources with other accounts, organizational units, or an entire organization, without duplicating anything. Mara's proposal wins: a dedicated network account owns one well-designed VPC, and RAM shares its subnets with prod, dev, and data. Each team sees the shared subnets natively in its own console and launches instances into them, while only the network account can touch route tables and the VPC itself.

AWS RAM

AWS RAM enables long-term sharing of supported resources without duplicating them.

How it works: the owner account creates a resource share, naming the resources and the principals (accounts, OUs, or the whole organization). Within AWS Organizations, access is automatic. Outside Organizations, the consumer must accept an invitation. Shared resources then appear natively in the consumer account consoles.

Best for: VPC subnet sharing (the centralized VPC model), Transit Gateway sharing, Route 53 Resolver rules, License Manager configurations, and any long-term, persistent resource access.

Why the Centralized VPC Wins

A single VPC managed by the network team, with shared subnets used by multiple accounts, gives Trailbase centralized control over network configuration, no duplicate VPCs wasting IP address space, and simplified connectivity because all workloads live in the same VPC.

Q

Which AWS service is used to share VPC subnets across accounts without duplication?

AIAM Roles
BAWS RAM
CVPC Peering
DAWS Organizations

Creating a share is a short piece of CLI work:

SHCreate a RAM Resource Share (CLI)
# Create resource share
aws ram create-resource-share \
  --name "SharedVPCSubnets" \
  --resource-arns arn:aws:ec2:us-east-1:123456789012:subnet/subnet-abc123 \
  --principals arn:aws:organizations::123456789012:ou/o-abc123/ou-def456 \
  --permission-arns arn:aws:ram::aws:permission/AWSRAMDefaultPermissionSubnet

# List resource shares
aws ram get-resource-shares --resource-owner SELF

# View shared resources
aws ram list-resources --resource-owner SELF

Notice the principal in that command is an OU, an organizational unit inside AWS Organizations. Trailbase now manages its accounts under Organizations, the multi-account management service whose SCP guardrails you met in lesson 1, and that changes how RAM behaves in a way the exam tests directly.

RAM Inside AWS Organizations

When sharing within AWS Organizations, no invitations are required because access is automatic. You can share with the entire organization or with specific OUs instead of listing individual accounts. Two switches make this work: enable sharing within the organization in the RAM settings, and enable RAM trusted access in Organizations.

Q

When sharing resources via RAM within AWS Organizations, what happens?

AInvitations must be manually accepted
BAccess is automatically granted
CResources are duplicated to each account
DIAM roles are automatically created

RAM covers far more than subnets, and the exam likes the edges of the list:

Common RAM Shareable Resources

ServiceResource TypeUse Case
Amazon VPCSubnetsCentralized VPC, shared networking
Amazon VPCTransit GatewaysHub-and-spoke network topology
Amazon VPCPrefix ListsShared IP address management
Route 53Resolver RulesCentralized DNS resolution
AWS License ManagerLicense ConfigurationsCentralized license management
AWS GlueData Catalogs, DatabasesShared data lake access
Amazon AuroraDB ClustersCross-account database cloning
AWS OutpostsOutpost ResourcesShared on-premises infrastructure
EC2Capacity ReservationsShared compute capacity

Picking the Right Doorway

Trailbase now uses all three doorways at once, and the pattern of which one fits where is the pattern the exam tests. When the company later connects an office network, the network account will own a Transit Gateway, a managed hub that links VPCs and on-premises networks, and share it through RAM rather than building one per account. When Mara centralizes DNS, she will share Route 53 Resolver rules the same way. Theo's CI/CD pipeline deploys to production by assuming a role, because deployments want temporary credentials and a clean audit trail. And Peakline keeps its two grants: an external-ID-protected role for the multi-tenant reporting tool, and a plain bucket policy for the designers.

Cross-Account Best Practices

Require an external ID for all third-party role access to prevent confused deputy attacks. Prefer RAM for long-term sharing, and enable Organizations integration so shares are automatic and OU-targeted. Apply least privilege to every grant, audit all cross-account activity with CloudTrail, use RAM managed permissions to define precise access, and add an MFA condition to trust policies protecting sensitive roles.

When to Use Each Method

ScenarioRecommended MethodWhy
Temporary API access to another accountIAM Role (AssumeRole)Temporary credentials, fine-grained control
Share VPC subnets with multiple accountsAWS RAMNative sharing, no duplication
Grant S3 access to specific external accountS3 Bucket PolicyDirect resource-based policy
Share Transit Gateway across organizationAWS RAMCentralized network sharing
CI/CD pipeline deploying to production accountIAM Role (AssumeRole)Temporary deployment credentials
Share Route 53 Resolver rulesAWS RAMDNS centralization
Lambda in Account A triggers Lambda in Account BResource Policy + IAM RoleCross-account invocation
Exam Tip

Translate the scenario keywords. Temporary, programmatic, or third party means AssumeRole, plus an external ID if the third party serves many customers. Share subnets, Transit Gateway, or Resolver rules across an organization means RAM. One resource admitting one outside account means a resource-based policy.

Exam Scenarios

ScenarioSolutionKey Point
Network team manages VPCs, app teams need accessRAM subnet sharingCentralized VPC model
External vendor needs temporary S3 accessIAM role with External IDPrevents confused deputy
Share Transit Gateway with 50 accountsRAM with organization sharingNo need to list each account
Account A Lambda needs to write to Account B DynamoDBIAM role assumptionTemporary credentials for API calls
Centralize Route 53 DNS across organizationRAM Resolver rule sharingDNS centralization
Share Aurora cluster for cloningRAM Aurora sharingCross-account database cloning
Development account needs read-only prod accessIAM role with read permissionsLeast privilege cross-account
Q

A company wants development teams to deploy resources into shared VPC subnets managed by the network team. What is the BEST approach?

ACreate separate VPCs for each team
BShare VPC subnets via AWS RAM
CUse VPC Peering between accounts
DCreate IAM roles for each subnet

Common Pitfalls

Trusting a Third Party Without an External ID

Granting a partner account AssumeRole with no external ID condition invites the confused deputy attack, and multi-tenant vendor tooling is exactly where it happens. A malicious actor can trick the vendor into using its legitimate access against your account. Always require an external ID in the trust policy for third-party access, generate a unique and unpredictable value, and share it securely with that one trusted party only.

RAM Without Organizations Integration

Sharing by listing individual account IDs means every share needs a manual invitation and acceptance, and you cannot target OUs at all. The operational overhead grows with every account. Enable RAM trusted access in AWS Organizations, turn on sharing within the organization in the RAM settings, and share with OUs instead of individual accounts.

The Wide-Open Trust Policy

A trust policy with Principal set to the AWS wildcard lets any AWS account on the planet assume your role, which defeats the entire point of cross-account security. Specify exact principal ARNs, add conditions such as an external ID or source account, and limit trust to specific users and roles rather than entire accounts where you can.

Duplicating Resources Instead of Sharing

Building a copy of the VPC or Transit Gateway in every account multiplies cost and complexity, exhausts IP address space, lets configurations drift apart, and turns connectivity into a mesh of workarounds. Centralize network resources in a single account and share them via RAM wherever the resource type supports it, keeping one source of truth.


Quick Reference

SHCommon RAM CLI Commands
# Create resource share
aws ram create-resource-share --name <name> --resource-arns <arns> --principals <principals>

# List your resource shares
aws ram get-resource-shares --resource-owner SELF

# List resource shares shared with you
aws ram get-resource-shares --resource-owner OTHER-ACCOUNTS

# Accept resource share invitation
aws ram accept-resource-share-invitation --resource-share-invitation-arn <arn>

# List shared resources
aws ram list-resources --resource-owner SELF

# Delete resource share
aws ram delete-resource-share --resource-share-arn <arn>

# Enable sharing with Organizations
aws ram enable-sharing-with-aws-organization

Method Comparison

AspectIAM RolesResource PoliciesAWS RAM
Access TypeTemporaryPermanentPermanent
Credential TypeSTS temporaryCaller credentialsCaller credentials
Setup ComplexityMediumLowLow
Supported ResourcesAll (via API)Select servicesSelect resources
Organization IntegrationManualManualAutomatic
Console AccessSwitch roleDirectNative appearance
Best ForAPI access, temp elevationSimple sharingVPC, TGW, persistent sharing


Further Reading

Related services

IAMRAMOrganizations