让用户连接应用网络

AWSBeginner
立即练习

介绍

应用即使已有正在运行的实例和公网地址,也可能仍然无法访问。你将使用 Terraform 定义缺失的路由和一条范围严格限定的安全组规则,然后测试允许和阻止的连接。

你应已了解 Terraform 资源引用、VPC、子网、互联网路由和安全组。这个独立环境提供一个应用目标、另一个正常工作的参考应用,以及已准备好的 Terraform 输入值。你只需管理新增的连接资源。

与认证考试的关联

认证 考试任务 实践内容
Solutions Architect – Associate (SAA-C03) 任务 1.2 通过互联网网关连接 VPC 子网,并按来源和端口限制应用的网络访问。

实验概览

概念总览:获授权的客户端通过互联网网关和默认路由访问应用子网,安全组则限制应用端口的访问。

建立互联网路由

在这一步中,你将为应用 VPC 附加互联网网关,并将路由表与其子网显式关联。

打开 Terminal 和 AWS View。应用网络与参考网络相互独立。application-server 已有公网地址,因为它所在的子网会在实例启动时分配公网 IP。仅有公网地址不会自动建立互联网路由或授予入站访问权限。

在 AWS View 中,选择 application-server、User · 198.51.100.10 和 Application · 8081,然后点击 Send request。预期看到 Blocked。选择 reference-server,保持相同的客户端和应用端口,再发送一次请求,确认参考应用能够响应。在整个实验中,保持该参考应用正常工作。

进入已准备好的工作目录:

cd /home/labex/project/application-access

提供的 terraform.tfvars.json 包含此全新环境中的 VPC、子网和安全组 ID。Terraform 会自动加载这些输入值。使用对应变量之前,先阅读这些值:

cat terraform.tfvars.json

已准备好的 Provider 配置选择课程环境。你无需从之前的虚拟机复制 ID,也无需输入个人凭据。保存并显示提供的目标实例 ID,供后续检查使用。$(...) 捕获命令输出,--output text 以纯文本形式返回 ID。

TARGET_ID=$(aws ec2 \
  describe-instances \
  --filters Name=tag:Name,Values=application-server Name=instance-state-name,Values=running \
  --query 'Reservations[0].Instances[0].InstanceId' \
  --output text)
echo "$TARGET_ID"

互联网网关附加到 VPC。路由表将发往某个目标的流量发送到对应网关,子网关联则决定哪张路由表控制该子网。如果没有显式关联,子网使用其 VPC 的主路由表。保持提供的主路由表不变。目标 0.0.0.0/0 匹配没有更具体路由的 IPv4 地址;它不会授予通过安全组的权限。

创建 routing.tf。带引号的 heredoc 将 HCL 原样写入。资源引用将路由连接到路由表和网关,并将子网关联连接到同一张路由表。

cat > routing.tf <<'HCL'
resource "aws_internet_gateway" "application" {
  vpc_id = var.vpc_id
}

resource "aws_route_table" "application" {
  vpc_id = var.vpc_id
}

resource "aws_route" "internet" {
  route_table_id         = aws_route_table.application.id
  destination_cidr_block = "0.0.0.0/0"
  gateway_id             = aws_internet_gateway.application.id
}

resource "aws_route_table_association" "application" {
  subnet_id      = var.subnet_id
  route_table_id = aws_route_table.application.id
}

output "route_table_id" {
  value = aws_route_table.application.id
}

output "subnet_id" {
  value = var.subnet_id
}
HCL

初始化、格式化并验证配置:

terraform init
terraform fmt
terraform validate

如果 init 显示 Incomplete lock file information for providers,它涉及其他平台的校验和。已准备好的虚拟机使用 linux_amd64;初始化和验证成功后即可继续。

审查四项新增资源:网关、路由表、路由和关联。提供的实例和参考网络不得出现在待替换或删除的资源中。

terraform plan

应用配置,并在提示时输入 yes:

terraform apply

保存并显示新路由表 ID 和提供的子网 ID:

TABLE_ID=$(terraform output -raw route_table_id)
echo "$TABLE_ID"
SUBNET_ID=$(terraform output -raw subnet_id)
echo "$SUBNET_ID"

独立查询路由表。找到默认目标、igw-... 网关,以及与你的子网 ID 对应的关联。VPC 本地路由也仍然保留。

aws ec2 \
  describe-route-tables \
  --route-table-ids "$TABLE_ID" \
  --query 'RouteTables[].{Routes:Routes[].{Destination:DestinationCidrBlock,Gateway:GatewayId},Subnets:Associations[].SubnetId}'

确认提供的子网启用了公网 IP 分配:

aws ec2 \
  describe-subnets \
  --subnet-ids "$SUBNET_ID" \
  --query 'Subnets[].{CIDR:CidrBlock,PublicIPOnLaunch:MapPublicIpOnLaunch}'

PublicIPOnLaunch 为 true。该设置控制新启动的实例;更改它不能为现有实例补分配地址。AWS View 现在显示实际的网关和生效的路由表。再次向应用发送 User/8081 请求:它仍然显示 Blocked,因为尚无入站规则允许该连接。

允许目标客户端并测试边界

在这一步中,你将允许 User 客户端访问应用端口,并验证其他客户端和其他端口仍然被阻止。

安全组是附加到实例网络接口上的有状态网络边界。路由使路径可用;安全组仍决定允许哪些入站连接。提供的应用安全组目前没有入站规则。

为该安全组创建一个独立的入站规则资源。cidr_ipv4 = "198.51.100.10/32" 选定 User 客户端的单个 IPv4 地址。将两个端口值都设为 8081,仅允许访问应用监听端口。参考应用使用自己的安全组。

cat > access.tf <<'HCL'
resource "aws_vpc_security_group_ingress_rule" "application" {
  security_group_id = var.security_group_id
  ip_protocol       = "tcp"
  from_port         = 8081
  to_port           = 8081
  cidr_ipv4         = "198.51.100.10/32"
}

output "security_group_id" {
  value = var.security_group_id
}
HCL

格式化并验证,然后审查计划。应新增一条入站规则,不应替换实例。

terraform fmt
terraform validate
terraform plan

应用规则,并输入 yes 确认:

terraform apply

保存并显示现有安全组 ID,然后读取实际的入站权限:

GROUP_ID=$(terraform output -raw security_group_id)
echo "$GROUP_ID"
aws ec2 \
  describe-security-groups \
  --group-ids "$GROUP_ID" \
  --query 'SecurityGroups[].{Group:GroupId,Ingress:IpPermissions}'

该权限必须描述来自 198.51.100.10/32、访问 TCP 端口 8081 的连接。确认 Terraform 已收敛:

terraform plan

预期看到 No changes.。现在在 AWS View 中执行全部三项测试,每次均选择 application-server:

选择 User · 198.51.100.10 和 Application · 8081。点击 Send request。预期看到 Connected · 200 及消息 Application network connected。

运行时检查点:实际目标网络、选定来源和应用端口产生成功响应。资源 ID 为示例。 将来源改为 Unrelated · 198.51.100.20,保持端口 8081,再次发送请求。预期看到 Blocked。 将来源改回 User,选择 SSH · 22,再次发送请求。预期看到 Blocked。应用请求成功并不代表获准访问实例中独立的 SSH 监听端口。

结果标识实际的来源、目标实例和端口。Request service unavailable 是环境错误,不能证明发生了预期的网络拒绝。不要将规则放宽为 0.0.0.0/0:这样会将同一个应用监听端口暴露给无关客户端。

AWS Provider 入站规则文档介绍了该资源的字段。CLI、Terraform 映射和实际请求结果应相互一致。

删除连接资源并保留应用

在这一步中,你将仅删除 Terraform 管理的连接资源,并确认提供的应用保持完整不变。

此工作目录拥有五个资源:互联网网关、路由表、默认路由、子网关联和入站规则。VPC、子网、主路由表、目标实例和参考应用均独立提供。它们不属于此状态的管理范围,必须保留。

审查销毁计划:

terraform plan -destroy

预期销毁五个资源。然后执行删除,并输入 yes:

terraform destroy

确认状态中没有受管理资源地址:

terraform state list

提供的目标应仍在运行,且 ID 不变:

aws ec2 \
  describe-instances \
  --instance-ids "$TARGET_ID" \
  --query 'Reservations[].Instances[].{ID:InstanceId,State:State.Name,Subnet:SubnetId}'

在 AWS View 中,再次向目标发送 User/8081 请求。它应显示 Blocked,因为你已删除连接资源。然后选择 reference-server、User 和端口 8081,发送请求。参考应用必须仍返回 Connected · 200 和 Reference application。

你的 HCL 文件仍然保留,可供审阅。之后再执行普通计划会提出重新创建已删除的资源;在 terraform destroy 后保留这些配置是正常的。

总结

你使用 Terraform 引用附加了互联网网关,定义了默认路由,并将路由表与应用子网关联。随后,你添加了一条范围限定的入站规则,测试了实际的来源和端口边界,确认配置已收敛,并且仅删除了自己的连接资源,同时保留了提供的应用。