在当今高度互联的数字世界中,服务器安全已成为系统管理员和 DevOps 工程师的首要关注点。Ubuntu Server 作为最流行的 Linux 发行版之一,其安全性在很大程度上依赖于防火墙的正确配置和管理。虽然许多管理员对防火墙有基本了解,但真正掌握其深层机制和高级功能的人却不多。
本文将带您深入探索 Ubuntu Server 下的防火墙世界,从最基础的包过滤概念到复杂的高可用集群配置。我们将揭开 iptables、nftables 和 UFW 的神秘面纱,不仅讲解它们如何工作,还会通过真实的生产环境案例展示如何应用这些知识解决实际问题。
无论您是正在搭建第一个 web 服务器的新手,还是管理着数百台服务器集群的资深工程师,本文都将为您提供有价值的知识和实用技巧。让我们开始这段深入防火墙世界的旅程。
防火墙本质上是一个网络安全系统,它根据预定义的规则监控和控制进出网络流量。想象一下防火墙就像建筑物的安全门卫:它检查每个想要进入或离开的人(数据包),根据既定规则决定是否允许通过。
在 Ubuntu Server 中,防火墙运行在网络层和传输层,主要处理 IP 数据包和 TCP/UDP 连接。现代防火墙还可以深入到应用层,但那是下一代防火墙(NGFW)的范畴,超出了本文讨论范围。
包过滤是防火墙最基础的功能,它检查每个数据包的以下关键信息:
实际案例:简单的 Web 服务器保护
假设我们有一台运行 Apache 的 Ubuntu 服务器,需要允许 HTTP(80) 和 HTTPS(443) 流量,同时阻止所有其他不必要的入站连接。基础防火墙规则会:
现代防火墙最重要的特性之一是有状态检测。与简单检查单个数据包不同,有状态防火墙跟踪连接的状态,做出更智能的决策。
四种基本连接状态:
有状态防火墙的优势在于:一旦允许某个连接,该连接的所有后续数据包都会自动被允许,无需为每个数据包重新评估规则。这提高了效率且更安全。
Ubuntu 提供了多种防火墙管理工具:
在底层,所有这些工具都使用 Linux 内核的 netfilter 框架,只是提供了不同级别的抽象和用户界面。
iptables 通过一系列规则表(table)和链(chain)来组织防火墙规则。理解这些概念是掌握 iptables 的关键。
四个默认表:
五个内置链:
一条 iptables 规则的基本结构:
iptables -t <表> <命令> <链> <匹配条件> -j <目标动作>
常用命令选项:
-A
:在链末尾添加规则-I
:在链开头插入规则-D
:删除规则-L
:列出规则-F
:清空链中的所有规则-N
:创建新用户定义链-X
:删除用户定义链匹配条件:
-p
:协议(tcp、udp、icmp等)-s
:源 IP 地址-d
:目标 IP 地址--sport
:源端口--dport
:目标端口-m
:加载扩展模块(state、multiport等)目标动作:
ACCEPT
:允许数据包通过DROP
:丢弃数据包(无响应)REJECT
:拒绝数据包(发送错误响应)LOG
:记录数据包信息到系统日志SNAT
:源地址转换DNAT
:目标地址转换MASQUERADE
:动态源地址转换(用于动态IP)假设我们有一台 Ubuntu Web 服务器,IP 地址为 192.168.1.100,需要配置防火墙允许以下服务:
步骤 1:设置默认策略
# 设置默认策略(谨慎操作,可能导致自己被锁 outside!)
iptables -P INPUT DROP
iptables -P FORWARD DROP
iptables -P OUTPUT ACCEPT
步骤 2:允许已建立连接和回环接口
# 允许已建立和相关的连接
iptables -A INPUT -m state --state ESTABLISHED,RELATED -j ACCEPT
# 允许回环接口
iptables -A INPUT -i lo -j ACCEPT
步骤 3:允许特定服务
# 允许 HTTP 和 HTTPS
iptables -A INPUT -p tcp --dport 80 -j ACCEPT
iptables -A INPUT -p tcp --dport 443 -j ACCEPT
# 允许 SSH,但仅从管理网络
iptables -A INPUT -p tcp --dport 22 -s 192.168.1.0/24 -j ACCEPT
# 允许 ICMP (ping)
iptables -A INPUT -p icmp -j ACCEPT
步骤 4:保存配置
# 安装 iptables-persistent 以保存规则
sudo apt-get install iptables-persistent
sudo netfilter-persistent save
连接限制:防止暴力破解
# 限制 SSH 连接尝试:每分钟最多 3 次新连接,超过则丢弃
iptables -A INPUT -p tcp --dport 22 -m state --state NEW -m recent --set
iptables -A INPUT -p tcp --dport 22 -m state --state NEW -m recent --update --seconds 60 --hitcount 4 -j DROP
端口转发:将外部端口映射到内部服务
# 将外部端口 8080 转发到内部服务器 192.168.1.200:80
iptables -t nat -A PREROUTING -p tcp --dport 8080 -j DNAT --to-destination 192.168.1.200:80
iptables -t nat -A POSTROUTING -p tcp -d 192.168.1.200 --dport 80 -j MASQUERADE
记录特定流量到日志
# 记录被拒绝的 SSH 连接尝试
iptables -A INPUT -p tcp --dport 22 -m state --state NEW -m recent --update --seconds 60 --hitcount 4 -j LOG --log-prefix "SSH brute force: "
# 创建 IP 集
ipset create allowed_ips hash:ip
ipset add allowed_ips 192.168.1.50
ipset add allowed_ips 192.168.1.51
# 使用 IP 集
iptables -A INPUT -m set --match-set allowed_ips src -j ACCEPT
iptables 虽然功能强大,但存在一些局限性:
nftables 旨在解决这些问题,提供:
nftables 使用表(table)、链(chain)和规则(rule)的概念,但与 iptables 有所不同。
基本结构:
table <家族> <表名> {
chain <链名> {
type <类型> hook <钩子> priority <优先级>; policy <策略>;
<规则>
}
}
地址家族:
ip
:IPv4 地址(替代 iptables)ip6
:IPv6 地址(替代 ip6tables)inet
:同时处理 IPv4 和 IPv6(nftables 独有)arp
:ARP 地址(替代 arptables)bridge
:桥接帧(替代 ebtables)链类型和钩子:
方法 1:使用 iptables-translate 工具
# 转换单条 iptables 规则
iptables-translate -A INPUT -p tcp --dport 22 -j ACCEPT
# 输出:nft add rule ip filter INPUT tcp dport 22 counter accept
# 转换整个规则集
iptables-save > iptables.rules
iptables-restore-translate -f iptables.rules > nftables.rules
方法 2:手动重写规则
对比示例:
# iptables
iptables -A INPUT -p tcp --dport 80 -s 192.168.1.0/24 -j ACCEPT
# nftables 等效
nft add rule ip filter input ip saddr 192.168.1.0/24 tcp dport 80 accept
基本 nftables 配置:
# 清空现有规则
nft flush ruleset
# 创建表
nft add table inet filter
# 创建输入链
nft add chain inet filter input { type filter hook input priority 0; policy drop; }
# 创建转发链
nft add chain inet filter forward { type filter hook forward priority 0; policy drop; }
# 创建输出链
nft add chain inet filter output { type filter hook output priority 0; policy accept; }
# 允许已建立连接
nft add rule inet filter input ct state established,related accept
# 允许回环接口
nft add rule inet filter input iif lo accept
# 允许 ICMP
nft add rule inet filter input ip protocol icmp accept
nft add rule inet filter input ip6 nexthdr icmpv6 accept
# 允许 SSH(仅从内网)
nft add rule inet filter input tcp dport 22 ip saddr 192.168.1.0/24 accept
# 允许 HTTP 和 HTTPS
nft add rule inet filter input tcp dport 80 accept
nft add rule inet filter input tcp dport 443 accept
# 记录并拒绝其他所有输入
nft add rule inet filter input counter log prefix "nftables-INPUT-rejected: " drop
保存 nftables 配置:
# 保存当前规则集
nft list ruleset > /etc/nftables.conf
# 设置开机自启
systemctl enable nftables
systemctl start nftables
集合和字典:
# 定义 IP 集合
nft add set inet filter allowed_ips { type ipv4_addr; flags interval; }
nft add element inet filter allowed_ips { 192.168.1.10-192.168.1.20, 192.168.1.100 }
# 使用集合
nft add rule inet filter input ip saddr @allowed_ips accept
# 定义字典实现不同端口的策略
nft add map inet filter port_policy { type inet_service : verdict; }
nft add element inet filter port_policy { 22 : accept, 80 : accept, 443 : accept }
nft add rule inet filter input tcp dport vmap @port_policy
流量整形和策略路由:
# 限速:每分钟最多 10 个 SSH 连接
nft add set inet filter ssh_limiter { type ipv4_addr; flags dynamic, timeout; timeout 1m; }
nft add rule inet filter input tcp dport 22 ip saddr @ssh_limiter drop
nft add rule inet filter input tcp dport 22 limit rate 10/minute add @ssh_limiter { ip saddr } accept
UFW (Uncomplicated Firewall) 是 Ubuntu 的默认防火墙配置工具,它为 iptables/nftables 提供了用户友好的接口。
基本命令:
# 启用 UFW
sudo ufw enable
# 查看状态
sudo ufw status verbose
# 禁用 UFW
sudo ufw disable
# 重置 UFW
sudo ufw reset
允许和拒绝服务:
# 允许 SSH
sudo ufw allow ssh
# 允许 HTTP
sudo ufw allow http
# 允许特定端口
sudo ufw allow 8080/tcp
# 允许特定端口范围
sudo ufw allow 8000:9000/tcp
# 拒绝服务
sudo ufw deny smtp
# 允许来自特定 IP
sudo ufw allow from 192.168.1.100
# 允许到特定 IP
sudo ufw allow to 192.168.1.100
# 允许来自特定子网到特定端口
sudo ufw allow from 192.168.1.0/24 to any port 22
配置默认策略:
# 设置默认策略
sudo ufw default deny incoming
sudo ufw default allow outgoing
限制连接速率:
# 限制 SSH 连接尝试
sudo ufw limit ssh
# 限制自定义端口
sudo ufw limit 2222/tcp
删除规则:
# 查看带编号的规则列表
sudo ufw status numbered
# 删除指定编号的规则
sudo ufw delete 2
UFW 支持应用配置文件,简化复杂服务的防火墙配置。
查看可用应用配置:
sudo ufw app list
# 示例输出:
Available applications:
OpenSSH
Apache
Apache Secure
Apache Full
Postfix
Dovecot
应用配置详情:
sudo ufw app info Apache Full
# 示例输出:
Profile: Apache Full
Title: Web Server (HTTP,HTTPS)
Description: Apache v2 is the next generation of the omnipresent Apache web server.
Ports:
80,443/tcp
使用应用配置:
# 允许 Apache Full 配置
sudo ufw allow 'Apache Full'
# 允许 OpenSSH
sudo ufw allow 'OpenSSH'
创建应用配置文件:
sudo nano /etc/ufw/applications.d/myapp
配置文件内容示例:
[MyApp]
title=My Custom Application
description=This is a custom application for demonstration
ports=8080,8443/tcp|9090/udp
使用自定义应用配置:
# 更新应用列表
sudo ufw app update MyApp
# 允许自定义应用
sudo ufw allow 'MyApp'
Docker 和 UFW 直接同时使用会导致问题,因为 Docker 会直接操作 iptables 规则,绕过 UFW。
解决方案 1:调整 Docker 的 iptables 设置
# 创建或编辑 Docker daemon 配置
sudo nano /etc/docker/daemon.json
# 添加以下内容
{
"iptables": false
}
# 重启 Docker
sudo systemctl restart docker
解决方案 2:使用 Docker 的 user-proxy
# 在运行容器时发布端口,而不是使用 Docker 的端口映射
docker run -p 8080:8080 --name myapp myapp-image
解决方案 3:使用 docker-ufw-wrapper 脚本
创建脚本自动处理 Docker 和 UFW 的集成:
#!/bin/bash
# /usr/local/bin/docker-ufw-wrapper
# 首先应用 UFW 规则
ufw reload
# 然后允许 Docker 容器访问
for i in $(docker ps -q); do
docker_ip=$(docker inspect -f '{{range .NetworkSettings.Networks}}{{.IPAddress}}{{end}}' $i)
if [ ! -z "$docker_ip" ]; then
ufw allow from $docker_ip
fi
done
监控防火墙性能指标:
# 查看连接跟踪表状态
conntrack -L
conntrack -S
# 查看内核日志中的防火墙相关信息
dmesg | grep -i firewall
dmesg | grep -i nftables
dmesg | grep -i iptables
# 使用系统监控工具
top -p $(pgrep firewalld) # 如果使用 firewalld
htop
诊断工具:
# 使用 tcpdump 分析流量
tcpdump -i eth0 -n not port 22
# 使用 traceroute 诊断网络路径
traceroute example.com
# 使用 nmap 扫描端口
nmap -sS -O localhost
# 检查规则命中计数
iptables -L -v -n
nft list ruleset
连接跟踪是有状态防火墙的核心,但可能成为性能瓶颈。
查看连接跟踪状态:
# 查看当前连接跟踪数
cat /proc/sys/net/netfilter/nf_conntrack_count
# 查看最大连接跟踪数
cat /proc/sys/net/netfilter/nf_conntrack_max
# 查看连接跟踪表内容
conntrack -L
优化连接跟踪设置:
# 增加最大连接数(根据内存调整)
echo 262144 > /proc/sys/net/netfilter/nf_conntrack_max
# 调整连接超时时间
echo 600 > /proc/sys/net/netfilter/nf_conntrack_tcp_timeout_established
echo 120 > /proc/sys/net/netfilter/nf_conntrack_udp_timeout
# 永久生效
echo "net.netfilter.nf_conntrack_max=262144" >> /etc/sysctl.conf
echo "net.netfilter.nf_conntrack_tcp_timeout_established=600" >> /etc/sysctl.conf
规则排序优化:
# 将最常用的规则放在前面
# 例如,将 ESTABLISHED,RELATED 规则放在最前面
iptables -I INPUT -m state --state ESTABLISHED,RELATED -j ACCEPT
# 按协议和端口分组规则
# 将相同协议的规则放在一起,减少协议匹配次数
使用 IP 集优化大量 IP 匹配:
# 创建 IP 集
ipset create allowed_ips hash:ip family inet hashsize 1024 maxelem 65536
ipset add allowed_ips 192.168.1.10
ipset add allowed_ips 192.168.1.11
# 使用 IP 集
iptables -A INPUT -m set --match-set allowed_ips src -j ACCEPT
减少规则数量:
# 使用多端口匹配减少规则数量
iptables -A INPUT -p tcp -m multiport --dports 80,443,8080 -j ACCEPT
# 使用 IP 范围而不是多个单独规则
iptables -A INPUT -s 192.168.1.0/24 -j ACCEPT
HAProxy 前端防火墙配置:
# 只允许 HAProxy 接收来自负载均衡器的流量
iptables -A INPUT -p tcp --dport 80 -s 192.168.1.50 -j ACCEPT
iptables -A INPUT -p tcp --dport 80 -j DROP
# 允许健康检查
iptables -A INPUT -s 192.168.1.50 -p tcp --dport 9200 -j ACCEPT
Nginx 负载均衡器防火墙配置:
# 允许 HTTP 和 HTTPS
iptables -A INPUT -p tcp --dports 80,443 -j ACCEPT
# 允许后端服务器通信
iptables -A INPUT -s 192.168.2.0/24 -j ACCEPT
# 限制连接速率防止 DDoS
iptables -A INPUT -p tcp --dport 80 -m limit --limit 100/minute --limit-burst 200 -j ACCEPT
Kubernetes 环境下的防火墙:
# 允许 Kubernetes API 服务器
iptables -A INPUT -p tcp --dport 6443 -j ACCEPT
# 允许 etcd 客户端和服务器通信
iptables -A INPUT -p tcp --dports 2379,2380 -j ACCEPT
# 允许节点间通信
iptables -A INPUT -s 192.168.0.0/16 -j ACCEPT
# 允许 Flannel/VXLAN 流量
iptables -A INPUT -p udp --dport 8472 -j ACCEPT
Docker Swarm 模式防火墙:
# 允许 Swarm 管理端口
iptables -A INPUT -p tcp --dport 2377 -j ACCEPT
# 允许节点间通信端口
iptables -A INPUT -p tcp --dport 7946 -j ACCEPT
iptables -A INPUT -p udp --dport 7946 -j ACCEPT
# 允许覆盖网络流量
iptables -A INPUT -p udp --dport 4789 -j ACCEPT
环境描述:
防火墙配置策略:
负载均衡器配置:
# 清空现有规则
iptables -F
iptables -X
# 设置默认策略
iptables -P INPUT DROP
iptables -P FORWARD DROP
iptables -P OUTPUT ACCEPT
# 允许已建立连接
iptables -A INPUT -m state --state ESTABLISHED,RELATED -j ACCEPT
# 允许回环接口
iptables -A INPUT -i lo -j ACCEPT
# 允许管理访问(仅从办公室IP)
iptables -A INPUT -p tcp --dport 22 -s 203.0.113.0/24 -j ACCEPT
# 允许 HTTP 和 HTTPS
iptables -A INPUT -p tcp --dport 80 -j ACCEPT
iptables -A INPUT -p tcp --dport 443 -j ACCEPT
# 允许健康检查端口
iptables -A INPUT -p tcp --dport 9200 -j ACCEPT
# 允许从Web服务器返回的流量
iptables -A INPUT -s 192.168.10.0/24 -j ACCEPT
# 记录并拒绝其他所有输入
iptables -A INPUT -j LOG --log-prefix "IPTABLES-DROPPED: "
iptables -A INPUT -j DROP
# 保存配置
iptables-save > /etc/iptables/rules.v4
Web服务器配置:
# 基本规则与负载均衡器类似,但只允许来自负载均衡器和管理网络的流量
iptables -A INPUT -p tcp --dport 80 -s 192.168.1.0/24 -j ACCEPT
iptables -A INPUT -p tcp --dport 443 -s 192.168.1.0/24 -j ACCEPT
# 允许应用服务器之间的通信
iptables -A INPUT -s 192.168.10.0/24 -j ACCEPT
# 允许访问数据库和缓存服务器
iptables -A OUTPUT -d 192.168.20.0/24 -j ACCEPT
iptables -A OUTPUT -d 192.168.30.0/24 -j ACCEPT
环境描述:
防火墙配置:
# Galera Cluster 特定端口
iptables -A INPUT -p tcp --dport 4567 -s 192.168.20.0/24 -j ACCEPT
iptables -A INPUT -p tcp --dport 4568 -s 192.168.20.0/24 -j ACCEPT
iptables -A INPUT -p tcp --dport 4444 -s 192.168.20.0/24 -j ACCEPT
# MySQL 标准端口
iptables -A INPUT -p tcp --dport 3306 -s 192.168.10.0/24 -j ACCEPT
# IST (Incremental State Transfer) 端口
iptables -A INPUT -p tcp --dport 4567 -s 192.168.20.0/24 -j ACCEPT
# 允许集群节点间的所有通信
iptables -A INPUT -s 192.168.20.0/24 -j ACCEPT
# 允许监控服务器访问
iptables -A INPUT -s 192.168.100.100 -j ACCEPT
环境描述:
防火墙配置:
# 允许站点到站点VPN流量
iptables -A INPUT -p udp --dport 500 -j ACCEPT
iptables -A INPUT -p udp --dport 4500 -j ACCEPT
iptables -A INPUT -p esp -j ACCEPT
# 允许来自云端的流量
iptables -A INPUT -s 172.16.0.0/16 -j ACCEPT
# 允许到云端的流量
iptables -A OUTPUT -d 172.16.0.0/16 -j ACCEPT
# 云特定安全组规则(AWS示例)
# 允许HTTP/HTTPS来自互联网
# 允许SSH仅从公司网络
# 允许数据库端口仅从应用服务器
策略管理流程:
规则文档化模板:
规则ID: FW-WEB-001
应用系统: 电子商务网站
规则描述: 允许互联网用户访问Web服务器
协议: TCP
端口: 80,443
源地址: 0.0.0.0/0
目标地址: 192.168.1.100
操作: ACCEPT
创建日期: 2023-01-15
创建人: admin
审核日期: 2023-07-15
业务理由: 支持电子商务网站HTTP/HTTPS访问
自动化审计脚本:
#!/bin/bash
# firewall-audit.sh
# 备份当前规则
iptables-save > /backup/iptables-backup-$(date +%Y%m%d).rules
# 检查默认策略
echo "Default policies:"
iptables -L | grep policy
# 检查开放端口
echo "Open ports:"
iptables -L -n | grep ACCEPT | grep -v 'RELATED,ESTABLISHED'
# 检查是否有过于宽松的规则
echo "Wide-open rules:"
iptables -L -n | grep '0.0.0.0/0'
# 生成差异报告
if [ -f /backup/iptables-backup-previous.rules ]; then
diff /backup/iptables-backup-previous.rules /backup/iptables-backup-$(date +%Y%m%d).rules > /backup/iptables-diff-$(date +%Y%m%d).txt
fi
# 更新前一个备份
cp /backup/iptables-backup-$(date +%Y%m%d).rules /backup/iptables-backup-previous.rules
合规性检查:
配置详细日志记录:
# 记录被拒绝的输入连接
iptables -A INPUT -j LOG --log-prefix "IPTABLES-INPUT-DROPPED: " --log-level 4
# 记录被拒绝的输出连接
iptables -A OUTPUT -j LOG --log-prefix "IPTABLES-OUTPUT-DROPPED: " --log-level 4
# 限制日志速率防止日志洪水
iptables -A INPUT -m limit --limit 5/min -j LOG --log-prefix "IPTABLES-INPUT-DROPPED: " --log-level 4
使用 rsyslog 集中管理防火墙日志:
# 配置 rsyslog 处理防火墙日志
echo ":msg, contains, \"IPTABLES\" /var/log/iptables.log" > /etc/rsyslog.d/10-iptables.conf
# 重启 rsyslog
systemctl restart rsyslog
# 日志轮转配置
echo "/var/log/iptables.log {
daily
missingok
rotate 7
compress
delaycompress
notifempty
create 640 root adm
sharedscripts
postrotate
/usr/lib/rsyslog/rsyslog-rotate
endscript
}" > /etc/logrotate.d/iptables
使用 Fail2ban 自动阻止恶意IP:
# 安装 Fail2ban
apt-get install fail2ban
# 创建自定义监狱配置
echo "[sshd]
enabled = true
port = ssh
filter = sshd
logpath = /var/log/auth.log
maxretry = 3
bantime = 3600
[nginx-http-auth]
enabled = true
port = http,https
filter = nginx-http-auth
logpath = /var/log/nginx/error.log
maxretry = 3
bantime = 3600" > /etc/fail2ban/jail.local
连接被拒绝但规则正确:
性能问题:
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。