玩轉Docker:解決Docker容器未授權直接繞過宿主機禁用端口的BUG

我以為經過前面四篇博文的學習,自己對docker的瞭解最起碼入門了,但是當我用docker啟動一個81端口的nginx後(宿主機:容器/81:80),在宿主機的firwall防火牆沒有添加81端口的情況下,竟然可以直接訪問成功,然後試下docker運行mysql容器用3308端口,發現也是在firwall沒有添加端口的情況下,彷彿繞過了防火牆可以直接訪問到容器,當時就懵逼了…

環境

<code>CentOS7
firewall
docker
nginx/<code>

解決流程

1、以為是docker和firewall的啟動順序問題導致的

開始我以為是因為我先啟動docker後面重啟了firewall導致firewall不能夠監控docker,然後我還美滋滋的覺得終於找到問題了。最後發現,太天真了,啟動順序完全沒影響。

2、宿主機的防火牆和docker容器的防火牆衝突

後面我想到docker也是一個輕量級的linux操作系統,也有自己的防火牆,會不會是因為docker啟動自己的防火牆後,權限級別直接繞過了宿主機的防火牆,因此百度了很多,後面按照網上的說法啟動容器的時候加上—iptables=false,這樣可能就關閉掉了容器的iptables防火牆,然而經過嘗試並沒有什麼用,而且好像第二次啟動容器直接就啟動不了了,報什麼iptables錯誤

3、直接修改配置文件不使用docker的iptables防火牆

因為我現在的操作系統是CentOS7,所以宿主機用的是firewall,而docker用的是iptables,百度查找說需要在文件

/etc/default/docker中添加如下內容

<code>DOCKER_OPTS="--dns 8.8.8.8 --dns 8.8.4.4 --iptables=false"/<code>

然後我美滋滋的跟著執行,發現這個文件根本不存在,因此我又直接新建這個文件,保存,接著執行如下兩條命令重新加載文件和重啟docker

<code>#重載
systemctl daemon-reload
#重啟docker服務
service docker restart/<code>

啟動容器,重新訪問,喵的,還是可以直接訪問,彷彿這個配置文件完全沒有用然後直接百度,發現需要在文件/usr/lib/systemd/system/docker.service中添加如下配置,一下是我的文件

<code>[Unit]
Description=Docker Application Container Engine
Documentation=https://docs.docker.com
BindsTo=containerd.service
After=network-online.target firewalld.service containerd.service
Wants=network-online.target
Requires=docker.socket
[Service]
Type=notify
# the default is not to use systemd for cgroups because the delegate issues still
# exists and systemd currently does not support the cgroup feature set required
# for containers run by docker
ExecStart=/usr/bin/dockerd -H fd:// --containerd=/run/containerd/containerd.sock $DOCKER_OPTS
ExecReload=/bin/kill -s HUP $MAINPID
TimeoutSec=0
RestartSec=2
Restart=always
EnvironmentFile=-/etc/default/docker
# Note that StartLimit* options were moved from "Service" to "Unit" in systemd 229.
# Both the old, and new location are accepted by systemd 229 and up, so using the old location
# to make them work for either version of systemd.
StartLimitBurst=3
# Note that StartLimitInterval was renamed to StartLimitIntervalSec in systemd 230.

# Both the old, and new name are accepted by systemd 230 and up, so using the old name to make
# this option work for either version of systemd.
StartLimitInterval=60s
# Having non-zero Limit*s causes performance problems due to accounting overhead
# in the kernel. We recommend using cgroups to do container-local accounting.
LimitNOFILE=infinity
LimitNPROC=infinity
LimitCORE=infinity
# Comment TasksMax if your systemd version does not supports it.
# Only systemd 226 and above support this option.
TasksMax=infinity
# set delegate yes so that systemd does not reset the cgroups of docker containers
Delegate=yes
# kill only the docker process, not all processes in the cgroup
KillMode=process
[Install]
WantedBy=multi-user.target/<code>
a、添加配置文件,(-代表ignore error)
<code>EnvironmentFile=-/etc/default/docker/<code>
b、在ExecStart後面添加如下內容
<code>$DOCKER_OPTS/<code>

雖然搞不懂為什麼,反正接下來修改完/etc/default/docker後重載重啟

<code>#重載
systemctl daemon-reload
#重啟docker服務
service docker restart/<code>

重新啟動nginx容器,我的天,終於不能訪問了。執行如下命令開啟81端口

<code>firewall-cmd --zone=public --add-port=81/tcp --permanent
firewall-cmd --reload/<code>

我的天,終於可以訪問了,測一下docker啟動mysql的訪問,也被firewall攔截了。真是要命的東西

結語

雖然最終解決了,但是具體原理並不是太過明瞭,但是最起碼docker啟動的容器再也不會繞過firewall的限制,服了。


分享到:


相關文章: