写在最前面

官网文档

关于docker如何开启远程连接,以及如何使用“内置的 HTTPS 加密套接字”来安全连接,docker官网上有非常详细的英文介绍,本文关于这部分的内容也大致上是官网文档的翻译。

参见:

  1. dockerd的命令行选项
  2. 使用TLS (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守护进程套接字

官网原文链接 https://docs.docker.com/engine/security/protect-access/#use-tls-https-to-protect-the-docker-daemon-socket

使用 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,有两种方法进行配置:

  1. 可以直接把上面的命令选项附加到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
    
  2. 也可以通过修改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:
在这里插入图片描述

Logo

权威|前沿|技术|干货|国内首个API全生命周期开发者社区

更多推荐