4. 安全组与网络 ACL 的纵深防御

在 AWS 的 VPC 网络隔离体系中,安全组(Security Group,SG)与网络 ACL(Network ACL,NACL)是两道作用层级不同、过滤机制也不同的防线。理解它们的关键,不是记住“一个在实例上、一个在子网上”,而是先分清有状态与无状态这两种过滤模型,再据此设计规则、排查误配置并建立审计方法。

一、有状态与无状态:两种过滤模型的本质差异

安全组是有状态的。当一条入站规则允许某个连接进入实例时,该连接的回程流量会被自动放行,无需再写一条出站规则。反过来,出站规则允许发起的连接,其响应流量也会自动返回。安全组只支持允许规则,不支持显式拒绝,默认拒绝所有未匹配流量。它绑定在弹性网卡(ENI)上,因此可以精确到单个实例或接口。

网络 ACL 是无状态的。它作用在子网边界,对每个数据包独立判断,不记忆连接状态。这意味着:如果允许 10.0.1.0/24 访问子网内实例的 443 端口,那么实例返回给 10.0.1.0/24 的响应流量,必须在出站规则中单独放行。NACL 同时支持允许和拒绝规则,按规则编号从小到大依次匹配,一旦命中即停止,因此规则顺序至关重要。默认 NACL 允许所有进出流量,而自定义 NACL 默认拒绝所有流量。

这两者的差异直接决定了规则设计思路:安全组关注“谁可以访问我”,NACL 关注“子网边界上哪些包可以通过”。

安全组(有状态)与网络 ACL(无状态)过滤对比 安全组 · 有状态 · 绑定 ENI 入站规则 允许 TCP 443 ← 10.0.1.0/24 允许 TCP 22 ← 10.0.0.5/32 连接状态跟踪表 已建立连接 → 回程自动放行 出站规则 默认允许所有出站(可收紧) 仅允许 → 0.0.0.0/0 TCP 443 关键特性 • 仅允许规则,无显式拒绝 • 回程流量自动放行,无需反向规则 网络 ACL · 无状态 · 绑定子网 入站规则(按编号顺序匹配) 100 允许 TCP 443 ← 10.0.1.0/24 200 允许 TCP 1024-65535 ← 0.0.0.0/0 * 拒绝所有 无连接状态记忆 每个包独立判断,回程需单独放行 出站规则(按编号顺序匹配) 100 允许 TCP 443 → 10.0.1.0/24 200 允许 TCP 1024-65535 → 0.0.0.0/0 * 拒绝所有 关键特性 • 支持允许与拒绝,顺序决定结果 子网边界

二、规则设计:从最小权限到可维护性

安全组规则设计应遵循最小权限原则。一个常见的生产实践是:Web 层安全组只允许来自 ALB 安全组的 443 端口,而不是写 0.0.0.0/0。AWS 支持在安全组规则中引用另一个安全组 ID 作为源,这样即使后端实例 IP 变化,规则依然有效,且天然形成层级引用关系。例如:

Web-SG 入站:TCP 443 ← ALB-SG
App-SG 入站:TCP 8080 ← Web-SG
DB-SG  入站:TCP 3306 ← App-SG

这种“安全组链”比按 CIDR 写死 IP 更安全、更易维护。出站规则同样应收紧,例如数据库安全组只允许出站到备份存储或监控端点,而不是默认全放行。

NACL 规则设计则要特别注意临时端口范围。客户端发起连接时,源端口通常是 1024–65535 之间的临时端口。如果 NACL 出站只允许 443,那么服务器返回给客户端的响应包(目标端口是客户端的临时端口)就会被拒绝。因此,NACL 出站规则通常需要放行 1024–65535 到 0.0.0.0/0,或者根据实际客户端范围精确限定。规则编号建议以 100、200、300 递增,预留插入空间;拒绝规则放在允许规则之前才能生效。

三、常见误配置与排障思路

实际运维中,以下几类误配置最为高频:

  • NACL 只放行入站、忘记出站回程:表现为连接建立后立即超时或无法返回数据。排查时先看 NACL 出站是否覆盖临时端口范围。
  • 安全组出站被收紧后未放行必要目标:例如实例需要访问 S3 网关端点或 NAT 网关,但出站规则未放行对应端口,导致软件更新、日志上传失败。
  • NACL 规则顺序错误:把拒绝规则编号设得比允许规则大,导致拒绝规则永远不生效;或把宽泛允许规则放在前面,使后面的精细拒绝形同虚设。
  • 安全组引用错误:跨 VPC 或跨账户引用安全组时,若未正确配置 VPC 对等连接或 RAM 共享,规则看似存在但实际不生效。
  • 默认 NACL 与自定义 NACL 混用:新建子网若未关联自定义 NACL,会使用默认 NACL 的全放行规则,形成隐性敞口。
排障时建议按“先 NACL 后安全组”的顺序检查:NACL 在子网边界先过滤,若包根本进不了子网,安全组日志也不会有记录。使用 VPC Flow Logs 可以观察 ACCEPT/REJECT 记录,结合安全组规则编号和 NACL 规则编号定位是哪一层拒绝。

四、审计方法:让规则可查、可证、可收敛

审计的目标是回答三个问题:当前有哪些规则、这些规则是否必要、是否存在过度放行。可落地的做法包括:

  1. 定期导出规则清单:使用 aws ec2 describe-security-groups 和 aws ec2 describe-network-acls 导出 JSON,转换为表格后逐条评审。重点关注 0.0.0.0/0 入站、0.0.0.0/0 出站、以及未使用的安全组。
  2. 启用 VPC Flow Logs:将日志发送到 CloudWatch Logs 或 S3,通过 Athena 查询被拒绝的流量,判断是误配置还是攻击探测。
  3. 使用 AWS Config 规则:例如 restricted-ssh、restricted-common-ports、vpc-sg-open-only-to-authorized-ports,自动检测并标记不合规的安全组。
  4. 建立规则变更审批:安全组和 NACL 的修改应纳入变更管理,结合 CloudTrail 记录 AuthorizeSecurityGroupIngress、CreateNetworkAclEntry 等事件,追溯谁在何时放行了什么。
  5. 定期清理未使用规则:结合 Flow Logs 统计规则命中次数,对长期零命中的规则进行复核,确认是否可删除或收紧。
安全组和 NACL 都不是“设好就忘”的静态配置。随着业务扩缩容、新服务上线、临时排障放行,规则会逐渐膨胀。建议至少每季度做一次规则评审,并把评审结果与合规基线比对,避免纵深防御退化为“层层放行”。

总结来说,安全组与 NACL 构成的是“实例级有状态过滤 + 子网级无状态过滤”的双层结构。安全组负责精细的、面向连接的最小权限控制;NACL 负责子网边界的粗粒度兜底和显式拒绝。只有同时理解有状态与无状态的差异,才能在设计时避免回程遗漏,在排障时快速定位过滤层,在审计时发现过度放行,让纵深防御真正生效。