为何AWS安全组放通的端口被UFW拦截后同子网EC2仍可访问?
先明确两层防火墙的逻辑边界:
- AWS安全组是跑在EC2宿主机虚拟化层的流量过滤器,流量在进入EC2实例操作系统网络栈之前就会先过安全组校验,这层逻辑和实例内部的ufw、iptables完全独立,互不影响。
- 正常来说安全组放通的流量到了OS层,应该受ufw规则管控,出现拦截不生效的情况,基本是以下三个原因:
1. ufw规则优先级不对
你直接敲sudo ufw deny 3306加的拒绝规则,默认会被追加到现有规则列表的最后。ufw是从上到下匹配规则,命中就直接生效不再往后走,如果你的规则列表前面已经有放通3306、或者放通同网段全流量的规则,后面加的deny根本轮不到匹配。
直接执行sudo ufw status numbered就能看到所有带优先级序号的规则,如果前面确实有放通规则,把deny规则插到它前面就行,比如放通3306的规则是序号3,就敲sudo ufw insert 2 deny 3306,把拒绝规则放到第2位,优先级更高。
2. 同子网二层流量绕过了ufw过滤链
AWS官方提供的Ubuntu AMI默认对本地直连子网做了特殊的内核参数配置,同子网属于二层直连通信,流量默认走local路由表,不会经过ufw绑定的filter表INPUT链,你没明确指定网卡和流量来源的普通deny规则,根本拦不到这部分流量。
这种情况直接指定网卡和来源段加规则就行,AWS默认主网卡是eth0,敲sudo ufw deny in on eth0 to any port 3306 from <你的私有子网CIDR段>,明确拦截eth0网卡上来自子网段的3306入向流量,规则就会生效。
3. 其他高优先级规则绕过了ufw
如果你是用Docker部署的3306端口服务,Docker默认会直接修改系统iptables规则,在ufw的用户规则前面插入自己的DOCKER链规则,直接放通所有映射到宿主机的端口流量,完全绕过ufw的校验,你加的普通ufw deny规则优先级低于Docker写入的规则,自然拦不住。
直接执行sudo iptables -L -n -v --line-numbers查看INPUT链、DOCKER链的规则顺序,就能看到是不是有更高优先级的规则提前放通了3306端口。
在实例A上敲tcpdump -i eth0 port 3306抓包,同时在实例B上发起对A的3306端口访问:
- 如果能抓到入向的SYN包,但没有回SYN+ACK包,说明OS层已经拦截了流量,问题出在规则匹配逻辑
- 如果能看到完整的TCP三次握手包,说明流量确实绕过了ufw的过滤链
- 如果完全抓不到包,问题出在安全组或路由层,和ufw无关
内容的提问来源于stack exchange,提问作者Call_Me_Jack

