写在最前面
官网文档
关于docker如何开启远程连接,以及如何使用“内置的 HTTPS 加密套接字”来安全连接,docker官网上有非常详细的英文介绍,本文关于这部分的内容也大致上是官网文档的翻译。
参见:
Docker Engine 客户端与服务端之间的通信
我们知道 Docker Engine 是一个客户端-服务器型的应用程序。dockerd作为一个守护进程在后台长时间运行(所以有时候也说是docker daemon)是docker的服务端。docker daemon不提供任何操作界面(CLI命令行或者图形界面),可供用户直接使用的操作界面由客户端(Docker CLI、各种docker的图形操作界面、idea的docker插件等等)提供。
docker demon提供了一套与之通信的api,并且支持unix域套接字、tcp和fd(Systemd socket activation)这三种套接字通信模式,通过dockerd的-H 选项来开启套接字支持,例如:
- UNIX套接字:
dockerd -H unix:///var/run/docker.sock
- fd:
dockerd -H fd://
危险的操作
By default, Docker runs through a non-networked UNIX socket. It can also optionally communicate using SSH or a TLS (HTTPS) socket.
——摘自docker官网
docker daemon默认是只开放UNIX域套接字来通信的,UNIX域套接字只能与本地的进程进行通信。也就是说默认情况下只能利用本地 Docker Engine 提供的docker CLI,使用docker命令来与docker daemon通信。如果要使用idea的docker插件来远程通信的话,就需要开启tcp:
例如:
dockerd -H tcp://0.0.0.0:2375
注意,上面的命令是非常危险的
,应为它允许任意IP的2375端口与docker daemon直接进行通信,并且不需要任何身份认证。如果你的docker daemon主机处于外网环境,这样做会直接让你的docker daemon裸奔在互联网,任意ip都可以连上你的docker daemon来搞事情。
之前买的云服务器,按照百度来的做法,这样搞了。后来直接被ip在荷兰的黑客黑去挖矿了,血淋淋的教训啊
国内现状,大伙懂得都懂,一抄十、十抄百,没几个去真正研究的。即使是这种非常危险的操作,也没有任何说明(因为都是抄的,自己也没弄明白怎么回事儿)。所以,即使官网的英文文档写的很详细的了,我觉得也有必要再写篇博客来好好捋一捋docker如何开启使用TLS保护的安全远程连接,不至于让你的docker daemon裸奔在互联网。
idea的docker插件
idea有个docker插件,使用这个插件来操作docker非常方便。
在使用前需要在插件里配置docker,具体位置如下:
可以看到这里是支持TCP socket远程连接的,并且支持使用 TLS ,需要提供CA证书(图中的Certification folder),所以第一步是开启docker的安全远程连接。
使用TSL,在docker daemon可以只允许来自由该 CA 签名的证书进行身份验证的客户端的连接。在客户端,它只连接到具有该 CA 签署的证书的服务器。也就是只有docker daemon和客户端的的证书对得上号,他们才能进行连接并通信,确保连接的客户端是受docker daemon信任的。
docker安全远程连接
使用TLS (HTTPS)保护Docker守护进程套接字
使用 OpenSSL 创建 CA、服务器和客户端密钥
首先,在远端的docker宿主主机上新建个文件夹,保存生成的 CA 私钥和公钥文件:
mkdir ~/ca
cd ~/ca
使用OpenSSL生成 CA 私钥和公钥文件
依次执行以下命令:
openssl genrsa -aes256 -out ca-key.pem 4096
这里需要输入一个密码,请牢记这个密码,后面要用到
openssl req -new -x509 -days 365 -key ca-key.pem -sha256 -out ca.pem
这里需要输入密码、国家、省、市、组织、单位、Common name、邮箱等。这里没啥特殊的,按要求写就行
openssl genrsa -out server-key.pem 4096
openssl req -subj "/CN=$HOST" -sha256 -new -key server-key.pem -out server.csr
注意,将
/CN=
后面的$HOST
替换成docker所在主机的域名或者IP地址。
使用 CA 签署公钥
echo subjectAltName = DNS:$HOST,IP:0.0.0.0 >> extfile.cnf
同样要替换
$HOST
为docker所在主机的域名或者IP地址。
上面是允许所有IP远程访问,也可以只允许指定的IP访问。例如,只允许10.10.10.20和10.10.10.30进行连接:
echo subjectAltName = DNS:$HOST,IP:10.10.10.20,IP:10.10.10.30 >> extfile.cnf
将 Docker 守护程序密钥的扩展使用属性设置为仅用于服务器身份验证:
echo extendedKeyUsage = serverAuth >> extfile.cnf
生成签名证书
openssl x509 -req -days 365 -sha256 -in server.csr -CA ca.pem -CAkey ca-key.pem \
-CAcreateserial -out server-cert.pem -extfile extfile.cnf
授权插件提供更细粒度的控制来补充来自双向 TLS 的身份验证。除了上述文档中描述的其他信息外,在 Docker 守护程序上运行的授权插件会收到用于连接 Docker 客户端的证书信息。
继续创建客户端密钥和证书签名请求:
openssl genrsa -out key.pem 4096
openssl req -subj '/CN=client' -new -key key.pem -out client.csr
要使密钥适合客户端身份验证,请创建一个新的扩展配置文件:
echo extendedKeyUsage = clientAuth > extfile-client.cnf
现在,生成签名证书:
openssl x509 -req -days 365 -sha256 -in client.csr -CA ca.pem -CAkey ca-key.pem \
-CAcreateserial -out cert.pem -extfile extfile-client.cnf
生成后cert.pem,server-cert.pem您可以安全地删除两个证书签名请求和扩展配置文件:
rm -v client.csr server.csr extfile.cnf extfile-client.cnf
默认umask值为 022,您的密钥对您和您的组来说是世界可读和可写的。
为保护您的密钥免受意外损坏,请移除其写入权限。要使它们只能由您读取,请按如下方式更改文件模式:
chmod -v 0400 ca-key.pem key.pem server-key.pem
证书可以是全世界可读的,但您可能希望删除写入权限以防止意外损坏:
chmod -v 0444 ca.pem server-cert.pem cert.pem
让 Docker daemon只接受来自提供 CA 信任的证书的客户端的连接
把dockerd要用到的文件找个地方单独存放:
cp {ca,server-*}.pem /etc/docker/
在启动docker daemon时开启TSL认证,并指定ca、公钥秘钥:
dockerd \
--tlsverify \
--tlscacert=/etc/docker/ca.pem \
--tlscert=/etc/docker/server-cert.pem \
--tlskey=/etc/docker/server-key.pem \
-H=0.0.0.0:2376
注意:基于 TLS 的 Docker 应该在 TCP 端口 2376 上运行。
使用service
上面是直接使用dockerd,但是一般是使用service管理docker daemon,有两种方法进行配置:
-
可以直接把上面的命令选项附加到ExecStart:
vim /lib/systemd/system/docker.service
修改ExecStart
ExecStart=/usr/bin/dockerd -H fd:// -H unix:///var/run/docker.sock --containerd=/run/containerd/containerd.sock --tlsverify --tlscacert=ca.pem --tlscert=server-cert.pem --tlskey=server-key.pem -H tcp://0.0.0.0:2376
修改后记得reload一下:
systemctl daemon-reload
重启docker daemon服务:
service docker restart
-
也可以通过修改daemon.json配置:
vim /etc/docker/daemon.json
修改以下几个配置:
{ "hosts": [ "fd://", "unix:///var/run/docker.sock", "tcp://0.0.0.0:2376" ], "tlsverify": true, "tlscacert": "/etc/docker/ca.pem", "tlscert": "/etc/docker/server-cert.pem", "tlskey": "/etc/docker/server-key.pem" }
同时需要去除
/lib/systemd/system/docker.service
文件中ExecStart
里全部的-H
选项,因为命令行选项的优先级高于daemon.json配置文件。
客户端设置
将客户端密钥和签名证书拉取到客户端
使用scp命令拉取服务器上的客户端秘钥和签名证书:
C:\Users\xxx> scp root@$HOST:~/ca/{ca,cert,key}.pem ./.ca/docker
同样将 $HOST 替换成docker daemon所在服务器的ip或域名,不熟悉 scp 命令的先百度下用法。
idea的docker插件配置
回到docker插件配置页面:
点击加号,选择TCP Socket,Engine API URL格式要填https://$HOST:2376
,$HOST换成docker daemon所在服务器的ip或域名,Certification folder选择你刚刚拉取的客户端秘钥和签名证书所在文件夹。
出现Connection successful表示配置成功。
service里面会出现一个docker: