CoursesAWS Solutions Architect AssociateAccounts, Organizations & billing

Accounts, Organizations & billing

Multi-account isolation, SCPs, consolidated billing.

Beginner25 min · lesson 3 of 15

A ship stays afloat after a hull breach because of bulkheads, watertight walls that trap the flooding in one compartment instead of letting it fill the whole vessel. An AWS (Amazon Web Services) account is the cloud's bulkhead: a container with its own 12-digit number, its own resources, its own permission system, its own usage limits, and its own line on the bill. Nothing crosses that wall unless you deliberately cut a door in it. Which is why architects draw the account layout *before* they draw the workloads. AWS Organizations links many accounts into one governed tree, Service Control Policies cap what each compartment is allowed to do, and consolidated billing folds every compartment into a single invoice. Many bulkheads, one bridge, one bill.

The account is the isolation boundary

Everything you make in AWS lives inside exactly one account: an EC2 (Elastic Compute Cloud) virtual machine, an S3 (Simple Storage Service) bucket of files, an IAM (Identity and Access Management) user. By default none of it is visible from any other account. Permissions do not reach across the wall unless somebody wires up cross-account trust on purpose, so a leaked access key in the dev account cannot touch production if production is its own account. Service quotas are per-account too. A runaway test job that eats the EC2 instance limit starves dev and leaves production untouched. Architects call this blast radius, the amount of stuff one mistake or one stolen key can wreck, and the account boundary is the strongest tool AWS gives you for shrinking it. So make this your first move in any terminal, before you build anything: confirm whose account your credentials point at.

terminal — know where you are
# Which account do these credentials belong to? Check before you build.
aws sts get-caller-identity
{
"UserId": "AIDAQ3EXAMPLE7EXAMPLE",
"Account": "111111111111",
"Arn": "arn:aws:iam::111111111111:user/admin"
}
# Is this account already part of an organization?
aws organizations describe-organization \
--query 'Organization.{Id:Id,FeatureSet:FeatureSet,Payer:MasterAccountId}'
{
"Id": "o-a1b2c3d4e5",
"FeatureSet": "ALL",
"Payer": "111111111111"
}

AWS Organizations: many accounts, one place to run them

AWS Organizations is a free service that arranges accounts into a tree, the way a company org chart arranges people. Whichever account creates the organization becomes the management account: it pays every bill and runs the hierarchy. Everything else is a member account. The tree starts at one root, a top-level container that has nothing to do with the root *user*, and branches into organizational units (OUs), folders for accounts that need the same governance. You can nest them five levels deep. Two feature sets exist. CONSOLIDATED_BILLING gives you shared billing and nothing more, while ALL adds policy-based control. Service Control Policies need ALL, so create the organization with ALL every time. Exam writers love that detail. Making an account is asynchronous (you ask, and AWS finishes the job in the background), and when it lands there is already an IAM role waiting inside it, OrganizationAccountAccessRole unless you name another, that the management account can assume. You have a way in from day one without anyone sharing a password.

terminal — bootstrap the org
# 1. Create the organization (run once, from the future management account)
aws organizations create-organization --feature-set ALL
# 2. Find the root container's id
aws organizations list-roots --query 'Roots[0].Id'
"r-9x2b"
# 3. Carve out an OU for workloads
aws organizations create-organizational-unit \
--parent-id r-9x2b --name Workloads
{
"OrganizationalUnit": {
"Id": "ou-9x2b-8f00qq1z",
"Arn": "arn:aws:organizations::111111111111:ou/o-a1b2c3d4e5/ou-9x2b-8f00qq1z",
"Name": "Workloads"
}
}
# 4. Create a member account — asynchronous, returns a request id
aws organizations create-account \
--email [email protected] --account-name prod \
--iam-user-access-to-billing DENY
{
"CreateAccountStatus": {
"Id": "car-1234567890abcdef01234567890abcde",
"AccountName": "prod",
"State": "IN_PROGRESS",
"RequestedTimestamp": "2026-07-13T09:14:02.113000+00:00"
}
}
# 5. Poll until SUCCEEDED, then file the new account under the OU
aws organizations describe-create-account-status \
--create-account-request-id car-1234567890abcdef01234567890abcde \
--query 'CreateAccountStatus.{State:State,AccountId:AccountId}'
{ "State": "SUCCEEDED", "AccountId": "222233334444" }
aws organizations move-account --account-id 222233334444 \
--source-parent-id r-9x2b --destination-parent-id ou-9x2b-8f00qq1z
# (no output on success)

Two practical details. Every account needs a globally unique email address, so teams use plus-addressing: [email protected] and [email protected] both land in one mailbox that somebody actually reads. And a brand-new organization is capped at ten accounts. That is a soft quota the management account raises through the Service Quotas console, not a ceiling on your design.

Service Control Policies: a ceiling, never a key

Some rental vans have a speed limiter bolted to the engine. It stops you going over 65 mph. It cannot make the van move, and it cannot hand you the keys. A Service Control Policy (SCP) works the same way. You attach it to the root, to an OU, or to a single account, and it sets the *maximum* of what anyone inside is allowed to do. It never grants a thing. For an API call (any request to AWS, whether clicked in the console, typed at the command line, or made by code) to succeed, the user or role has to be allowed by its own IAM policy *and* by every SCP above it in the tree. The effective permissions are the overlap. Straight out of the box AWS attaches a wide-open FullAWSAccess SCP everywhere, so nothing is blocked until you block it. Most teams work deny-list style: leave FullAWSAccess alone and stack narrow Deny statements on top. Here is one that stops everybody, account administrators included, from tampering with CloudTrail, the service that records every API call made in the account:

deny-audit-tamper.json → attach to OU
# deny-audit-tamper.json — an SCP is just an IAM-style policy document
{
"Version": "2012-10-17",
"Statement": [{
"Sid": "ProtectAuditTrail",
"Effect": "Deny",
"Action": [
"cloudtrail:StopLogging",
"cloudtrail:DeleteTrail",
"cloudtrail:UpdateTrail"
],
"Resource": "*"
}]
}
# Create the policy, then pin it to the Workloads OU
aws organizations create-policy \
--name deny-audit-tamper \
--type SERVICE_CONTROL_POLICY \
--description "Nobody disables CloudTrail, admins included" \
--content file://deny-audit-tamper.json
{
"Policy": {
"PolicySummary": {
"Id": "p-k3jl9z7q",
"Arn": "arn:aws:organizations::111111111111:policy/o-a1b2c3d4e5/service_control_policy/p-k3jl9z7q",
"Name": "deny-audit-tamper",
"Description": "Nobody disables CloudTrail, admins included",
"Type": "SERVICE_CONTROL_POLICY",
"AwsManaged": false
},
"Content": "{\n \"Version\": \"2012-10-17\", ..."
}
}
aws organizations attach-policy --policy-id p-k3jl9z7q \
--target-id ou-9x2b-8f00qq1z
# (no output on success)
# Now, from the prod account — even as a full administrator:
aws cloudtrail stop-logging --name org-trail
An error occurred (AccessDeniedException) when calling the StopLogging
operation: ...user/admin is not authorized to perform:
cloudtrail:StopLogging with an explicit deny in a service control policy
Reference multi-account landing zone
Management account (payer)
Org admin + billing
Workload-free; SCPs never apply here; root locked with hardware MFA
Security OU
log-archive
Immutable CloudTrail & Config history
security-tooling
GuardDuty & Security Hub administration
Infrastructure OU
shared-network
Shared VPCs and networking
ci-cd
Build and deploy pipelines
Workloads OU
prod
Production, split per team
non-prod
Dev/test; isolated blast radius
SCP guardrails attach to the OUs and cap the member accounts under them; the management account sits outside their reach. AWS Control Tower builds this layout for you and calls the result a 'landing zone', the least-effort answer for multi-account setup.

A few points worth burning into memory. An SCP constrains every principal in a member account, *including that account's root user*, and very few controls in AWS can claim that. It does not touch service-linked roles (the roles AWS services create for their own housekeeping), and it has no say over anyone outside the organization. The hard limits: ten SCPs attached directly to any one root, OU or account, with policies inherited from parents not counting toward that number, and 10,240 characters per policy document. The character cap is why a region lockdown gets written as one compact Deny with an aws:RequestedRegion condition rather than a long list of services.

SCPs never apply to the management account
Every guardrail above counts for nothing inside the management account. It is permanently exempt, and so is anything running in it. A compromised workload sitting there holds org-wide billing and policy power, with no SCP anywhere to stop it. Keep that account empty: no EC2 instances, no application buckets, no logins people use day to day. Lock its root user behind hardware MFA (multi-factor authentication, here a physical key you plug in and tap) and sign in only for the handful of tasks that genuinely need it.

Consolidated billing: one bill, pooled discounts

Consolidated billing makes the management account the payer: all member usage rolls into one invoice, the way a family phone plan charges one card for five handsets. The pooling is the part people miss. Usage from every account is added together *before* pricing tiers apply, so ten accounts holding 10 TB (terabytes) each in S3 reach the same volume discount as one account holding 100 TB. Reserved Instance and Savings Plans discounts drift the same way. Buy them in one account and they cover matching usage anywhere in the family, though sharing can be switched off per account. Two traps the exam likes: an organization gets *one* free tier shared across all its accounts, measured org-wide rather than per account, and the payer sees everyone's spend while a member sees only its own. Read the pooled bill with Cost Explorer (the aws ce API) and hang tripwires on it with AWS Budgets:

terminal — payer account
# Month-to-date spend, broken out per member account
aws ce get-cost-and-usage \
--time-period Start=2026-07-01,End=2026-07-13 \
--granularity MONTHLY \
--metrics UnblendedCost \
--group-by Type=DIMENSION,Key=LINKED_ACCOUNT
{
"ResultsByTime": [{
"TimePeriod": { "Start": "2026-07-01", "End": "2026-07-13" },
"Groups": [
{ "Keys": ["222233334444"],
"Metrics": { "UnblendedCost": { "Amount": "1841.2211", "Unit": "USD" } } },
{ "Keys": ["333344445555"],
"Metrics": { "UnblendedCost": { "Amount": "212.0490", "Unit": "USD" } } }
],
"Estimated": true
}]
}
# Alert at 80% of a $2,500/month budget — before the invoice surprises you
aws budgets create-budget --account-id 111111111111 \
--budget '{"BudgetName":"org-monthly","BudgetLimit":{"Amount":"2500","Unit":"USD"},"TimeUnit":"MONTHLY","BudgetType":"COST"}' \
--notifications-with-subscribers '[{"Notification":{"NotificationType":"ACTUAL","ComparisonOperator":"GREATER_THAN","Threshold":80,"ThresholdType":"PERCENTAGE"},"Subscribers":[{"SubscriptionType":"EMAIL","Address":"[email protected]"}]}]'
# (no output on success)

Numbers with no labels go stale fast, so pair the budget with a tagging convention: owner, environment and cost-center on every resource. Then switch those keys on as cost allocation tags so Cost Explorer can slice the bill by them. The deeper cost work, rightsizing and commitment strategy, gets a lesson of its own later in this course.

A reference structure, and what it costs you

One layout keeps showing up, in real estates and in exam answers alike. A management account with no workloads in it. A *Security OU* holding a log-archive account for CloudTrail and AWS Config history that nobody can alter, plus a security-tooling account running GuardDuty (threat detection) and Security Hub (findings gathered in one place) on behalf of everyone. An *Infrastructure OU* for shared networking and build pipelines. A *Workloads OU* where prod and non-prod are split per team. AWS Control Tower builds exactly this and calls the result a *landing zone*, so whenever a question asks for a multi-account setup with the least operational effort, that is your answer. The compartments are not free, though. Every boundary you gain in isolation you pay back in cross-account IAM plumbing, network wiring between VPCs (Virtual Private Clouds, your own private networks inside AWS), and one more root credential to defend, so give each account a unique email alias, hardware MFA, and zero access keys. Small shop? Start with two accounts, production and everything-else, rather than one big one. Most resources cannot be moved between accounts, so splitting later hurts.

That gives you compartments, a ceiling on each one, and a single metered bill: an estate you can govern before a single workload exists. Time to put something inside it. The next lesson opens the biggest compartment door of all, EC2: how instances are sized, launched and priced, and why the pricing model you pick matters as much as the instance type.

One shared account feels convenient right up to the afternoon a developer's experiment deletes a production security group. Splitting the estate is blast-radius control, not bureaucracy. Prod, non-prod, security tooling and shared services each get a bulkhead, and Organizations and SCPs are the valves between them.

SCPs hand out nothing. They set the maximum. Someone carrying AdministratorAccess in a member account still cannot switch off CloudTrail if an SCP forbids it. That distinction shows up on the exam, and in every incident review where somebody asks why the break-glass role could not stop the logging.

Consolidated billing pools volume discounts. It does not pool quotas or IAM. You still size limits account by account. And tag policies and cost allocation tags only pay off if every account spells the keys the same way, so agree the taxonomy before you open the twentieth account.

Try this

In a sandbox organization, or read-only against your real one, list the roots and OUs and print the SCPs attached to a target. You want the hierarchy on your screen, not buried in a wiki page somebody last touched a year ago.

terminal
aws organizations describe-organization --query 'Organization.{Id:Id,Master:MasterAccountId}'
aws organizations list-roots --query 'Roots[].{Id:Id,Name:Name}' --output table
aws organizations list-organizational-units-for-parent --parent-id r-exampleroot \
--query 'OrganizationalUnits[].{Id:Id,Name:Name}' --output table
aws organizations list-policies-for-target --target-id ou-xxxx-yyyy --filter SERVICE_CONTROL_POLICY \
--query 'Policies[].{Name:Name,Id:Id}' --output table
output
{
"Id": "o-abc12defgh",
"Master": "111122223333"
}
-----------------------------
| ListRoots |
+--------+------------------+
| Id | Name |
+--------+------------------+
| r-ex1 | Root |
+--------+------------------+
Security OU | ou-xxxx-sec
Workloads OU | ou-xxxx-wl
DenyLeaveOrganization | p-deny-leave

Takeaway

Three things to hold on to: the account is the isolation boundary, Organizations and SCPs set ceilings without granting anyone anything, and one shared bill does not mean one shared blast radius.

Next, sketch your OU layout for prod, non-prod and security, write one SCP that forbids disabling CloudTrail, and test it in a throwaway member account.

Quick check
01You attach a Deny SCP covering your most dangerous actions to the organization's root, expecting it to cover every account. Then a compromised workload inside the management account runs those exact actions without a hitch. What went wrong?
Incorrect — No. An explicit Deny always wins, and IAM can never override an SCP. Effective permission is the overlap of IAM and every SCP layer, so this is not why the call went through.
Incorrect — No. There is no propagation delay. SCP inheritance takes effect immediately, so this mechanism does not exist.
Correct — Every guardrail counts for nothing in the management account, so a compromised workload there holds org-wide power with no SCP to stop it. Keep it empty and put its root user behind hardware MFA.
Incorrect — No. SCPs do constrain a member account's root user, one of the very few controls that can. The management account is exempt as an account, not because a root user was involved.
02Which statement about consolidated billing in an AWS Organization is true?
Incorrect — No. An organization shares one Free Tier, measured across the whole org rather than handed out per account.
Correct — Ten accounts holding 10 TB each reach the same S3 volume discount as one account holding 100 TB, because usage is summed before pricing.
Incorrect — No. The payer sees everyone's costs. A member sees only its own.
Incorrect — No. Reserved Instance and Savings Plans discounts float to matching usage anywhere in the family, though sharing can be switched off per account.
03A company wants a multi-account AWS environment with a dedicated log-archive account, guardrails on the organizational units, and central governance, all with the LEAST operational effort. Which option is BEST?
Incorrect — No. You reach the right structure by the most laborious route, which is exactly what the requirement rules out.
Incorrect — No. One account is one blast radius, and this throws away the account-level isolation the design exists to give you.
Correct — Control Tower's landing zone is the low-effort route whenever a question asks for a multi-account setup with minimal operational overhead.
Incorrect — No. SCP guardrails need the ALL feature set. CONSOLIDATED_BILLING on its own cannot enforce a single policy.

Related