aws-cloudformation-vpc ยท diff
git:20260316.91dc3c4 to git:20260323.2528036
88 added, 1264 removed. Audit A to A.
---
name: aws-cloudformation-vpc
- description: Provides AWS CloudFormation patterns for VPC infrastructure. Use when creating VPCs, Subnets, Route Tables, NAT Gateways, Internet Gateways, and implementing template structure with Parameters, Outputs, Mappings, Conditions, and cross-stack references.
+ description: Provides AWS CloudFormation patterns for VPC foundations, including subnets, route tables, internet and NAT gateways, endpoints, and reusable outputs. Use when creating a new network baseline, segmenting public and private workloads, or preparing CloudFormation networking stacks for application deployments.
allowed-tools: Read, Write, Bash
---
# AWS CloudFormation VPC Infrastructure
## Overview
- Create production-ready VPC infrastructure using AWS CloudFormation templates. This skill covers VPC components (Subnets, Route Tables, NAT Gateways, Internet Gateways), template structure best practices, parameter patterns, and cross-stack references for modular, reusable infrastructure as code.
-
- ## When to Use
-
- Use this skill when:
- - Creating new VPCs with public and private subnets
- - Configuring route tables for internet and NAT connectivity
- - Setting up Internet Gateways and NAT Gateways
- - Implementing template Parameters with AWS-specific types
- - Creating Outputs for cross-stack references
- - Organizing templates with Mappings and Conditions
- - Designing reusable, modular CloudFormation templates
-
- ## Instructions
+ Use this skill to build a VPC foundation with CloudFormation in a way that stays readable, reusable, and safe to evolve.
- Follow these steps to create VPC infrastructure with CloudFormation:
+ The key goals are:
+ - a clear subnet and routing model
+ - predictable connectivity for public and private workloads
+ - outputs that downstream stacks can consume without duplicating network logic
- 1. **Define VPC Parameters**: Specify CIDR block and DNS settings
- 2. **Create Subnets**: Configure public and private subnets across AZs
- 3. **Set Up Internet Gateway**: Enable internet connectivity for public subnets
- 4. **Configure NAT Gateways**: Provide outbound connectivity for private subnets
- 5. **Create Route Tables**: Define routing rules for each subnet type
- 6. **Add Security Groups**: Configure network access controls
- 7. **Implement VPC Endpoints**: Enable private connectivity to AWS services
- 8. **Create VPC Peering**: Connect multiple VPCs if needed
+ Use the `references/` files for larger templates and extended service combinations.
- For complete examples, see the [EXAMPLES.md](references/examples.md) file.
+ ## When to Use
- ## Examples
+ Use this skill when:
+ - creating a new VPC stack for an application or shared platform
+ - adding public and private subnets across one or more Availability Zones
+ - wiring internet access, NAT egress, or private endpoints
+ - exporting VPC, subnet, route table, and security-group-adjacent identifiers for other stacks
+ - reviewing a networking change for blast radius, route correctness, or cost
+ - preparing reusable infrastructure for ECS, EKS, Lambda, EC2, or RDS stacks
- The following examples demonstrate common VPC patterns:
+ Typical trigger phrases include `cloudformation vpc`, `private subnet`, `nat gateway`, `route table`, `vpc endpoint`, and `export subnet ids`.
- ### Example 1: VPC with Public and Private Subnets
+ ## Instructions
- ```yaml
- VPC:
- Type: AWS::EC2::VPC
- Properties:
- CidrBlock: 10.0.0.0/16
- EnableDnsHostnames: true
- EnableDnsSupport: true
+ ### 1. Start with the address plan
- PublicSubnet:
- Type: AWS::EC2::Subnet
- Properties:
- VpcId: !Ref VPC
- CidrBlock: 10.0.1.0/24
- AvailabilityZone: !Select [0, !GetAZs ""]
- MapPublicIpOnLaunch: true
+ Before writing resources, define:
+ - VPC CIDR range
+ - number of Availability Zones
+ - public, private, and isolated subnet ranges
+ - which workloads need internet ingress, NAT egress, or only private AWS service access
- PrivateSubnet:
- Type: AWS::EC2::Subnet
- Properties:
- VpcId: !Ref VPC
- CidrBlock: 10.0.2.0/24
- AvailabilityZone: !Select [0, !GetAZs ""]
- ```
+ This prevents route-table sprawl and painful subnet replacement later.
- ### Example 2: Internet Gateway and Routes
+ ### 2. Build the core network resources in layers
- ```yaml
- InternetGateway:
- Type: AWS::EC2::InternetGateway
+ Create the stack in this order:
+ - VPC and subnets
+ - Internet Gateway for public ingress and egress
+ - NAT gateways if private subnets need outbound internet access
+ - route tables and subnet associations
+ - optional VPC endpoints for private access to AWS services
- VPCGatewayAttachment:
- Type: AWS::EC2::VPCGatewayAttachment
- Properties:
- VpcId: !Ref VPC
- InternetGatewayId: !Ref InternetGateway
+ Keep each layer easy to inspect in the template and avoid mixing unrelated application resources into the same stack.
- PublicRouteTable:
- Type: AWS::EC2::RouteTable
- Properties:
- VpcId: !Ref VPC
+ ### 3. Parameterize only the environment-dependent values
- PublicRoute:
- Type: AWS::EC2::Route
- DependsOn: VPCGatewayAttachment
- Properties:
- RouteTableId: !Ref PublicRouteTable
- DestinationCidrBlock: 0.0.0.0/0
- GatewayId: !Ref InternetGateway
- ```
+ Useful parameters usually include:
+ - environment name
+ - VPC CIDR and subnet CIDRs
+ - number of AZs or explicit subnet IDs in nested-stack scenarios
+ - flags for optional endpoints or NAT layout
- ### Example 3: NAT Gateway
+ Do not parameterize every route or tag unless it meaningfully changes between environments.
- ```yaml
- NatGateway:
- Type: AWS::EC2::NatGateway
- Properties:
- AllocationId: !GetAtt EIP.AllocationId
- SubnetId: !Ref PublicSubnet
+ ### 4. Export only what consumers really need
- EIP:
- Type: AWS::EC2::EIP
+ Typical outputs are:
+ - VPC ID
+ - public, private, and isolated subnet IDs
+ - route table IDs when downstream stacks must attach routes
+ - security boundaries or prefix-list references only when another stack consumes them
- PrivateRouteTable:
- Type: AWS::EC2::RouteTable
- Properties:
- VpcId: !Ref VPC
+ Stable outputs make application stacks easier to compose and migrate.
- PrivateRoute:
- Type: AWS::EC2::Route
- Properties:
- RouteTableId: !Ref PrivateRouteTable
- DestinationCidrBlock: 0.0.0.0/0
- NatGatewayId: !Ref NatGateway
- ```
+ ### 5. Validate networking behavior, not just template syntax
- For complete production-ready examples, see [EXAMPLES.md](references/examples.md).
+ Before rollout:
+ - validate the template and review change sets
+ - confirm subnet associations and default routes are correct
+ - check NAT placement and expected egress paths
+ - verify endpoint routes or prefix lists for private AWS service access
+ - review overlapping CIDR or peering implications when integrating with existing networks
- ## Quick Start
+ ## Examples
- ### Basic VPC with Public Subnet
+ ### Example 1: Two-tier VPC baseline
```yaml
- AWSTemplateFormatVersion: 2010-09-09
- Description: Simple VPC with public subnet
-
Resources:
- VPC:
+ Vpc:
Type: AWS::EC2::VPC
Properties:
CidrBlock: 10.0.0.0/16
EnableDnsHostnames: true
EnableDnsSupport: true
- Tags:
- - Key: Name
- Value: !Sub ${AWS::StackName}-vpc
- PublicSubnet:
- Type: AWS::EC2::Subnet
- Properties:
- VpcId: !Ref VPC
- CidrBlock: 10.0.1.0/24
- AvailabilityZone: !Select [0, !GetAZs '']
- MapPublicIpOnLaunch: true
- Tags:
- - Key: Name
- Value: !Sub ${AWS::StackName}-public-subnet
-
- InternetGateway:
- Type: AWS::EC2::InternetGateway
- Properties:
- Tags:
- - Key: Name
- Value: !Sub ${AWS::StackName}-igw
-
- VPCGatewayAttachment:
- Type: AWS::EC2::VPCGatewayAttachment
- Properties:
- VpcId: !Ref VPC
- InternetGatewayId: !Ref InternetGateway
-
- PublicRouteTable:
- Type: AWS::EC2::RouteTable
- Properties:
- VpcId: !Ref VPC
- Tags:
- - Key: Name
- Value: !Sub ${AWS::StackName}-public-rt
-
- DefaultPublicRoute:
- Type: AWS::EC2::Route
- DependsOn: VPCGatewayAttachment
- Properties:
- RouteTableId: !Ref PublicRouteTable
- DestinationCidrBlock: 0.0.0.0/0
- GatewayId: !Ref InternetGateway
-
- PublicSubnetRouteTableAssociation:
- Type: AWS::EC2::SubnetRouteTableAssociation
- Properties:
- SubnetId: !Ref PublicSubnet
- RouteTableId: !Ref PublicRouteTable
- ```
-
- ### VPC with Public and Private Subnets
-
- ```yaml
- AWSTemplateFormatVersion: 2010-09-09
- Description: VPC with public and private subnets across multiple AZs
-
- Parameters:
- EnvironmentName:
- Type: String
- Default: production
- Description: Environment name for resource tagging
-
- VpcCidr:
- Type: String
- Default: 10.0.0.0/16
- Description: CIDR block for the VPC
-
- Resources:
- VPC:
- Type: AWS::EC2::VPC
- Properties:
- CidrBlock: !Ref VpcCidr
- EnableDnsHostnames: true
- EnableDnsSupport: true
- Tags:
- - Key: Environment
- Value: !Ref EnvironmentName
- - Key: Name
- Value: !Sub ${AWS::StackName}-vpc
-
- InternetGateway:
- Type: AWS::EC2::InternetGateway
- Properties:
- Tags:
- - Key: Environment
- Value: !Ref EnvironmentName
- - Key: Name
- Value: !Sub ${AWS::StackName}-igw
-
- VPCGatewayAttachment:
- Type: AWS::EC2::VPCGatewayAttachment
- Properties:
- VpcId: !Ref VPC
- InternetGatewayId: !Ref InternetGateway
-
- # Public Subnet 1
- PublicSubnet1:
+ PublicSubnetA:
Type: AWS::EC2::Subnet
Properties:
- VpcId: !Ref VPC
+ VpcId: !Ref Vpc
CidrBlock: 10.0.1.0/24
- AvailabilityZone: !Select [0, !GetAZs '']
MapPublicIpOnLaunch: true
- Tags:
- - Key: Environment
- Value: !Ref EnvironmentName
- - Key: SubnetType
- Value: Public
- - Key: Name
- Value: !Sub ${AWS::StackName}-public-1
-
- PublicRouteTable1:
- Type: AWS::EC2::RouteTable
- Properties:
- VpcId: !Ref VPC
- Tags:
- - Key: Environment
- Value: !Ref EnvironmentName
- - Key: Name
- Value: !Sub ${AWS::StackName}-public-rt-1
-
- DefaultPublicRoute1:
- Type: AWS::EC2::Route
- DependsOn: VPCGatewayAttachment
- Properties:
- RouteTableId: !Ref PublicRouteTable1
- DestinationCidrBlock: 0.0.0.0/0
- GatewayId: !Ref InternetGateway
-
- PublicSubnetRouteTableAssociation1:
- Type: AWS::EC2::SubnetRouteTableAssociation
- Properties:
- SubnetId: !Ref PublicSubnet1
- RouteTableId: !Ref PublicRouteTable1
+ AvailabilityZone: !Select [0, !GetAZs ""]
- # Private Subnet 1
- PrivateSubnet1:
+ PrivateSubnetA:
Type: AWS::EC2::Subnet
Properties:
- VpcId: !Ref VPC
- CidrBlock: 10.0.10.0/24
- AvailabilityZone: !Select [0, !GetAZs '']
- Tags:
- - Key: Environment
- Value: !Ref EnvironmentName
- - Key: SubnetType
- Value: Private
- - Key: Name
- Value: !Sub ${AWS::StackName}-private-1
-
- PrivateRouteTable1:
- Type: AWS::EC2::RouteTable
- Properties:
- VpcId: !Ref VPC
- Tags:
- - Key: Environment
- Value: !Ref EnvironmentName
- - Key: Name
- Value: !Sub ${AWS::StackName}-private-rt-1
-
- PrivateSubnetRouteTableAssociation1:
- Type: AWS::EC2::SubnetRouteTableAssociation
- Properties:
- SubnetId: !Ref PrivateSubnet1
- RouteTableId: !Ref PrivateRouteTable1
-
- Outputs:
- VpcId:
- Description: VPC ID
- Value: !Ref VPC
- Export:
- Name: !Sub ${AWS::StackName}-VpcId
-
- PublicSubnet1Id:
- Description: Public Subnet 1 ID
- Value: !Ref PublicSubnet1
- Export:
- Name: !Sub ${AWS::StackName}-PublicSubnet1Id
-
- PrivateSubnet1Id:
- Description: Private Subnet 1 ID
- Value: !Ref PrivateSubnet1
- Export:
- Name: !Sub ${AWS::StackName}-PrivateSubnet1Id
- ```
-
- ## Template Structure
-
- ### Template Sections Overview
-
- AWS CloudFormation templates are JSON or YAML files with specific sections. Each section serves a purpose in defining your infrastructure.
-
- ```yaml
- AWSTemplateFormatVersion: 2010-09-09 # Required - template version
- Description: Optional description string # Optional description
-
- # Section order matters for readability but CloudFormation accepts any order
- Mappings: {} # Static configuration tables
- Metadata: {} # Additional information about resources
- Parameters: {} # Input values for customization
- Rules: {} # Parameter validation rules
- Conditions: {} # Conditional resource creation
- Transform: {} # Macro processing (e.g., AWS::Serverless)
- Resources: {} # AWS resources to create (REQUIRED)
- Outputs: {} # Return values after stack creation
- ```
-
- ### Format Version
-
- The `AWSTemplateFormatVersion` identifies the template version. Current version is `2010-09-09`.
-
- ```yaml
- AWSTemplateFormatVersion: 2010-09-09
- Description: My CloudFormation Template
- ```
-
- ### Description
-
- Add a description to document the template's purpose. Must appear after the format version.
-
- ```yaml
- AWSTemplateFormatVersion: 2010-09-09
- Description: >
- This template creates a VPC with public and private subnets
- for hosting web applications. It includes:
- - Internet Gateway for public access
- - NAT Gateway for private subnet outbound access
- - Security groups for web and database tiers
- ```
-
- ### Metadata
-
- Use `Metadata` for additional information about resources or parameters.
-
- ```yaml
- Metadata:
- AWS::CloudFormation::Interface:
- ParameterGroups:
- - Label:
- default: Network Configuration
- Parameters:
- - VpcCidr
- - PublicSubnetCidr
- - PrivateSubnetCidr
- - Label:
- default: Tags
- Parameters:
- - EnvironmentName
- - ProjectName
- ParameterLabels:
- VpcCidr:
- default: VPC CIDR Block
- EnvironmentName:
- default: Environment Name
- ```
-
- ### Resources Section
-
- The `Resources` section is the only required section. It defines AWS resources to provision.
-
- ```yaml
- Resources:
- MyVPC:
- Type: AWS::EC2::VPC
- Properties:
- CidrBlock: 10.0.0.0/16
- EnableDnsHostnames: true
- EnableDnsSupport: true
- Tags:
- - Key: Name
- Value: !Sub ${AWS::StackName}-vpc
- ```
-
- ## Parameters
-
- ### Parameter Types
-
- Use AWS-specific parameter types for validation and easier selection in the console.
-
- ```yaml
- Parameters:
- VpcId:
- Type: AWS::EC2::VPC::Id
- Description: Select an existing VPC
-
- SubnetId:
- Type: AWS::EC2::Subnet::Id
- Description: Select a subnet
-
- SecurityGroupIds:
- Type: List<AWS::EC2::SecurityGroup::Id>
- Description: Select existing security groups
-
- InstanceType:
- Type: AWS::EC2::InstanceType
- Description: EC2 instance type
- Default: t3.micro
- AllowedValues:
- - t3.micro
- - t3.small
- - t3.medium
- - t3.large
-
- AmiId:
- Type: AWS::EC2::Image::Id
- Description: Select an AMI
-
- KeyName:
- Type: AWS::EC2::KeyPair::KeyName
- Description: Select an existing key pair
- ```
-
- ### Parameter Constraints
-
- Add constraints to validate parameter values.
-
- ```yaml
- Parameters:
- VpcCidr:
- Type: String
- Description: CIDR block for the VPC
- Default: 10.0.0.0/16
- AllowedPattern: ^([0-9]{1,3}\.){3}[0-9]{1,3}/[0-9]{1,2}$
- ConstraintDescription: Must be a valid CIDR block (x.x.x.x/x)
-
- InstanceCount:
- Type: Number
- Description: Number of instances to launch
- Default: 1
- MinValue: 1
- MaxValue: 10
-
- Environment:
- Type: String
- Description: Deployment environment
- Default: development
- AllowedValues:
- - development
- - staging
- - production
- ConstraintDescription: Must be development, staging, or production
- ```
-
- ### SSM Parameter Types
-
- Reference Systems Manager parameters for dynamic values.
-
- ```yaml
- Parameters:
- LatestAmiId:
- Type: AWS::SSM::Parameter::Value<AWS::EC2::Image::Id>
- Description: Latest AMI ID from SSM
- Default: /aws/service/ami-amazon-linux-latest/amzn2-ami-hvm-x86_64-gp2
- ```
-
- ## Mappings
-
- Use `Mappings` for static configuration data based on regions or other factors.
-
- ```yaml
- Mappings:
- RegionMap:
- us-east-1:
- HVM64: ami-0ff8a95407f89df2f
- HVMG2: ami-0a0c776d80e2a1f3c
- us-west-2:
- HVM64: ami-0a0c776d80e2a1f3c
- HVMG2: ami-0a0c776d80e2a1f3c
- eu-west-1:
- HVM64: ami-0ff8a95407f89df2f
- HVMG2: ami-0a0c776d80e2a1f3c
-
- EnvironmentConfig:
- development:
- InstanceType: t3.micro
- MinInstances: 1
- MaxInstances: 2
- staging:
- InstanceType: t3.small
- MinInstances: 1
- MaxInstances: 3
- production:
- InstanceType: t3.medium
- MinInstances: 2
- MaxInstances: 10
-
- Resources:
- Instance:
- Type: AWS::EC2::Instance
- Properties:
- ImageId: !FindInMap [RegionMap, !Ref AWS::Region, HVM64]
- InstanceType: !FindInMap [EnvironmentConfig, !Ref Environment, InstanceType]
- ```
-
- ## Conditions
-
- Use `Conditions` to conditionally create resources based on parameters.
-
- ```yaml
- Parameters:
- DeployNatGateway:
- Type: String
- Default: true
- AllowedValues:
- - true
- - false
-
- Environment:
- Type: String
- Default: development
- AllowedValues:
- - development
- - staging
- - production
-
- Conditions:
- ShouldDeployNat: !Equals [!Ref DeployNatGateway, true]
- IsProduction: !Equals [!Ref Environment, production]
-
- Resources:
- NatGateway:
- Type: AWS::EC2::NatGateway
- Condition: ShouldDeployNat
- Properties:
- AllocationId: !If
- - ShouldDeployNat
- - !GetAtt EIP.AllocationId
- - !Ref AWS::NoValue
- SubnetId: !Ref PublicSubnet
-
- ProductionOnlyResource:
- Type: AWS::EC2::VPCEndpoint
- Condition: IsProduction
- Properties:
- ServiceName: !Sub com.amazonaws.${AWS::Region}.s3
- VpcId: !Ref VPC
- ```
-
- ## Transform
-
- Use `Transform` for macros like AWS::Serverless for SAM templates.
-
- ```yaml
- AWSTemplateFormatVersion: 2010-09-09
- Transform: AWS::Serverless-2016-10-31
- Description: SAM template for serverless application
-
- Resources:
- MyFunction:
- Type: AWS::Serverless::Function
- Properties:
- Handler: index.handler
- Runtime: nodejs18.x
- CodeUri: function/
- Events:
- ApiEvent:
- Type: Api
- Properties:
- Path: /{proxy+}
- Method: ANY
- ```
-
- ## Outputs and Cross-Stack References
-
- ### Basic Outputs
-
- ```yaml
- Outputs:
- VpcId:
- Description: VPC ID
- Value: !Ref VPC
-
- PublicSubnetId:
- Description: Public Subnet ID
- Value: !Ref PublicSubnet
-
- VpcCidr:
- Description: VPC CIDR Block
- Value: !GetAtt VPC.CidrBlock
+ VpcId: !Ref Vpc
+ CidrBlock: 10.0.11.0/24
+ AvailabilityZone: !Select [0, !GetAZs ""]
```
- ### Exporting Values for Cross-Stack References
+ Use this as the base layer, then add route tables, gateway attachments, and endpoint resources explicitly.
- Export values so other stacks can import them.
+ ### Example 2: Export subnet IDs for application stacks
```yaml
Outputs:
- VpcId:
- Description: VPC ID for other stacks
- Value: !Ref VPC
- Export:
- Name: !Sub ${AWS::StackName}-VpcId
-
- PublicSubnetIds:
- Description: Comma-separated public subnet IDs
- Value: !Join [",", [!Ref PublicSubnet1, !Ref PublicSubnet2]]
- Export:
- Name: !Sub ${AWS::StackName}-PublicSubnetIds
-
PrivateSubnetIds:
- Description: Comma-separated private subnet IDs
- Value: !Join [",", [!Ref PrivateSubnet1, !Ref PrivateSubnet2]]
- Export:
- Name: !Sub ${AWS::StackName}-PrivateSubnetIds
- ```
-
- ### Importing Values in Another Stack
-
- ```yaml
- Parameters:
- VpcId:
- Type: AWS::EC2::VPC::Id
- Description: VPC ID from network stack
- # User selects from exported values in console
-
- # Or use Fn::ImportValue for programmatic access
- Resources:
- SecurityGroup:
- Type: AWS::EC2::SecurityGroup
- Properties:
- VpcId: !ImportValue
- Fn::Sub: ${NetworkStackName}-VpcId
- GroupDescription: Security group for application
- ```
-
- ### Cross-Stack Reference Pattern
-
- Create a dedicated network stack that exports values:
-
- ```yaml
- # network-stack.yaml
- AWSTemplateFormatVersion: 2010-09-09
- Description: Network infrastructure stack
-
- Resources:
- VPC:
- Type: AWS::EC2::VPC
- Properties:
- CidrBlock: 10.0.0.0/16
- Tags:
- - Key: Name
- Value: !Sub ${AWS::StackName}-vpc
-
- PublicSubnets:
- Type: AWS::EC2::Subnet
- Properties:
- VpcId: !Ref VPC
- CidrBlock: 10.0.1.0/24
- AvailabilityZone: !Select [0, !GetAZs '']
- MapPublicIpOnLaunch: true
-
- Outputs:
- VpcId:
- Value: !Ref VPC
- Export:
- Name: !Sub ${AWS::StackName}-VpcId
-
- PublicSubnetIds:
- Value: !Ref PublicSubnets
+ Description: Private subnets for ECS, Lambda, or RDS workloads
+ Value: !Join [",", [!Ref PrivateSubnetA, !Ref PrivateSubnetB]]
Export:
- Name: !Sub ${AWS::StackName}-PublicSubnetIds
- ```
-
- Application stack imports these values:
-
- ```yaml
- # application-stack.yaml
- AWSTemplateFormatVersion: 2010-09-09
- Description: Application stack that imports from network
-
- Parameters:
- NetworkStackName:
- Type: String
- Description: Name of the network stack
- Default: network-stack
-
- Resources:
- Instance:
- Type: AWS::EC2::Instance
- Properties:
- SubnetId: !ImportValue
- Fn::Sub: ${NetworkStackName}-PublicSubnetIds
- InstanceType: t3.micro
+ Name: !Sub "${AWS::StackName}-PrivateSubnetIds"
```
- ## VPC Components
-
- ### VPC with All Components
-
- ```yaml
- AWSTemplateFormatVersion: 2010-09-09
- Description: Complete VPC with public/private subnets, NAT, and IGW
-
- Parameters:
- EnvironmentName:
- Type: String
- Default: production
-
- Resources:
- # VPC
- VPC:
- Type: AWS::EC2::VPC
- Properties:
- CidrBlock: 10.0.0.0/16
- EnableDnsHostnames: true
- EnableDnsSupport: true
- Tags:
- - Key: Name
- Value: !Sub ${EnvironmentName}-vpc
- - Key: Environment
- Value: !Ref EnvironmentName
-
- # Internet Gateway
- InternetGateway:
- Type: AWS::EC2::InternetGateway
- Properties:
- Tags:
- - Key: Name
- Value: !Sub ${EnvironmentName}-igw
- - Key: Environment
- Value: !Ref EnvironmentName
-
- InternetGatewayAttachment:
- Type: AWS::EC2::VPCGatewayAttachment
- Properties:
- VpcId: !Ref VPC
- InternetGatewayId: !Ref InternetGateway
-
- # NAT Gateway (with EIP)
- NatGatewayEIP:
- Type: AWS::EC2::EIP
- DependsOn: InternetGatewayAttachment
- Properties:
- Domain: vpc
- Tags:
- - Key: Name
- Value: !Sub ${EnvironmentName}-nat-eip
-
- NatGateway:
- Type: AWS::EC2::NatGateway
- Properties:
- AllocationId: !GetAtt NatGatewayEIP.AllocationId
- SubnetId: !Ref PublicSubnet1
- Tags:
- - Key: Name
- Value: !Sub ${EnvironmentName}-nat-gw
- - Key: Environment
- Value: !Ref EnvironmentName
-
- # Public Subnets
- PublicSubnet1:
- Type: AWS::EC2::Subnet
- Properties:
- VpcId: !Ref VPC
- CidrBlock: 10.0.1.0/24
- AvailabilityZone: !Select [0, !GetAZs '']
- MapPublicIpOnLaunch: true
- Tags:
- - Key: Name
- Value: !Sub ${EnvironmentName}-public-1
- - Key: SubnetType
- Value: Public
-
- PublicSubnet2:
- Type: AWS::EC2::Subnet
- Properties:
- VpcId: !Ref VPC
- CidrBlock: 10.0.2.0/24
- AvailabilityZone: !Select [1, !GetAZs '']
- MapPublicIpOnLaunch: true
- Tags:
- - Key: Name
- Value: !Sub ${EnvironmentName}-public-2
- - Key: SubnetType
- Value: Public
-
- # Private Subnets
- PrivateSubnet1:
- Type: AWS::EC2::Subnet
- Properties:
- VpcId: !Ref VPC
- CidrBlock: 10.0.10.0/24
- AvailabilityZone: !Select [0, !GetAZs '']
- Tags:
- - Key: Name
- Value: !Sub ${EnvironmentName}-private-1
- - Key: SubnetType
- Value: Private
-
- PrivateSubnet2:
- Type: AWS::EC2::Subnet
- Properties:
- VpcId: !Ref VPC
- CidrBlock: 10.0.11.0/24
- AvailabilityZone: !Select [1, !GetAZs '']
- Tags:
- - Key: Name
- Value: !Sub ${EnvironmentName}-private-2
- - Key: SubnetType
- Value: Private
-
- # Public Route Table
- PublicRouteTable:
- Type: AWS::EC2::RouteTable
- Properties:
- VpcId: !Ref VPC
- Tags:
- - Key: Name
- Value: !Sub ${EnvironmentName}-public-rt
-
- DefaultPublicRoute:
- Type: AWS::EC2::Route
- DependsOn: InternetGatewayAttachment
- Properties:
- RouteTableId: !Ref PublicRouteTable
- DestinationCidrBlock: 0.0.0.0/0
- GatewayId: !Ref InternetGateway
-
- PublicSubnetRouteTableAssociation1:
- Type: AWS::EC2::SubnetRouteTableAssociation
- Properties:
- SubnetId: !Ref PublicSubnet1
- RouteTableId: !Ref PublicRouteTable
-
- PublicSubnetRouteTableAssociation2:
- Type: AWS::EC2::SubnetRouteTableAssociation
- Properties:
- SubnetId: !Ref PublicSubnet2
- RouteTableId: !Ref PublicRouteTable
-
- # Private Route Table (with NAT)
- PrivateRouteTable:
- Type: AWS::EC2::RouteTable
- Properties:
- VpcId: !Ref VPC
- Tags:
- - Key: Name
- Value: !Sub ${EnvironmentName}-private-rt
-
- DefaultPrivateRoute:
- Type: AWS::EC2::Route
- Properties:
- RouteTableId: !Ref PrivateRouteTable
- DestinationCidrBlock: 0.0.0.0/0
- NatGatewayId: !Ref NatGateway
-
- PrivateSubnetRouteTableAssociation1:
- Type: AWS::EC2::SubnetRouteTableAssociation
- Properties:
- SubnetId: !Ref PrivateSubnet1
- RouteTableId: !Ref PrivateRouteTable
-
- PrivateSubnetRouteTableAssociation2:
- Type: AWS::EC2::SubnetRouteTableAssociation
- Properties:
- SubnetId: !Ref PrivateSubnet2
- RouteTableId: !Ref PrivateRouteTable
-
- Outputs:
- VpcId:
- Value: !Ref VPC
- Export:
- Name: !Sub ${EnvironmentName}-VpcId
-
- InternetGatewayId:
- Value: !Ref InternetGateway
- Export:
- Name: !Sub ${EnvironmentName}-InternetGatewayId
-
- PublicSubnetIds:
- Value: !Join [",", [!Ref PublicSubnet1, !Ref PublicSubnet2]]
- Export:
- Name: !Sub ${EnvironmentName}-PublicSubnetIds
-
- PrivateSubnetIds:
- Value: !Join [",", [!Ref PrivateSubnet1, !Ref PrivateSubnet2]]
- Export:
- Name: !Sub ${EnvironmentName}-PrivateSubnetIds
-
- NatGatewayId:
- Value: !Ref NatGateway
- Export:
- Name: !Sub ${EnvironmentName}-NatGatewayId
- ```
+ If consumers need a list object rather than a joined string, prefer nested stacks or stack parameters over brittle parsing in downstream templates.
## Best Practices
- ### Use AWS-Specific Parameter Types
-
- Always use AWS-specific parameter types for validation and easier selection.
-
- ```yaml
- Parameters:
- VpcId:
- Type: AWS::EC2::VPC::Id
- Description: Select a VPC
-
- SubnetIds:
- Type: List<AWS::EC2::Subnet::Id>
- Description: Select subnets
-
- SecurityGroupIds:
- Type: List<AWS::EC2::SecurityGroup::Id>
- Description: Select security groups
- ```
-
- ### Organize by Lifecycle
-
- Separate resources that change at different rates into different stacks.
-
- ```yaml
- # Network stack - rarely changes
- AWSTemplateFormatVersion: 2010-09-09
- Description: Network infrastructure (VPC, subnets, routes)
- Resources:
- VPC: AWS::EC2::VPC
- Subnets: AWS::EC2::Subnet
- RouteTables: AWS::EC2::RouteTable
-
- # Application stack - changes frequently
- AWSTemplateFormatVersion: 2010-09-09
- Description: Application resources
- Parameters:
- NetworkStackName:
- Type: String
- Resources:
- Instances: AWS::EC2::Instance
- ```
-
- ### Use Meaningful Names
-
- Use `AWS::StackName` and parameters for consistent naming.
-
- ```yaml
- Resources:
- VPC:
- Type: AWS::EC2::VPC
- Properties:
- Tags:
- - Key: Name
- Value: !Sub ${AWS::StackName}-vpc
- - Key: Environment
- Value: !Ref EnvironmentName
- ```
-
- ### Use Pseudo Parameters
-
- Use pseudo parameters for region-agnostic templates.
-
- ```yaml
- Resources:
- S3Bucket:
- Type: AWS::S3::Bucket
- Properties:
- BucketName: !Sub ${AWS::StackName}-${AWS::AccountId}-${AWS::Region}
-
- LambdaFunction:
- Type: AWS::Lambda::Function
- Properties:
- Runtime: nodejs18.x
- Handler: index.handler
- Role: !GetAtt LambdaExecutionRole.Arn
- ```
-
- ### Validate Before Deployment
-
- ```bash
- # Validate template
- aws cloudformation validate-template --template-body file://template.yaml
-
- # Check for syntax errors
- aws cloudformation validate-template \
- --template-body file://template.yaml \
- --query 'Description'
-
- # Use cfn-lint for advanced validation
- pip install cfn-lint
- cfn-lint template.yaml
- ```
-
- ### Stack Policies
-
- Stack Policies prevent unintentional updates to critical resources. Use them to protect production infrastructure.
-
- ```json
- {
- "Statement": [
- {
- "Effect": "Allow",
- "Action": "Update:*",
- "Principal": "*",
- "Resource": "*"
- },
- {
- "Effect": "Deny",
- "Action": ["Update:Replace", "Update:Delete"],
- "Principal": "*",
- "Resource": "LogicalId=ProductionDatabase"
- },
- {
- "Effect": "Deny",
- "Action": "Update:Replace",
- "Principal": "*",
- "Resource": "LogicalId=VPC"
- }
- ]
- }
- ```
-
- Apply the stack policy:
-
- ```bash
- aws cloudformation set-stack-policy \
- --stack-name my-production-stack \
- --stack-policy-body file://stack-policy.json
- ```
-
- **Common Stack Policy Use Cases:**
-
- - **Protect database resources**: Prevent accidental replacement of RDS instances
- - **Protect VPC infrastructure**: Prevent changes that could disrupt connectivity
- - **Protect IAM roles**: Prevent modifications that could break authorization
-
- ### Termination Protection
-
- Enable termination protection to prevent accidental stack deletion. This is critical for production environments.
-
- **Enable via AWS Console:**
- 1. Go to CloudFormation > Stacks
- 2. Select your stack
- 3. Click "Stack actions" > "Enable termination protection"
-
- **Enable via AWS CLI:**
-
- ```bash
- # Enable termination protection
- aws cloudformation update-termination-protection \
- --stack-name my-production-stack \
- --enable-termination-protection
-
- # Disable termination protection (requires console access)
- aws cloudformation update-termination-protection \
- --stack-name my-production-stack \
- --no-enable-termination-protection
- ```
-
- **Enable via CloudFormation (for new stacks):**
-
- ```yaml
- Resources:
- ProductionStack:
- Type: AWS::CloudFormation::Stack
- Properties:
- TemplateURL: https://s3.amazonaws.com/my-bucket/production.yaml
- TerminationProtection: true
- ```
-
- **Important Considerations:**
- - Termination protection does not prevent stack updates
- - To delete a protected stack, you must first disable termination protection
- - Nested stacks inherit termination protection from parent stacks
- - Always enable for production and staging environments
-
- ### Drift Detection
-
- Drift detection identifies differences between your CloudFormation stack and the actual infrastructure. Run regular drift checks to ensure compliance.
-
- **Detect Drift on a Stack:**
-
- ```bash
- # Detect drift on a stack
- aws cloudformation detect-drift \
- --stack-name my-vpc-stack
-
- # Check drift status
- aws cloudformation describe-stack-drift-detection-status \
- --stack-drift-detection-id <detection-id>
-
- # Get drift detection results
- aws cloudformation describe-stack-resource-drifts \
- --stack-name my-vpc-stack
- ```
-
- **Drift Status Values:**
- - `IN_SYNC`: Resource matches the template
- - `DRIFTED`: Resource has been modified outside CloudFormation
- - `NOT_CHECKED`: Resource was not checked
- - `UNKNOWN`: Drift status could not be determined
-
- **Automated Drift Detection with Events:**
-
- ```yaml
- # Use AWS Config for continuous drift monitoring
- Resources:
- ConfigRule:
- Type: AWS::Config::ConfigRule
- Properties:
- ConfigRuleName: cloudformation-drift-detection
- Scope:
- ComplianceResourceTypes:
- - AWS::EC2::VPC
- - AWS::EC2::Subnet
- - AWS::EC2::SecurityGroup
- Source:
- Owner: CUSTOM_LAMBDA
- SourceIdentifier:
- Fn::GetAtt: [DriftDetectionFunction, Arn]
- ```
-
- **Best Practices for Drift Detection:**
- - Run drift detection weekly for production stacks
- - Set up CloudWatch Events to trigger drift detection on schedule
- - Document and address all drift immediately
- - Use drift detection as part of change management process
-
- ### Change Sets
-
- Change Sets allow you to preview stack changes before applying them. This is essential for production deployments.
-
- **Create and Review a Change Set:**
-
- ```bash
- # Create a change set
- aws cloudformation create-change-set \
- --stack-name my-vpc-stack \
- --template-body file://updated-template.yaml \
- --change-set-name vpc-update-changeset \
- --capabilities CAPABILITY_IAM
-
- # List change sets
- aws cloudformation list-change-sets \
- --stack-name my-vpc-stack
-
- # Describe change set
- aws cloudformation describe-change-set \
- --stack-name my-vpc-stack \
- --change-set-name vpc-update-changeset
-
- # Execute change set
- aws cloudformation execute-change-set \
- --stack-name my-vpc-stack \
- --change-set-name vpc-update-changeset
-
- # Delete change set (if not executing)
- aws cloudformation delete-change-set \
- --stack-name my-vpc-stack \
- --change-set-name vpc-update-changeset
- ```
-
- **Change Set Types:**
-
- | Type | Description | Use Case |
- |------|-------------|----------|
- | `UPDATE` | Standard update | Regular changes |
- | `CREATE` | Creates new stack | Initial deployment |
- | `IMPORT` | Imports existing resources | Lift-and-shift |
-
- **Change Set Output Example:**
-
- ```json
- {
- "ChangeSetId": "arn:aws:cloudformation:us-east-1:123456789:changeSet/...",
- "Changes": [
- {
- "Type": "Resource",
- "ResourceChange": {
- "Action": "Modify",
- "LogicalResourceId": "VPC",
- "PhysicalResourceId": "vpc-12345678",
- "Replacement": "False",
- "Details": [
- {
- "Target": {
- "Attribute": "Tags",
- "RequiresRecreation": "Never"
- },
- "Evaluation": "Static",
- "ChangeSource": "DirectModification"
- }
- ]
- }
- }
- ],
- "ExecutionStatus": "AVAILABLE",
- "Status": "CREATE_COMPLETE"
- }
- ```
-
- **Best Practices for Change Sets:**
- - Always create a change set before updating production stacks
- - Review all changes carefully before execution
- - Use meaningful change set names (e.g., `vpc-security-update-2024-01`)
- - Execute change sets promptly after review
- - Set a TTL on change sets if your organization requires approval workflows
-
- ### CI/CD Integration with Change Sets
-
- ```yaml
- # GitHub Actions workflow for safe deployments
- name: Deploy CloudFormation
- on:
- push:
- branches: [main]
-
- jobs:
- deploy:
- runs-on: ubuntu-latest
- steps:
- - uses: actions/checkout@v4
-
- - name: Configure AWS Credentials
- uses: aws-actions/configure-aws-credentials@v4
- with:
- role-to-assume: arn:aws:iam::123456789:role/GitHubActionsRole
- aws-region: us-east-1
-
- - name: Create Change Set
- id: changeset
- run: |
- aws cloudformation create-change-set \
- --stack-name ${{ env.STACK_NAME }} \
- --template-body file://template.yaml \
- --change-set-name preview-changes \
- --capabilities CAPABILITY_IAM \
- --query 'Id' \
- --output text
-
- - name: Describe Change Set
- run: |
- aws cloudformation describe-change-set \
- --stack-name ${{ env.STACK_NAME }} \
- --change-set-name preview-changes
-
- - name: Execute Change Set (Manual approval required)
- if: github.event_name == 'push' && github.ref == 'refs/heads/main'
- run: |
- aws cloudformation execute-change-set \
- --stack-name ${{ env.STACK_NAME }} \
- --change-set-name preview-changes
- ```
-
- ## Related Resources
-
- - For advanced patterns: See [EXAMPLES.md](references/examples.md)
- - For reference: See [REFERENCE.md](references/reference.md)
- - AWS CloudFormation User Guide: https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/
- - AWS VPC Documentation: https://docs.aws.amazon.com/vpc/latest/userguide/
+ - Keep public, private, and isolated subnet purposes explicit in names and tags.
+ - Prefer one NAT gateway per AZ for resilient production environments when the budget allows it.
+ - Use VPC endpoints to reduce unnecessary NAT traffic for AWS service access.
+ - Export VPC and subnet identifiers from the network stack instead of recreating network assumptions elsewhere.
+ - Review network changes with dependency stacks because route and subnet changes can have broad blast radius.
+ - Keep the root skill focused and move larger networking variants to `references/examples.md`.
## Constraints and Warnings
- ### Resource Limits
-
- - **VPC Limits**: Maximum 5 VPCs per region (soft limit, can be increased)
- - **Subnet Limits**: Maximum 200 subnets per VPC
- - **Route Table Limits**: Maximum 200 route tables per VPC
- - **Internet Gateway**: One Internet Gateway per VPC
- - **NAT Gateway**: One NAT Gateway per availability zone
-
- ### Network Constraints
-
- - **CIDR Overlap**: VPC CIDR blocks cannot overlap with peered VPCs or connected networks
- - **CIDR Changes**: VPC CIDR blocks cannot be modified after creation; recreation required
- - **Subnet Sizing**: Subnet CIDR ranges cannot be changed after subnet creation
- - **Route Propagation**: Route propagation affects all routes in the route table
-
- ### Security Constraints
-
- - **Security Group Limits**: Maximum 60 inbound and 60 outbound rules per security group
- - **NACL Stateless**: Network ACLs are stateless; return traffic must be explicitly allowed
- - **Flow Logs Costs**: VPC Flow Logs can generate significant CloudWatch Logs costs
- - **Security Group References**: Security group references cannot span VPC peering in some configurations
-
- ### Operational Constraints
-
- - **Subnet Isolation**: Subnets cannot be moved between AZs after creation
- - **Gateway Attachments**: attaching/detaching Internet Gateways and VPGs takes time
- - **Peering Limitations**: VPC peering has limitations with transitive routing
- - **VPN Connections**: Site-to-Site VPN connections have bandwidth limitations
-
- ### Cost Considerations
+ - NAT gateways can dominate network cost in small environments.
+ - CIDR overlap blocks peering, transit, and future network expansion.
+ - Route-table or subnet replacements can interrupt traffic even when the template is valid.
+ - Endpoint quotas, AZ availability, and service-specific subnet requirements vary by region.
+ - Hardcoding Availability Zones can reduce portability across accounts and regions.
- - **NAT Gateway**: NAT gateways incur hourly costs plus data processing per GB
- - **Transit Gateway**: Transit Gateway attachments incur per-AZ hourly and data transfer costs
- - **PrivateLink**: Interface VPC endpoints incur hourly and per-GB data processing costs
- - **Traffic Mirroring**: Traffic mirroring doubles network costs
+ ## References
- ### Availability Constraints
+ - `references/examples.md`
+ - `references/reference.md`
- - **Multi-AZ Requirements**: Resources should be distributed across multiple AZs for HA
- - **AZ Isolation**: Entire AZ failures can affect applications not distributed across AZs
- - **Gateway Redundancy**: Internet Gateways and NAT Gateways are single points of failure within AZ
- - **Route Table Limits**: Associate each subnet with only one route table
+ ## Related Skills
- ## Additional Files
+ - `aws-cloudformation-ec2`
+ - `aws-cloudformation-rds`
+ - `aws-cloudformation-ecs`
+ - `aws-cloudformation-security`