CloudFormation
Part 1: Understanding the Fundamentals
Section titled “Part 1: Understanding the Fundamentals”1.1 What is Infrastructure as Code (IaC)?
Section titled “1.1 What is Infrastructure as Code (IaC)?”Infrastructure as Code is the practice of managing and provisioning infrastructure through code instead of manual processes.
The Problem (Manual Approach)
Section titled “The Problem (Manual Approach)”1.2 What is AWS CloudFormation?
Section titled “1.2 What is AWS CloudFormation?”CloudFormation is AWS’s native Infrastructure as Code service. You write a template (JSON or YAML) describing what resources you want, and CloudFormation creates them in the correct order.
1.3 CloudFormation Core Concepts
Section titled “1.3 CloudFormation Core Concepts”The Building Blocks
Section titled “The Building Blocks”┌──────────────────────────────────────────────────────────────────────────────┐│ CLOUDFORMATION ANATOMY │├──────────────────────────────────────────────────────────────────────────────┤│ ││ ┌─────────────────────────────────────────────────────────────────────┐ ││ │ TEMPLATE │ ││ │ ┌─────────────────────────────────────────────────────────────┐ │ ││ │ │ Parameters │ │ ││ │ │ (Input values like environment name, instance type) │ │ ││ │ └─────────────────────────────────────────────────────────────┘ │ ││ │ │ │ ││ │ ▼ │ ││ │ ┌─────────────────────────────────────────────────────────────┐ │ ││ │ │ Resources │ │ ││ │ │ (AWS components to create: VPC, EC2, S3, IAM, etc.) │ │ ││ │ └─────────────────────────────────────────────────────────────┘ │ ││ │ │ │ ││ │ ▼ │ ││ │ ┌─────────────────────────────────────────────────────────────┐ │ ││ │ │ Outputs │ │ ││ │ │ (Values returned after creation: IPs, URLs, IDs) │ │ ││ │ └─────────────────────────────────────────────────────────────┘ │ ││ └─────────────────────────────────────────────────────────────────────┘ ││ ││ ┌─────────────────────────────────────────────────────────────────────┐ ││ │ STACK │ ││ │ A running instance of a template - the actual created resources │ ││ └─────────────────────────────────────────────────────────────────────┘ │└──────────────────────────────────────────────────────────────────────────────┘Key Terminology Table
Section titled “Key Terminology Table”| Concept | What It Is | Real Example |
|---|---|---|
| Template | A YAML/JSON file that describes what to build | template.yml |
| Stack | All resources created from one template | cmtr-29vd4qvr-basic-infra |
| Resource | A single AWS component | AWS::EC2::VPC |
| Parameter | A variable you pass when creating stack | Maintainer: cmtr-29vd4qvr-maintainer |
| Output | A value returned after stack is created | Instance1PublicIP |
| Stack Event | Status update during creation | CREATE_COMPLETE |
| Change Set | Preview of changes before updating | (Not used in this task) |
1.4 Template Structure Explained
Section titled “1.4 Template Structure Explained”The Complete Template Skeleton
Section titled “The Complete Template Skeleton”---AWSTemplateFormatVersion: "2010-10-09" # ═══ ALWAYS include this ═══Description: "What this stack creates" # Human-readable description
Parameters: # ═══ INPUT VALUES ═══ MyParameter: # Values user provides Type: String # when creating stack Default: some-value
Resources: # ═══ WHAT TO CREATE ═══ MyResource: # Logical name (your choice) Type: AWS::Service::ResourceType # AWS resource type Properties: # Configuration PropertyName: Value
Outputs: # ═══ RETURN VALUES ═══ MyOutput: # What to output Value: !Ref MyResource # after creationOur Template’s Structure
Section titled “Our Template’s Structure”template.yml│├── Parameters (1)│ └── Maintainer: cmtr-29vd4qvr-maintainer│├── Resources (17 total)│ ├── Networking (9)│ │ ├── VPC│ │ ├── Subnet1, Subnet2│ │ ├── Internet Gateway│ │ ├── VPC-IGW Attachment│ │ ├── RouteTable1, RouteTable2│ │ └── RouteTableAssociation1, RouteTableAssociation2│ ││ ├── Security (1)│ │ └── Security Group (SSH + HTTP)│ ││ ├── IAM (2)│ │ ├── IAM Role (for SSM)│ │ └── Instance Profile│ ││ └── Compute (2)│ ├── EC2 Instance 1 (with Apache/httpd)│ └── EC2 Instance 2 (with Apache/httpd)│└── Outputs (3) ├── Instance1PublicIP ├── Instance2PublicIP └── VPCId1.5 CloudFormation Functions (How Resources Talk to Each Other)
Section titled “1.5 CloudFormation Functions (How Resources Talk to Each Other)”!Ref - Reference Another Resource
Section titled “!Ref - Reference Another Resource”# Example: EC2 needs to know which Subnet to usecmtr29vd4qvrInstance1: Type: AWS::EC2::Instance Properties: SubnetId: !Ref cmtr29vd4qvrSubnet1 # ← Gets Subnet IDWhat happens: CloudFormation replaces !Ref cmtr29vd4qvrSubnet1 with the actual Subnet ID (e.g., subnet-abc123).
!GetAtt - Get an Attribute
Section titled “!GetAtt - Get an Attribute”# Example: Output the Public IP of an instanceOutputs: Instance1PublicIP: Value: !GetAtt cmtr29vd4qvrInstance1.PublicIp # ← Gets PublicIp attributeFn::Base64 & !Sub - UserData Scripts
Section titled “Fn::Base64 & !Sub - UserData Scripts”UserData: Fn::Base64: !Sub | # ← Encodes script as Base64 #!/bin/bash yum install -y httpd echo "Server running" > /var/www/html/index.htmlWhy Base64? EC2 UserData must be Base64-encoded.
Dependency Management (DependsOn)
Section titled “Dependency Management (DependsOn)”cmtr29vd4qvrPublicRoute1: Type: AWS::EC2::Route DependsOn: cmtr29vd4qvrVPCGatewayAttachment # ← Wait for IGW to attach firstWhy? You can’t create a route to an IGW before the IGW is attached to the VPC.
1.6 Understanding VPC Networking
Section titled “1.6 Understanding VPC Networking”What You’re Building
Section titled “What You’re Building” INTERNET │ ▼ ┌─────────────────────────┐ │ Internet Gateway (IGW) │ │ cmtr-29vd4qvr-igw │ └───────────┬─────────────┘ │ ┌─────────────┴─────────────┐ │ │ ▼ ▼ ┌────────────────┐ ┌────────────────┐ │ Route Table 1 │ │ Route Table 2 │ │ 0.0.0.0/0→IGW │ │ 0.0.0.0/0→IGW │ └───────┬────────┘ └───────┬────────┘ │ │ ▼ ▼ ┌────────────────┐ ┌────────────────┐ │ Subnet 1 │ │ Subnet 2 │ │ 10.0.1.0/24 │ │ 10.0.2.0/24 │ │ eu-west-1a │ │ eu-west-1b │ └───────┬────────┘ └───────┬────────┘ │ │ ▼ ▼ ┌────────────────┐ ┌────────────────┐ │ EC2 Instance1 │ │ EC2 Instance2 │ │ Apache/httpd │ │ Apache/httpd │ └────────────────┘ └────────────────┘How Traffic Flows
Section titled “How Traffic Flows”1. User types: <http://54.123.45.67> │2. ▼ Internet Gateway receives request │3. ▼ Route Table says: "Send 0.0.0.0/0 traffic to IGW" (For incoming, it routes to the subnet) │4. ▼ Subnet receives traffic │5. ▼ Security Group checks: "Is port 80 allowed? Yes!" │6. ▼ EC2 Instance serves the web page "Hello from Region eu-west-1a"1.7 Understanding EC2 UserData
Section titled “1.7 Understanding EC2 UserData”What Happens When an EC2 Instance Boots
Section titled “What Happens When an EC2 Instance Boots”┌──────────────────────────────────────────────────────────────────────────────┐│ EC2 BOOT SEQUENCE │├──────────────────────────────────────────────────────────────────────────────┤│ ││ Time 0: Instance starts ││ │ ││ ▼ ││ Time 0: AWS checks UserData ││ │ ││ ▼ ││ Time 1: UserData script executes (ONCE only) ││ │ ┌─────────────────────────────────────────────┐ ││ │ │ #!/bin/bash │ ││ │ │ yum update -y # Update OS │ ││ │ │ yum install -y httpd # Install Apache │ ││ │ │ systemctl start httpd # Start Apache │ ││ │ │ systemctl enable httpd # Auto-start │ ││ │ │ echo "<h1>Hello</h1>" > /var/www/html/index.html ││ │ └─────────────────────────────────────────────┘ ││ │ ││ ▼ ││ Time 2: Apache (httpd) is running on port 80 ││ │ ││ ▼ ││ Time 3: Instance is ready to serve web traffic ││ ││ ⚠️ Important: UserData runs ONLY on first boot! │└──────────────────────────────────────────────────────────────────────────────┘1.8 CloudFormation Stack Lifecycle
Section titled “1.8 CloudFormation Stack Lifecycle”States Your Stack Goes Through
Section titled “States Your Stack Goes Through” ┌─────────────────┐ │ create-stack │ ← You run this command └────────┬────────┘ │ ▼ ┌─────────────────┐ │ CREATE_IN_ │ │ PROGRESS │ ← Resources being created └────────┬────────┘ │ ┌──────────────┴──────────────┐ │ │ ▼ ▼ ┌────────────────┐ ┌────────────────┐ │ CREATE_COMPLETE│ │ CREATE_FAILED │ │ ✅ Success! │ │ ❌ Error! │ └────────┬───────┘ └────────┬───────┘ │ │ ▼ ▼ ┌────────────────┐ ┌────────────────┐ │ Stack is ready │ │ ROLLBACK_ │ │ to use! │ │ IN_PROGRESS │ └────────────────┘ └────────┬───────┘ │ ▼ ┌────────────────┐ │ ROLLBACK_ │ │ COMPLETE │ │ (Everything │ │ deleted) │ └────────────────┘1.9 Common Errors and How to Fix Them
Section titled “1.9 Common Errors and How to Fix Them”| Error Message | What It Means | How to Fix |
|---|---|---|
AlreadyExistsException | Stack name already in use | Delete old stack or use different name |
Properties validation failed | Invalid property in template | Check AWS docs for correct property names |
extraneous key [Tags] is not permitted | That resource doesn’t support Tags | Remove Tags from that resource |
ROLLBACK_COMPLETE | Something failed during creation | Check stack events for specific error |
CAPABILITY_NAMED_IAM required | Template creates IAM resources | Add --capabilities CAPABILITY_NAMED_IAM |
📗 Part 2: Step-by-Step Execution Guide
Section titled “📗 Part 2: Step-by-Step Execution Guide”2.1 Prerequisites Check
Section titled “2.1 Prerequisites Check”Verify AWS CLI is Working
Section titled “Verify AWS CLI is Working”aws sts get-caller-identityExpected output:
{ "UserId": "AROA...", "Account": "537124972913", "Arn": "arn:aws:sts::537124972913:assumed-role/..."}Note Your Account ID
Section titled “Note Your Account ID”aws sts get-caller-identity --query "Account" --output textYou’ll need this for IAM role ARN.
2.2 Complete Execution Flow
Section titled “2.2 Complete Execution Flow”┌──────────────────────────────────────────────────────────────────────────────┐│ EXECUTION CHECKLIST │├──────────────────────────────────────────────────────────────────────────────┤│ ││ ☐ Step 1: Create IAM Role for CloudFormation ││ ☐ Step 2: Save template.yml file ││ ☐ Step 3: Validate template ││ ☐ Step 4: Create the stack ││ ☐ Step 5: Monitor progress ││ ☐ Step 6: Verify resources ││ ☐ Step 7: Test HTTP endpoints ││ ☐ Step 8: Submit task ││ ☐ Step 9: Cleanup (delete stack when done) │└──────────────────────────────────────────────────────────────────────────────┘2.3 Step 1: Create IAM Role for CloudFormation
Section titled “2.3 Step 1: Create IAM Role for CloudFormation”What This Does
Section titled “What This Does”Creates a role that CloudFormation service can assume to create resources on your behalf.
Command 1: Create the Role
Section titled “Command 1: Create the Role”aws iam create-role --role-name cmtr-29vd4qvr-cfn-role --assume-role-policy-document "{\\"Version\\":\\"2012-10-17\\",\\"Statement\\":[{\\"Effect\\":\\"Allow\\",\\"Principal\\":{\\"Service\\":\\"cloudformation.amazonaws.com\\"},\\"Action\\":\\"sts:AssumeRole\\"}]}"Command 2: Attach AdministratorAccess Policy
Section titled “Command 2: Attach AdministratorAccess Policy”aws iam attach-role-policy --role-name cmtr-29vd4qvr-cfn-role --policy-arn arn:aws:iam::aws:policy/AdministratorAccessCommand 3: Get the Role ARN
Section titled “Command 3: Get the Role ARN”aws iam get-role --role-name cmtr-29vd4qvr-cfn-role --query "Role.Arn" --output textCopy this output! You’ll need it for Step 4.
2.4 Step 2: Save the Template
Section titled “2.4 Step 2: Save the Template”Create the File
Section titled “Create the File”notepad template.ymlPaste the Template
Section titled “Paste the Template”Copy the complete template from Section 3 below, paste into Notepad, save and close.
2.5 Step 3: Validate the Template
Section titled “2.5 Step 3: Validate the Template”What This Does
Section titled “What This Does”Checks your template for syntax errors WITHOUT creating any resources.
aws cloudformation validate-template --template-body file://template.yml --region eu-west-1Expected success output:
{ "Parameters": [ { "ParameterKey": "Maintainer", "DefaultValue": "cmtr-29vd4qvr-maintainer" } ], "Capabilities": ["CAPABILITY_NAMED_IAM"]}Common Validation Errors
Section titled “Common Validation Errors”| Error | Fix |
|---|---|
Yaml not well-formed | Check indentation (use spaces, not tabs) |
Unresolved resource dependencies | Check !Ref values match resource names |
2.6 Step 4: Create the Stack
Section titled “2.6 Step 4: Create the Stack”Option A: With IAM Role (Recommended)
Section titled “Option A: With IAM Role (Recommended)”aws cloudformation create-stack --stack-name cmtr-29vd4qvr-basic-infra --template-body file://template.yml --capabilities CAPABILITY_NAMED_IAM --role-arn "arn:aws:iam::YOUR_ACCOUNT_ID:role/cmtr-29vd4qvr-cfn-role" --region eu-west-1Replace YOUR_ACCOUNT_ID with your actual account ID.
Option B: Without IAM Role
Section titled “Option B: Without IAM Role”aws cloudformation create-stack --stack-name cmtr-29vd4qvr-basic-infra --template-body file://template.yml --capabilities CAPABILITY_NAMED_IAM --region eu-west-1Expected output:
{ "StackId": "arn:aws:cloudformation:eu-west-1:537124972913:stack/cmtr-29vd4qvr-basic-infra/..."}2.7 Step 5: Monitor Stack Creation
Section titled “2.7 Step 5: Monitor Stack Creation”Quick Status Check
Section titled “Quick Status Check”aws cloudformation describe-stacks --stack-name cmtr-29vd4qvr-basic-infra --region eu-west-1 --query "Stacks[0].StackStatus" --output textWait for Completion
Section titled “Wait for Completion”aws cloudformation wait stack-create-complete --stack-name cmtr-29vd4qvr-basic-infra --region eu-west-1If this returns with no error → Stack created successfully!
If Stack Fails (ROLLBACK_COMPLETE)
Section titled “If Stack Fails (ROLLBACK_COMPLETE)”Get the error details:
aws cloudformation describe-stack-events --stack-name cmtr-29vd4qvr-basic-infra --region eu-west-1 --query "StackEvents[?ResourceStatus=='CREATE_FAILED'].[LogicalResourceId,ResourceStatusReason]" --output tableThen delete and retry:
aws cloudformation delete-stack --stack-name cmtr-29vd4qvr-basic-infra --region eu-west-1aws cloudformation wait stack-delete-complete --stack-name cmtr-29vd4qvr-basic-infra --region eu-west-12.8 Step 6: Verify Resources
Section titled “2.8 Step 6: Verify Resources”Get Stack Outputs
Section titled “Get Stack Outputs”aws cloudformation describe-stacks --stack-name cmtr-29vd4qvr-basic-infra --region eu-west-1 --query "Stacks[0].Outputs" --output tableGet EC2 Instance Details
Section titled “Get EC2 Instance Details”aws ec2 describe-instances --filters "Name=tag:Name,Values=cmtr-29vd4qvr-instance1,cmtr-29vd4qvr-instance2" --region eu-west-1 --query "Reservations[*].Instances[*].[Tags[?Key=='Name'].Value|[0],InstanceId,PublicIpAddress,State.Name]" --output tableVerify VPC
Section titled “Verify VPC”aws ec2 describe-vpcs --filters "Name=tag:Name,Values=cmtr-29vd4qvr-vpc" --region eu-west-1Verify Subnets
Section titled “Verify Subnets”aws ec2 describe-subnets --filters "Name=tag:Name,Values=cmtr-29vd4qvr-subnet1,cmtr-29vd4qvr-subnet2" --region eu-west-1 --query "Subnets[*].[AvailabilityZone,Tags[?Key=='Name'].Value|[0]]" --output tableVerify IAM Role
Section titled “Verify IAM Role”aws iam get-role --role-name cmtr-29vd4qvr-role --query "Role.RoleName" --output text2.9 Step 7: Test HTTP Endpoints
Section titled “2.9 Step 7: Test HTTP Endpoints”Get Public IPs
Section titled “Get Public IPs”aws ec2 describe-instances --filters "Name=tag:Name,Values=cmtr-29vd4qvr-instance1" --region eu-west-1 --query "Reservations[0].Instances[0].PublicIpAddress" --output textaws ec2 describe-instances --filters "Name=tag:Name,Values=cmtr-29vd4qvr-instance2" --region eu-west-1 --query "Reservations[0].Instances[0].PublicIpAddress" --output textTest Instance 1
Section titled “Test Instance 1”curl http://INSTANCE1_PUBLIC_IPExpected: <h1>Hello from Region eu-west-1a</h1>
Test Instance 2
Section titled “Test Instance 2”curl http://INSTANCE2_PUBLIC_IPExpected: <h1>Hello from Region eu-west-1b</h1>
2.10 Step 8: Submit Task
Section titled “2.10 Step 8: Submit Task”Once all verifications pass, submit the task!
2.11 Step 9: Cleanup (Delete When Done)
Section titled “2.11 Step 9: Cleanup (Delete When Done)”aws cloudformation delete-stack --stack-name cmtr-29vd4qvr-basic-infra --region eu-west-1Wait for deletion:
aws cloudformation wait stack-delete-complete --stack-name cmtr-29vd4qvr-basic-infra --region eu-west-1📙 Part 3: The Complete Template
Section titled “📙 Part 3: The Complete Template”---AWSTemplateFormatVersion: "2010-09-09"Description: "Basic infrastructure with VPC, EC2 instances, and httpd"
Parameters: Maintainer: Type: String Default: cmtr-29vd4qvr-maintainer Description: Maintainer tag value
Resources: # ═══════════════════════════════════════════════════════════════ # VPC - The network container for all resources # ═══════════════════════════════════════════════════════════════ cmtr29vd4qvrVPC: Type: AWS::EC2::VPC Properties: CidrBlock: 10.0.0.0/16 EnableDnsHostnames: true EnableDnsSupport: true Tags: - Key: Name Value: cmtr-29vd4qvr-vpc - Key: Maintainer Value: !Ref Maintainer
# ═══════════════════════════════════════════════════════════════ # SUBNETS - Two public subnets in different Availability Zones # ═══════════════════════════════════════════════════════════════
# Subnet 1 - eu-west-1a cmtr29vd4qvrSubnet1: Type: AWS::EC2::Subnet Properties: VpcId: !Ref cmtr29vd4qvrVPC CidrBlock: 10.0.1.0/24 AvailabilityZone: eu-west-1a MapPublicIpOnLaunch: true Tags: - Key: Name Value: cmtr-29vd4qvr-subnet1 - Key: Maintainer Value: !Ref Maintainer
# Subnet 2 - eu-west-1b cmtr29vd4qvrSubnet2: Type: AWS::EC2::Subnet Properties: VpcId: !Ref cmtr29vd4qvrVPC CidrBlock: 10.0.2.0/24 AvailabilityZone: eu-west-1b MapPublicIpOnLaunch: true Tags: - Key: Name Value: cmtr-29vd4qvr-subnet2 - Key: Maintainer Value: !Ref Maintainer
# ═══════════════════════════════════════════════════════════════ # INTERNET GATEWAY - Connects VPC to the Internet # ═══════════════════════════════════════════════════════════════ cmtr29vd4qvrIGW: Type: AWS::EC2::InternetGateway Properties: Tags: - Key: Name Value: cmtr-29vd4qvr-igw - Key: Maintainer Value: !Ref Maintainer
# Attach Internet Gateway to VPC cmtr29vd4qvrVPCGatewayAttachment: Type: AWS::EC2::VPCGatewayAttachment Properties: VpcId: !Ref cmtr29vd4qvrVPC InternetGatewayId: !Ref cmtr29vd4qvrIGW
# ═══════════════════════════════════════════════════════════════ # ROUTE TABLES - Direct traffic to the Internet Gateway # ═══════════════════════════════════════════════════════════════
# Route Table 1 cmtr29vd4qvrPublicRT1: Type: AWS::EC2::RouteTable Properties: VpcId: !Ref cmtr29vd4qvrVPC Tags: - Key: Name Value: cmtr-29vd4qvr-public-rt1 - Key: Maintainer Value: !Ref Maintainer
# Route: Send all traffic (0.0.0.0/0) to Internet Gateway cmtr29vd4qvrPublicRoute1: Type: AWS::EC2::Route Properties: RouteTableId: !Ref cmtr29vd4qvrPublicRT1 DestinationCidrBlock: 0.0.0.0/0 GatewayId: !Ref cmtr29vd4qvrIGW DependsOn: cmtr29vd4qvrVPCGatewayAttachment
# Associate Route Table 1 with Subnet 1 cmtr29vd4qvrSubnetRTAssociation1: Type: AWS::EC2::SubnetRouteTableAssociation Properties: SubnetId: !Ref cmtr29vd4qvrSubnet1 RouteTableId: !Ref cmtr29vd4qvrPublicRT1
# Route Table 2 cmtr29vd4qvrPublicRT2: Type: AWS::EC2::RouteTable Properties: VpcId: !Ref cmtr29vd4qvrVPC Tags: - Key: Name Value: cmtr-29vd4qvr-public-rt2 - Key: Maintainer Value: !Ref Maintainer
# Route: Send all traffic (0.0.0.0/0) to Internet Gateway cmtr29vd4qvrPublicRoute2: Type: AWS::EC2::Route Properties: RouteTableId: !Ref cmtr29vd4qvrPublicRT2 DestinationCidrBlock: 0.0.0.0/0 GatewayId: !Ref cmtr29vd4qvrIGW DependsOn: cmtr29vd4qvrVPCGatewayAttachment
# Associate Route Table 2 with Subnet 2 cmtr29vd4qvrSubnetRTAssociation2: Type: AWS::EC2::SubnetRouteTableAssociation Properties: SubnetId: !Ref cmtr29vd4qvrSubnet2 RouteTableId: !Ref cmtr29vd4qvrPublicRT2
# ═══════════════════════════════════════════════════════════════ # SECURITY GROUP - Firewall rules for EC2 instances # ═══════════════════════════════════════════════════════════════ cmtr29vd4qvrSG: Type: AWS::EC2::SecurityGroup Properties: GroupName: cmtr-29vd4qvr-sg GroupDescription: Security group for SSH and HTTP VpcId: !Ref cmtr29vd4qvrVPC SecurityGroupIngress: - IpProtocol: tcp FromPort: 22 ToPort: 22 CidrIp: 0.0.0.0/0 - IpProtocol: tcp FromPort: 80 ToPort: 80 CidrIp: 0.0.0.0/0 Tags: - Key: Name Value: cmtr-29vd4qvr-sg - Key: Maintainer Value: !Ref Maintainer
# ═══════════════════════════════════════════════════════════════ # IAM ROLE - Permissions for EC2 instances (SSM access) # ═══════════════════════════════════════════════════════════════ cmtr29vd4qvrRole: Type: AWS::IAM::Role Properties: RoleName: cmtr-29vd4qvr-role AssumeRolePolicyDocument: Version: "2012-10-17" Statement: - Effect: Allow Principal: Service: ec2.amazonaws.com Action: sts:AssumeRole ManagedPolicyArns: - arn:aws:iam::aws:policy/AmazonSSMManagedInstanceCore Tags: - Key: Name Value: cmtr-29vd4qvr-role - Key: Maintainer Value: !Ref Maintainer
# Instance Profile - Container for the IAM Role cmtr29vd4qvrInstanceProfile: Type: AWS::IAM::InstanceProfile Properties: InstanceProfileName: cmtr-29vd4qvr-role Roles: - !Ref cmtr29vd4qvrRole
# ═══════════════════════════════════════════════════════════════ # EC2 INSTANCES - Virtual servers with Apache/httpd # ═══════════════════════════════════════════════════════════════
# Instance 1 - in eu-west-1a cmtr29vd4qvrInstance1: Type: AWS::EC2::Instance Properties: InstanceType: t2.micro ImageId: ami-0442403fb8d244144 SubnetId: !Ref cmtr29vd4qvrSubnet1 SecurityGroupIds: - !Ref cmtr29vd4qvrSG IamInstanceProfile: !Ref cmtr29vd4qvrInstanceProfile UserData: Fn::Base64: !Sub | #!/bin/bash yum update -y yum install -y httpd systemctl start httpd systemctl enable httpd echo "<h1>Hello from Region eu-west-1a</h1>" > /var/www/html/index.html Tags: - Key: Name Value: cmtr-29vd4qvr-instance1 - Key: Maintainer Value: !Ref Maintainer
# Instance 2 - in eu-west-1b cmtr29vd4qvrInstance2: Type: AWS::EC2::Instance Properties: InstanceType: t2.micro ImageId: ami-0442403fb8d244144 SubnetId: !Ref cmtr29vd4qvrSubnet2 SecurityGroupIds: - !Ref cmtr29vd4qvrSG IamInstanceProfile: !Ref cmtr29vd4qvrInstanceProfile UserData: Fn::Base64: !Sub | #!/bin/bash yum update -y yum install -y httpd systemctl start httpd systemctl enable httpd echo "<h1>Hello from Region eu-west-1b</h1>" > /var/www/html/index.html Tags: - Key: Name Value: cmtr-29vd4qvr-instance2 - Key: Maintainer Value: !Ref Maintainer
# ═══════════════════════════════════════════════════════════════# OUTPUTS - Values returned after stack creation# ═══════════════════════════════════════════════════════════════Outputs: Instance1PublicIP: Description: Public IP of Instance 1 Value: !GetAtt cmtr29vd4qvrInstance1.PublicIp Instance2PublicIP: Description: Public IP of Instance 2 Value: !GetAtt cmtr29vd4qvrInstance2.PublicIp VPCId: Description: VPC ID Value: !Ref cmtr29vd4qvrVPCPart 4: Troubleshooting Guide
Section titled “Part 4: Troubleshooting Guide”| Problem | Cause | Solution |
|---|---|---|
ROLLBACK_COMPLETE | Resource creation failed | Check stack events for specific error |
AlreadyExistsException | Stack name exists | Delete old stack first |
| Template validation fails | YAML syntax error | Check indentation, use spaces not tabs |
| HTTP curl returns nothing | UserData still running | Wait 2-3 minutes, try again |
| Instance not in SSM | SSM agent not ready | Wait 3-5 minutes |
Tags is not permitted | Resource doesn’t support tags | Remove Tags from that resource |
📋 Quick Reference Card
Section titled “📋 Quick Reference Card”| Action | Command |
|---|---|
| Validate template | aws cloudformation validate-template --template-body file://template.yml --region eu-west-1 |
| Create stack | aws cloudformation create-stack --stack-name cmtr-29vd4qvr-basic-infra --template-body file://template.yml --capabilities CAPABILITY_NAMED_IAM --region eu-west-1 |
| Check status | aws cloudformation describe-stacks --stack-name cmtr-29vd4qvr-basic-infra --region eu-west-1 --query "Stacks[0].StackStatus" --output text |
| Wait for complete | aws cloudformation wait stack-create-complete --stack-name cmtr-29vd4qvr-basic-infra --region eu-west-1 |
| Get errors | aws cloudformation describe-stack-events --stack-name cmtr-29vd4qvr-basic-infra --region eu-west-1 --query "StackEvents[?ResourceStatus=='CREATE_FAILED']" --output table |
| Delete stack | aws cloudformation delete-stack --stack-name cmtr-29vd4qvr-basic-infra --region eu-west-1 |
| Test instance | curl http://PUBLIC_IP |
This documentation covers everything needed to understand and complete the CloudFormation task. Save this as a reference!