AWS 上的 IPv6:VPC、EC2、ELB 及更多
在 Amazon Web Services 上部署 IPv6 的完整指南。配置 VPC、子网、安全组、负载均衡器和仅出口网关。
AWS 在大多数服务中都有全面的 IPv6 支持,但默认情况下不启用。你必须选择加入,配置分布在多个层次。
TL;DR - 快速摘要
要点:
- AWS 提供双栈 IPv6(大多数服务不支持仅 IPv6)
- 你从
2600::/12范围获得 Amazon 分配的/56块 - 所有 IPv6 地址都是全局唯一且可路由的(无 NAT)
- 仅出口网关提供有状态过滤而不需要地址转换
跳转至: VPC 配置 | EC2 实例 | 安全组 | 负载均衡器 | Terraform 示例
AWS IPv6 架构概述#
AWS 以双栈配置提供 IPv6。你的资源获得 IPv4 和 IPv6 地址。在大多数服务中,你不能仅运行 IPv6(除了一些容器和无服务器工作负载)。
Amazon 从其公共池分配 IPv6 CIDR 块。你无法选择前缀——AWS 从 2600::/12 范围为你的 VPC 分配 /56 块。
与 IPv4 使用私有 RFC1918 地址(10.0.0.0/8、172.16.0.0/12、192.168.0.0/16)不同,所有 AWS IPv6 地址都是全局唯一且可路由的(GUA)。IPv6 没有传统意义上的 NAT——如果你想要仅出站连接,请使用仅出口互联网网关。
VPC IPv6 配置#
从 VPC 开始。添加 IPv6 不会中断现有的 IPv4 资源。
关联 IPv6 CIDR 块#
将 Amazon 提供的 IPv6 CIDR 添加到 VPC:
aws ec2 associate-vpc-cidr-block \
--vpc-id vpc-0abc123def456 \
--amazon-provided-ipv6-cidr-blockAWS 分配 /56 块。响应显示分配的范围:
{
"Ipv6CidrBlockAssociation": {
"Ipv6CidrBlock": "2600:1f13:1234:5600::/56",
"Ipv6CidrBlockState": {
"State": "associating"
}
}
}等待状态变为 associated:
aws ec2 describe-vpcs --vpc-ids vpc-0abc123def456 \
--query 'Vpcs[0].Ipv6CidrBlockAssociationSet[0].Ipv6CidrBlockState.State'如果你有提供商独立的 IPv6 空间并希望跨 AWS 账户或迁移维护地址,还可以使用"自带 IP"(BYOIP)。大多数用户使用 Amazon 提供的地址。
子网 IPv6 配置#
子网需要从 VPC 的 /56 块中获取自己的 /64 切片。
列出 VPC 的 IPv6 CIDR:
aws ec2 describe-vpcs --vpc-ids vpc-0abc123def456 \
--query 'Vpcs[0].Ipv6CidrBlockAssociationSet[0].Ipv6CidrBlock'输出:2600:1f13:1234:5600::/56
将 /64 块分配给子网。对子网部分使用十六进制值 00-FF:
# 公有子网 A - 2600:1f13:1234:5600::/64
aws ec2 associate-subnet-cidr-block \
--subnet-id subnet-0abc111 \
--ipv6-cidr-block 2600:1f13:1234:5600::/64
# 公有子网 B - 2600:1f13:1234:5601::/64
aws ec2 associate-subnet-cidr-block \
--subnet-id subnet-0abc222 \
--ipv6-cidr-block 2600:1f13:1234:5601::/64
# 私有子网 A - 2600:1f13:1234:5610::/64
aws ec2 associate-subnet-cidr-block \
--subnet-id subnet-0abc333 \
--ipv6-cidr-block 2600:1f13:1234:5610::/64为在公有子网中启动的实例启用自动分配 IPv6 地址:
aws ec2 modify-subnet-attribute \
--subnet-id subnet-0abc111 \
--assign-ipv6-address-on-creation路由表#
IPv6 路由与 IPv4 分离。为 IPv6 CIDR 块创建路由。
对于公有子网,将所有 IPv6 流量(::/0)路由到互联网网关:
aws ec2 create-route \
--route-table-id rtb-0abc123 \
--destination-ipv6-cidr-block ::/0 \
--gateway-id igw-0def456互联网网关无需修改即可处理 IPv4 和 IPv6。
对于私有子网,你将使用仅出口互联网网关(稍后解释):
aws ec2 create-route \
--route-table-id rtb-0abc789 \
--destination-ipv6-cidr-block ::/0 \
--egress-only-internet-gateway-id eigw-0ghi012验证路由:
aws ec2 describe-route-tables --route-table-ids rtb-0abc123 \
--query 'RouteTables[0].Routes'EC2 实例 IPv6 配置#
EC2 实例需要显式分配 IPv6 地址。
使用 IPv6 启动新实例#
启动时指定 --ipv6-address-count:
aws ec2 run-instances \
--image-id ami-0abc123 \
--instance-type t3.medium \
--subnet-id subnet-0abc111 \
--ipv6-address-count 1 \
--key-name mykey \
--security-group-ids sg-0abc456或从子网范围分配特定的 IPv6 地址:
aws ec2 run-instances \
--image-id ami-0abc123 \
--instance-type t3.medium \
--subnet-id subnet-0abc111 \
--ipv6-addresses Ipv6Address=2600:1f13:1234:5600::a \
--key-name mykey \
--security-group-ids sg-0abc456将 IPv6 添加到现有实例#
获取网络接口 ID(ENI):
aws ec2 describe-instances --instance-ids i-0abc123 \
--query 'Reservations[0].Instances[0].NetworkInterfaces[0].NetworkInterfaceId'分配 IPv6 地址:
aws ec2 assign-ipv6-addresses \
--network-interface-id eni-0def456 \
--ipv6-address-count 1或指定确切地址:
aws ec2 assign-ipv6-addresses \
--network-interface-id eni-0def456 \
--ipv6-addresses 2600:1f13:1234:5600::b实例操作系统配置#
大多数现代 AMI(Amazon Linux 2023、Amazon Linux 2、Ubuntu 20.04+)通过 cloud-init 和 DHCPv6 自动配置 IPv6。
SSH 到实例并验证:
ip -6 addr show你应该在 eth0 接口上看到分配的 IPv6 地址:
2: eth0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 9001
inet6 2600:1f13:1234:5600::a/128 scope global
valid_lft forever preferred_lft forever
inet6 fe80::4a2:c9ff:fe12:3456/64 scope link
valid_lft forever preferred_lft forever测试连接:
ping6 google.com
curl -6 https://ifconfig.co如果 IPv6 未配置,检查 cloud-init 日志:
sudo cat /var/log/cloud-init.log | grep -i ipv6一些较旧的 AMI 可能需要手动配置。添加到 /etc/network/interfaces(Debian/Ubuntu)或 /etc/sysconfig/network-scripts/ifcfg-eth0(RHEL/CentOS)。
安全组#
安全组需要显式的 IPv6 规则。IPv4 规则不适用于 IPv6 流量。
创建双栈安全组规则#
允许来自任何地方的 HTTP/HTTPS(IPv4 和 IPv6):
# IPv4
aws ec2 authorize-security-group-ingress \
--group-id sg-0abc123 \
--ip-permissions IpProtocol=tcp,FromPort=443,ToPort=443,IpRanges='[{CidrIp=0.0.0.0/0}]'
# IPv6
aws ec2 authorize-security-group-ingress \
--group-id sg-0abc123 \
--ip-permissions IpProtocol=tcp,FromPort=443,ToPort=443,Ipv6Ranges='[{CidrIpv6=::/0}]'允许来自特定 IPv6 前缀的 SSH:
aws ec2 authorize-security-group-ingress \
--group-id sg-0abc123 \
--ip-permissions IpProtocol=tcp,FromPort=22,ToPort=22,Ipv6Ranges='[{CidrIpv6=2001:db8::/32,Description="Office IPv6"}]'允许所有 ICMPv6(IPv6 操作所需):
aws ec2 authorize-security-group-ingress \
--group-id sg-0abc123 \
--ip-permissions IpProtocol=ipv6-icmp,FromPort=-1,ToPort=-1,Ipv6Ranges='[{CidrIpv6=::/0}]'ICMPv6 对 IPv6 至关重要。不要阻止它。这不是安全风险——这是协议要求。
安全组最佳实践#
- 将 IPv4 规则镜像到 IPv6,除非有特定原因不这样做
- 始终允许 ICMPv6,来源与应用程序流量相同
- 使用前缀列表来管理跨两个系列的复杂规则集
- 标记安全组以识别双栈与仅 IPv4
示例:为组织的 IPv6 范围创建托管前缀列表:
aws ec2 create-managed-prefix-list \
--prefix-list-name org-ipv6-ranges \
--address-family IPv6 \
--max-entries 10 \
--entries Cidr=2001:db8:100::/40,Description=HQ \
Cidr=2001:db8:200::/40,Description=DataCenter在安全组规则中引用它:
aws ec2 authorize-security-group-ingress \
--group-id sg-0abc123 \
--ip-permissions IpProtocol=tcp,FromPort=443,ToPort=443,PrefixListIds='[{PrefixListId=pl-0abc123}]'弹性负载均衡#
应用程序负载均衡器(ALB)和网络负载均衡器(NLB)支持双栈。经典负载均衡器不支持。
应用程序负载均衡器双栈#
创建或修改 ALB 以使用双栈:
aws elbv2 create-load-balancer \
--name my-alb \
--subnets subnet-0abc111 subnet-0abc222 \
--security-groups sg-0abc123 \
--ip-address-type dualstack对于现有负载均衡器:
aws elbv2 set-ip-address-type \
--load-balancer-arn arn:aws:elasticloadbalancing:us-east-1:123456789012:loadbalancer/app/my-alb/1234567890abcdef \
--ip-address-type dualstack负载均衡器自动获取 A 和 AAAA DNS 记录:
dig my-alb-1234567890.us-east-1.elb.amazonaws.com A
dig my-alb-1234567890.us-east-1.elb.amazonaws.com AAAA客户端可以通过 IPv4 或 IPv6 连接。负载均衡器使用其配置的地址系列(后端实例通常为 IPv4)将流量转发到目标。
网络负载均衡器双栈#
NLB 类似地支持双栈:
aws elbv2 create-load-balancer \
--name my-nlb \
--type network \
--subnets subnet-0abc111 subnet-0abc222 \
--ip-address-type dualstackNLB 保留客户端 IP 地址,因此目标看到实际的 IPv6 源地址。确保应用程序日志和安全组处理两个地址系列。
目标组#
目标组通过其 IPv4 地址(最常见)或 IPv6 注册实例。你不能在单个目标组中混合地址系列。
创建 IPv4 目标组:
aws elbv2 create-target-group \
--name my-targets-ipv4 \
--protocol HTTP \
--port 80 \
--vpc-id vpc-0abc123 \
--ip-address-type ipv4创建 IPv6 目标组:
aws elbv2 create-target-group \
--name my-targets-ipv6 \
--protocol HTTP \
--port 80 \
--vpc-id vpc-0abc123 \
--ip-address-type ipv6即使使用双栈负载均衡器,大多数部署也使用 IPv4 目标组。负载均衡器透明地处理协议转换。
仅出口互联网网关#
仅出口互联网网关允许来自私有子网的出站 IPv6 连接,同时阻止入站连接。这类似于 IPv4 的 NAT,但没有地址转换——IPv6 地址保持全局唯一。
创建仅出口网关#
aws ec2 create-egress-only-internet-gateway \
--vpc-id vpc-0abc123注意网关 ID:
{
"EgressOnlyInternetGateway": {
"EgressOnlyInternetGatewayId": "eigw-0abc123"
}
}路由私有子网流量#
在私有子网路由表中添加路由:
aws ec2 create-route \
--route-table-id rtb-0abc789 \
--destination-ipv6-cidr-block ::/0 \
--egress-only-internet-gateway-id eigw-0abc123私有子网中的实例现在可以发起出站 IPv6 连接,但不会接受来自互联网的入站流量。
使用场景:
- 需要软件更新的数据库服务器
- 访问外部 API 的应用服务器
- 通过 IPv6 调用 AWS API(S3、DynamoDB 等)的内部服务
安全注意事项#
仅出口网关不提供匿名性。你的 IPv6 地址仍然对外部服务可见。这是有状态防火墙,而不是 NAT。
如果你需要带地址掩码的真正出站,则需要 NAT64 网关(设置更复杂,很少需要)。
Route 53 DNS#
Route 53 完全支持 IPv6 和 AAAA 记录。
创建 AAAA 记录#
为实例或负载均衡器添加 AAAA 记录:
aws route53 change-resource-record-sets \
--hosted-zone-id Z1234567890ABC \
--change-batch '{
"Changes": [{
"Action": "CREATE",
"ResourceRecordSet": {
"Name": "app.example.com",
"Type": "AAAA",
"TTL": 300,
"ResourceRecords": [{"Value": "2600:1f13:1234:5600::a"}]
}
}]
}'负载均衡器的别名记录#
对 ALB/NLB 使用别名记录(比 AAAA 记录更好——如果 LB IP 更改则自动更新):
aws route53 change-resource-record-sets \
--hosted-zone-id Z1234567890ABC \
--change-batch '{
"Changes": [{
"Action": "CREATE",
"ResourceRecordSet": {
"Name": "app.example.com",
"Type": "AAAA",
"AliasTarget": {
"HostedZoneId": "Z35SXDOTRQ7X7K",
"DNSName": "my-alb-1234567890.us-east-1.elb.amazonaws.com",
"EvaluateTargetHealth": true
}
}
}]
}'AliasTarget 中的 HostedZoneId 是该区域中 ELB 的规范托管区域(请参阅 AWS 文档 获取正确值)。
健康检查#
Route 53 健康检查支持 IPv6:
aws route53 create-health-check \
--health-check-config \
IPAddress=2600:1f13:1234:5600::a,Port=443,Type=HTTPS,ResourcePath=/health,RequestInterval=30,FailureThreshold=3 \
--caller-reference $(uuidgen)将健康检查与故障转移或加权路由策略一起使用以实现高可用性。
CloudFront IPv6#
CloudFront 分发默认支持 IPv6(在大多数情况下无法禁用)。
CloudFront 的全球边缘网络使用双栈。通过 IPv6 连接的客户端访问与 IPv4 客户端相同的边缘位置。
验证 IPv6 支持:
dig d111111abcdef8.cloudfront.net AAAACloudFront 处理协议转换。如果源仅支持 IPv4,CloudFront 仍然向 IPv6 客户端提供内容。
源配置不需要更改:
aws cloudfront create-distribution \
--distribution-config file://distribution-config.json示例 distribution-config.json(缩写):
{
"Origins": {
"Items": [{
"Id": "my-origin",
"DomainName": "example.com",
"CustomOriginConfig": {
"OriginProtocolPolicy": "https-only"
}
}]
},
"Enabled": true,
"Comment": "My distribution"
}CloudFront 自动为分发配置 IPv6 地址。无需额外配置。
Terraform 示例#
双栈 AWS 设置的基础设施即代码:
# 带 IPv6 的 VPC
resource "aws_vpc" "main" {
cidr_block = "10.0.0.0/16"
assign_generated_ipv6_cidr_block = true
enable_dns_support = true
enable_dns_hostnames = true
tags = {
Name = "main-vpc"
}
}
# 互联网网关
resource "aws_internet_gateway" "main" {
vpc_id = aws_vpc.main.id
}
# 仅出口互联网网关
resource "aws_egress_only_internet_gateway" "main" {
vpc_id = aws_vpc.main.id
}
# 公有子网
resource "aws_subnet" "public" {
vpc_id = aws_vpc.main.id
cidr_block = "10.0.1.0/24"
ipv6_cidr_block = cidrsubnet(aws_vpc.main.ipv6_cidr_block, 8, 1)
assign_ipv6_address_on_creation = true
availability_zone = "us-east-1a"
tags = {
Name = "public-subnet"
}
}
# 公有子网的路由表
resource "aws_route_table" "public" {
vpc_id = aws_vpc.main.id
route {
cidr_block = "0.0.0.0/0"
gateway_id = aws_internet_gateway.main.id
}
route {
ipv6_cidr_block = "::/0"
gateway_id = aws_internet_gateway.main.id
}
tags = {
Name = "public-rt"
}
}
resource "aws_route_table_association" "public" {
subnet_id = aws_subnet.public.id
route_table_id = aws_route_table.public.id
}
# 安全组
resource "aws_security_group" "web" {
name = "web-sg"
description = "Allow HTTP/HTTPS"
vpc_id = aws_vpc.main.id
ingress {
from_port = 443
to_port = 443
protocol = "tcp"
cidr_blocks = ["0.0.0.0/0"]
ipv6_cidr_blocks = ["::/0"]
}
ingress {
from_port = -1
to_port = -1
protocol = "ipv6-icmp"
ipv6_cidr_blocks = ["::/0"]
}
egress {
from_port = 0
to_port = 0
protocol = "-1"
cidr_blocks = ["0.0.0.0/0"]
ipv6_cidr_blocks = ["::/0"]
}
}
# 带 IPv6 的 EC2 实例
resource "aws_instance" "web" {
ami = "ami-0c55b159cbfafe1f0" # Amazon Linux 2023
instance_type = "t3.medium"
subnet_id = aws_subnet.public.id
ipv6_address_count = 1
vpc_security_group_ids = [aws_security_group.web.id]
tags = {
Name = "web-server"
}
}
# 应用程序负载均衡器
resource "aws_lb" "main" {
name = "main-alb"
internal = false
load_balancer_type = "application"
security_groups = [aws_security_group.web.id]
subnets = [aws_subnet.public.id]
ip_address_type = "dualstack"
tags = {
Name = "main-alb"
}
}
# 输出 IPv6 CIDR
output "vpc_ipv6_cidr" {
value = aws_vpc.main.ipv6_cidr_block
}
output "instance_ipv6" {
value = aws_instance.web.ipv6_addresses
}应用:
terraform init
terraform plan
terraform apply测试 AWS IPv6 部署#
验证端到端连接:
# 测试 DNS 解析
dig app.example.com AAAA
# 测试 HTTP/HTTPS 访问
curl -6 https://app.example.com
# 从实例测试
ssh ec2-user@<instance-ipv6>
ping6 google.com
curl -6 https://ifconfig.co使用 AWS 可达性分析器验证网络路径:
aws ec2 create-network-insights-path \
--source <instance-eni> \
--destination <alb-eni> \
--protocol tcp \
--destination-port 443
aws ec2 start-network-insights-analysis \
--network-insights-path-id <path-id>检查可能阻止 IPv6 的错误配置。
常见问题和解决方案#
问题:实例有 IPv6 地址但无法访问互联网
解决方案:检查路由表是否有到 IGW 的 ::/0 路由,验证安全组允许出站 IPv6
问题:负载均衡器没有 AAAA 记录
解决方案:确保 ip-address-type 设置为 dualstack,验证子网有 IPv6 CIDR 块
问题:无法通过 IPv6 SSH 到实例
解决方案:从 ::/0 或特定 IPv6 CIDR 添加允许 TCP 端口 22 的安全组规则
问题:仅出口网关不工作 解决方案:验证路由表关联,检查实例是否分配了 IPv6 地址
问题:CloudFront 不通过 IPv6 提供服务 解决方案:CloudFront IPv6 是自动的,无法禁用——检查 DNS 解析和客户端连接
成本注意事项#
AWS 上的 IPv6 本身是免费的。你不需要为 IPv6 CIDR 块或地址付费。
IPv4 和 IPv6 的数据传输成本相同。IPv6 没有定价优势——好处是架构简单性和避免 IPv4 耗尽。
仅出口互联网网关是免费的(与 NAT 网关不同,NAT 网关每小时成本约为 $0.045,外加数据处理费用)。
相关文章#
- AWS、Azure 和 GCP 中的 IPv6 - 多云 IPv6 概述
- IPv6 最佳实践 - 生产部署指南
- 双栈迁移指南 - 从仅 IPv4 过渡到双栈