CloudFormation = Magic

Table of Contents
Intro and tooling
The main idea behind CloudFormation is to declare your infrastructure as in "I want to launch two VMs, one in a poublic, one in private subnets" in a text file - a "stack" and instruct AWS to launch these resources.
Natively you can do this via the CloudFormation Designer but since we are l33t h4x0rz we'll try something else - Visual Studio Code + some cool extensions. If you are a paranoid, tinfoild hat sporting individual, concerned about telemetry data you can grab VSCodium instead.
CF templates can be in JSON or YAML. I had no idea what YAML is but it is much more user readable than JSON so even people like me, without developer background, can make sense of it.
Behold the same declaration in JSON (top) and in YAML (bottom):


Template structure and "Hellow World"To setup Visual Studio Code optimally I would suggest following this excellent guide written by Matthew Hodgkins. I would also suggest installing this extension - Cloudformation YAML snippets for VS Code.
One of the simplest objects to declare is an S3 bucket. And we do so like this:

The "skeleton" of a template includes the sections below but only Resources: is mandatory:
AWSTemplateFormatVersion: 2010-09-09
Description:
Parameters:
Metadata:
Mappings:
Conditions:
Resources:
Transform:
Outputs:
Invocation, aka launching the stack
Now that we have a template, we can launch the stack using the AWS CLI (if you have it installed) like this:
aws cloudformation create-stack --stack-name s3bucket --template-body file:///s3bucket.yaml

You can just as easily deprovision the deployed resources by deleting the stack which makes sure nothing gets oveloooked (and you don't get billed for lingering resources).
aws cloudformation delete-stack --stack-name s3bucket
Of course we can also use the CloudFormation web UI to launch/delete/change the stack.

Here's a bit more fleshed out example of a template demonstrating the use of the Parameters section and the !Ref function. It creates a VPC and a private subnet:
AWSTemplateFormatVersion: 2010-09-09
Description: |
Test CF template - create a VPC and a private subnet
Parameters:
VPCCidrBlock:
Default: 10.0.0.0/16
Description: VPC CIDR Block
Type: String
Subnet1Block:
Default: 10.20.0.0/24
Description: Private Subnet CIDR Block
Type: String
Resources:
VPC:
Type: "AWS::EC2::VPC"
Properties:
CidrBlock: !Ref VPCCidrBlock #required
EnableDnsHostnames: true
EnableDnsSupport: true
InstanceTenancy: default
Tags:
- Key: Name
Value: TestVPC
PrivateSubnet:
Type: "AWS::EC2::Subnet"
Properties:
CidrBlock: !Ref Subnet1Block #required
MapPublicIpOnLaunch: false
VpcId: !Ref VPC #required
Tags:
- Key: Name
Value: PrivateSubnet
Once you have a base template structure you can keep iterating. For example, you can add a NAT Gateway so that the resource in the private subnet can communicate with the internet, a public subnet, Internet Gateway, routing table, security groups, etc. - all can be easily defined.
Using such unholy incantations you can conjure up infrastructure in the cloud literallty in minutes (and you can also add to your resume that IaC is in your skillset).
Lessons learned
If you create a template with sections like Parameters, Outputs, etc. they cannot be empty. This is why in the gif above you see me removing them. If you leave them, the template will fail validation and you will be greeted with the following messages: