2. AWS网络基础与IaC映射

在AWS上做网络基础设施即代码(IaC),第一步不是写代码,而是把控制台上那些“点出来”的网络对象,翻译成代码里可声明、可复用、可版本管理的资源模型。VPC、子网、路由表、网关、安全组这些组件,在控制台里是图形化的卡片和连线,在IaC里则是一组带有明确依赖关系的资源声明。理解这种映射关系,是后续用Terraform、CloudFormation或CDK正确编排网络的前提。

从控制台对象到代码资源

AWS的VPC本质上是一个逻辑隔离的虚拟网络,它由CIDR块定义地址空间。在IaC中,VPC通常映射为一个顶层资源,例如Terraform的aws_vpc,其核心参数是cidr_block和enable_dns_support等。子网(Subnet)依附于VPC,必须指定所属VPC ID和可用区,并划分自己的CIDR段。路由表(Route Table)同样属于VPC,通过关联(Association)绑定到子网,决定子网的流量去向。网关分为互联网网关(IGW)和NAT网关:IGW直接挂载到VPC,为公有子网提供双向互联网访问;NAT网关部署在公有子网中,为私有子网提供出站访问。安全组(Security Group)则作用于弹性网卡(ENI)层面,是实例级别的有状态防火墙。

这些对象在代码中的抽象方式,核心是“资源声明 + 引用关系”。IaC工具通过资源之间的属性引用自动推导依赖顺序,例如子网引用VPC的ID,路由表关联引用子网的ID,路由条目引用网关的ID。这种引用关系替代了控制台里的手动点击和拖拽,也让网络拓扑变得可审查、可回滚。

AWS网络核心组件与IaC资源映射关系 VPC aws_vpc cidr_block = "10.0.0.0/16" Internet Gateway aws_internet_gateway 公有子网 aws_subnet cidr_block = "10.0.1.0/24" availability_zone = "ap-northeast-1a" 公有路由表 aws_route_table 0.0.0.0/0 → IGW 10.0.0.0/16 → local 关联:aws_route_table_association NAT Gateway aws_nat_gateway 部署于公有子网 私有子网 aws_subnet cidr_block = "10.0.2.0/24" availability_zone = "ap-northeast-1a" 私有路由表 aws_route_table 0.0.0.0/0 → NAT GW 10.0.0.0/16 → local 关联:aws_route_table_association 安全组 aws_security_group vpc_id = aws_vpc.main.id 入站规则 ingress TCP 443 ← 0.0.0.0/0 | TCP 22 ← 10.0.0.0/16 出站规则 egress TCP 443 → 0.0.0.0/0 | 默认允许全部出站 resource "aws_vpc" "main" { cidr_block = "10.0.0.0/16" } 公有子网 私有子网 / NAT 安全组 互联网网关

依赖关系与引用机制

在IaC中,资源之间的依赖不是靠人工排序,而是靠属性引用自动建立。例如,子网资源中写vpc_id = aws_vpc.main.id,IaC引擎就会先创建VPC,再创建子网。路由表关联资源中写subnet_id = aws_subnet.public.id和route_table_id = aws_route_table.public.id,引擎就会在两者都就绪后再建立关联。这种机制让网络拓扑的创建顺序变得确定且可重复。

路由条目是另一个关键抽象。在Terraform中,aws_route资源用于向路由表添加具体路由,例如destination_cidr_block = "0.0.0.0/0"和gateway_id = aws_internet_gateway.igw.id。对于私有子网,则指向NAT网关的ID。这里有一个容易出错的细节:NAT网关必须部署在公有子网中,并且需要分配弹性IP(EIP)。在代码中,这意味着NAT网关资源会引用公有子网的ID和EIP的分配ID,形成一条清晰的依赖链。

安全组的代码抽象

安全组在代码中通常拆分为“安全组本体”和“规则”两部分。以Terraform为例,aws_security_group定义组本身,aws_security_group_rule或内联的ingress/egress块定义规则。规则中的cidr_blocks、from_port、to_port、protocol等参数,直接对应控制台里的入站/出站规则表。安全组是有状态的,返回流量自动放行,这一点在代码中不需要额外声明,但理解它有助于避免重复配置。

安全组与子网的关系也值得注意:安全组作用于实例的弹性网卡,而不是子网本身。因此,在代码中安全组通常与EC2实例、RDS实例或负载均衡器关联,而不是与子网直接绑定。子网层面的访问控制由网络ACL(NACL)负责,NACL是无状态的,需要分别配置入站和出站规则。在IaC中,NACL对应aws_network_acl和aws_network_acl_rule资源。

一个可参考的代码结构示例

下面给出一个简化的Terraform结构示例,展示VPC、公有子网、私有子网、IGW、NAT网关、路由表和安全组之间的引用关系。参数为教学示例,实际使用时需根据区域和地址规划调整。

resource "aws_vpc" "main" {
  cidr_block           = "10.0.0.0/16"
  enable_dns_support   = true
  enable_dns_hostnames = true
  tags = { Name = "demo-vpc" }
}

resource "aws_subnet" "public_a" {
  vpc_id            = aws_vpc.main.id
  cidr_block        = "10.0.1.0/24"
  availability_zone = "ap-northeast-1a"
  tags = { Name = "public-a" }
}

resource "aws_subnet" "private_a" {
  vpc_id            = aws_vpc.main.id
  cidr_block        = "10.0.2.0/24"
  availability_zone = "ap-northeast-1a"
  tags = { Name = "private-a" }
}

resource "aws_internet_gateway" "igw" {
  vpc_id = aws_vpc.main.id
}

resource "aws_eip" "nat" {
  domain = "vpc"
}

resource "aws_nat_gateway" "nat" {
  allocation_id = aws_eip.nat.id
  subnet_id     = aws_subnet.public_a.id
}

resource "aws_route_table" "public" {
  vpc_id = aws_vpc.main.id
  route {
    cidr_block = "0.0.0.0/0"
    gateway_id = aws_internet_gateway.igw.id
  }
}

resource "aws_route_table_association" "public_a" {
  subnet_id      = aws_subnet.public_a.id
  route_table_id = aws_route_table.public.id
}

resource "aws_route_table" "private" {
  vpc_id = aws_vpc.main.id
  route {
    cidr_block     = "0.0.0.0/0"
    nat_gateway_id = aws_nat_gateway.nat.id
  }
}

resource "aws_route_table_association" "private_a" {
  subnet_id      = aws_subnet.private_a.id
  route_table_id = aws_route_table.private.id
}

resource "aws_security_group" "web" {
  name   = "web-sg"
  vpc_id = aws_vpc.main.id

  ingress {
    from_port   = 443
    to_port     = 443
    protocol    = "tcp"
    cidr_blocks = ["0.0.0.0/0"]
  }

  egress {
    from_port   = 0
    to_port     = 0
    protocol    = "-1"
    cidr_blocks = ["0.0.0.0/0"]
  }
}
在IaC中,资源名称(如aws_vpc.main)是代码内部的逻辑标识,不是AWS上的实际名称。实际名称通过tags中的Name标签或资源自身的name参数指定。逻辑标识用于引用,标签用于控制台识别和成本分摊。

映射中的常见误区

第一个误区是把子网当作安全边界。子网是路由和可用区的边界,安全组才是实例级别的访问控制。第二个误区是忽略路由表关联。创建了路由表但没有关联到子网,路由规则不会生效。第三个误区是NAT网关的可用区选择。NAT网关是可用区级别的资源,如果私有子网分布在多个可用区,通常需要为每个可用区创建独立的NAT网关,否则跨可用区流量可能产生额外费用或单点故障。第四个误区是安全组规则的协议字段。使用-1表示所有协议,使用tcp、udp、icmp等指定具体协议,端口范围在from_port和to_port中定义。