Where do you even click first? This chapter takes you from "I have an Azure subscription, where's the AWS equivalent?" to a working CLI that talks to your AWS account. Account hierarchy, regions, AZs, auth, profiles, and the one command that proves it's all wired up.
Coming from Azure, the first hurdle in AWS isn't technical - it's mental. The shape of "where stuff lives" is different. Subscriptions become accounts. Resource groups disappear. Regions feel familiar but their internal structure is two layers, not one. This chapter establishes the mental map you'll hang every later concept off.
If you remember nothing else from this chapter, internalize this table. Every concept the rest of the chapter introduces hangs off one of these rows.
| Concept | Azure | AWS |
|---|---|---|
| Identity boundary | Microsoft Entra tenant | AWS Organization root |
| Org hierarchy node | Management Group | Organizational Unit (OU) |
| Billing & isolation boundary | Subscription | AWS Account |
| Logical resource grouping | Resource Group (RG) | no clean equivalent - use tags + naming conventions |
| Region | eastus, westeurope (~60) |
us-east-1, eu-west-1 (~33) |
| Availability Zone | 3 AZs per region (most) | 2-6 AZs per region (varies) |
| Default region picker | Set per resource or via --location |
Set per CLI profile via region = ... |
| CLI | az (Azure CLI) |
aws (AWS CLI v2) |
| Web console URL | portal.azure.com | console.aws.amazon.com |
| Browser auth | az login (opens browser) |
aws sso login (opens browser, only if SSO configured) |
| Service principal | App Registration / SP | IAM User (long-lived) or IAM Role (assumed) |
| Resource ID format | /subscriptions/<id>/resourceGroups/<rg>/.../<name> |
arn:aws:<svc>:<region>:<account>:<type>/<name> |
An AWS account is the fundamental unit of billing, security, and resource isolation. It's most similar to an Azure Subscription, but with one important twist: in AWS, the account is also the strongest practical security boundary. AWS culture leans on "use lots of accounts" - one per environment, one per team, sometimes one per workload. In Azure, you tend to use fewer subscriptions and lean on RGs and AAD groups for isolation.
Microsoft Entra tenant
└─ Management Group (root)
└─ Management Group (corp)
└─ Subscription (prod)
└─ Resource Group (rg-web-prod)
└─ App Service (myapi)
└─ Storage Account (mystg)
└─ Key Vault (kv-prod)
AWS Organization (root)
└─ OU (corp)
└─ AWS Account (prod, 123456789012)
└─ # no RG layer
└─ Lambda (myapi) # tagged env=prod
└─ S3 Bucket (mystg) # tagged env=prod
└─ Secrets Manager (kv) # tagged env=prod
Notice the missing layer on the AWS side. The Resource Group concept just isn't there. In AWS, the way you express "these things belong together" is:
env=prod, app=web, team=platform. Tags drive cost allocation, automation, and search.prod-web-api, prod-web-bucket. Yes, really. AWS culture leans on naming a lot more than Azure does.Both clouds have regions (geographic locations) and within each region, multiple availability zones (physically separate data centers). The naming and the way you reference them is where Azure habits break.
# Human-readable, location-based
eastus
westeurope
northeurope
australiaeast
japaneast
# Also has paired regions for DR
# eastus ↔ westus
# pairs are fixed and prescriptive
# Code-style with sequence numbers
us-east-1 # N. Virginia (default)
us-west-2 # Oregon
eu-west-1 # Ireland
ap-southeast-2 # Sydney
ap-northeast-1 # Tokyo
# No "paired regions" concept
# DR pairing is up to you
us-east-1 matters more than any other region. It's AWS's oldest region, hosts the most services, and is the default for many global services (IAM, Route 53, CloudFront). Many AWS bugs and outages historically center there. If you're picking a region for a "global" service, default to us-east-1. For everything else, pick by proximity to users.
us-east-1. The naming convention assumed many east-coast regions would follow. They didn't. us-east-2 (Ohio) wasn't added until 2016 - a full decade later. That ten-year monopoly is why so many "global" services still resolve through us-east-1 even today. If you're wondering why us-east-1 outages cause Slack to break - now you know.
An AWS engineer was debugging a billing-system slowdown in us-east-1 and ran a aws s3 command intended to remove a small set of capacity servers. The command had a typo and removed a much larger set. The S3 index subsystem went down for ~4 hours.
Casualties: Slack, Trello, Quora, Imgur, Medium, Coursera, GitHub status, IFTTT, and - in a moment of perfect dark comedy - the AWS Service Health Dashboard itself, which depended on S3 to render its "everything is fine" icons.
Lesson for Azure devs: us-east-1 is more like a tier-zero dependency than a region. If your service "must stay up", design for us-east-1 to disappear. Multi-region failover is a chapter-12 topic, but the awareness starts here.
us-east-1a, the a doesn't mean the same physical zone across accounts. AWS randomizes the letter assignment per account to prevent everyone from piling into "zone a". If you want to coordinate AZ placement across accounts, use the AZ ID (e.g., use1-az1) returned by aws ec2 describe-availability-zones. Azure has no equivalent randomization.
# Set per command
az group create -n rg-test \
--location eastus
# Or set a CLI default
az configure --defaults \
location=eastus
# Set per command
aws s3 ls --region us-east-1
# Or set per profile (typical)
aws configure set region us-east-1
# Or via env var (CI/CD)
export AWS_REGION=us-east-1
You deploy a chatty microservice across 3 AZs in us-east-1 for high availability. Each of the 6 services sends roughly 10 GB/day to each peer (typical for sidecar-heavy designs). Your dev environment bill is $40/month. Prod is $5,200/month. Where did the extra ~$5,160 come from?
$0.01/GB each way ($0.02/GB round-trip). Your "highly available" 3-AZ spread means most service-to-service calls cross an AZ boundary.
Math: 6 services × 5 peers each × 10 GB/day × 30 days × $0.02/GB ≈ $1,800/month per service tier. Multiply across all tiers in a realistic prod deployment and $5K is conservative; large meshes routinely hit $20K-$50K/month here.
Fix: use a single AZ for chatty service meshes (with replica failover, not active-active across AZs), or use VPC endpoints / PrivateLink for AWS-service calls, or refactor to reduce chattiness. Tools like VPC Flow Logs + Cost Explorer's data-transfer breakdown are how you discover this.
Azure trap reminder: Azure currently charges nothing for cross-AZ traffic within a region for most services. "Spread everything across AZs by default" is a habit that's safe in Azure and expensive in AWS.
az login vs aws configure
az, the Azure CLI quietly checks a cookie-like file on your laptop with a token. az login refreshed that token by opening a browser. AWS does almost the same thing, but uses a different file (~/.aws/credentials) and historically used long-lived access keys (like passwords you paste in once) instead of browser logins. Modern AWS shops use SSO, which is browser-based like Azure.# Homebrew is the easy path
brew install awscli
# Verify
aws --version
# aws-cli/2.15.0 Python/3.11.6 Darwin/23.0.0
curl "https://awscli.amazonaws.com/awscli-exe-linux-x86_64.zip" -o "awscli.zip"
unzip awscli.zip
sudo ./aws/install
aws --version
AWS has two ways to authenticate the CLI, and you need to know which one your org expects:
| Style | When to use | What gets stored |
|---|---|---|
| Long-lived access key | Personal AWS accounts, CI/CD machines, legacy setups. AWS now discourages this for human users. | ~/.aws/credentials with aws_access_key_id + aws_secret_access_key. Effectively forever. |
| SSO (IAM Identity Center) | Any company AWS environment in 2025+. Equivalent to az login - browser-based, short-lived tokens. |
~/.aws/sso/cache/*.json with a token. Expires (typically 8-12 hours). Refresh via aws sso login. |
# Service principal style
az login --service-principal \
--username <app-id> \
--password <client-secret> \
--tenant <tenant-id>
# Token cached in ~/.azure/
# Interactive, prompts for 4 values
aws configure
# AWS Access Key ID: AKIA...
# AWS Secret Access Key: ********
# Default region: us-east-1
# Default output format: json
# Or set directly:
aws configure set aws_access_key_id AKIA...
aws configure set aws_secret_access_key ********
After aws configure, you have a file:
[default]
aws_access_key_id = AKIAIOSFODNN7EXAMPLE
aws_secret_access_key = wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY
[default]
region = us-east-1
output = json
aws s3 ls fail with "Unable to locate credentials"?
A colleague pings you. They swear they ran aws configure and pasted in their access key. But every command fails. Their ~/.aws/credentials file looks like this:
[default]
access_key_id = AKIAIOSFODNN7EXAMPLE
secret_access_key = wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY
What's wrong? (One small thing. Look closely at the key names.)
aws_ prefix. AWS CLI looks for aws_access_key_id and aws_secret_access_key - not the unprefixed names. The file is parseable, the section is valid, but the CLI silently treats those values as unknown options and falls back to "no credentials found".
Fix: prefix both keys with aws_. Or better, just run aws configure and let the CLI write the file for you.
This is the az login equivalent. Browser-based, short-lived tokens, no secrets on your laptop.
# Created once via `aws configure sso`
[profile dev]
sso_session = my-org
sso_account_id = 123456789012
sso_role_name = DeveloperAccess
region = us-east-1
[profile prod]
sso_session = my-org
sso_account_id = 987654321098
sso_role_name = ReadOnlyAccess
region = us-east-1
[sso-session my-org]
sso_start_url = https://my-org.awsapps.com/start
sso_region = us-east-1
sso_registration_scopes = sso:account:access
# Once per session (~8-12 hour token)
aws sso login --profile dev
# Then every command picks up the token
aws sts get-caller-identity --profile dev
aws s3 ls --profile dev
aws configure and an IAM user with an access key. It's simpler. Move to Identity Center / SSO later when you're working in a multi-account org.
In Azure, AAD handles human identity for the whole tenant. In AWS, IAM was originally per-account, which made multi-account life painful (one IAM user per account!). AWS Identity Center (née AWS SSO) fixed that by acting as a federation layer above all your accounts.
Three things to know about Identity Center:
ExpiredToken, run aws sso login --profile <name> to refresh.aws s3 ls --profile work-prod, the CLI uses that specific set. Azure has the same idea but calls them "subscriptions in your context" and you switch with az account set - not quite the same shape but the goal is identical.Because AWS pushes you toward multi-account, profiles become essential. Almost every AWS user has at least 2-3 profiles in their ~/.aws/config.
# List subscriptions
az account list -o table
# Switch active subscription
az account set --subscription "prod-sub"
# Then all subsequent commands
# use that subscription
az group list
# List configured profiles
aws configure list-profiles
# Pass --profile per command
aws s3 ls --profile prod
# Or set for the shell session
export AWS_PROFILE=prod
aws s3 ls # now uses prod
AWS_PROFILE + shell prompt. Many engineers add their active profile to their shell prompt - it's the single best way to avoid running prod commands in a dev shell or vice versa.
~/.aws/config[sso-session my-org]
sso_start_url = https://my-org.awsapps.com/start
sso_region = us-east-1
[profile sandbox]
sso_session = my-org
sso_account_id = 111111111111
sso_role_name = AdministratorAccess
region = us-east-1
output = json
[profile dev]
sso_session = my-org
sso_account_id = 222222222222
sso_role_name = DeveloperAccess
region = us-east-1
output = json
[profile prod-readonly]
sso_session = my-org
sso_account_id = 333333333333
sso_role_name = ReadOnlyAccess
region = us-east-1
output = json
# Role chaining: assume a role in prod from your dev creds
[profile prod-deploy]
source_profile = dev
role_arn = arn:aws:iam::333333333333:role/DeployerRole
region = us-east-1
That last profile is worth a closer look. source_profile + role_arn is the AWS equivalent of "run this command as a different identity that I'm allowed to switch into". You stay authenticated as your normal dev user, but for this profile the CLI silently calls sts:AssumeRole and uses the returned credentials. We'll dig into this in Chapter 2.
One command. Confirms your CLI is installed, your credentials are valid, and AWS can see you. The AWS equivalent of az account show.
# If you set up SSO:
aws sso login --profile dev
# If you used aws configure (access keys), skip the login.
aws sts get-caller-identity
Expected output:
{
"UserId": "AROA...EXAMPLE:sunilt",
"Account": "123456789012",
"Arn": "arn:aws:sts::123456789012:assumed-role/DeveloperAccess/sunilt"
}
Read the ARN closely. It tells you four things at once: that you authenticated via STS (the temporary-credential service), the account ID, the role name you assumed, and your session name. This is the single most useful debugging command in AWS - whenever something says "access denied", start by running this to confirm who you actually are.
# What region am I defaulting to?
aws configure get region
# What regions exist?
aws ec2 describe-regions \
--query 'Regions[].RegionName' --output table
# Any S3 buckets in this account?
aws s3 ls
# Account-level summary (free)
aws iam get-account-summary
All of these are describe / list / get calls - read-only and free. Get comfortable with this rhythm: every AWS service has describe-* and list-* commands that cost nothing to call.
Don't peek. Think first, then click to reveal the answer.
1. You created an S3 bucket five minutes ago. You log into the AWS console, navigate to S3, but the bucket isn't there. What's the most likely cause?
2. Which of these is a global AWS service (not scoped to one region)?
EC2RDSIAMS3 (the bucket itself)3. aws sts get-caller-identity tells you...
4. Your teammate launches an EC2 instance in us-east-1a. You launch one in us-east-1a too. Are you in the same physical data center?
use1-az1) from aws ec2 describe-availability-zones --query 'AvailabilityZones[].[ZoneName,ZoneId]'. This becomes important when peering VPCs across accounts in chapter 3.
us-east-1 is special, and that's also a risk. Many global services route through it. A us-east-1 outage has cascading effects on services you thought were in other regions (IAM, billing, CloudFront edges). If you're building anything where global availability matters, read the AWS multi-region guidance.
From here on, every chapter has a Project Compass section that advances one fictional NVIDIA-flavored service: gfn-reports. It reads GeForce NOW session telemetry from a queue, aggregates it, exposes a query API, and emits alerts. By chapter 12 you'll have wired up almost the whole AWS stack to support it.
Compass exists so you're not learning services in isolation. Each chapter's slice connects to the previous one - the IAM role you create in chapter 2 will get S3 permissions in chapter 5, Lambda permissions in chapter 11, and Terraform-managed in chapter 12.
Goal: a clean, named profile we can refer to as compass in every following chapter. Pick a non-prod AWS account you can experiment in freely.
aws configure sso --profile compass
# Walks through SSO start URL, account, role, region
aws sso login --profile compass
aws sts get-caller-identity --profile compass
aws configure --profile compass
# Paste your access key, region (us-east-1), output (json)
aws sts get-caller-identity --profile compass
Once get-caller-identity returns a healthy ARN, you're done with chapter 1's Compass slice. Every subsequent chapter will add --profile compass to its commands and assume this profile is configured.
us-east-1) and AZ letters are randomized per account.AWS_PROFILE are how you switch context between accounts. Equivalent to az account set but more explicit.aws sts get-caller-identity is the "who am I" command you'll run constantly.| Trap | Fix |
|---|---|
| "Bucket disappeared!" | Wrong region in console picker. Check top-right. |
| "Access denied" but I'm an admin | Run aws sts get-caller-identity - you're probably on the wrong profile. |
| "My access key works for everything I tested" | That's the problem. Rotate it, use SSO. |
| "My teammate sees different AZs" | Letter assignment is per-account. Use AZ IDs (use1-az1) for coordination. |