Overview
AWS resources live in an account and, for regional services, a selected region made of multiple Availability Zones. The account is the fundamental billing, quota, and security isolation boundary; regions contain service endpoints, and Availability Zones provide physically separate failure domains within a region. IAM decides who can call each service API, while services such as EC2, S3, RDS, Lambda, VPC, CloudWatch, and CloudTrail provide compute, storage, databases, networking, observability, and audit history.
AWS Organizations lets many accounts be managed together: organizational units (OUs) group accounts for policy application, and Service Control Policies (SCPs) cap the maximum permissions available underneath them, on top of, never instead of, IAM policies that grant access. Tags and AWS Resource Groups provide cross-resource visibility inside an account, but they are a query mechanism rather than an ownership or deletion boundary.
Quick Reference
| Level | Purpose | Deleting/removing it |
|---|---|---|
| Organization | Root container managing multiple accounts centrally | Requires all member accounts to be removed first |
| Organizational unit (OU) | Groups accounts for SCPs and policy application | Doesn't delete member accounts, just removes grouping |
| Member account | Billing and security isolation boundary | Closing an account is a distinct, deliberate, multi-step process |
| SCP | Caps maximum permissions for everything beneath it | Detaching it removes the ceiling, doesn't grant new access |
| Scope | What it controls | First diagnostic |
|---|---|---|
| Profile/credentials | Which user or role the CLI authenticates as | aws sts get-caller-identity --profile <name> |
| Region | Which regional endpoint and resources a command targets | aws configure get region --profile <name> |
| IAM and resource policies | Which API actions the principal may perform | Read the complete access-denied message |
| Organization SCP | The maximum permissions available in a member account | Check inherited SCPs on the account and OUs |
The commands below are grouped by service, not an exhaustive reference (see the official AWS CLI command reference for every flag), but the set that covers nearly all day-to-day aws CLI work.
| Command | Description | Copy |
|---|---|---|
aws configure sso --profile <name> | Configure a named CLI profile using IAM Identity Center instead of long-lived access keys. | |
aws sso login --profile <name> | Acquire or refresh the IAM Identity Center session for a configured profile. | |
aws sts get-caller-identity --profile <name> | Show the account ID and principal ARN currently authenticated as. This is the fastest context check. | |
aws configure list --profile <name> | Show the profile, credential source, region, and where each value came from. |
| Command | Description | Copy |
|---|---|---|
aws iam list-users | List IAM users in the account. | |
aws iam create-user --user-name <name> | Create an IAM user. | |
aws iam attach-user-policy --user-name <name> --policy-arn <arn> | Attach a managed policy to a user. | |
aws iam list-roles | List IAM roles in the account. |
| Command | Description | Copy |
|---|---|---|
aws ec2 describe-instances | List EC2 instances and their details. | |
aws ec2 run-instances --image-id <ami> --instance-type t3.micro --count 1 | Launch a new EC2 instance. | |
aws ec2 start-instances --instance-ids <id> | Start a stopped instance. | |
aws ec2 stop-instances --instance-ids <id> | Stop a running instance. |
| Command | Description | Copy |
|---|---|---|
aws s3 ls | List S3 buckets in the account. | |
aws s3 ls s3://<bucket> | List objects inside a bucket. | |
aws s3 cp <file> s3://<bucket>/<key> | Upload a local file to a bucket. | |
aws s3 sync <dir> s3://<bucket> | Sync a local directory to a bucket, uploading only changed files. | |
aws s3 rb s3://<bucket> --force | Remove a bucket and its current objects. On a versioned bucket this does not remove prior object versions or delete markers; those must be explicitly cleaned up first, or the bucket deletion fails. |
| Command | Description | Copy |
|---|---|---|
aws cloudwatch list-metrics | List available CloudWatch metrics. | |
aws logs describe-log-groups | List CloudWatch Logs log groups. | |
aws logs tail <log-group> --follow | Stream a log group's events live. |
Syntax
aws organizations create-organizational-unit \
--parent-id r-abcd --name Production
aws organizations create-account \
--email prod-payments@example.com --account-name payments-prodExamples
scp-deny-outside-approved-regions.json, an SCP that caps every identity in the attached OU to two approved regions, no matter what their own IAM policy allows:
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Deny",
"Action": "*",
"Resource": "*",
"Condition": {
"StringNotEquals": { "aws:RequestedRegion": ["us-east-1", "eu-west-1"] }
}
}
]
}SCPs restrict, they never grant
Attaching this SCP to an OU does not give anyone permission to do anything in us-east-1 or eu-west-1, it only blocks every action everywhere else. An identity still needs its own IAM allow within that region to do anything at all.
Troubleshooting AWS CLI and Access
I start every investigation by proving the caller, account, and region:
aws configure list --profile production
aws sts get-caller-identity --profile production
aws configure get region --profile productionThen I I classify the failure:
- Authentication or session: if the CLI cannot load credentials or reports an expired token, run
aws sso login --profile <name>and retry with the profile explicitly selected. - Wrong context: compare the returned account ID, assumed-role ARN, and region with the resource ARN. A successful command against the wrong account or region often looks like a missing resource.
- Authorization: read the entire
AccessDeniedmessage. Effective permission is the intersection of applicable identity policies, resource policies, permissions boundaries, session policies, and Organizations SCPs; an explicit deny overrides an allow. - Service boundary: if identity is correct and authorization allows the action, check service quotas, resource state, region support, and the service's own logs or events. I use CloudTrail event history and the request ID from the error to establish who called which API.
get-caller-identity is intentionally useful during failures: AWS STS returns the caller identity even when an explicit deny applies to that action. I do not debug access by attaching AdministratorAccess; identify the missing allow or explicit deny at the correct policy layer.
Visual Diagram
Common Mistakes
- Assuming AWS Resource Groups behave like an Azure resource group, a deletion/lifecycle boundary, when they're really just a saved tag-based query with no ownership semantics.
- Running an entire company, production included, out of a single AWS account instead of separating environments and teams by account.
- Writing an SCP and expecting it to grant access, then being confused when everything underneath it still returns access denied without a matching IAM allow.
- Assuming an org-wide SCP also restricts the management account itself; SCPs only ever apply to member accounts, never to the management account.
- Debugging with an implicit default profile or region, then changing permissions in an account that the failing command was not actually using.
- Creating long-lived IAM user access keys for people when IAM Identity Center can provide short-lived CLI sessions.
- Skipping AWS Organizations and centralized logging entirely, leaving no org-wide guardrail against an individual account drifting out of compliance.
Performance
- SCP evaluation happens alongside normal IAM policy evaluation and adds no meaningful latency, the real cost is organizational complexity if the OU/SCP structure isn't kept simple.
- Account creation and OU membership changes through AWS Organizations are eventually consistent, propagation to all regions/services can take a few minutes, don't assume it's instantaneous.
Best Practices
- Separate accounts by environment (production, staging, development) and by team or workload boundary, using AWS Organizations to manage them centrally rather than tags inside one account.
- Apply SCPs at the OU level for guardrails that should apply organization-wide (approved regions, disallowed services), rather than repeating them per account.
- I use a dedicated management account for billing/Organizations and a separate log-archive account for centralized CloudTrail logs, following the landing-zone pattern instead of overloading one account with every responsibility.
- Restrict access to the Organizations management account, keep workloads out of it, and delegate supported administration to member accounts.
- I use IAM Identity Center and short-lived role sessions for human CLI access; reserve IAM user access keys for exceptional legacy cases with an explicit rotation plan.
- I use tags and AWS Resource Groups for cross-resource visibility and cost allocation within an account, not as a substitute for real account-level isolation.
- Continue into AWS IAM, AWS Compute, AWS Storage, AWS Networking, and AWS Monitoring for service-specific depth.