Overview
Today, I’ll build a basic VPC baseline, the same as Day1, using CloudFormation. CloudFormation makes it easier to create and update resources.
I'll deploy two CloudFormation stacks to learn cross-stack references. The network stack contains network resources (VPC, subnets, IGW...) and the app stack contains app resources (EC2, SG...).
Hands-on
1. Create YAML templates
Create two YAML files using the templates below.
"day7-network.yaml"
AWSTemplateFormatVersion: '2010-09-09'
Description: Day7 Network Stack - VPC baseline with Exports (2AZ public/private, IGW, S3 Gateway Endpoint)
# Create Variables
Parameters:
VpcCidr:
Type: String
Default: 10.0.0.0/16
Az1:
Type: AWS::EC2::AvailabilityZone::Name
Az2:
Type: AWS::EC2::AvailabilityZone::Name
Resources:
VPC:
Type: AWS::EC2::VPC
Properties:
CidrBlock: !Ref VpcCidr
EnableDnsSupport: true
EnableDnsHostnames: true
Tags:
- Key: Name
Value: hs-day7-vpc
IGW:
Type: AWS::EC2::InternetGateway
Properties:
Tags:
- Key: Name
Value: hs-day7-igw
AttachIgw:
Type: AWS::EC2::VPCGatewayAttachment
Properties:
VpcId: !Ref VPC
InternetGatewayId: !Ref IGW
PublicSubnetA:
Type: AWS::EC2::Subnet
Properties:
VpcId: !Ref VPC
AvailabilityZone: !Ref Az1
CidrBlock: 10.0.0.0/24
MapPublicIpOnLaunch: true
Tags:
- Key: Name
Value: hs-day7-public-a
PublicSubnetB:
Type: AWS::EC2::Subnet
Properties:
VpcId: !Ref VPC
AvailabilityZone: !Ref Az2
CidrBlock: 10.0.1.0/24
MapPublicIpOnLaunch: true
Tags:
- Key: Name
Value: hs-day7-public-b
PublicRT:
Type: AWS::EC2::RouteTable
Properties:
VpcId: !Ref VPC
Tags:
- Key: Name
Value: hs-day7-rt-public
PublicRouteDefault:
Type: AWS::EC2::Route
DependsOn: AttachIgw
Properties:
RouteTableId: !Ref PublicRT
DestinationCidrBlock: 0.0.0.0/0
GatewayId: !Ref IGW
AssocPublicA:
Type: AWS::EC2::SubnetRouteTableAssociation
Properties:
SubnetId: !Ref PublicSubnetA
RouteTableId: !Ref PublicRT
AssocPublicB:
Type: AWS::EC2::SubnetRouteTableAssociation
Properties:
SubnetId: !Ref PublicSubnetB
RouteTableId: !Ref PublicRT
# Output resource information for reference from the stack
Outputs:
VpcId:
Value: !Ref VPC
Export:
Name: !Sub "${AWS::StackName}-VpcId"
PublicSubnetAId:
Value: !Ref PublicSubnetA
Export:
Name: !Sub "${AWS::StackName}-PublicSubnetAId"
PublicSubnetBId:
Value: !Ref PublicSubnetB
Export:
Name: !Sub "${AWS::StackName}-PublicSubnetBId"
PublicRouteTableId:
Value: !Ref PublicRT
Export:
Name: !Sub "${AWS::StackName}-PublicRouteTableId"
"day7-app.yaml"
AWSTemplateFormatVersion: '2010-09-09'
Description: Day7 App Stack - Create EC2 in imported VPC/Subnet (SSM enabled)
Parameters:
NetworkStackName:
Type: String
Description: Name of the Network stack that exports VPC/Subnets (e.g., hs-day7-network)
InstanceType:
Type: String
Default: t3.micro
Resources:
Ec2Role:
Type: AWS::IAM::Role
Properties:
RoleName: !Sub "hs-day7-ec2-ssm-role-${AWS::StackName}"
AssumeRolePolicyDocument:
Version: '2012-10-17'
Statement:
- Effect: Allow
Principal:
Service: ec2.amazonaws.com
Action: sts:AssumeRole
ManagedPolicyArns:
- arn:aws:iam::aws:policy/AmazonSSMManagedInstanceCore
Ec2InstanceProfile:
Type: AWS::IAM::InstanceProfile
Properties:
Roles:
- !Ref Ec2Role
# Create SG for EC2 instance using VPC ID imported by the network stack
Ec2Sg:
Type: AWS::EC2::SecurityGroup
Properties:
GroupDescription: hs-day7-ec2-sg (no inbound, all outbound)
VpcId: !ImportValue
Fn::Sub: "${NetworkStackName}-VpcId"
SecurityGroupEgress:
- IpProtocol: -1
CidrIp: 0.0.0.0/0
# Create an EC2 instance using subnet ID imported by the network stack
Ec2Instance:
Type: AWS::EC2::Instance
Properties:
ImageId: !Sub "{{resolve:ssm:/aws/service/ami-amazon-linux-latest/al2023-ami-kernel-default-x86_64}}"
InstanceType: !Ref InstanceType
IamInstanceProfile: !Ref Ec2InstanceProfile
SubnetId: !ImportValue
Fn::Sub: "${NetworkStackName}-PublicSubnetAId"
SecurityGroupIds:
- !Ref Ec2Sg
Tags:
- Key: Name
Value: hs-day7-app-ec2
# Output the instance id to review the instance.
Outputs:
InstanceId:
Value: !Ref Ec2Instance
2. Create CloudFormation stack
1. Network stack
CloudFormation → Create stack
Upload "day7-network.yaml".
Choose two Availability Zones (AZs).
You can review the resources created by this stack in the "Resources" tab. (Network resources like VPC, subnets, IGW...)
2. App stack
CloudFormation → Create stack
Upload "day7-app.yaml".
NetworkStackName = the network stack name created in the previous step.
You can review the resources created by this stack in the "Resources" tab. (App resources like EC2, SG, IAMrole...)
3. Functionality Verification
Systems Manager → Session Manager → Start session
If you can start a Session Manager session to the EC2 instance, you’ve successfully created both stacks.
Update "day7-app.yaml" to add a tag to the EC2 instance.
※"Environment : dev" tag!
"day7-app.yaml"
AWSTemplateFormatVersion: '2010-09-09'
Description: Day7 App Stack - Create EC2 in imported VPC/Subnet (SSM enabled)
Parameters:
NetworkStackName:
Type: String
Description: Name of the Network stack that exports VPC/Subnets (e.g., hs-day7-network)
InstanceType:
Type: String
Default: t3.micro
Resources:
Ec2Role:
Type: AWS::IAM::Role
Properties:
RoleName: !Sub "hs-day7-ec2-ssm-role-${AWS::StackName}"
AssumeRolePolicyDocument:
Version: '2012-10-17'
Statement:
- Effect: Allow
Principal:
Service: ec2.amazonaws.com
Action: sts:AssumeRole
ManagedPolicyArns:
- arn:aws:iam::aws:policy/AmazonSSMManagedInstanceCore
Ec2InstanceProfile:
Type: AWS::IAM::InstanceProfile
Properties:
Roles:
- !Ref Ec2Role
# Create SG for EC2 instance using VPC ID imported by the network stack
Ec2Sg:
Type: AWS::EC2::SecurityGroup
Properties:
GroupDescription: hs-day7-ec2-sg (no inbound, all outbound)
VpcId: !ImportValue
Fn::Sub: "${NetworkStackName}-VpcId"
SecurityGroupEgress:
- IpProtocol: -1
CidrIp: 0.0.0.0/0
# Create an EC2 instance using subnet ID imported by the network stack
Ec2Instance:
Type: AWS::EC2::Instance
Properties:
ImageId: !Sub "{{resolve:ssm:/aws/service/ami-amazon-linux-latest/al2023-ami-kernel-default-x86_64}}"
InstanceType: !Ref InstanceType
IamInstanceProfile: !Ref Ec2InstanceProfile
SubnetId: !ImportValue
Fn::Sub: "${NetworkStackName}-PublicSubnetAId"
SecurityGroupIds:
- !Ref Ec2Sg
Tags:
- Key: Name
Value: hs-day7-app-ec2
- Key: Environment
Value: dev
# Output the instance id to review the instance.
Outputs:
InstanceId:
Value: !Ref Ec2Instance
CloudFormation → Stacks → the app stack → Create a change set → Update stack → Replace template → Create change set
You can review the differences in the "Resource changes" tab.
※In this time, there are differences with tag settings.
Execute change set.
Execute change set, and the tag is added.
Tidying up
- Delete the app stack
- Delete the network stack
For test
Key exam points related to today's services.
CloudFormation
- Cross-stack references: export values from one stack (Outputs/Export) and import them in another stack (ImportValue). Export names must be unique within the same account and region.
- Change set is used when you change the template. Depending on the changes made, either in-place update or replacement are performed. (※In case of replacement, the resource is recreated. Some parameters like EC2 instance ID are changed.)
It's a last hands-on lab, see you soon in the Day8!
I'll summarize the key points of the services not covered in hands-on sessions.













Top comments (0)