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.
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.

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.

First, the target account (Trailbase production, the account that owns the data) creates the role and its trust policy:
{
"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:
{
"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:
{
"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.
What is the purpose of the External ID in a cross-account role trust policy?
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.
{
"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
| Service | Resource | Policy Name |
|---|---|---|
| Amazon S3 | Buckets | Bucket Policy |
| Amazon SQS | Queues | Queue Policy |
| Amazon SNS | Topics | Topic Policy |
| AWS KMS | Keys | Key Policy |
| AWS Lambda | Functions | Function Policy |
| Amazon ECR | Repositories | Repository Policy |
| AWS Secrets Manager | Secrets | Resource 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.
Which AWS service is used to share VPC subnets across accounts without duplication?
Creating a share is a short piece of CLI work:
# 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 SELFNotice 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.
When sharing resources via RAM within AWS Organizations, what happens?
RAM covers far more than subnets, and the exam likes the edges of the list:
Common RAM Shareable Resources
| Service | Resource Type | Use Case |
|---|---|---|
| Amazon VPC | Subnets | Centralized VPC, shared networking |
| Amazon VPC | Transit Gateways | Hub-and-spoke network topology |
| Amazon VPC | Prefix Lists | Shared IP address management |
| Route 53 | Resolver Rules | Centralized DNS resolution |
| AWS License Manager | License Configurations | Centralized license management |
| AWS Glue | Data Catalogs, Databases | Shared data lake access |
| Amazon Aurora | DB Clusters | Cross-account database cloning |
| AWS Outposts | Outpost Resources | Shared on-premises infrastructure |
| EC2 | Capacity Reservations | Shared 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
| Scenario | Recommended Method | Why |
|---|---|---|
| Temporary API access to another account | IAM Role (AssumeRole) | Temporary credentials, fine-grained control |
| Share VPC subnets with multiple accounts | AWS RAM | Native sharing, no duplication |
| Grant S3 access to specific external account | S3 Bucket Policy | Direct resource-based policy |
| Share Transit Gateway across organization | AWS RAM | Centralized network sharing |
| CI/CD pipeline deploying to production account | IAM Role (AssumeRole) | Temporary deployment credentials |
| Share Route 53 Resolver rules | AWS RAM | DNS centralization |
| Lambda in Account A triggers Lambda in Account B | Resource Policy + IAM Role | Cross-account invocation |
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
| Scenario | Solution | Key Point |
|---|---|---|
| Network team manages VPCs, app teams need access | RAM subnet sharing | Centralized VPC model |
| External vendor needs temporary S3 access | IAM role with External ID | Prevents confused deputy |
| Share Transit Gateway with 50 accounts | RAM with organization sharing | No need to list each account |
| Account A Lambda needs to write to Account B DynamoDB | IAM role assumption | Temporary credentials for API calls |
| Centralize Route 53 DNS across organization | RAM Resolver rule sharing | DNS centralization |
| Share Aurora cluster for cloning | RAM Aurora sharing | Cross-account database cloning |
| Development account needs read-only prod access | IAM role with read permissions | Least privilege cross-account |
A company wants development teams to deploy resources into shared VPC subnets managed by the network team. What is the BEST approach?
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
# 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-organizationMethod Comparison
| Aspect | IAM Roles | Resource Policies | AWS RAM |
|---|---|---|---|
| Access Type | Temporary | Permanent | Permanent |
| Credential Type | STS temporary | Caller credentials | Caller credentials |
| Setup Complexity | Medium | Low | Low |
| Supported Resources | All (via API) | Select services | Select resources |
| Organization Integration | Manual | Manual | Automatic |
| Console Access | Switch role | Direct | Native appearance |
| Best For | API access, temp elevation | Simple sharing | VPC, TGW, persistent sharing |