3. 安全组与网络ACL实战
在 AWS 的 VPC 中,安全组(Security Group,SG)和网络 ACL(Network ACL,NACL)是两道作用位置、工作方式完全不同的过滤层。很多生产事故并非因为“没有配规则”,而是因为把两者的语义搞混:以为 NACL 也像 SG 一样“出去放行、回来自动放行”,结果只开了入站 443,返回流量被无状态丢弃,表现为“TCP 三次握手成功但应用超时”。理解这两层,是设计可预测网络边界的前提。
一、作用位置与状态语义
安全组附着在弹性网卡(ENI)上,作用于实例级别,是有状态的:只要入站规则允许某个连接建立,该连接的返回流量会被自动放行,无需为出站方向再写一条对应规则。网络 ACL 附着在子网边界上,作用于子网级别,是无状态的:入站和出站方向各自独立评估,返回流量必须由对方向的规则显式允许。
两者都只支持“允许”规则,没有显式拒绝(NACL 的默认规则除外),因此判断逻辑是“命中任意允许规则即通过,否则丢弃”。安全组默认拒绝所有入站、允许所有出站;NACL 默认规则是编号 100 允许全部、编号 * 拒绝全部,自定义规则按编号从小到大依次匹配,命中即停止。
二、规则设计:从“能通”到“最小权限”
安全组规则设计应遵循“引用优先、网段其次、0.0.0.0/0 最后”的原则。生产环境常见的三层结构是:面向公网的 ALB 安全组只允许 443 来自 0.0.0.0/0;应用层安全组只允许来自 ALB 安全组 ID 的流量;数据库安全组只允许来自应用层安全组 ID 的 3306。这样即使应用层实例被替换、IP 变化,规则依然有效,且不依赖具体网段。
网络 ACL 的规则设计则要同时考虑两个方向。以允许公网访问子网内 Nginx 为例,入站需要允许 443(源 0.0.0.0/0),出站需要允许返回流量。由于客户端源端口是临时端口,通常放行 1024-65535 到 0.0.0.0/0。若实例还需主动访问外网,则入站也要放行 1024-65535 作为返回方向。规则编号建议按 100、110、120 递增,预留插入空间,避免后续调整时大面积重排。
三、分层安全策略
推荐的分层模型是:网络 ACL 做粗粒度子网边界控制,安全组做细粒度实例级控制,两者职责不重叠。NACL 适合做“整段子网只允许特定端口范围”的兜底,例如数据库子网 NACL 只允许 3306 入站、只允许来自应用子网 CIDR;安全组则精确到“哪个安全组的哪个端口”。
一个可参考的生产分层示例:
| 层级 | 对象 | 入站规则示例 | 出站规则示例 |
|---|---|---|---|
| 子网边界 | 公网子网 NACL | 100 允许 443 来自 0.0.0.0/0 | 100 允许 1024-65535 到 0.0.0.0/0 |
| 实例级 | ALB 安全组 | 443 来自 0.0.0.0/0 | 默认全部允许 |
| 实例级 | 应用安全组 | 8080 来自 ALB 安全组 | 3306 到数据库安全组 |
| 实例级 | 数据库安全组 | 3306 来自应用安全组 | 默认全部允许 |
四、生产环境常见误配置与排错
误配一:NACL 只放行入站,忽略出站返回。现象是 curl 卡住直到超时,tcpdump 能看到 SYN 到达但看不到 SYN-ACK 发出。排查时先看 VPC Flow Logs 中该 ENI 的出站记录是否为 REJECT,再核对 NACL 出站规则是否覆盖临时端口范围。
误配二:安全组出站被收紧后忘记放行返回。安全组本身有状态,但如果出站规则被改成只允许特定目标,而应用需要访问外部 API,则连接无法建立。此时应检查出站规则是否包含目标端口,而不是怀疑返回流量。
误配三:NACL 规则编号顺序错误。例如先写了 100 拒绝某网段,再写 110 允许,结果允许规则永远不会被匹配。NACL 按编号从小到大匹配,命中即停止,拒绝规则必须放在允许规则之后,或使用更精确的编号规划。
误配四:安全组引用跨账户或跨 VPC 失效。安全组引用仅在同一 VPC 内有效(跨 VPC 需通过 VPC Peering 或 Transit Gateway 并配合相应规则)。跨 VPC 场景下应改用 CIDR 或前缀列表。
排错时建议按“从外到内、从下到上”的顺序:先用 Reachability Analyzer 判断路径是否可达,再查 VPC Flow Logs 定位是 NACL 还是 SG 拒绝,最后在实例上用 ss -tn 或 tcpdump 确认连接状态。以下命令可用于快速观察:
# 查看当前监听端口与连接状态
ss -tnlp | grep -E '443|8080|3306'
# 抓取 443 端口握手过程,确认 SYN / SYN-ACK 是否成对出现
sudo tcpdump -ni eth0 'tcp port 443 and (tcp[tcpflags] & (tcp-syn|tcp-ack) != 0)'
# 从应用实例测试到数据库的连通性
nc -vz -w 3 10.0.2.15 3306
把安全组和网络 ACL 当成两层互补的过滤器:NACL 管“子网这道门”,安全组管“实例这扇窗”。有状态与无状态的差异决定了返回流量是否需要显式放行,而规则编号与引用方式决定了策略能否随架构演进保持可维护。掌握这两点,绝大多数“能 ping 通但服务不通”“握手成功但超时”的问题都能在几分钟内定位到具体规则。