Создание VPC с CloudFormation: 2 публичных и 2 приватных подсети
В этой статье показано, как подготовить шаблон CloudFormation и развернуть стек, который создаёт VPC с подсетями, маршрутными таблицами, Интернет-шлюзом и NAT-шлюзами. Внимание: исходный шаблон в этом руководстве создаёт по три публичные и приватные подсети; в тексте уточнено отличие от заголовка и предлагаются варианты для двух подсетей.
Введение
CloudFormation позволяет описывать и управлять ресурсами AWS текстовым шаблоном в формате YAML или JSON. Шаблон обеспечивает воспроизводимость инфраструктуры, уменьшает ручные операции и делает процессы единообразными.
Короткое определение: шаблон — это файл YAML/JSON, который описывает ресурсы AWS и их связи.
Предварительные требования
- Учетная запись AWS (создайте, если ещё нет).
- Базовое понимание шаблонов CloudFormation.
Что мы сделаем
- Войдём в AWS Console.
- Подготовим шаблон CloudFormation.
- Создадим стек CloudFormation и проверим ресурсы.
Вход в AWS
- Перейдите на страницу входа в AWS.
Когда вы откроете страницу входа, введите свои учётные данные.

После успешного входа вы увидите консоль с перечнем сервисов.

Создание шаблона
Ниже приведён пример шаблона. Скопируйте его и сохраните локально. Обратите внимание: в самом шаблоне заданы 3 публичные и 3 приватные подсети — это важно для понимания результатов развертывания.
---
AWSTemplateFormatVersion: 2010-09-09
Description: >
This Templates creates a VPC with 3 public and 3 private subnets.
Parameters:
VpcCIDR:
Type: String
Description: VPC CIDR (Do Not Change if no customization is required).
Default: 10.10.0.0/16
PrivateAZ1SubnetCIDR:
Type: String
Description: Subnet CIDR for 1st Availability Zone (Do Not Change if no customization is required).
Default: 10.10.80.0/21
PrivateAZ2SubnetCIDR:
Type: String
Description: Subnet CIDR for 2nd Availability Zone (Do Not Change if no customization is required).
Default: 10.10.88.0/21
PrivateAZ3SubnetCIDR:
Type: String
Description: Subnet CIDR for 3rd Availability Zone (Do Not Change if no customization is required).
Default: 10.10.96.0/21
PublicAZ1SubnetCIDR:
Type: String
Description: Subnet CIDR for 1st Availability Zone (Do Not Change if no customization is required).
Default: 10.10.0.0/21
PublicAZ2SubnetCIDR:
Type: String
Description: Subnet CIDR for 2nd Availability Zone (Do Not Change if no customization is required).
Default: 10.10.8.0/21
PublicAZ3SubnetCIDR:
Type: String
Description: Subnet CIDR for 3rd Availability Zone (Do Not Change if no customization is required).
Default: 10.10.16.0/21
Metadata:
AWS::CloudFormation::Interface:
ParameterGroups:
- Label:
default: VPC
Parameters:
- VpcCIDR
- Label:
default: Availabilty Zone 1
Parameters:
- PublicAZ1SubnetCIDR
- PrivateAZ1SubnetCIDR
- Label:
default: Availabilty Zone 1
Parameters:
- PublicAZ2SubnetCIDR
- PrivateAZ2SubnetCIDR
- Label:
default: Availabilty Zone 1
Parameters:
- PublicAZ3SubnetCIDR
- PrivateAZ3SubnetCIDR
Resources:
Vpc:
Type: AWS::EC2::VPC
Properties:
CidrBlock: !Ref VpcCIDR
Tags:
- Key: Name
Value: !Sub ${AWS::StackName}
InternetGateway:
Type: AWS::EC2::InternetGateway
Properties:
Tags:
- Key: Name
Value: !Sub ${AWS::StackName}
VPCGatewayAttachment:
Type: AWS::EC2::VPCGatewayAttachment
Properties:
InternetGatewayId: !Ref InternetGateway
VpcId: !Ref Vpc
# Public Subnets - Route Table
PublicRouteTable:
Type: AWS::EC2::RouteTable
Properties:
VpcId: !Ref Vpc
Tags:
- Key: Name
Value: !Sub ${AWS::StackName}-public
- Key: Type
Value: public
PublicSubnetsRoute:
Type: AWS::EC2::Route
Properties:
RouteTableId: !Ref PublicRouteTable
DestinationCidrBlock: 0.0.0.0/0
GatewayId: !Ref InternetGateway
DependsOn: VPCGatewayAttachment
# Public Subnets
PublicAZ1Subnet:
Type: AWS::EC2::Subnet
Properties:
VpcId: !Ref Vpc
CidrBlock: !Ref PublicAZ1SubnetCIDR
AvailabilityZone: !Select [0, !GetAZs ""]
MapPublicIpOnLaunch: true
Tags:
- Key: Name
Value: !Sub
- ${AWS::StackName}-public-${AZ}
- { AZ: !Select [0, !GetAZs ""] }
- Key: Type
Value: public
PublicAZ1SubnetRouteTableAssociation:
Type: AWS::EC2::SubnetRouteTableAssociation
Properties:
SubnetId: !Ref PublicAZ1Subnet
RouteTableId: !Ref PublicRouteTable
PublicAZ2Subnet:
Type: AWS::EC2::Subnet
Properties:
VpcId: !Ref Vpc
CidrBlock: !Ref PublicAZ2SubnetCIDR
AvailabilityZone: !Select [1, !GetAZs ""]
MapPublicIpOnLaunch: true
Tags:
- Key: Name
Value: !Sub
- ${AWS::StackName}-public-${AZ}
- { AZ: !Select [1, !GetAZs ""] }
- Key: Type
Value: public
PublicAZ2SubnetRouteTableAssociation:
Type: AWS::EC2::SubnetRouteTableAssociation
Properties:
SubnetId: !Ref PublicAZ2Subnet
RouteTableId: !Ref PublicRouteTable
PublicAZ3Subnet:
Type: AWS::EC2::Subnet
Properties:
VpcId: !Ref Vpc
CidrBlock: !Ref PublicAZ3SubnetCIDR
AvailabilityZone: !Select [2, !GetAZs ""]
MapPublicIpOnLaunch: true
Tags:
- Key: Name
Value: !Sub
- ${AWS::StackName}-public-${AZ}
- { AZ: !Select [2, !GetAZs ""] }
- Key: Type
Value: public
PublicAZ3SubnetRouteTableAssociation:
Type: AWS::EC2::SubnetRouteTableAssociation
Properties:
SubnetId: !Ref PublicAZ3Subnet
RouteTableId: !Ref PublicRouteTable
# Private Subnets - NAT Gateways
AZ1NatGatewayEIP:
Type: AWS::EC2::EIP
Properties:
Domain: vpc
DependsOn: VPCGatewayAttachment
AZ1NatGateway:
Type: AWS::EC2::NatGateway
Properties:
AllocationId: !GetAtt AZ1NatGatewayEIP.AllocationId
SubnetId: !Ref PublicAZ1Subnet
AZ2NatGatewayEIP:
Type: AWS::EC2::EIP
Properties:
Domain: vpc
DependsOn: VPCGatewayAttachment
AZ2NatGateway:
Type: AWS::EC2::NatGateway
Properties:
AllocationId: !GetAtt AZ2NatGatewayEIP.AllocationId
SubnetId: !Ref PublicAZ2Subnet
AZ3NatGatewayEIP:
Type: AWS::EC2::EIP
Properties:
Domain: vpc
DependsOn: VPCGatewayAttachment
AZ3NatGateway:
Type: AWS::EC2::NatGateway
Properties:
AllocationId: !GetAtt AZ3NatGatewayEIP.AllocationId
SubnetId: !Ref PublicAZ3Subnet
# Private Subnets
PrivateAZ1Subnet:
Type: AWS::EC2::Subnet
Properties:
VpcId: !Ref Vpc
CidrBlock: !Ref PrivateAZ1SubnetCIDR
AvailabilityZone: !Select [0, !GetAZs ""]
Tags:
- Key: Name
Value: !Sub
- ${AWS::StackName}-private-${AZ}
- { AZ: !Select [0, !GetAZs ""] }
- Key: Type
Value: private
PrivateAZ1RouteTable:
Type: AWS::EC2::RouteTable
Properties:
VpcId: !Ref Vpc
Tags:
- Key: Name
Value: !Sub
- ${AWS::StackName}-private-${AZ}
- { AZ: !Select [0, !GetAZs ""] }
- Key: Type
Value: private
PrivateAZ1Route:
Type: AWS::EC2::Route
Properties:
RouteTableId: !Ref PrivateAZ1RouteTable
DestinationCidrBlock: 0.0.0.0/0
NatGatewayId: !Ref AZ1NatGateway
PrivateAZ1RouteTableAssociation:
Type: AWS::EC2::SubnetRouteTableAssociation
Properties:
SubnetId: !Ref PrivateAZ1Subnet
RouteTableId: !Ref PrivateAZ1RouteTable
PrivateAZ2Subnet:
Type: AWS::EC2::Subnet
Properties:
VpcId: !Ref Vpc
CidrBlock: !Ref PrivateAZ2SubnetCIDR
AvailabilityZone: !Select [1, !GetAZs ""]
Tags:
- Key: Name
Value: !Sub
- ${AWS::StackName}-private-${AZ}
- { AZ: !Select [1, !GetAZs ""] }
- Key: Type
Value: private
PrivateAZ2RouteTable:
Type: AWS::EC2::RouteTable
Properties:
VpcId: !Ref Vpc
Tags:
- Key: Name
Value: !Sub
- ${AWS::StackName}-private-${AZ}
- { AZ: !Select [1, !GetAZs ""] }
- Key: Type
Value: private
PrivateAZ2Route:
Type: AWS::EC2::Route
Properties:
RouteTableId: !Ref PrivateAZ2RouteTable
DestinationCidrBlock: 0.0.0.0/0
NatGatewayId: !Ref AZ2NatGateway
PrivateAZ2RouteTableAssociation:
Type: AWS::EC2::SubnetRouteTableAssociation
Properties:
SubnetId: !Ref PrivateAZ2Subnet
RouteTableId: !Ref PrivateAZ2RouteTable
PrivateAZ3Subnet:
Type: AWS::EC2::Subnet
Properties:
VpcId: !Ref Vpc
CidrBlock: !Ref PrivateAZ3SubnetCIDR
AvailabilityZone: !Select [2, !GetAZs ""]
Tags:
- Key: Name
Value: !Sub
- ${AWS::StackName}-private-${AZ}
- { AZ: !Select [2, !GetAZs ""] }
- Key: Type
Value: private
PrivateAZ3RouteTable:
Type: AWS::EC2::RouteTable
Properties:
VpcId: !Ref Vpc
Tags:
- Key: Name
Value: !Sub
- ${AWS::StackName}-private-${AZ}
- { AZ: !Select [2, !GetAZs ""] }
- Key: Type
Value: private
PrivateAZ3Route:
Type: AWS::EC2::Route
Properties:
RouteTableId: !Ref PrivateAZ3RouteTable
DestinationCidrBlock: 0.0.0.0/0
NatGatewayId: !Ref AZ3NatGateway
PrivateAZ3RouteTableAssociation:
Type: AWS::EC2::SubnetRouteTableAssociation
Properties:
SubnetId: !Ref PrivateAZ3Subnet
RouteTableId: !Ref PrivateAZ3RouteTable
Outputs:
VpcId:
Description: VPC Id
Value: !Ref Vpc
Export:
Name: !Sub "${AWS::StackName}-VPC-ID"Important
- Несмотря на заголовок статьи, шаблон создаёт 3 публичные и 3 приватные подсети. Если вам нужны только 2 публичные и 2 приватные подсети, удалите из шаблона ресурсы, связанные с третьей AZ (PublicAZ3Subnet, AZ3NatGateway и т.д.), и скорректируйте параметры.
Создание стека CloudFormation
- В консоли AWS выберите Services и найдите CloudFormation.

- На панели нажмите Create stack → With new resources (standard).

- Загрузите локальный файл шаблона: Template is ready → Upload a template file → Choose file → Next.

- Задайте имя стека, оставьте параметры по умолчанию или при необходимости измените CIDR блоки.

- При необходимости добавьте теги.

- Нажмите Create stack и дождитесь завершения. Развёртывание займёт несколько минут.


Вы можете отслеживать события в вкладке Events.

Перейдите в сервис VPC, чтобы увидеть созданные ресурсы (VPC, подсети, маршруты, Интернет-шлюз, NAT-шлюзы).


Чтобы удалить все созданные ресурсы, просто удалите стек CloudFormation — все ресурсы, созданные через стек, будут удалены автоматически (если для них нет зависимостей вне стека).

Лучшие практики и советы
- Версионируйте шаблоны в системе контроля версий (Git).
- Тестируйте шаблон в отдельном тестовом аккаунте или в изолированной среде перед продом.
- Используйте описательные теги (Environment, Owner, Project) для ресурсов.
- Для высокодоступных решений распределяйте NAT-шлюзы по AZ или рассмотрите использование NAT-инстансов как альтернативы при ограниченном бюджете.
- Сохраняйте аккуратную структуру параметров и делайте значения по умолчанию удобными для CI/CD.
Когда такой подход не подходит (контрпримеры)
- Очень мелкие одноразовые эксперименты: проще создать ресурсы вручную.
- Нужно управлять очень сложной логикой на время выполнения — для неё чаще используют AWS CDK или Terraform с модулями.
- Если требуется мультиоблачная инфраструктура — выбирайте Terraform.
Альтернативные подходы
- AWS CDK: инфраструктура на знакомом языке программирования (TypeScript, Python, Java).
- Terraform: мультиоблачное управление ресурсами с модульной архитектурой.
- Ручное создание в консоли: быстрый способ для разовых действий.
Стоимость и влияние
- NAT Gateway тарифицируется отдельно и может существенно влиять на счёт при больших объёмах исходящего трафика. Если важна экономия, рассмотрите NAT-инстансы или централизованный NAT в отдельном AZ.
- Интернет-шлюз сам по себе бесплатен, но ресурсы, к нему подключённые, генерируют стоимость.
Роли и чек-листы
Для разработчика/инженера, разворачивающего стек:
- Проверить CIDR-планы и избежать пересечений.
- Убедиться, что шаблон синтаксически корректен (aws cloudformation validate-template).
- Тестировать в изолированной среде.
Для владельца проекта:
- Убедиться, что заданы теги Billing/Owner/Environment.
- Оценить стоимость NAT-шлюзов.
Мини-методология тестирования
- validate-template — проверка синтаксиса.
- Развёртывание в тестовом аккаунте с префиксом test-.
- Проверка созданных ресурсов через консоль и CLI (aws ec2 describe-vpcs, describe-subnets).
- Удаление стека и проверка отчистки ресурсов.
Критерии приёмки
- Стек завершил создание без ошибок.
- Созданный VPC имеет ожидаемый CIDR.
- Количество подсетей соответствует обновлённому шаблону (2 или 3 в зависимости от правок).
- Публичные подсети имеют MapPublicIpOnLaunch: true.
Безопасность и соответствие
- Ограничьте доступ к CloudFormation и правам на создание сетевых ресурсов через IAM-политики.
- Не храните чувствительные данные в шаблоне; используйте Parameter Store/Secrets Manager.
Краткий глоссарий (1 строка)
- VPC — виртуальная приватная сеть в AWS; CIDR — сетевой диапазон; NAT Gateway — сервис для исходящего доступа приватных подсетей.
Часто задаваемые вопросы
Q: Почему в шаблоне 3 подсети, если заголовок говорит про 2?
A: Шаблон, включённый в эту статью, создаёт 3 публичные и 3 приватные подсети. Если нужен вариант с двумя подсетями, удалите ресурсы для третьей зоны Availability Zone из шаблона.
Q: Как удалить все ресурсы, созданные этим шаблоном?
A: Удалите стек CloudFormation — ресурсы, связанные со стеком, будут удалены автоматически, если нет внешних зависимостей.
Q: Можно ли избежать затрат на NAT Gateway?
A: Да — использовать NAT-инстансы, централизованный NAT или proxy в зависимости от нагрузки и требований к отказоустойчивости.
Заключение
Мы рассмотрели, как подготовить и развернуть шаблон CloudFormation, который создаёт VPC с подсетями, маршрутами, Интернет- и NAT-шлюзами. Обратите внимание на несоответствие между заголовком и шаблоном и выберите нужную вам конфигурацию (2 или 3 AZ). Следуйте лучшим практикам: тестируйте шаблоны, версионируйте, отслеживайте стоимость и применяйте IAM для контроля доступа.
Короткое объявление
Это руководство показывает шаги для создания сети AWS с помощью CloudFormation: подготовка шаблона, загрузка в консоль и создание стека. Подходит для быстрой автоматизации сетевой инфраструктуры и повторяемого развёртывания.
Похожие материалы
Троян Herodotus: как он работает и как защититься
Включить новое меню «Пуск» в Windows 11
Панель полей PivotTable в Excel — руководство
Включить новый Пуск в Windows 11 — инструкция
Как убрать дубликаты Диспетчера задач Windows 11