使用安全组控制应用访问

AWSBeginner
立即练习

简介

配送应用的公有访问路径已可用,但供应的访问规则允许来自任意 IPv4 来源的 HTTP。你将为应用配置一个独立安全组,仅允许预期的客户端和端口。真实请求将展示来源限制、端口限制和有状态回复如何影响访问。

请先完成“将公有子网连接到互联网”。本全新环境供应自己的网络、公网地址、路由和应用,不复用之前的 VM。CLI 已配置。保留供应的资源和无关的参考网络;只有新建的安全组是需要删除的练习资源。

认证关联

本实验为以下考试主题提供动手练习。

关联空的练习安全组

本步骤中,你将检查可用的应用,并用自己的空组替换其宽泛的访问组。

使用 Terminal 执行命令,点击旁边的 AWS View。视图读取与 CLI 相同的资源状态,显示 application-network、其中的公有和私有子网,以及私有地址为 10.20.1.10 的应用。公网地址和互联网网关路由已供应;请保持不变。

cd /home/labex/project

按 Name 标签选择 VPC。--filters 限定服务器结果,--query 选择 ID,$(...) 将结果保存到 shell 变量:

VPC_ID=$(aws ec2 describe-vpcs \
  --filters Name=tag:Name,Values=application-network \
  --query 'Vpcs[0].VpcId' \
  --output text)

选择该 VPC 内供应的应用接口:

ENI_ID=$(aws ec2 describe-network-interfaces \
  --filters "Name=vpc-id,Values=$VPC_ID" Name=tag:Name,Values=application-interface \
  --query 'NetworkInterfaces[0].NetworkInterfaceId' \
  --output text)

安全组在关联资源的网络接口处控制允许的流量。入站规则允许到达应用的流量;出站规则允许应用主动发起的流量。保存唯一供应组的 ID,以便清理时恢复。[0] 选择此单组列表的第一项:

SUPPLIED_GROUP_ID=$(aws ec2 describe-network-interfaces \
  --network-interface-ids "$ENI_ID" \
  --query 'NetworkInterfaces[0].Groups[0].GroupId' \
  --output text)

读取规则,但不要修改:

aws ec2 describe-security-groups \
  --group-ids "$SUPPLIED_GROUP_ID" \
  --query 'SecurityGroups[].{ID:GroupId,Inbound:IpPermissions,Outbound:IpPermissionsEgress}' \
  --output json

供应组允许来自 0.0.0.0/0(任意 IPv4 来源)的入站 TCP 端口 80,并允许全部出站流量。HTTP使用请求和响应;端口标识接收服务。应用在 TCP 端口 80 和 8081 上提供 HTTP,但供应规则仅允许端口 80。

在 AWS View 中,依次点击 Request application · client A 和 Request application · client B。两者均在端口 80 返回 Success 和 Application online。客户端 A 使用 198.51.100.10,客户端 B 使用 198.51.100.20。点击 Request port 8081;这个来自客户端 A 的请求失败,因为该端口尚未获准。

在同一 VPC 中创建独立组。--group-name 设置名称,--description 说明用途,引号中的标签规范作为一个参数添加所有权标签。保存新 ID:

GROUP_ID=$(aws ec2 create-security-group \
  --group-name parcel-web \
  --description "Parcel HTTP access" \
  --vpc-id "$VPC_ID" \
  --tag-specifications 'ResourceType=security-group,Tags=[{Key=Name,Value=parcel-web},{Key=Project,Value=parcel}]' \
  --query 'GroupId' \
  --output text)

新组没有入站授权,并允许全部出站流量。安全组包含允许规则,不包含显式拒绝规则。没有匹配允许规则的流量会被阻断。

--groups 替换接口的组列表。仅关联新组;若同时保留宽泛的供应组,两组权限会合并,两个客户端仍会获准:

aws ec2 modify-network-interface-attribute \
  --network-interface-id "$ENI_ID" \
  --groups "$GROUP_ID"

修改成功时没有输出。确认接口现在仅关联自己的组:

aws ec2 describe-network-interfaces \
  --network-interface-ids "$ENI_ID" \
  --query 'NetworkInterfaces[].{ID:NetworkInterfaceId,Groups:Groups}' \
  --output json

AWS View 现在显示 parcel-web 和 Inbound · none。从客户端 A 和 B 发送新请求;两者都变为 Connection failed。公网地址和路由仍在,但空组不允许任何入站请求。保持此 Terminal 打开,以保留保存的 ID。

仅允许预期 HTTP 客户端

本步骤中,你将允许客户端 A 访问端口 80,并验证其他来源和端口仍被阻断。

入站规则指定协议、端口范围和来源。--protocol tcp 选择 TCP,--port 80 选择这一个端口,--cidr 198.51.100.10/32 仅选择客户端 A 的 IPv4 地址。/32 包含一个 IPv4 地址,比 0.0.0.0/0 更窄。

将规则添加到自己的组,而不是供应组:

aws ec2 authorize-security-group-ingress \
  --group-id "$GROUP_ID" \
  --protocol tcp \
  --port 80 \
  --cidr 198.51.100.10/32

响应表示成功,可能包含新规则 ID。读取全部入站规则:

aws ec2 describe-security-groups \
  --group-ids "$GROUP_ID" \
  --query 'SecurityGroups[].IpPermissions' \
  --output json

现在有一条 TCP 规则,FromPort 和 ToPort 均为 80,来源为 198.51.100.10/32。AWS View 显示相同的入站来源和端口。

点击 Request application · client A。结果为 Success,来源 198.51.100.10,目标端口 80,正文 Application online。这是供应应用返回的真实响应。

再点击 Request application · client B 和 Request port 8081。两者均返回 Connection failed。第一个请求的来源不匹配;第二个来自客户端 A,但端口不匹配。公网地址和路由提供路径,安全组决定哪些流量可以使用该路径。

测试并移除临时端口授权

本步骤中,你将证明另一个监听端口只有存在对应规则时才可达,然后移除临时授权。

供应的应用也在端口 8081 提供 HTTP。保持相同的允许来源,为该端口添加一条临时规则:

aws ec2 authorize-security-group-ingress \
  --group-id "$GROUP_ID" \
  --protocol tcp \
  --port 8081 \
  --cidr 198.51.100.10/32

再次读取规则:

aws ec2 describe-security-groups \
  --group-ids "$GROUP_ID" \
  --query 'SecurityGroups[].IpPermissions' \
  --output json

现在有两条 TCP 规则:端口 80 和 8081,均仅允许客户端 A。AWS View 显示两者。点击 Request port 8081。结果变为 Success,目标端口为 8081,正文为 Application online。这确认第二个服务正在运行;之前失败是访问规则的限制。

临时 TCP 8081 规则允许来自客户端 A 的真实请求

AWS View 示例:两条窄范围入站规则均存在,客户端 A 在端口 8081 收到应用响应。你的环境生成的资源 ID 会不同。

本练习仅需要端口 80。撤销规则会移除其允许授权。指定相同的协议、端口和来源,仅移除临时规则:

aws ec2 revoke-security-group-ingress \
  --group-id "$GROUP_ID" \
  --protocol tcp \
  --port 8081 \
  --cidr 198.51.100.10/32

响应表示成功。查询最终规则:

aws ec2 describe-security-groups \
  --group-ids "$GROUP_ID" \
  --query 'SecurityGroups[].IpPermissions' \
  --output json

仅剩客户端 A 的端口 80 规则。AWS View 移除 8081 规则后,再次点击 Request port 8081;现在请求失败。客户端 A 的端口 80 仍成功,客户端 B 的端口 80 仍失败。你只改变了一个端口授权,没有替换应用或路由。

观察有状态 HTTP 回复

本步骤中,你将移除自己组的默认出站规则,并确认获准入站 HTTP 的响应仍然可用。

安全组是有状态的:获准入站请求的响应可以离开应用,即使没有出站规则允许新连接。出站规则控制应用主动发起的流量;此 HTTP 响应不需要该规则。

读取当前出站权限:

aws ec2 describe-security-groups \
  --group-ids "$GROUP_ID" \
  --query 'SecurityGroups[].IpPermissionsEgress' \
  --output json

新组具有默认的全部流量目标 0.0.0.0/0。下一条命令的 --ip-permissions 将 JSON 规则规范列表作为一个带引号的参数接收。IpProtocol 的值 -1 表示全部协议,IpRanges 标识出站规则的目标。精确移除该默认规则:

aws ec2 revoke-security-group-egress \
  --group-id "$GROUP_ID" \
  --ip-permissions '[{"IpProtocol":"-1","IpRanges":[{"CidrIp":"0.0.0.0/0"}]}]'

响应表示成功。读取两个方向的规则:

aws ec2 describe-security-groups \
  --group-ids "$GROUP_ID" \
  --query 'SecurityGroups[].{Inbound:IpPermissions,Outbound:IpPermissionsEgress}' \
  --output json

入站仍仅允许客户端 A 的端口 80;出站为空。AWS View 显示 Outbound · none。再次点击 Request application · client A。仍返回 Success 和 Application online:回复属于已获准的入站连接。

重新检查 Request application · client B 和 Request port 8081。两者仍失败。有状态回复不会允许其他来源或端口的新入站访问。此测试证明响应行为,不测试应用主动发起的新出站连接。

无出站授权时,获准入站 HTTP 请求仍收到响应

AWS View 示例:入站仅允许客户端 A 的端口 80,出站为空,而真实 HTTP 响应仍成功。你的环境生成的资源 ID 会不同。

恢复供应组并删除自己的组

本步骤中,你将恢复原来的应用关联,并仅删除自己的练习安全组。

关联到网络接口的组无法删除。先用保存的供应组替换自己的组;不要删除或修改供应组:

aws ec2 modify-network-interface-attribute \
  --network-interface-id "$ENI_ID" \
  --groups "$SUPPLIED_GROUP_ID"

确认关联:

aws ec2 describe-network-interfaces \
  --network-interface-ids "$ENI_ID" \
  --query 'NetworkInterfaces[].{ID:NetworkInterfaceId,Groups:Groups}' \
  --output json

仅关联原来的 supplied-application 组。现在删除已不再使用的组:

aws ec2 delete-security-group --group-id "$GROUP_ID"

删除成功时没有输出。查询完整组清单,以独立于可移除的标签证明资源不存在:

aws ec2 describe-security-groups \
  --query 'SecurityGroups[].{ID:GroupId,Name:GroupName,VPC:VpcId}' \
  --output table

parcel-web 已不存在。供应组和默认组仍在,VPC、子网、应用接口、公网地址和路由也保留。清单查询失败不能证明已删除。

AWS View 再次显示 supplied-application。点击客户端 A 和 B 的请求按钮;两个端口 80 请求都返回 Success,与初始基线一致。Request port 8081 失败,因为未修改的供应组仅允许端口 80。

运行本步骤的完成检查。

总结

你创建并关联了独立安全组,仅允许客户端 A 的 TCP 端口 80,测试并撤销临时第二端口授权,还确认了没有出站授权时的有状态 HTTP 回复。真实请求区分了获准和被阻断的流量。最后,你恢复供应组,并仅删除自己的练习组。

继续学习“为私有子网提供出站访问”,构建私有应用的出站路径,同时不允许未经请求的外部访问。