为什么iptables在input drop能拦截本机所有进程但拦截不了docker
场景
我们想要使用iptables来拦截外部某些流量进入所有本地进程的流量,可以下发drop规则:
-
封禁 IP 地址:
iptables -I INPUT -s x.x.x.x -j DROP
-
封禁 IP 段
iptables -I INPUT -s x.x.x.x/x -j DROP
拦截后却发现其实流量进入不了本地进程,但是依旧可以进入到docker进程
原因
因为docker daemon下发了一些预置的iptables规则,来把流量引入到docker容器,而且这部分规则将流量以宿主机和容器为视角进行切分,尽量使网络在两者上能隔离(只是一定程度上)
预置规则:
-A PREROUTING -m addrtype --dst-type LOCAL -j DOCKER
-A DOCKER -i docker0 -j RETURN
剖析:
-
-A PREROUTING -m addrtype --dst-type LOCAL -j DOCKER
其实流量在进入本机器后,在PREROUTING的时候就会被送到docker链去了,这时候你的INPUT链路上的drop规则是无法起作用的,因为INPUT还在PREROUTING后面,除非流量到达docker链路后发现不是容器所需要的(目的端口非容器监听端口),才会return回来进入其它进程
-
-A DOCKER -i docker0 -j RETURN
流量到达docker链路后发现不是容器所需要的(目的端口非容器监听端口),return并进入其它的链路继续往下走,送到机器上非docker进程
如何限制docker流量
解决方法:在DOCKER-USER链路中插入规则即可
原因:
Docker链中还有一条DOCKER-USER,默认是空的,但是优先级在Docker链跳转时优先级最高,流量来到docker链路都会先送到DOCKER-USER,用于处理我们用户的自定义规则
Docker 安装了两个名为 DOCKER-USER 和 DOCKER 的自定义 iptables 链,并确保传入的数据包始终首先由这两个链检查。这些链是 FORWARD 链的一部分。
Docker 的所有 iptables 规则都添加到 DOCKER 链中。请勿手动操作该链条。如果您需要添加在 Docker 规则之前加载的规则,请将它们添加到 DOCKER-USER 链中。这些规则在 Docker 自动创建任何规则之前应用
限制与Docker守护程序的iptables规则示例:
默认情况下,允许所有外部源IP连接到Docker守护程序。要仅允许特定的IP或网络访问容器,请在DOCKER过滤器链的顶部插入一个否定的规则。
-
以下规则将外部访问限制为除192.168.1.1之外的所有IP地址:
iptables -I DOCKER-USER -i ext_if ! -s 192.168.1.1 -j DROP
注意,将需要更改ext_if以与主机的实际外部接口相对应。您可以改为允许来自源子网的连接。
-
以下规则仅允许从子网192.168.1.0/24访问:
iptables -I DOCKER-USER -i ext_if ! -s 192.168.1.0/24 -j DROP
-
可以使用–src-range指定要接受的IP地址–src-range (使用–src-range或–dst-range时也要添加-m iprange --dst-range ):
iptables -I DOCKER-USER -m iprange -i ext_if ! --src-range 192.168.1.1-192.168.1.3 -j DROP
您可以将-s或–src-range与-d或–dst-range以控制源和目标。例如,如果Docker守护程序同时监听192.168.1.99和10.1.2.3,则可以制定特定于10.1.2.3规则,并使192.168.1.99打开状态。