封锁端口

端口说明

使用kubeasz 安装 k8s 后,暴露的端口。会被扫描,需要仅在 集群内部访问

  1. udp (不需要处理)
1
2
3
53   kube-dns-upstream
68 dhclient,服务器自带分配 IP
123 chronyd
  1. tcp (需要处理)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
111   nfs rpc
179 calico-bird
2379 etcd
2380 etcd
5000 docker-registry
6443 kube-lb, kube-apiserver
9100 node_exporter
9253 kube-dns-upstream
9353 kube-dns-upstream
10248 kubelet
10249 kube-proxy
10250 kubelet
10256 kube-proxy
10257 kube-controller
10259 kube-scheduler
30900 prometheus-kube-prometheus-operator
30901 prometheus-kube-prometheus-prometheus
30902 prometheus-kube-prometheus-alertmanager
30903 prometheus-grafana
55443 harbor(自定)
55080 harbor (自定)
  1. tcp (不需要处理),仅 localhost(127.0.0.1) 访问
1
2
3
4
5
1514   docker-proxy (docker节点会有)
9099 calico-felix
42399 containerd (可能不是这个端口,随机)

8080 kube-dns-upstream 绑定到IP 169.254.20.10 仅 169.254.20.10:8080 能访问

这里封 raw 链是因为 有docker或者k8s端口,免得区分

1
2
3
4
5
6
7
8
9
10
11
12
ports="111 179 2379 2380 5000 6443 9100 9253 9353 10248 10249 10250 10256 10257 10259 30900 30901 30902 30903  55443 55080"
for port in $ports; do
iptables -t raw -I PREROUTING -p tcp --dport $port -j DROP
iptables -t raw -I PREROUTING -p tcp -s 192.168.1.0/24 --dport $port -j ACCEPT
iptables -t raw -I PREROUTING -p tcp -s 172.20.0.0/16 --dport $port -j ACCEPT
iptables -t raw -I PREROUTING -p tcp -s 10.68.0.0/16 --dport $port -j ACCEPT
iptables -t raw -I PREROUTING -p tcp -m iprange --src-range 192.168.2.100-192.168.2.200 --dport $port -j ACCEPT
iptables -t raw -I PREROUTING -p tcp -s localhost --dport $port -j ACCEPT
iptables -t raw -I PREROUTING -p tcp -s 192.168.2.2 --dport $port -j ACCEPT
done

iptables-save > /etc/sysconfig/iptables

8080 不需要操作

1
2
3
4
5
6
7
ports="8080"
for port in $ports; do
iptables -I INPUT -p tcp --dport $port -j DROP
iptables -I INPUT -p tcp -d 169.254.20.10 --dport $port -j ACCEPT
done

iptables-save > /etc/sysconfig/iptables

为什么规则要写在 raw / mangle,而不是 INPUT

下面几节反复在 rawmangleDOCKERINPUT 之间试探,原因是同一条规则写在不同位置效果差别很大。把包在 netfilter 里的路径摊开就清楚了:

1
2
3
4
5
6
7
8
9
10
网卡收包

├─ raw PREROUTING ← 在连接跟踪之前(NOTRACK 就写在这里)
├─ conntrack ← 连接跟踪在这里建表
├─ mangle PREROUTING
├─ nat PREROUTING ← DNAT 在这里发生!docker -p / NodePort 就是它做的

└─ 路由决策
├─ 目的是本机 ──→ mangle INPUT → filter INPUT → 本地进程
└─ 需要转发 ──→ mangle FORWARD → filter FORWARD → nat POSTROUTING → 出网卡

这张图能解释三件事。

一、为什么 NodePort 和 docker -p 的端口在 INPUT 链上封不住。

nat PREROUTING 里的 DNAT 已经把 --dport 从”你想封的那个端口”改成了容器/Pod 里的端口。等包走到 filter INPUT 时,--dport 30900 这个条件根本匹配不上了(而且如果目的变成了 Pod IP,它走的是 FORWARD 而不是 INPUT,连 INPUT 链都不经过)。所以想按原始端口拦,只能在 DNAT 之前下手,也就是 rawmanglePREROUTING

反过来,--network host 的容器端口就是宿主端口、没有 DNAT,用 INPUT 完全没问题——这也是下面两节位置不同的根本原因。

二、选 raw 而不是 mangle 是有代价的。

raw 在连接跟踪之前,此时内核还不知道这个包属于哪条连接。好处是最早、最省开销(NOTRACK 正是写在这里);代价是你写不出基于连接状态的规则:

1
2
# 这条在 raw 里是无效的,conntrack 还没建表
-m conntrack --ctstate ESTABLISHED,RELATED -j ACCEPT

mangle PREROUTING 在 conntrack 之后、DNAT 之前,既躲过了 DNAT 改端口的问题,又能用连接状态做精确放行——“默认拒绝 + 放行已建立连接”这种标准写法只有在这里(或更后面)才写得出来。

三、为什么最后倒向 mangle

calico 的 felix 会在 raw 表里插入自己的 cali-PREROUTING 链做策略和 NAT 前处理,手工规则和它同处一表,容易被顺序或跳转搅乱;而它对 mangle PREROUTING 的介入相对少。所以文末”建议直接封锁 mangle 链”这个经验判断是有依据的,不是随便选的——查看规则时也建议 iptables -t raw -Siptables -t mangle -S 都看一遍,确认自己的规则没有被别人的链抢先跳走。

一句话总结取舍:要拦 DNAT 之前的原始端口 → 用 mangle PREROUTING;要极致省开销或做 NOTRACK → 用 raw;只是宿主自己的端口 → INPUT 最直观。

允许访问的 IP

localhost,10.68.0.0/16, 172.20.0.0/16, 192.168.1.0/24, 192.168.2.2, 192.168.2.100 - 192.168.2.200

iptables表的优先级:raw>mangle>nat>filter

一般的端口

eg: 80,443 等

1
2
3
4
5
6
7
8
9
10
11
12
ports="80 443 "
for port in $ports; do
iptables -I INPUT -p tcp --dport $port -j DROP
iptables -I INPUT -p tcp -s 192.168.1.0/24 --dport $port -j ACCEPT
iptables -I INPUT -p tcp -s 172.20.0.0/16 --dport $port -j ACCEPT
iptables -I INPUT -p tcp -s 10.68.0.0/16 --dport $port -j ACCEPT
iptables -I INPUT -p tcp -m iprange --src-range 192.168.2.100-192.168.2.200 --dport $port -j ACCEPT
iptables -I INPUT -p tcp -s localhost --dport $port -j ACCEPT
iptables -I INPUT -p tcp -s 192.168.2.2 --dport $port -j ACCEPT
done

iptables-save > /etc/sysconfig/iptables

k8s

1
2
3
4
5
6
7
8
9
10
11
12
ports="111 179 2379 2380 5000 6443 9100 9253 9353 10248 10249 10250 10256 10257 10259"
for port in $ports; do
iptables -I INPUT -p tcp --dport $port -j DROP
iptables -I INPUT -p tcp -s 192.168.1.0/24 --dport $port -j ACCEPT
iptables -I INPUT -p tcp -s 172.20.0.0/16 --dport $port -j ACCEPT
iptables -I INPUT -p tcp -s 10.68.0.0/16 --dport $port -j ACCEPT
iptables -I INPUT -p tcp -m iprange --src-range 192.168.2.100-192.168.2.200 --dport $port -j ACCEPT
iptables -I INPUT -p tcp -s localhost --dport $port -j ACCEPT
iptables -I INPUT -p tcp -s 192.168.2.2 --dport $port -j ACCEPT
done

iptables-save > /etc/sysconfig/iptables

docker 直接使用host 网络的端口(推荐直接使用 raw)

eg 5432 3306

--network host 的容器和宿主共享 netns,它的端口就等于宿主进程的端口,流量走 PREROUTING → INPUT 本地投递,根本不经过 FORWARD 路径上的 DOCKER 链,规则写在 DOCKER 里一条都命中不了,用 INPUT 就行(标题里说的 raw 表 PREROUTING 也一样有效)。

顺带说明:DOCKER 链本身是 dockerd 自己管理的,容器启停、端口发布变化或者 docker 重启时会被重建清空,手工插进去的规则会静默消失。如果要处理的是 bridge 模式下发布出来的端口,规则应该写到 DOCKER-USER 链,那是官方留给用户的位置。

1
2
3
4
5
6
7
8
9
10
11
12
ports="5432 3306 "
for port in $ports; do
iptables -I INPUT -p tcp --dport $port -j DROP
iptables -I INPUT -p tcp -s 192.168.1.0/24 --dport $port -j ACCEPT
iptables -I INPUT -p tcp -s 172.20.0.0/16 --dport $port -j ACCEPT
iptables -I INPUT -p tcp -s 10.68.0.0/16 --dport $port -j ACCEPT
iptables -I INPUT -p tcp -m iprange --src-range 192.168.2.100-192.168.2.200 --dport $port -j ACCEPT
iptables -I INPUT -p tcp -s localhost --dport $port -j ACCEPT
iptables -I INPUT -p tcp -s 192.168.2.2 --dport $port -j ACCEPT
done

iptables-save > /etc/sysconfig/iptables

k8s 网络以及 端口映射的端口

封 raw 链

eg: 30900 30901

1
2
3
4
5
6
7
8
9
10
11
12
ports="30900 30901"
for port in $ports; do
iptables -t raw -I PREROUTING -p tcp --dport $port -j DROP
iptables -t raw -I PREROUTING -p tcp -s 192.168.1.0/24 --dport $port -j ACCEPT
iptables -t raw -I PREROUTING -p tcp -s 172.20.0.0/16 --dport $port -j ACCEPT
iptables -t raw -I PREROUTING -p tcp -s 10.68.0.0/16 --dport $port -j ACCEPT
iptables -t raw -I PREROUTING -p tcp -m iprange --src-range 192.168.2.100-192.168.2.200 --dport $port -j ACCEPT
iptables -t raw -I PREROUTING -p tcp -s localhost --dport $port -j ACCEPT
iptables -t raw -I PREROUTING -p tcp -s 192.168.2.2 --dport $port -j ACCEPT
done

iptables-save > /etc/sysconfig/iptables

建议直接封锁 mangle 链

raw 链等也会被 calico 等 规则改写,查看 mangle 未被操作

使用 calico 可以用 calico 的网络规则,不过需要先安装 各种 crd

1
2
3
4
5
6
7
8
9
10
11
12
ports="30900 30901"
for port in $ports; do
iptables -t mangle -I PREROUTING -p tcp --dport $port -j DROP
iptables -t mangle -I PREROUTING -p tcp -s 192.168.1.0/24 --dport $port -j ACCEPT
iptables -t mangle -I PREROUTING -p tcp -s 172.20.0.0/16 --dport $port -j ACCEPT
iptables -t mangle -I PREROUTING -p tcp -s 10.68.0.0/16 --dport $port -j ACCEPT
iptables -t mangle -I PREROUTING -p tcp -m iprange --src-range 192.168.2.100-192.168.2.200 --dport $port -j ACCEPT
iptables -t mangle -I PREROUTING -p tcp -s localhost --dport $port -j ACCEPT
iptables -t mangle -I PREROUTING -p tcp -s 192.168.2.2 --dport $port -j ACCEPT
done

iptables-save > /etc/sysconfig/iptables

开机自启

  1. systemd 不推荐 ,docker 服务,k8s 服务未启动时,会自启失败
1
2
systemctl enable iptables
systemctl restart iptables
  1. crontab

手动执行,或者 crontab 添加自动启动

1
iptables-restore < /etc/sysconfig/iptables

重启自启动

1
(crontab -l|grep -v "@reboot iptables-restore < /etc/sysconfig/iptables";echo "@reboot iptables-restore < /etc/sysconfig/iptables")| crontab

推荐使用脚本

/etc/iptables_rule.sh

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
source /etc/profile
# 默认的环境变量 /usr/bin:/bin 没有 iptables 命令
export PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:$PATH

ports="111 179 2379 2380 5000 6443 9100 9253 9353 10248 10249 10250 10256 10257 10259 30900 30901 30902 30903 55443 55080"
for port in $ports; do
iptables -t raw -I PREROUTING -p tcp --dport $port -j DROP
iptables -t raw -I PREROUTING -p tcp -s 10.0.10.0/24 --dport $port -j ACCEPT
iptables -t raw -I PREROUTING -p tcp -s 172.20.0.0/16 --dport $port -j ACCEPT
iptables -t raw -I PREROUTING -p tcp -s 10.68.0.0/16 --dport $port -j ACCEPT
iptables -t raw -I PREROUTING -p tcp -s localhost --dport $port -j ACCEPT
done
iptables -t raw -I PREROUTING -p tcp -s 172.18.0.0/16 --dport 55443 -j ACCEPT
iptables -t raw -I PREROUTING -p tcp -s 172.18.0.0/16 --dport 55080 -j ACCEPT
iptables -t raw -I PREROUTING -p tcp -s 172.18.0.0/16 --dport 5000 -j ACCEPT

echo `date` >> /root/reboot.txt
echo init_iptables_sucess >> /etc/reboot.txt

加入自启

1
(crontab -l|grep -v "@reboot /bin/sh /etc/iptables_rule.sh";echo "@reboot /bin/sh /etc/iptables_rule.sh")| crontab

补充

老版本封锁 harbor 时发现, 使用 docker 无法拉取镜像

systemctl status docker

1
2
/usr/bin/docker-proxy -proto tcp -host-ip 127.0.0.1 -host-port 55443 -container-ip 172.21.0.2 -container-port 8443
/usr/bin/docker-proxy -proto tcp -host-ip 127.0.0.1 -host-port 55080 -container-ip 172.21.0.2 -container-port 8443

harbor-core 会连接 registry 的 5000 端口

harbor 机器新增规则

1
2
3
iptables -t raw -I PREROUTING  -p tcp -s 172.21.0.0/16 --dport 55443 -j ACCEPT
iptables -t raw -I PREROUTING -p tcp -s 172.21.0.0/16 --dport 55080 -j ACCEPT
iptables -t raw -I PREROUTING -p tcp -s 172.21.0.0/16 --dport 5000 -j ACCEPT