From your first authenticated CLI call to a mental model of the services every DevOps engineer touches daily — IAM, networking, compute, storage, and how it all fits together securely. This is a concepts-and-hands-on guide, not a click-through of 200 services. Work top to bottom, or jump to a part.
The journey:
| You need | Why |
|---|---|
| An AWS account | The free tier covers everything here |
| The AWS CLI v2 installed | You'll authenticate and make calls |
| Basic networking + Linux familiarity | Subnets, ports, SSH come up constantly |
Cost warning: most of this fits the free tier, but always run terraform destroy / delete resources when done, and set a billing alarm first (Part 7). Confirm the CLI: aws --version.
AWS is a global platform organized into a few key boundaries:
| Concept | What it is |
|---|---|
| Account | The top-level container + billing boundary. Real orgs use many accounts (prod/dev/security) under AWS Organizations |
| Region | A geographic location (us-east-1) with its own isolated infrastructure. You choose one; data mostly stays there |
| Availability Zone (AZ) | One or more datacenters within a region. Spread across AZs for high availability |
| Service | A managed capability (EC2, S3, RDS…) accessed via API |
The shared responsibility model is the mindset: AWS secures the cloud infrastructure; you secure what you put in it — IAM policies, security groups, encryption, patching your instances. Most breaches are the customer's side (a public S3 bucket, an over-broad IAM role), not AWS's.
The #1 AWS security mistake is long-lived access keys. Prefer IAM Identity Center (SSO) for humans:
aws configure sso # set up SSO once
aws sso login # short-lived session, refreshed on demand
aws sts get-caller-identity # confirm WHO you are — run this constantly
For scripts and CI, use IAM roles, never static keys:
If you must use aws configure with an access key for a quick test, treat it as temporary and delete the key after. aws sts get-caller-identity is your "who am I / am I authenticated" reflex.
Every API call is authorized (or denied) by IAM. The pieces:
| Term | Meaning |
|---|---|
| Principal | Who's acting — a user, role, or service |
| Policy | A JSON document granting/denying actions on resources |
| Role | An identity you assume temporarily (the secure default for workloads) |
| Permission | Effect + Action + Resource (+ optional Condition) |
{
"Version": "2012-10-17",
"Statement": [{
"Effect": "Allow",
"Action": ["s3:GetObject"],
"Resource": "arn:aws:s3:::my-bucket/*"
}]
}
Least privilege is the whole game: grant the narrowest actions on the narrowest resources. An explicit Deny always wins over an Allow. Never attach AdministratorAccess to workloads, and never use the root account for daily work — lock it with MFA and put it away.
A VPC is your private network in a region. Inside it:
aws ec2 describe-vpcs
aws ec2 describe-security-groups --group-ids sg-0abc123
The rule that prevents most incidents: put databases and app servers in private subnets, expose only a load balancer publicly, and open security-group ports to the narrowest source (a specific SG or CIDR, never 0.0.0.0/0 for SSH/DB ports).
Three tiers, increasingly managed:
| Option | You manage | Use when |
|---|---|---|
| EC2 | The whole VM (OS, patching, scaling) | You need full control or lift-and-shift |
| ECS / EKS (containers) | Containers; AWS runs the plane | You've containerized (see Docker) |
| Lambda (serverless) | Just your function code | Event-driven, spiky, or glue workloads |
| Fargate | Containers without managing servers | ECS/EKS without node ops |
# Launch a tiny instance (free-tier eligible)
aws ec2 run-instances --image-id ami-xxxx --instance-type t3.micro \
--key-name mykey --security-group-ids sg-xxxx --subnet-id subnet-xxxx
Pair compute with an Auto Scaling Group behind an Application Load Balancer across multiple AZs — that's the standard resilient web tier. Prefer the most managed option that fits; every VM you own is a VM you must patch.
| Service | Shape | Use for |
|---|---|---|
| S3 | Object storage (buckets) | Files, backups, static sites, data lakes, logs |
| EBS | Block volumes attached to EC2 | An instance's disk |
| EFS | Shared network filesystem | Many instances mounting the same files |
| RDS / DynamoDB | Managed SQL / NoSQL databases | App data — don't self-host DBs on EC2 |
aws s3 mb s3://my-unique-bucket-name
aws s3 cp file.txt s3://my-unique-bucket-name/
aws s3 ls s3://my-unique-bucket-name/
S3 buckets are private by default — keep them that way. Enable Block Public Access at the account level, turn on default encryption and versioning, and never make a bucket public unless it's genuinely a public website. A public S3 bucket is the classic AWS data-leak headline.
Cloud bills surprise everyone once. Guardrails:
Environment, Owner, Project) so Cost Explorer can attribute spend.aws cloudwatch describe-alarms
aws ce get-cost-and-usage --time-period Start=2026-07-01,End=2026-07-15 \
--granularity MONTHLY --metrics UnblendedCost
Click-ops doesn't reproduce, review, or roll back. Define AWS in code:
resource "aws_s3_bucket" "logs" {
bucket = "acme-logs-prod"
}
resource "aws_s3_bucket_public_access_block" "logs" {
bucket = aws_s3_bucket.logs.id
block_public_acls = true
block_public_policy = true
ignore_public_acls = true
restrict_public_buckets = true
}
Everything you provisioned by hand in this guide should ultimately live in a repo, reviewed via PR and applied by CI.
0.0.0.0/0 on SSH/DB ports. Open only to a specific SG or CIDR; put databases in private subnets.AdministratorAccess everywhere. Least privilege — an explicit deny beats a broad allow.aws sts get-caller-identity. Whose ARN is it, and what can it do?plan it. Then destroy everything you created by hand.Self-check:
You now have the mental model: account/region/AZ → authenticate with roles → IAM least privilege → private networking → managed compute → private storage → cost guardrails → IaC. That's AWS the way it's run in production.
Learned the concepts? Test yourself with AWS interview questions.
Go to the question bank →