AWS sub-accounts: isolating resources with Organizations
Most teams dump client resources into their main AWS account, creating an administrative nightmare when projects end or security issues arise. AWS Organizations sub-accounts provide hard security boundaries that separate resources, limit blast radius from incidents, and make cleanup trivial—yet many developers avoid them, assuming the setup complexity outweighs the benefits.Every AWS account starts with good intentions. You'll keep things organised. You'll use tags properly. You'll implement least-privilege access. Then three months later, you're staring at a tangled mess of production and development resources, wondering whose EC2 instance that is and whether shutting it down will break something important.
AWS Organizations sub-accounts solve this by providing what Amazon calls a "hard boundary"1—a complete isolation of resources, permissions, and billing that prevents one environment's problems from becoming everyone's emergency.
What AWS Organizations provides
AWS Organizations transforms a single AWS account into a hierarchical structure where a master account (now called the management account) can create and manage multiple sub-accounts (member accounts). Each sub-account operates as a completely independent AWS environment with its own root user, IAM policies, and resource namespace. The management account maintains centralized billing and can apply service control policies (SCPs) that set permission boundaries across all member accounts, but cannot directly access resources in those accounts without explicit cross-account roles.
This structure reflects AWS's fundamental security model: accounts are the primary isolation mechanism in the platform. Identity and access management policies, resource namespaces, and billing boundaries all exist at the account level2. When you need to share resources between accounts, you must explicitly configure that access—by default, accounts are completely isolated from each other.
The typical use case involves creating a sub-account for each project, client, or environment that needs strict separation. Development teams get sandbox accounts where experiments can't affect production. Client projects get dedicated accounts that simplify both security audits and eventual handoff or termination. This approach reduces the blast radius when something goes wrong, limits which users can access sensitive resources, and makes cleanup a matter of closing an account rather than hunting through tags and permissions.
Understanding the email address constraint
AWS Organizations has one constraint that catches everyone off guard: every account requires a unique email address that can never be reused, even after the account is closed. This isn't a temporary limitation or a quirk of the console—it's a permanent architectural decision. The email address you choose when creating a sub-account is burned forever in AWS's namespace.
This creates an interesting planning problem. Personal email addresses with plus-addressing (user+project@domain.com) work but fill your inbox with AWS notifications. Project-specific email lists provide better organisation but require creating and managing those lists first. Some teams use a pattern like aws-project-name@company.com, routing all these addresses to a shared administrative inbox.
I've found that using the project's internal email distribution list works well, assuming it's configured to accept external mail from AWS services. This provides a natural correspondence between the project and its AWS account, and ensures that password reset emails and billing notifications reach the people who need to see them. The alternative—discovering six months later that critical AWS notifications have been bouncing because nobody configured the email forwarding—is less amusing than it sounds.
If you accidentally use an email address you didn't intend to, you might be able to change it before closing the account, which releases it back to the pool of available addresses3. Emphasis on "might"—AWS's documentation hedges on this point, and the support forums contain enough horror stories to suggest treating this as a last resort rather than standard practice.
Creating the sub-account
The process begins in the AWS Organizations console, which handles the account creation and automatically establishes the cross-account role that enables switching between accounts. This automation eliminates the manual IAM configuration that used to make multi-account setups a day-long exercise in JSON policy documents.
Start by logging into the management account and navigating to the Organizations console at console.aws.amazon.com/organizations. The "Add account" button presents two options: "Create account" for new accounts, and "Invite account" for bringing existing AWS accounts under organizational management. For a new sub-account, select "Create account."
The form requires three pieces of information: a full name (any descriptive identifier for the account), the email address discussed above, and crucially, an IAM role name. This role name deserves more thought than it typically receives. It's displayed when users switch between accounts, which means "OrganizationAccountAccessRole" (the default suggestion) will appear identical for all your sub-accounts. Instead, use something that clearly identifies which account you're switching to—matching the full name but in PascalCase or hyphen-separated format works well.
After clicking "Create," AWS spins up the new account in the background. The Organizations console shows it greyed out initially, then transitions to normal display once provisioning completes. This typically takes a minute or two, though AWS documentation carefully avoids promising any specific timeframe. The console's account list will show the new account with its account ID (a twelve-digit number), full name, email address, and status.
At this point, the sub-account exists and has a root user (identified by the email address), but that root user has no password. This is intentional—AWS creates the account in a state where the only access path is through the cross-account role from the management account.
Setting the root password
The password reset mechanism serves as the initial password creation for a newly provisioned sub-account. While this feels like a workaround, it's the standard process that AWS documents for this scenario.
Navigate to the AWS console sign-in page and click "Sign in to the Console" in the top right. If the form shows "Account ID or alias" as the first field, click the small-print link below that reads "Sign-in using root account credentials." This switches to the email-based login form.
Enter the sub-account's email address and click "Next." Instead of entering a password (which doesn't exist yet), click "Forgot password?" This triggers AWS's password reset flow: solve the CAPTCHA challenge, click "Send email," and watch for the password reset message to arrive at that email address. The message typically arrives within seconds, and contains a link that leads to a password creation form.
Set a strong password using a password manager, because you'll need it rarely enough to forget it but critically enough that you don't want to go through password reset during an incident. The root user provides unrestricted access to the account, which makes it both powerful and dangerous—the kind of access you want available in emergencies but locked away otherwise.
Configuring the cross-account role
The sub-account now has a root user with a password, but the goal is to enable team members to access it through their existing IAM users in the management account, not to hand out root credentials. AWS Organizations automatically created a cross-account role during account provisioning, and configuring it properly determines which users can access the sub-account and what they can do once they get there.
Log into the AWS console using the sub-account's root credentials (the email address and password just set). Navigate to the IAM service and select "Roles" from the left sidebar. Search for the role name you specified during account creation—it should appear in the list with a trust policy allowing the management account to assume it.
Click on the role to view its details. The "Role ARN" (Amazon Resource Name) appears near the top of the page, looking like "arn:aws:iam::123456789012:role/YourRoleName" where the twelve-digit number is your sub-account's ID. Copy this ARN and save it somewhere permanent—you'll need it shortly to configure access from the management account.
Just below the ARN, there's a link labelled "Give this link to users who can switch roles in the console." This URL encodes the account ID, role name, and display name into a single clickable link that opens the AWS console's role-switching interface with all fields pre-populated. Copy this link as well—it transforms the role-switching process from "remember and type five different pieces of information" into "click a bookmark."
The Permissions tab shows what users can do after assuming this role. By default, AWS attaches the AdministratorAccess managed policy, which grants unrestricted access to all AWS services and resources in the sub-account. This makes sense for most scenarios where you're delegating complete responsibility for an environment, but you can modify it here if you need more restrictive permissions.
The Tags tab allows adding key-value pairs that help with organization and automation. These tags don't affect functionality, but they make it easier to write scripts that operate across multiple accounts or to generate reports about account usage.
After noting the ARN and link, log out of the sub-account. The next phase happens back in the management account.
Enabling access from the management account
The management account needs an IAM policy that permits specific users to assume the role in the sub-account. AWS uses Security Token Service (STS) for this, with the AssumeRole action serving as the gatekeeping mechanism. Creating an IAM group with an inline policy provides a clean way to manage which users have this capability.
Log back into the management account and navigate to IAM, then Groups. Click "Create New Group" and provide a name that clearly indicates its purpose—something like "ProjectNameAdmins" or "AccessProjectName" where ProjectName matches your sub-account. The naming matters less than the clarity: six months from now, you want the purpose obvious from the name.
The group creation wizard presents an "Attach Policy" page, showing all the AWS-managed and customer-managed policies available. Skip this page by clicking "Next Step"—the policy you need is an inline policy, which can only be attached after the group exists.
After creating the group, the console shows the group details page. Under the Permissions tab, expand the "Inline Policies" section and click "click here" (where it says to create new policies). This opens the policy editor, which defaults to the Policy Generator. Switch the radio button from "Policy Generator" to "Custom Policy" and click "Select."
The policy name should be simple and descriptive—"SwitchToProjectName" captures both the action (switching) and the destination. The policy document itself requires this structure:
{
"Version": "2012-10-17",
"Statement": {
"Effect": "Allow",
"Action": "sts:AssumeRole",
"Resource": "arn:aws:iam::123456789012:role/YourRoleName"
}
}
Replace the Resource value with the Role ARN you copied from the sub-account earlier. This policy states that members of this group are allowed to perform the AssumeRole action against that specific role in that specific account. The policy language is precise: it doesn't grant any permissions in the sub-account itself (those come from the role's permissions), it only grants permission to assume the role.
Click "Apply Policy" to attach it to the group. At this point, the group exists and has the right permissions, but contains no users, which means it does nothing yet.
Adding users to the group
Switch to the group's Users tab and click "Add Users to Group." The console displays a list of all IAM users in the management account with checkboxes next to each. Select the users who should have access to the sub-account—including yourself, to test that the access works—and click "Add Users."
Users added to this group can now switch to the sub-account, but the mechanics of how they do that deserve explanation. AWS's role-switching mechanism replaces their current session with a temporary session in the target account. They don't maintain simultaneous access to both accounts—switching to the sub-account means temporarily giving up access to the management account, and they must explicitly switch back when finished.
Switching between accounts
The role-switching process works through the AWS console's built-in account switcher, accessible by clicking the account name in the top-right corner of any AWS console page. This reveals a dropdown menu that includes "Switch Role" as an option.
Clicking "Switch Role" opens a form requesting four pieces of information: account ID (the twelve-digit number), role name (exactly as specified when creating the role), display name (what the console shows in the top-right when you're using this role), and display colour (purely cosmetic, to help distinguish between accounts at a glance).
This is where the link you saved earlier becomes useful. That "Give this link to users" URL pre-populates all these fields, turning a error-prone typing exercise into a single click. Users can bookmark this link in their browser or save it in their password manager alongside their AWS credentials.
After switching roles, the console shows the sub-account's resources and the display name you specified appears in the top-right corner where the username normally appears. All actions taken whilst in this role are logged as being performed by that role, with AWS CloudTrail recording which IAM user from the management account assumed it. This provides an audit trail that connects actions in the sub-account back to specific individuals in the management account.
To return to the management account, click the display name in the top-right and select "Back to" followed by the management account username. This terminates the temporary credentials and restores the original session.
One implementation detail worth noting: some password managers aggressively auto-fill form fields, which can interfere with the role-switching form by changing values after the pre-populated link loads them. If the role switch fails with cryptic errors about invalid account IDs or role names, try temporarily disabling the password manager extension for the AWS console domain.
API access to sub-accounts
The console-based role switching provides interactive access, but automated tools, scripts, and CI/CD pipelines need programmatic access through the AWS API. This requires a different approach: create IAM users directly in the sub-account, not in the management account.
The cross-account role mechanism exists to let human users leverage their existing identity in the management account. API access doesn't need this indirection—creating an IAM user in the sub-account with programmatic access (access key and secret key) provides the most straightforward approach. This user exists only in the sub-account, has no console access, and follows the standard IAM security practices around key rotation and least-privilege permissions.
Log into the sub-account (using the root user or by switching roles), navigate to IAM, and create a new user with programmatic access enabled and console access disabled. Attach only the specific permissions this user needs—if it's deploying application infrastructure, give it the minimum set of permissions required for those deployments. If it's reading CloudWatch metrics, grant read-only access to CloudWatch and nothing else.
Generate access keys for this user and store them securely in whatever secret management system your tools use. Treat these credentials with the same care you'd give any other privileged access—they provide direct access to the sub-account without going through the management account's IAM policies.
Cleaning up sub-accounts
Sub-accounts accumulate over time. Projects end, clients move on, experiments conclude, and sandbox environments outlive their usefulness. Unlike traditional cloud resource cleanup—hunting through regions looking for forgotten EC2 instances and S3 buckets—closing an AWS Organizations sub-account removes everything in one operation.
This requires logging in as the root user of the sub-account being closed. The AWS account management page sits at console.aws.amazon.com/billing/home#/account, and whilst AWS has presumably added other ways to reach it since the original documentation was written, that URL remains the reliable path.
Scroll to the bottom of the page to find the "Close Account" section. AWS presents several checkboxes acknowledging various consequences of account closure: you understand that closure is permanent, that you won't be able to access resources after closure, that you may still receive charges for resources that were running, and that you cannot reuse the email address for future accounts. Check all the boxes and click "Close Account."
The account enters a closing state, which takes ninety days to complete. During this period, you cannot access the account, but AWS continues charging for any resources that were running at closure time. This creates a minor problem: if you forgot to delete something expensive, you'll get ninety days of bills for it before the account fully closes. The solution is to audit and clean up resources before initiating closure, or to explicitly terminate all resources through the AWS console or API before clicking the close button.
After ninety days, the account disappears completely. The account ID becomes invalid, the email address remains permanently consumed, and all resources are irrevocably deleted. This provides both the benefit (complete cleanup with no lingering resources) and the risk (no recovery if you closed the wrong account or forgot to extract something important).
Why this matters
AWS accounts are not folders, tags, or naming conventions—they are security boundaries. AWS's architecture makes accounts the hardest boundary in the platform, harder than VPCs, security groups, or IAM policies1. When you need to guarantee that one environment cannot affect another, accounts provide that guarantee. When you need to ensure that an incident in development doesn't cascade into production, accounts prevent that cascade. When you need to hand off infrastructure to a client or partner, accounts make that handoff a matter of changing organization membership.
The twenty minutes spent creating a sub-account saves hours of untangling permissions when you need to grant temporary access to a contractor. It saves days of hunting through resources when a project ends and you need to verify everything was cleaned up. It saves the awkward conversation where you explain that the client's resources are thoroughly mixed with your own infrastructure and separation would take weeks of careful work.
None of this is obvious from the AWS Organizations documentation, which focuses on the mechanics of account creation rather than the strategic value of proper isolation. The documentation explains that you'll need an email address and a role name, but doesn't emphasise that you're creating a hard security boundary that prevents one environment's problems from becoming everyone's emergency.
Start with proper isolation. Create sub-accounts for anything that deserves its own security boundary. Future you will appreciate the clarity.
Footnotes
-
AWS. (2024). "AWS account management and separation." AWS Well-Architected Framework - Security Pillar. https://docs.aws.amazon.com/wellarchitected/latest/security-pillar/aws-account-management-and-separation.html ↩ ↩2
-
AWS. (2024). "Organizing Your AWS Environment Using Multiple Accounts." AWS Whitepapers. https://docs.aws.amazon.com/whitepapers/latest/organizing-your-aws-environment/organizing-your-aws-environment.html ↩
-
AWS. (n.d.). "How do I change the email address that is associated with my AWS account?" AWS Premium Support Knowledge Center. https://aws.amazon.com/premiumsupport/knowledge-center/change-email-address/ ↩
Published on:
Updated on:
Reading time:
15 min read
Article counts:
67 paragraphs, 2,936 words
Topics
TL;DR
AWS Organizations sub-accounts create hard security boundaries that prevent issues in one environment from affecting others, with AWS documenting that account-level separation is their strongest isolation mechanism. Creating a sub-account involves picking a unique email address, using AWS Organizations to provision the account with a cross-account role, then configuring IAM groups in the master account to control which users can assume that role. The process takes twenty minutes initially but saves hours of untangling permissions and cleaning up resources later. Key insight: AWS accounts are isolation boundaries by design—separate accounts mean separate problems, whilst shared accounts mean cascading failures.