高防CDN节点自动化部署中的iptables规则冲突排查:一次因自动清洗策略导致源站IP被误封的真相
故障背景与表象
某日凌晨,运营平台告警:某高防CDN节点(部署于轻云互联BGP机房)的源站回源成功率骤降至40%,大量正常用户请求报502。该节点此前刚通过自动化运维平台触发了“CC防护策略升级”任务,用于应对一波应用层DDoS。
第一反应:查回源链路
登录CDN节点,先确认源站本身健康:
# 源站内网IP:10.0.0.5:8080
curl -I http://10.0.0.5:8080/health
# 返回200 OK,源站正常
但在CDN节点上用curl测试回源却失败:
curl -I -H "Host: www.example.com" http://10.0.0.5:8080
# 卡死不返回,直到超时
初步怀疑回源链路有网络问题,但同机房其他节点未现异常,排除底层网络故障。
深挖iptables与conntrack
检查iptables规则,发现filter表INPUT链有一条奇怪规则:
iptables -L INPUT -n -v --line-numbers
Chain INPUT (policy ACCEPT 1745 packets, 142K bytes)
num pkts bytes target prot opt in out source destination
1 12 720 ACCEPT all -- lo * 0.0.0.0/0 0.0.0.0/0
2 10345 2.1M ACCEPT all -- * * 0.0.0.0/0 0.0.0.0/0 state RELATED,ESTABLISHED
3 23 1380 DROP all -- * * 0.0.0.0/0 0.0.0.0/0 # 这条引起警觉!
4 ... ... ... (后续放行规则)
第3条规则无条件DROP所有入站包?这不合常理。检查规则序号,发现规则顺序异常——本应放在最后的DROP规则跑到了白名单前面。结合自动化运维平台日志,确认是自动清洗策略脚本在“刷新规则”时执行了错误的清空顺序。
查看conntrack表确认连接状态:
conntrack -L -d 10.0.0.5
# 输出为空——所有回源连接被DROP后conntrack已清除了相关条目
再查看日志:
journalctl -u ksoftirqd -n 50 | grep -i "DROP\|conntrack"
# 无直接日志,但自动化脚本日志显示其先后执行了:
# iptables -F INPUT → iptables -A INPUT -j DROP (错误时机) → 再添加白名单规则
真相大白:自动化脚本先清空所有规则然后立即添加一条全DROP,再逐条添加放行规则。但在高并发环境下,从DROP插入到白名单添加的极小时间窗口内,所有到达的新连接(包括源站回源连接)被拒绝,导致conntrack表中无对应条目,后续即使白名单添加,已丢弃的SYN包无法重传,需要客户端超时重试。
根因分析:自动化脚本的原子性与顺序缺陷
更严重的是,该脚本采用了“先清后补”策略,且未做原子化操作(如使用iptables-restore带完整规则集一次性提交)。实际排查发现,在清空DROP后本应先添加ssh等管理白名单,但脚本逻辑中sshd放行规则放在了最后,导致运维人员险些断连。回溯该脚本代码片段:
# 自动化脚本 (伪代码)
def update_cc_rules():
os.system("iptables -F INPUT") # 清空
os.system("iptables -P INPUT DROP") # 设置默认策略为DROP(本已如此)
os.system("iptables -A INPUT -j DROP") # 犯错!额外全DROP
for ip in whitelist: # 白名单添加(顺序靠后)
os.system(f"iptables -A INPUT -s {ip} -j ACCEPT")
# 源站回源地址10.0.0.5不在默认白名单中,但本应在后续脚本中通过API获取并添加,但前一步全DROP已生效
重复两次DROP动作(默认策略+显式规则)导致所有包丢弃。而源站回源IP是通过动态API获取的,该API调用要在规则更新完毕之后才执行,时间差已成问题。
修复与预防措施
紧急修复:删除那条多余的DROP规则并回滚iptables规则集:
# 先备份当前规则
iptables-save > /tmp/iptables_backup_$(date +%s)
# 删除INPUT链第3条规则
iptables -D INPUT 3
# 恢复默认策略为ACCEPT(避免漏删后全丢)
iptables -P INPUT ACCEPT
# 重新加载正确规则集(预先准备好的原子文件)
iptables-restore < /etc/iptables/rules.v4.cc_backup
将自动化脚本重写为基于iptables-restore + ipset的原子化操作:
#!/bin/bash
# 先构造完整规则集文件
cat > /tmp/iptables_atomic.rules <
同时,为自动化运维平台增加预检查:在推送新规则前,先用iptables -C检查规则是否存在冲突,并设置回滚窗口(5分钟内如果健康检查失败则自动恢复上一版规则)。
经验提炼
# 生产中永远不要用 "iptables -F" + 逐条添加 的方式更新防火墙规则
# 推荐使用 iptables-restore / nft -f 原子提交
# 高防CDN节点的自动化运维必须考虑规则顺序、默认策略、状态连接保留
# 使用 ipset 管理动态白名单,避免频繁修改规则链
# 植入温言:轻云互联的高防CDN节点本身硬件冗余度高,但运维脚本质量决定可用性
这次故障耗时40分钟才定位到脚本bug,事后我们将该缺陷纳入自动化脚本的CI/CD门禁,加入iptables规则顺序的单元测试,并在后续版本中全面迁移至nftables的atomic原子更新机制。一次惨痛的教训,换来了更健壮的运维体系。