AWS for DevOps — AWS Organizations
2.5 — AWS Organizations
AWS Organizations lets you manage multiple AWS accounts from a single management account. In real-world DevOps, you almost never run everything in one account — you separate environments, teams, and workloads across accounts for security and billing isolation.
Why Multiple Accounts?
| Single Account | Multiple Accounts |
|---|---|
| One blast radius — a mistake affects everything | Isolated blast radius per account |
| Shared billing — hard to track costs per team | Per-account billing and cost allocation |
| IAM becomes complex at scale | Clean separation of concerns |
| One set of service limits | Independent service limits per account |
Organization Structure
Management Account (root)
│
├── OU: Production
│ ├── Account: prod-app (111111111111)
│ └── Account: prod-data (222222222222)
│
├── OU: Staging
│ └── Account: staging (333333333333)
│
├── OU: Development
│ ├── Account: dev-team-a (444444444444)
│ └── Account: dev-team-b (555555555555)
│
└── OU: Security
├── Account: audit (666666666666)
└── Account: logging (777777777777)
OU = Organizational Unit — a container for accounts that lets you apply policies at the group level.
Creating an Organization
# Create the organization (run from the management account)
$ aws organizations create-organization --feature-set ALL
{
"Organization": {
"Id": "o-abc123def4",
"MasterAccountId": "123456789012",
"FeatureSet": "ALL"
}
}
# Create an OU under the root
$ aws organizations list-roots --query 'Roots[0].Id' --output text
r-abc1
$ aws organizations create-organizational-unit \
--parent-id r-abc1 \
--name Production
{
"OrganizationalUnit": {
"Id": "ou-abc1-prod1234",
"Name": "Production"
}
}
Creating a Member Account
$ aws organizations create-account \
--email prod-app@example.com \
--account-name prod-app
{
"CreateAccountStatus": {
"Id": "car-abc123",
"AccountName": "prod-app",
"State": "IN_PROGRESS"
}
}
# Check status
$ aws organizations describe-create-account-status --create-account-request-id car-abc123
{
"CreateAccountStatus": {
"AccountId": "111111111111",
"State": "SUCCEEDED"
}
}
# Move account to Production OU
$ aws organizations move-account \
--account-id 111111111111 \
--source-parent-id r-abc1 \
--destination-parent-id ou-abc1-prod1234
Service Control Policies (SCPs)
SCPs are guardrails that restrict what accounts in an OU can do. They do not grant permissions — they set the maximum permissions allowed.
SCP says: "No EC2 outside ap-south-1"
IAM says: "Allow ec2:*"
Result: EC2 allowed ONLY in ap-south-1
SCP ∩ IAM Policy = Effective Permissions
Example — Deny all actions outside allowed regions:
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "DenyOutsideAllowedRegions",
"Effect": "Deny",
"NotAction": [
"iam:*",
"organizations:*",
"sts:*",
"support:*",
"budgets:*"
],
"Resource": "*",
"Condition": {
"StringNotEquals": {
"aws:RequestedRegion": [
"ap-south-1",
"us-east-1"
]
}
}
}
]
}
Note: Some global services (IAM, Organizations, STS) must be excluded because they only run in
us-east-1.
Example — Prevent member accounts from leaving the organization:
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "DenyLeaveOrg",
"Effect": "Deny",
"Action": "organizations:LeaveOrganization",
"Resource": "*"
}
]
}
Attaching an SCP
# Attach SCP to an OU
$ aws organizations attach-policy \
--policy-id p-abc123 \
--target-id ou-abc1-prod1234
# List policies attached to an OU
$ aws organizations list-policies-for-target \
--target-id ou-abc1-prod1234 \
--filter SERVICE_CONTROL_POLICY
Common DevOps Account Strategy
| Account | Purpose | SCP |
|---|---|---|
| Management | Billing, Organizations | Minimal — only org management |
| Security / Audit | CloudTrail, Config, GuardDuty | Read-only to other accounts |
| Shared Services | ECR, shared VPC, DNS | Allow networking + container services |
| Production | Live workloads | Deny region changes, deny resource deletion |
| Staging | Pre-production testing | Same policies as prod |
| Development | Developer sandboxes | Relaxed — allow experimentation |
Consolidated Billing
All accounts in the organization share a single bill:
- Volume discounts — combined usage across accounts qualifies for lower pricing tiers
- Reserved Instance sharing — an RI purchased in one account can apply to usage in another
- Cost allocation tags — tag resources to track costs per team, project, or environment
# View the organization's accounts
$ aws organizations list-accounts \
--query 'Accounts[*].[Id,Name,Status]' \
--output table
-------------------------------------------
| ListAccounts |
+--------------+----------+--------+
| 123456789012 | mgmt | ACTIVE |
| 111111111111 | prod-app | ACTIVE |
| 333333333333 | staging | ACTIVE |
+--------------+----------+--------+
Cross-Account Access Pattern
The management account creates a role in each member account that trusted accounts can assume:
# From the management account, assume a role in the prod account
$ aws sts assume-role \
--role-arn arn:aws:iam::111111111111:role/OrganizationAccountAccessRole \
--role-session-name admin-session
For CI/CD, your pipeline account assumes deployment roles in each target account.
Common Mistakes
| Mistake | Why It Hurts | Fix |
|---|---|---|
| Running everything in one account | No isolation — one mistake affects all | Use Organizations |
| Overly restrictive SCPs on management account | Can lock yourself out | Never attach restrictive SCPs to management account |
| No SCP testing | Policy breaks production | Test in dev OU first |
| Not using consolidated billing tags | Cannot track costs per team | Enable cost allocation tags |
Quick Reference
| Task | Command |
|---|---|
| Create organization | aws organizations create-organization --feature-set ALL |
| Create OU | aws organizations create-organizational-unit --parent-id ID --name NAME |
| Create account | aws organizations create-account --email EMAIL --account-name NAME |
| Move account | aws organizations move-account --account-id ID --source-parent-id SRC --destination-parent-id DST |
| Create SCP | aws organizations create-policy --type SERVICE_CONTROL_POLICY --name NAME --content file://scp.json |
| Attach SCP | aws organizations attach-policy --policy-id ID --target-id TARGET |
| List accounts | aws organizations list-accounts |
Next → IAM & Security Exercises