The AWS Building Blocks
Amazon Web Services offers over 200 services, but the vast majority of architectures rest on a small core: EC2 for compute, S3 for object storage, VPC for networking, IAM for identity, RDS for relational databases, and Lambda for serverless functions. Master these and everything else slots in around them.
Everything in this guide uses the aws CLI v2. Configure credentials once with aws configure or, preferably, IAM Identity Center SSO via aws configure sso.
IAM: Identity and Access Management
IAM controls who can do what on which resources. It is global (not region-scoped) and free. The building blocks are users, groups, roles, and policies (JSON documents attached to identities or resources).
Prefer roles over long-lived access keys: an EC2 instance, Lambda function, or another account assumes a role to get short-lived credentials. Always follow least privilege.
# A least-privilege policy: read one S3 bucket only
{
"Version": "2012-10-17",
"Statement": [{
"Effect": "Allow",
"Action": ["s3:GetObject", "s3:ListBucket"],
"Resource": [
"arn:aws:s3:::my-app-assets",
"arn:aws:s3:::my-app-assets/*"
]
}]
}
# Create the policy and attach it to a role
aws iam create-policy --policy-name ReadAssets \
--policy-document file://read-assets.json
aws iam attach-role-policy --role-name app-role \
--policy-arn arn:aws:iam::123456789012:policy/ReadAssets
Never use the root user
Lock the root account with MFA and use it only for a handful of account-level tasks. Create individual IAM identities (ideally through IAM Identity Center / SSO) for everyday work, and enable MFA everywhere.
EC2: Elastic Compute Cloud
EC2 provides resizable virtual machines (instances). You choose an AMI (machine image), an instance type (CPU/RAM combination), a key pair for SSH, a security group (stateful virtual firewall), and a subnet.
| Family | Optimized for | Example |
|---|---|---|
| T / M | General purpose, balanced | t3.micro, m7g.large |
| C | Compute / CPU heavy | c7g.xlarge |
| R / X | Memory heavy (in-memory DBs) | r7g.large |
| P / G | GPU (ML, rendering) | g5.xlarge, p5.48xlarge |
Instance names ending in g (e.g. m7g) use AWS's ARM-based Graviton chips, which give the best price-performance for most workloads.
# Launch a Graviton instance in a specific subnet + security group
aws ec2 run-instances \
--image-id ami-0abcdef1234567890 \
--instance-type t4g.micro \
--key-name my-key \
--security-group-ids sg-0a1b2c3d \
--subnet-id subnet-0e1f2g3h \
--tag-specifications 'ResourceType=instance,Tags=[{Key=Name,Value=web-1}]'
# List running instances
aws ec2 describe-instances \
--filters "Name=instance-state-name,Values=running" \
--query "Reservations[].Instances[].[InstanceId,InstanceType,PrivateIpAddress]" \
--output table
S3: Simple Storage Service
S3 stores objects (files up to 5 TB) in globally-named buckets. It offers 11 nines of durability and multiple storage classes that trade retrieval speed for cost.
| Storage class | Use case |
|---|---|
| S3 Standard | Frequently accessed, low latency |
| S3 Intelligent-Tiering | Unknown / changing access patterns |
| S3 Standard-IA | Infrequent access, still fast |
| S3 Glacier / Deep Archive | Archival, minutes-to-hours retrieval |
# Create a bucket, block public access, enable versioning + encryption
aws s3api create-bucket --bucket my-app-assets \
--region us-east-1
aws s3api put-public-access-block --bucket my-app-assets \
--public-access-block-configuration \
BlockPublicAcls=true,IgnorePublicAcls=true,BlockPublicPolicy=true,RestrictPublicBuckets=true
aws s3api put-bucket-versioning --bucket my-app-assets \
--versioning-configuration Status=Enabled
# Sync a local folder up to the bucket
aws s3 sync ./dist s3://my-app-assets/site --delete
Public buckets are the #1 cloud leak
S3 blocks public access by default. Never turn that off to "make it work" — serve public content through CloudFront with an Origin Access Control instead, so the bucket itself stays private.
VPC: Virtual Private Cloud
A VPC is your isolated virtual network. Inside it you carve out subnets (public or private), route traffic with route tables, reach the internet through an Internet Gateway, and let private instances make outbound calls via a NAT Gateway.
- Security Group — stateful, attached to instances/ENIs; allow rules only.
- Network ACL — stateless, attached to subnets; allow and deny rules.
- Public subnet — has a route to the Internet Gateway.
- Private subnet — no direct inbound from the internet; egress via NAT.
# Create a VPC and a subnet
aws ec2 create-vpc --cidr-block 10.0.0.0/16 \
--tag-specifications 'ResourceType=vpc,Tags=[{Key=Name,Value=app-vpc}]'
aws ec2 create-subnet --vpc-id vpc-0abc123 \
--cidr-block 10.0.1.0/24 --availability-zone us-east-1a
# Security group rule: allow HTTPS from anywhere
aws ec2 authorize-security-group-ingress --group-id sg-0a1b2c3d \
--protocol tcp --port 443 --cidr 0.0.0.0/0
RDS and Serverless Databases
RDS is managed relational database hosting (PostgreSQL, MySQL, MariaDB, Oracle, SQL Server). It handles patching, backups, and Multi-AZ failover. Aurora is Amazon's cloud-native, MySQL/PostgreSQL-compatible engine with an option for Aurora Serverless v2 that scales capacity automatically. For key-value / document workloads, DynamoDB is a fully managed, single-digit-millisecond NoSQL store.
# Create a Multi-AZ PostgreSQL instance
aws rds create-db-instance \
--db-instance-identifier app-db \
--engine postgres --engine-version 16.4 \
--db-instance-class db.t4g.medium \
--allocated-storage 50 --storage-encrypted \
--multi-az \
--master-username admin \
--manage-master-user-password # store the secret in Secrets Manager
Lambda: Serverless Functions
Lambda runs your code in response to events (an API call via API Gateway, an S3 upload, a queue message) with no servers to manage. You pay per request and per GB-second of execution, and it scales to zero when idle.
# Package and deploy a Node.js function
zip function.zip index.mjs
aws lambda create-function \
--function-name resize-image \
--runtime nodejs20.x \
--handler index.handler \
--role arn:aws:iam::123456789012:role/lambda-exec \
--zip-file fileb://function.zip \
--memory-size 512 --timeout 30
# Invoke it and capture the response
aws lambda invoke --function-name resize-image \
--payload '{"key":"photo.jpg"}' out.json
Service Equivalents Across Clouds
| Category | AWS | Azure | GCP |
|---|---|---|---|
| VMs | EC2 | Virtual Machines | Compute Engine |
| Object storage | S3 | Blob Storage | Cloud Storage |
| Serverless functions | Lambda | Azure Functions | Cloud Run functions |
| Managed SQL | RDS / Aurora | Azure SQL / DB for PostgreSQL | Cloud SQL / AlloyDB |
| Managed Kubernetes | EKS | AKS | GKE |
| Identity | IAM | Entra ID + RBAC | Cloud IAM |
Practice Exercises
- Write an IAM policy that lets a role write objects to
arn:aws:s3:::uploads/*but never delete them. Which singleActiondo you allow? - Launch a
t4g.microinstance in a private subnet. How does it reach the internet for OS updates without being publicly reachable? - Explain the difference between a Security Group and a Network ACL, including which one is stateful.
- Your bucket must serve a public website but stay private at the bucket level. Describe the CloudFront + Origin Access Control pattern.
- Compare RDS Multi-AZ with an Aurora Serverless v2 cluster: which gives automatic capacity scaling, and which gives synchronous standby failover?
- Map these AWS services to their Azure and GCP equivalents from memory: S3, Lambda, EKS, and IAM.