限制 docker 容器互联网访问
Restrict docker container internet access
TLDR; - 向 docker 容器添加了一些 iptable 规则以限制互联网访问。工作正常,除了现在我无法从主机访问容器应用程序,但可以从容器本身内部访问
我有一个容器 运行 一个网络应用程序。此容器使用 mysql
、redis
等。每个依赖项都是远程的,可通过特定端口上的 ip 地址访问。
因此,例如,mysql 可通过 ip 13.255.255.255
访问
我想要的是让容器只能使用 mysql ip 地址,而不能使用任何其他地址。很少有 curl
请求来自我不想超出主机网络的代码。
我在 docker 中添加了一个入口点脚本,它在容器中添加了一些 iptables
规则。
ALLOWED_CIDR1=172.0.0.0/16
ALLOWED_CIDR2=13.255.255.255 #For mysql access
#iptables -P FORWARD DROP # we aren't a router
iptables -A INPUT -m state --state INVALID -j DROP
iptables -A INPUT -m state --state RELATED,ESTABLISHED -j ACCEPT
iptables -A INPUT -i lo -j ACCEPT
iptables -A INPUT -s 127.0.0.1 -j ACCEPT
iptables -A OUTPUT -d 127.0.0.1 -j ACCEPT
iptables -P INPUT DROP # Drop everything we don't accept
iptables -A INPUT -s 0.0.0.0 -j ACCEPT
iptables -A INPUT -s ::1 -j ACCEPT
iptables -A OUTPUT -d ::1 -j ACCEPT
iptables -A INPUT -s $ALLOWED_CIDR1 -j ACCEPT
iptables -A INPUT -s $ALLOWED_CIDR1 -j ACCEPT
iptables -A OUTPUT -d $ALLOWED_CIDR2 -j ACCEPT
iptables -A OUTPUT -d $ALLOWED_CIDR2 -j ACCEPT
iptables -P INPUT DROP
iptables -P OUTPUT DROP
当我运行容器并做
docker-compose exec <container-name> curl http://google.com
我得到以下回应:
curl: (6) Could not resolve host: google.com
这是意料之中的。现在,当我做
docker-compose exec <container-name> curl http://0.0.0.0
我收到以下回复:
"Hello World!"
这又是意料之中的事情。但是,当我从我的主机执行 curl http://0.0.0.0
时,以下是输出
* Trying 0.0.0.0...
* TCP_NODELAY set
* Connected to 0.0.0.0 (127.0.0.1) port 80 (#0)
> GET / HTTP/1.1
> Host: 0.0.0.0
> User-Agent: curl/7.62.0
> Accept: */*
> // Hangs here
所以,我无法从主机连接到 http://0.0.0.0,但可以从 docker.
内部连接
我太蠢了,竟然忽略了我自己发布的 iptables 规则。
规则集错误
ALLOWED_CIDR1=172.0.0.0/16
ALLOWED_CIDR2=13.255.255.255 #For mysql access
#iptables -P FORWARD DROP # we aren't a router
iptables -A INPUT -m state --state INVALID -j DROP
iptables -A INPUT -m state --state RELATED,ESTABLISHED -j ACCEPT
iptables -A INPUT -i lo -j ACCEPT
iptables -A INPUT -s 127.0.0.1 -j ACCEPT
iptables -A OUTPUT -d 127.0.0.1 -j ACCEPT
iptables -P INPUT DROP # Drop everything we don't accept
iptables -A INPUT -s 0.0.0.0 -j ACCEPT
iptables -A INPUT -s ::1 -j ACCEPT
iptables -A OUTPUT -d ::1 -j ACCEPT
iptables -A INPUT -s $ALLOWED_CIDR1 -j ACCEPT
iptables -A INPUT -s $ALLOWED_CIDR1 -j ACCEPT
iptables -A OUTPUT -d $ALLOWED_CIDR2 -j ACCEPT
iptables -A OUTPUT -d $ALLOWED_CIDR2 -j ACCEPT
iptables -P INPUT DROP
iptables -P OUTPUT DROP
你可以看到,在上面的部分:
- IP 0.0.0.0
没有OUTPUT ACCEPT
- ip
192.168.x.x
没有 OUTPUT ACCEPT 规则,它是我的 docker-0
网络接口 的 IP 地址
如果在启动容器时使用网络模式bridged
,docker和主机都使用docker0
网络接口进行通信(这恰好是我的情况)。
我注意到的另一件事是,我根本不需要 0.0.0.0
或 127.0.0.1
规则。由于入口点脚本将在 docker 容器中添加 iptable 规则,我们可能永远不想从容器本身访问 webapp。因此,为什么要费心使用 127.0.0.1?
总而言之,这是我所做的:
- 获取
docker0
网络的 IP 地址。 ip addr show docker0
。它输出 192.168.144.1/20
- 我在我的入口点 iptable 规则中添加了 192.168.0.0/16 到 ACCEPT 规则,它在第 1 点覆盖了我的 IP 地址
- 现在我可以从外部访问我的容器
我的 iptable 规则现在看起来像这样:
ALLOWED_CIDR1=172.0.0.0/16
ALLOWED_CIDR2=13.255.255.255
ALLOWED_CIDR3=192.168.0.0/16
iptables -A INPUT -m state --state INVALID -j DROP
iptables -A INPUT -m state --state RELATED,ESTABLISHED -j ACCEPT
iptables -A INPUT -i lo -j ACCEPT
iptables -P INPUT DROP # Drop everything we don't accept
iptables -P OUTPUT DROP
iptables -A INPUT -s $ALLOWED_CIDR1 -j ACCEPT
iptables -A INPUT -s $ALLOWED_CIDR2 -j ACCEPT
iptables -A INPUT -s $ALLOWED_CIDR3 -j ACCEPT
iptables -A OUTPUT -d $ALLOWED_CIDR1 -j ACCEPT
iptables -A OUTPUT -d $ALLOWED_CIDR2 -j ACCEPT
iptables -A OUTPUT -d $ALLOWED_CIDR3 -j ACCEPT
TLDR; - 向 docker 容器添加了一些 iptable 规则以限制互联网访问。工作正常,除了现在我无法从主机访问容器应用程序,但可以从容器本身内部访问
我有一个容器 运行 一个网络应用程序。此容器使用 mysql
、redis
等。每个依赖项都是远程的,可通过特定端口上的 ip 地址访问。
因此,例如,mysql 可通过 ip 13.255.255.255
访问我想要的是让容器只能使用 mysql ip 地址,而不能使用任何其他地址。很少有 curl
请求来自我不想超出主机网络的代码。
我在 docker 中添加了一个入口点脚本,它在容器中添加了一些 iptables
规则。
ALLOWED_CIDR1=172.0.0.0/16
ALLOWED_CIDR2=13.255.255.255 #For mysql access
#iptables -P FORWARD DROP # we aren't a router
iptables -A INPUT -m state --state INVALID -j DROP
iptables -A INPUT -m state --state RELATED,ESTABLISHED -j ACCEPT
iptables -A INPUT -i lo -j ACCEPT
iptables -A INPUT -s 127.0.0.1 -j ACCEPT
iptables -A OUTPUT -d 127.0.0.1 -j ACCEPT
iptables -P INPUT DROP # Drop everything we don't accept
iptables -A INPUT -s 0.0.0.0 -j ACCEPT
iptables -A INPUT -s ::1 -j ACCEPT
iptables -A OUTPUT -d ::1 -j ACCEPT
iptables -A INPUT -s $ALLOWED_CIDR1 -j ACCEPT
iptables -A INPUT -s $ALLOWED_CIDR1 -j ACCEPT
iptables -A OUTPUT -d $ALLOWED_CIDR2 -j ACCEPT
iptables -A OUTPUT -d $ALLOWED_CIDR2 -j ACCEPT
iptables -P INPUT DROP
iptables -P OUTPUT DROP
当我运行容器并做
docker-compose exec <container-name> curl http://google.com
我得到以下回应:
curl: (6) Could not resolve host: google.com
这是意料之中的。现在,当我做
docker-compose exec <container-name> curl http://0.0.0.0
我收到以下回复:
"Hello World!"
这又是意料之中的事情。但是,当我从我的主机执行 curl http://0.0.0.0
时,以下是输出
* Trying 0.0.0.0...
* TCP_NODELAY set
* Connected to 0.0.0.0 (127.0.0.1) port 80 (#0)
> GET / HTTP/1.1
> Host: 0.0.0.0
> User-Agent: curl/7.62.0
> Accept: */*
> // Hangs here
所以,我无法从主机连接到 http://0.0.0.0,但可以从 docker.
内部连接我太蠢了,竟然忽略了我自己发布的 iptables 规则。
规则集错误
ALLOWED_CIDR1=172.0.0.0/16
ALLOWED_CIDR2=13.255.255.255 #For mysql access
#iptables -P FORWARD DROP # we aren't a router
iptables -A INPUT -m state --state INVALID -j DROP
iptables -A INPUT -m state --state RELATED,ESTABLISHED -j ACCEPT
iptables -A INPUT -i lo -j ACCEPT
iptables -A INPUT -s 127.0.0.1 -j ACCEPT
iptables -A OUTPUT -d 127.0.0.1 -j ACCEPT
iptables -P INPUT DROP # Drop everything we don't accept
iptables -A INPUT -s 0.0.0.0 -j ACCEPT
iptables -A INPUT -s ::1 -j ACCEPT
iptables -A OUTPUT -d ::1 -j ACCEPT
iptables -A INPUT -s $ALLOWED_CIDR1 -j ACCEPT
iptables -A INPUT -s $ALLOWED_CIDR1 -j ACCEPT
iptables -A OUTPUT -d $ALLOWED_CIDR2 -j ACCEPT
iptables -A OUTPUT -d $ALLOWED_CIDR2 -j ACCEPT
iptables -P INPUT DROP
iptables -P OUTPUT DROP
你可以看到,在上面的部分:
- IP 0.0.0.0 没有OUTPUT ACCEPT
- ip
192.168.x.x
没有 OUTPUT ACCEPT 规则,它是我的docker-0
网络接口 的 IP 地址
如果在启动容器时使用网络模式bridged
,docker和主机都使用docker0
网络接口进行通信(这恰好是我的情况)。
我注意到的另一件事是,我根本不需要 0.0.0.0
或 127.0.0.1
规则。由于入口点脚本将在 docker 容器中添加 iptable 规则,我们可能永远不想从容器本身访问 webapp。因此,为什么要费心使用 127.0.0.1?
总而言之,这是我所做的:
- 获取
docker0
网络的 IP 地址。ip addr show docker0
。它输出 192.168.144.1/20 - 我在我的入口点 iptable 规则中添加了 192.168.0.0/16 到 ACCEPT 规则,它在第 1 点覆盖了我的 IP 地址
- 现在我可以从外部访问我的容器
我的 iptable 规则现在看起来像这样:
ALLOWED_CIDR1=172.0.0.0/16
ALLOWED_CIDR2=13.255.255.255
ALLOWED_CIDR3=192.168.0.0/16
iptables -A INPUT -m state --state INVALID -j DROP
iptables -A INPUT -m state --state RELATED,ESTABLISHED -j ACCEPT
iptables -A INPUT -i lo -j ACCEPT
iptables -P INPUT DROP # Drop everything we don't accept
iptables -P OUTPUT DROP
iptables -A INPUT -s $ALLOWED_CIDR1 -j ACCEPT
iptables -A INPUT -s $ALLOWED_CIDR2 -j ACCEPT
iptables -A INPUT -s $ALLOWED_CIDR3 -j ACCEPT
iptables -A OUTPUT -d $ALLOWED_CIDR1 -j ACCEPT
iptables -A OUTPUT -d $ALLOWED_CIDR2 -j ACCEPT
iptables -A OUTPUT -d $ALLOWED_CIDR3 -j ACCEPT