π§ͺ Hands-On Labs#
Practical exercises to reinforce your AWS knowledge. These labs use the AWS Free Tier wherever possible.
π Getting Started#
- Create an AWS account (if you haven’t already)
- Set up IAM admin user with MFA (never use root!)
- Install AWS CLI and configure with your credentials
- Set a budget alert to avoid unexpected charges
Lab 1: IAM Users, Groups, and Policies#
Objective: Create IAM users, organize them into groups, and apply policies.
β οΈ Cost: Free (IAM has no cost)
β±οΈ Time: 20 minutesSteps:
- Create groups:
Admins,Developers,Auditors - Attach policies:
Adminsβ AdministratorAccessDevelopersβ AmazonEC2FullAccess, AmazonS3ReadOnlyAccessAuditorsβ ReadOnlyAccess
- Create IAM users and add to groups
- Create an IAM role for EC2 with S3 read access
# Create group
aws iam create-group --group-name Developers
aws iam attach-group-policy --group-name Developers \
--policy-arn arn:aws:iam::aws:policy/AmazonEC2FullAccess
aws iam attach-group-policy --group-name Developers \
--policy-arn arn:aws:iam::aws:policy/AmazonS3ReadOnlyAccessLab 2: Launch an EC2 Instance#
Objective: Launch and connect to an EC2 instance.
β οΈ Cost: ~$0.01/hr (t3.micro free tier eligible)
β±οΈ Time: 20 minutesSteps:
- Launch a
t3.microinstance with Amazon Linux 2 - Create a key pair for SSH access
- Configure security group (SSH from your IP only)
- SSH into the instance
- Install a web server
# Launch instance
aws ec2 run-instances \
--image-id resolve-ssm:/aws/service/ami-amazon-linux-latest/al2023-ami-kernel-6.1-x86_64 \
--instance-type t3.micro \
--key-name my-key-pair \
--security-groups web-sg \
--user-data '#!/bin/bash
yum update -y
yum install -y httpd
systemctl enable httpd
systemctl start httpd
echo "<h1>Hello from EC2!</h1>" > /var/www/html/index.html'
# SSH into instance
ssh -i my-key-pair.pem ec2-user@<public-ip>Lab 3: Create an S3 Bucket#
Objective: Create, configure, and manage an S3 bucket.
β οΈ Cost: Free tier eligible (5 GB storage)
β±οΈ Time: 15 minutesSteps:
- Create an S3 bucket with a globally unique name
- Upload objects (files, images)
- Enable versioning
- Configure lifecycle policy (transition to IA after 30 days)
- Enable static website hosting
- Generate a pre-signed URL
# Create bucket
aws s3 mb s3://my-unique-bucket-name-$(date +%s)
# Upload file
aws s3 cp hello.txt s3://my-bucket/
# Enable versioning
aws s3api put-bucket-versioning \
--bucket my-bucket \
--versioning-configuration Status=Enabled
# Generate pre-signed URL (valid for 1 hour)
aws s3 presign s3://my-bucket/hello.txt --expires-in 3600Lab 4: Build a VPC from Scratch#
Objective: Create a custom VPC with public and private subnets.
β οΈ Cost: ~$0.05/hr (NAT Gateway is the main cost)
β±οΈ Time: 30 minutesSteps:
- Create VPC (10.0.0.0/16)
- Create public subnets in 2 AZs (10.0.1.0/24, 10.0.2.0/24)
- Create private subnets in 2 AZs (10.0.10.0/24, 10.0.11.0/24)
- Create and attach Internet Gateway
- Create NAT Gateway in public subnet
- Create route tables and associate subnets
- Launch EC2 in public subnet (verify internet access)
- Launch EC2 in private subnet (verify NAT access)
Lab 5: Set Up RDS Database#
Objective: Launch and connect to an RDS database.
β οΈ Cost: ~$0.02/hr (db.t3.micro free tier eligible)
β±οΈ Time: 25 minutesSteps:
- Create an RDS MySQL/PostgreSQL instance (db.t3.micro)
- Configure security group (allow your IP on port 3306/5432)
- Enable automated backups (7-day retention)
- Connect using MySQL Workbench or CLI
- Create a database and table
- Enable deletion protection
- Take a manual snapshot
# Create RDS instance
aws rds create-db-instance \
--db-instance-identifier my-test-db \
--db-instance-class db.t3.micro \
--engine mysql \
--master-username admin \
--master-user-password 'MyP@ssword!' \
--allocated-storage 20 \
--backup-retention-period 7 \
--deletion-protection \
--vpc-security-group-ids sg-db-access
# Connect
mysql -h my-test-db.xxx.us-east-1.rds.amazonaws.com -u admin -pLab 6: Serverless API with Lambda + API Gateway + DynamoDB#
Objective: Build a fully serverless REST API.
β οΈ Cost: Free tier eligible (1M Lambda requests, 25 GB DynamoDB)
β±οΈ Time: 30 minutesSteps:
- Create DynamoDB table (On-Demand capacity)
- Create Lambda function with DynamoDB permissions
- Create HTTP API in API Gateway
- Connect API Gateway to Lambda
- Test the API endpoint
# Lambda function (index.py)
import json
import boto3
import uuid
from datetime import datetime
dynamodb = boto3.resource('dynamodb')
table = dynamodb.Table('items')
def lambda_handler(event, context):
if event['requestContext']['http']['method'] == 'GET':
# List items
response = table.scan()
return {'statusCode': 200, 'body': json.dumps(response['Items']) }
elif event['requestContext']['http']['method'] == 'POST':
# Create item
body = json.loads(event['body'])
item = {'id': str(uuid.uuid4()), 'data': body['data'], 'created_at': datetime.now().isoformat() }
table.put_item(Item=item)
return {'statusCode': 201, 'body': json.dumps(item) }Lab 7: Auto Scaling + Load Balancing#
Objective: Set up an auto-scaled, load-balanced web application.
β οΈ Cost: ~$0.05/hr (ALB + EC2 instances)
β±οΈ Time: 30 minutesSteps:
- Create launch template with web server user data
- Create target group with health check
- Create ALB
- Create Auto Scaling group (min: 2, max: 4)
- Configure scaling policy (CPU at 60%)
- Test by generating load
# Create launch template
aws ec2 create-launch-template \
--launch-template-name web-template \
--launch-template-data '{"ImageId": "ami-0abcdef1234567890", "InstanceType": "t3.micro", "SecurityGroupIds": ["sg-web"], "UserData": "'$(base64 -w0 userdata.sh)'" }'
# Create auto scaling group
aws autoscaling create-auto-scaling-group \
--auto-scaling-group-name web-asg \
--launch-template LaunchTemplateName=web-template \
--min-size 2 --max-size 4 --desired-capacity 2 \
--vpc-zone-identifier "subnet-abc,subnet-def" \
--target-group-arns "arn:aws:...:targetgroup/web-tg/abc"