OnCallReady

Lesson 35.1 · AWS I: CLI, IAM, S3 & KMS · 19 min read

AWS for Azure people: accounts, regions, ARNs and the API

In plain words

Imagine a company that rents space in many cities. In each city (a Region) it has several separate buildings far enough apart that a flood in one does not reach the others (Availability Zones). Your company signs one contract (an account) that comes with its own staff list and its own bill, and you can rent rooms in any city under that contract.

Some things, like the staff list, are the same in every city. Others, like the rooms themselves, exist only in the city where you rented them. Asking for a room in the wrong city means being told it does not exist.

AWS for Azure people

You already run things in Azure: subscriptions, resource groups, Entra ID, role assignments, storage accounts, Key Vault. AWS solves the same problems with different boundaries, and the boundaries are what bite you on call. This lesson maps one cloud onto the other, then shows the three ideas everything else in AWS rests on: the account, the Region, and the API call.

Need to know: an AWS account (a 12-digit number) is the unit of isolation, billing and quotas, and it has its own identity store (IAM). Most resources live in one Region; IAM is global. Everything is named by an ARN. Every action - console click, CLI command, Terraform apply - is a signed HTTPS call to a service API, and IAM policies talk about those calls by name (s3:GetObject).

The account is the boundary

An AWS account is a container for resources with a 12-digit account ID. It is the line AWS draws for:

That last point is the biggest change from Azure. In Azure, identities live in the Entra ID tenant and a role assignment gives them rights on a subscription. In AWS, an IAM user exists in exactly one account. To work in a second account you either have a user there too, or - the normal way - you assume a role in it.

Every account also has a root user: the email address and password used to create it. Root can do everything, including closing the account and changing the payment method, and no policy can limit it inside the account. The rules for root are short: a strong password, MFA, no access keys, locked away, used only for the handful of tasks only root can do.

Companies run many accounts - one per environment, per team, per workload - grouped with AWS Organizations:

In an interview: "An account is the hard boundary for security, billing and quotas. Regions are where resources physically live; Availability Zones are isolated data centres inside a Region. IAM is global to the account, most other services are regional."

Regions, Availability Zones and global services

A Region is a geographic area with its own copy of most services: eu-central-1 (Frankfurt), eu-west-1 (Ireland), us-east-1 (N. Virginia). Inside each Region are three or more Availability Zones (AZs) - one or more data centres each, with independent power and networking, close enough for synchronous replication. Their names are eu-central-1a, -1b, -1c; the letters are shuffled per account, so the stable names are the AZ IDs (euc1-az1).

Most resources belong to one Region: a KMS key in eu-central-1 cannot decrypt data in eu-west-1, and aws kms list-keys only lists the keys of the Region you ask. A few services are global: IAM (users, roles and policies are the same everywhere), Organizations, Route 53, CloudFront. S3 is in between: bucket names are global (unique across all of AWS), but each bucket lives in one Region.

$ aws sts get-caller-identity
{
    "UserId": "AIDAEVXTZTVCSMBGJ2WDW",
    "Account": "111122223333",
    "Arn": "arn:aws:iam::111122223333:user/learner"
}
$ aws s3api list-buckets --query 'Buckets[].[Name,BucketRegion]' --output text
oncall-lab-docs-111122223333	eu-central-1
oncall-lab-dr-111122223333	eu-west-1
oncall-lab-logs-111122223333	eu-central-1

The DR bucket is in Ireland, the others in Frankfurt - one account, one list, two Regions. KMS keys are strictly per Region:

$ KEY=$(aws kms create-key --description 'try: Frankfurt only' --query KeyMetadata.KeyId --output text)
$ aws kms describe-key --key-id $KEY --query KeyMetadata.Arn --output text
arn:aws:kms:eu-central-1:111122223333:key/46a9b14b-238e-4e21-8153-217a14708778
$ aws kms describe-key --key-id $KEY --region eu-west-1
aws: [ERROR]: An error occurred (NotFoundException) when calling the DescribeKey operation: Key 'arn:aws:kms:eu-west-1:111122223333:key/46a9b14b-238e-4e21-8153-217a14708778' does not exist

The key exists - in eu-central-1 (the profile's Region, so the first describe-key needed no --region). Asked in eu-west-1, KMS has never heard of it: there is no global list of keys to fall back on. IAM does not care about Regions at all:

$ aws iam get-user --region eu-west-1 --query User.Arn --output text
arn:aws:iam::111122223333:user/learner
$ aws iam get-user --region us-east-1 --query User.Arn --output text
arn:aws:iam::111122223333:user/learner

Azure to AWS: the mapping

AzureAWSWatch out for
Entra ID tenantIAM Identity Center (people), IAM in each accountIAM users and roles exist in one account only
Management groupOrganizations OUSCPs are deny-style guardrails, not grants
SubscriptionAccountThe account is also the identity boundary
Resource groupNo direct equivalent: tags, CloudFormation stacks, Resource GroupsYou delete "everything for this app" by tag or stack, not by group
Role assignment (RBAC)An IAM policy attached to a user, group or roleOne policy language covers management AND data (s3:GetObject)
Azure Policy (deny)SCPs, plus AWS Config rules for auditing
Managed identityIAM role (an instance profile on EC2, IRSA / Pod Identity on EKS)Roles have a trust policy saying who may use them
Service principal + client secretIAM user + access key (avoid), or a role with OIDCLong-lived keys are the classic AWS leak
Key Vault keysKMSEvery key has a key policy that must allow you
Key Vault secretsSecrets Manager / SSM Parameter Store
Storage account + blob containerS3 bucketThe bucket name is global; no account-level key
VNet / subnetVPC / subnetAWS subnets live in one AZ
NSGSecurity group (stateful) + network ACL (stateless)
Load Balancer / Application GatewayNLB / ALB
AKSEKS
Azure Monitor, Log Analytics (KQL)CloudWatch metrics, Logs, Logs Insights
Activity LogCloudTrail
Cost ManagementCost Explorer, Budgets
ARM / BicepCloudFormation / CDK (and Terraform for both)
az CLIaws CLI--query is JMESPath in both

The row that changes how you debug: Azure splits the control plane (manage the storage account) from the data plane (read a blob), and an Owner cannot read Key Vault secrets without a data role. AWS has one IAM policy language for both: s3:CreateBucket and s3:GetObject are just two actions, and an admin policy ("Action": "*") covers both - unless a resource's own policy (a bucket policy, a KMS key policy) says otherwise. You will meet that "unless" in every lab of this chapter.

ARNs: the name of everything

An Amazon Resource Name identifies a resource across all of AWS:

arn:partition:service:region:account-id:resource
arn:aws:iam::111122223333:user/learner                          IAM: global, no Region
arn:aws:iam::111122223333:role/ci-deploy
arn:aws:sts::111122223333:assumed-role/ci-deploy/build-4711     a session of that role
arn:aws:s3:::oncall-lab-docs-111122223333                       S3: no Region, no account
arn:aws:s3:::oncall-lab-docs-111122223333/runbooks/s3-public.md an object
arn:aws:kms:eu-central-1:111122223333:key/1234abcd-...          KMS: Region and account

The partition is aws almost everywhere (aws-cn in China, aws-us-gov in GovCloud). Empty fields are part of the format: a bucket ARN has no Region and no account because bucket names are already globally unique. Policies match resources by ARN, with * and ? as wildcards - arn:aws:s3:::oncall-lab-docs-111122223333/runbooks/* is "every object under runbooks/".

$ aws iam get-user --query User.Arn --output text
arn:aws:iam::111122223333:user/learner
$ aws iam list-groups-for-user --user-name learner --query 'Groups[].Arn' --output text
arn:aws:iam::111122223333:group/platform-admins

Every action is an API call

The console, the CLI, the SDKs, Terraform: all of them send signed HTTPS requests to service endpoints such as iam.amazonaws.com, sts.eu-central-1.amazonaws.com or s3.eu-central-1.amazonaws.com. The signature (SigV4) is computed from your secret key, so the key itself never travels. Each request names one action in the form service:Operation:

You typeThe API action
aws iam create-user --user-name anaiam:CreateUser
aws s3 ls s3://buckets3:ListBucket (the ListObjectsV2 operation)
aws s3 cp s3://bucket/key .s3:GetObject (after a HeadObject)
aws kms decrypt ...kms:Decrypt

Policies grant and deny those action names, AccessDenied errors quote them, and CloudTrail records them. When a command fails, the question is always: which API call, made by which principal, against which resource ARN?

$ aws cloudtrail lookup-events --region us-east-1 --max-items 2 --query 'Events[].[EventTime,EventName,Username]' --output text
2026-09-22T20:00:04+00:00	ListGroupsForUser	learner
2026-09-22T20:00:04+00:00	GetUser	learner

IAM calls are recorded in us-east-1 even though you sent them from Frankfurt: IAM is a global service and CloudTrail keeps global events there. Remember that the day you hunt for "who deleted this role".

The lab account

(simulator) Everything in this chapter runs against a simulated AWS account, 111122223333 (the account ID AWS uses in its own documentation), alias oncall-lab, home Region eu-central-1, DR Region eu-west-1. You are the IAM user learner, an administrator through the group platform-admins. The account is a member of an organization whose SCPs you will meet later. No request leaves the box and nothing costs money - but every output, error message and policy decision follows the real services. The lab installed the CLI for this lesson; in the first lab you install it yourself.

You can now: say what an account, a Region and an AZ are and which services are global; map an Azure concept to its AWS counterpart and name the difference that matters; read an ARN; and name the API action behind a CLI command.

Why it helps

Every AWS command needs two answers before it can work: which account, and which Region. Half of the "it is gone!" moments on call are a wrong Region, and half of the security reviews start with "which accounts do we have and who controls them". Knowing that IAM is global while KMS keys and most resources are regional saves real panic.

The ARN format comes back in every policy, every error message and every log record in this chapter, so learning to read it once pays off in every lesson after this one.

Commands in this lesson

aws

FAQ

What is the difference between an account and a Region?

An account is an ownership and security boundary: its own IAM, its own bill, its own quotas. A Region is a place where AWS runs a copy of most services, such as eu-central-1 in Frankfurt. One account can use every Region; the resources you create in a Region stay there unless you copy them. The two are independent axes.

Why do companies have dozens of AWS accounts?

Because the account is the strongest isolation AWS offers. Separate accounts for production, staging, security logging and each team mean a mistake or a leaked credential in one cannot touch the others, and each bill is clear. AWS Organizations groups them under one management account and lets you apply guardrails (SCPs) to whole groups at once.

What does the root user do, and why not use it?

The root user is the email address that created the account; it can do everything, including closing the account, and policies cannot limit it inside the account. It is needed for a handful of tasks only. Protect it with MFA, never create access keys for it, and use IAM Identity Center or roles for daily work.

How do I read an ARN?

arn:partition:service:region:account-id:resource. For example arn:aws:kms:eu-central-1:111122223333:key/1234... is a KMS key in Frankfurt in account 111122223333. Global services leave the Region empty (arn:aws:iam::111122223333:user/learner), and S3 bucket ARNs leave both Region and account empty because bucket names are globally unique.

Is an Availability Zone the same in every account?

Not by name. The names like eu-central-1a are mapped to physical zones differently per account, so your 1a may be someone else's 1b. The zone ID (euc1-az1) is the same everywhere. It matters when two accounts must use the same physical zone, for example to keep traffic local.

In an interview Junior

What is the difference between an AWS account, a Region and an Availability Zone?

An account is the hard boundary for security, billing and quotas: it has its own IAM and nothing crosses it unless a policy allows it. A Region is a geographic area with its own copy of most services, such as eu-central-1; resources live in one Region. An Availability Zone is one or more isolated data centres inside a Region, so spreading across zones survives a data-centre failure. IAM is global to the account, most other services, such as KMS, are regional, and S3 bucket names are global while each bucket lives in one Region.

Also asked: What is an ARN and what are its parts? · Why would a company use many AWS accounts instead of one? · Which AWS services are global, and which are regional?

Practise this lesson in the terminal Free, in your browser - a real Ubuntu terminal to try it in, with missions that check your work.