What you will learn
- What Infrastructure as Code is and why clicking through the console does not scale
- CloudFormation templates — the YAML structure and every key section
- Stacks — how CloudFormation deploys, updates, and deletes infrastructure as a unit
- StackSets — deploying the same infrastructure across multiple accounts and regions
- CloudFormation Service Role — who actually creates the resources
- AWS Infrastructure Composer — visual drag-and-drop template builder
- AWS Systems Manager — the umbrella service with eight tools under one roof
- SSM Session Manager — SSH without port 22, without key pairs, with full audit trail
- SSM Run Command — run scripts on many servers simultaneously
- SSM Patch Manager — automated OS patching across your fleet
- SSM Parameter Store — already covered in security, revisited in context here
Why this matters
A Swiggy engineer clicks through the AWS console to create 15 resources — VPC, subnets, security groups, EC2 instances, RDS, load balancer — for a new microservice. Three weeks later a different engineer repeats the same process for staging. The two environments are subtly different. One works. One has a bug nobody can find. With CloudFormation, one template creates identical environments every time. At Razorpay, 200 EC2 instances need a security patch applied before Friday. SSM Patch Manager applies it to all 200 in parallel, logs every result, and reports which ones failed. No SSH. No manual work. No missed servers.
What is Infrastructure as Code
Infrastructure as Code means your AWS resources are defined in a file — not clicked in a console. That file lives in Git. It is versioned, reviewed, tested, and deployed the same way application code is.
Without IaC: Click → Create VPC → Click → Create Subnet → Click → ... Repeat for every environment Environments drift apart silently over time No record of what changed or why With IaC (CloudFormation): Write template once Deploy to dev → identical environment Deploy to staging → identical environment Deploy to prod → identical environment Change the template → change is tracked in GitThe template is the source of truth. The console reflects the template. Not the other way around.
CloudFormation Template Structure
A CloudFormation template is a YAML (or JSON) file describing what AWS resources to create.
AWSTemplateFormatVersion: "2010-09-09"Description: "DevOps Network production VPC and EC2 setup" Parameters: ## Variables — passed in at deploy time InstanceType: Type: String Default: t2.micro AllowedValues: [t2.micro, t3.small, t3.medium] Description: EC2 instance type Environment: Type: String AllowedValues: [dev, staging, prod] Mappings: ## Lookup tables — choose values based on conditions RegionAMI: ap-south-1: AMI: ami-0f5ee92e2d63afc18 ap-southeast-1: AMI: ami-0abcdef1234567890 Resources: ## The actual AWS resources — this section is mandatory MyEC2Instance: Type: AWS::EC2::Instance Properties: InstanceType: !Ref InstanceType ImageId: !FindInMap [RegionAMI, !Ref AWS::Region, AMI] Tags: - Key: Environment Value: !Ref Environment - Key: Name Value: devops-web-server MyS3Bucket: Type: AWS::S3::Bucket Properties: BucketName: !Sub "devops-assets-${Environment}-${AWS::AccountId}" VersioningConfiguration: Status: Enabled Outputs: ## Values to export after stack is created InstanceId: Description: EC2 instance ID Value: !Ref MyEC2Instance Export: Name: !Sub "${AWS::StackName}-InstanceId"Key intrinsic functions:
| Function | What it does |
|---|---|
| !Ref | Reference a parameter or resource |
| !Sub | String substitution — embed variables in strings |
| !GetAtt | Get an attribute of a resource (e.g. the DNS name of an ALB) |
| !FindInMap | Look up a value in a Mappings table |
| !ImportValue | Import an output from another stack |
| !If | Conditional — create resource only if condition is true |
Stacks — Deploy, Update, Delete as a Unit
A Stack is one deployed instance of a CloudFormation template.
Template (file in Git) ↓ create-stackStack: devops-prod-vpc Creates: VPC, 4 subnets, 2 route tables, NAT GW, IGW All resources tracked as part of this stack Template updated (added a security group) ↓ update-stackCloudFormation figures out what changedOnly creates the new security group — does not recreate existing resources Stack deleted ↓ delete-stackCloudFormation deletes ALL resources in the stack in the correct orderNo orphaned resources. No manual cleanup.Change Sets — preview before applying:
You modify the templateCreate a Change Set — CloudFormation shows exactly what will changeReview: "will add 1 Security Group, will modify 1 Route Table, will delete 0 resources"Execute the Change Set → changes appliedNever apply a CloudFormation update to production without reviewing a Change Set first.
Stack Drift:
Someone manually changed a resource outside of CloudFormation (clicked in console). Stack Drift detection compares the actual resource state to what the template says it should be.
CloudFormation → Stack → Stack actions → Detect driftResult shows: which resources drifted and what changedFix: update the template to match, or revert the manual changeCloudFormation Service Role
By default CloudFormation uses your credentials to create resources. This means you need permissions for every resource type in the template.
With a Service Role, CloudFormation assumes a specific IAM role to create resources. Your user only needs permission to create stacks and pass the role — not permissions for every resource.
Your user: iam:PassRole + cloudformation:CreateStack onlyCloudFormation assumes the Service RoleService Role has: ec2:*, rds:*, s3:*, etc.Useful for: giving developers the ability to deploy infrastructure via CloudFormation without giving them direct resource creation permissions.
StackSets — Deploy Across Many Accounts
StackSets deploy the same CloudFormation template across multiple AWS accounts and regions simultaneously.
One template: "create CloudTrail Trail and Config recorder"StackSet deploys this to: all 15 accounts in your AWS OrganisationAll 15 accounts: ap-south-1 and ap-southeast-1 regions30 stacks created in one operationUse cases:
- Enforce security baselines across all organisation accounts
- Deploy shared infrastructure (VPC, monitoring) to every new account automatically
- Ensure compliance resources exist in every account and region
AWS Infrastructure Composer
A visual, drag-and-drop tool for building CloudFormation templates. Drag resources onto a canvas, connect them, and Infrastructure Composer writes the YAML.
Open Infrastructure ComposerDrag: Lambda function, API Gateway, DynamoDB tableConnect: API Gateway → Lambda → DynamoDBInfrastructure Composer generates the CloudFormation templateDownload and deployGood for: learning CloudFormation structure, quickly scaffolding new services, visualising existing templates.
AWS Systems Manager — Eight Tools, One Service
SSM is an umbrella service. Eight distinct tools, all accessed through the Systems Manager console. All require the SSM Agent installed on EC2 instances (pre-installed on Amazon Linux 2 and Windows Server AMIs).
The eight SSM capabilities:
| Tool | What it does |
|---|---|
| Session Manager | Browser-based SSH without port 22 |
| Run Command | Run scripts on many EC2s simultaneously |
| Patch Manager | Automated OS patching |
| Parameter Store | Secure configuration and secret storage |
| Automation | Runbooks for complex multi-step operations |
| Maintenance Windows | Schedule operations during off-peak hours |
| Inventory | Collect and query software inventory across fleet |
| State Manager | Keep instances in a defined configuration state |
SSM Session Manager — SSH Without Port 22
Session Manager gives you a browser-based terminal into any EC2 instance. No SSH key pairs needed. No port 22 open in Security Groups. Every session is logged in CloudTrail and optionally recorded in S3.
Without Session Manager: EC2 must have public IP or Bastion Host Security Group must allow port 22 SSH key pair must exist and be managed No audit trail of commands run With Session Manager: EC2 can be fully private — no public IP, no port 22 Access via console or CLI — AWS handles the connection Every session logged: who, when, what commands MFA can be required before starting a sessionRequirements:
SSM Agent running on the instance (pre-installed on Amazon Linux 2)
IAM Role with AmazonSSMManagedInstanceCore policy attached to EC2
EC2 → Select instance → Connect → Session Manager → Connect Browser terminal opens — you are in the instance
SSM Run Command — Scripts at Scale
Run Command executes scripts on one instance, a group of instances, or all instances matching a tag — simultaneously.
Tag: Environment=prod on 50 EC2 instancesRun Command: restart the nginx service on all of themAll 50 restart simultaneouslyResults show per-instance: success or failure with outputUse cases:
- Apply a configuration change across the entire fleet
- Restart a service on all app servers after a deployment
- Run a diagnostic script to collect information from many instances
- Install software on a group of servers
No SSH. No Ansible. No manual logins. Just select targets, paste the script, run.
SSM Patch Manager — Automated Patching
Patch Manager scans your EC2 fleet for missing patches and applies them automatically based on a schedule and a patch baseline you define.
Patch Baseline: Which patches to apply (critical security patches, all patches, specific CVEs) Which patches to exclude (drivers, kernel updates if you want to control those) Maintenance Window: When patching is allowed to happen (Friday 11 PM to Saturday 3 AM) Instances rebooted only during this window Patch Groups: Tag instances: Patch Group = prod-web Apply different baselines and windows to different groups Patch scan → shows compliance report: Instance i-0abc123: 3 patches missing → Patch Group: prod-web → NONCOMPLIANT Instance i-0def456: up to date → COMPLIANTSSM Automation — Runbooks
Automation runbooks define multi-step operations that run on AWS resources — not just inside instances.
Runbook: "Restart RDS instance safely" Step 1: Take RDS snapshot (backup before restart) Step 2: Stop RDS Step 3: Start RDS Step 4: Wait for Available status Step 5: Run health check query Notify on success or failureAWS provides 250+ pre-built runbooks for common operations. Write your own for anything custom.
Hands-on Lab — CloudFormation Stack and SSM Session Manager
Step 1 — Write a CloudFormation template
Create a file: devops-lab-stack.yamlAWSTemplateFormatVersion: "2010-09-09"Description: "DevOps Network Lab — EC2 with SSM access" Parameters: Environment: Type: String Default: dev AllowedValues: [dev, prod] Resources: SSMRole: Type: AWS::IAM::Role Properties: RoleName: !Sub "devops-ssm-role-${Environment}" AssumeRolePolicyDocument: Version: "2012-10-17" Statement: - Effect: Allow Principal: Service: ec2.amazonaws.com Action: sts:AssumeRole ManagedPolicyArns: - arn:aws:iam::aws:policy/AmazonSSMManagedInstanceCore SSMInstanceProfile: Type: AWS::IAM::InstanceProfile Properties: Roles: [!Ref SSMRole] WebServer: Type: AWS::EC2::Instance Properties: InstanceType: t2.micro ImageId: ami-0f5ee92e2d63afc18 IamInstanceProfile: !Ref SSMInstanceProfile Tags: - Key: Name Value: !Sub "devops-web-${Environment}" - Key: Environment Value: !Ref Environment Outputs: InstanceId: Value: !Ref WebServer Description: EC2 Instance IDStep 2 — Deploy the stack
CloudFormation → Stacks → Create stackTemplate source: Upload a template file → upload devops-lab-stack.yamlStack name: devops-lab-stackParameters: Environment = devNext → Next → Create stack Watch Events tab — resources created in order:SSMRole → SSMInstanceProfile → WebServerStep 3 — Connect via Session Manager (no SSH needed)
Systems Manager → Session Manager → Start sessionSelect your EC2 instance → Start session Browser terminal opens. You are inside the EC2 instance.No key pair. No port 22. No Bastion Host.## Run commands inside the Session Manager terminalwhoamihostnameaws sts get-caller-identity## Shows the SSM role — the instance has its IAM role workingStep 4 — Run a command on the instance via Run Command
Systems Manager → Run Command → Run commandCommand document: AWS-RunShellScriptTarget: Choose instances manually → select your instanceCommands:echo "Hello from SSM Run Command"uptimedf -hRun → watch output appear per-instanceStep 5 — Preview a Change Set
Modify your template — add a tag to the EC2 instance:- Key: ManagedBy Value: CloudFormation CloudFormation → devops-lab-stack → UpdateReplace current template → upload modified fileNext → Next → Create change set Review: shows "Modify AWS::EC2::Instance — tag added"Execute change set → CloudFormation applies only the tag changeStep 6 — Detect drift
In the console, manually add a tag to the EC2 instance directly(This simulates someone changing infrastructure outside CloudFormation) CloudFormation → devops-lab-stack → Stack actions → Detect driftResult: WebServer — MODIFIED (tag added outside of template)Step 7 — Cleanup
CloudFormation → devops-lab-stack → Delete stackCloudFormation deletes EC2, InstanceProfile, and IAM Role in correct orderNo manual cleanup neededCommon Mistakes to Avoid
Common MistakeMaking manual changes to resources managed by CloudFormation. Once a resource is in a stack, changes should only come through the template. Manual console changes cause stack drift, create inconsistency between environments, and can cause the next CloudFormation update to fail or overwrite your manual change.
Common MistakeNot enabling Session Manager and keeping port 22 open instead. Port 22 open on a Security Group is a permanent security risk. Session Manager connects through the SSM service — no inbound ports needed, full audit trail, no key pair management. There is no good reason to prefer SSH over Session Manager for most workloads.
Common MistakeDeleting a CloudFormation stack without knowing it will delete RDS databases. By default CloudFormation deletes every resource in a stack on deletion — including databases with data. Set DeletionPolicy: Retain on critical resources like RDS and S3 so they survive a stack deletion.
TipUse CloudFormation Outputs and cross-stack references to share resource IDs between stacks. Stack A creates a VPC and exports the VPC ID. Stack B imports it. Each stack is smaller and easier to manage. And you never hardcode resource IDs in templates.