一、Docker Remote API的认证
自Docker的0.9版本开始Docker Remote API开始提供了认证机制。这种认证机制采用了TLS/SSL证书来确保用户与API之间连接的安全。
备注:该认证不仅仅适用于API。通过这个认证,还需要配置Docker客户来支持TLS认证。在本文我们也将看到如何对客户端进行配置。
有几种方法可以对我们的连接进行认证,包括使用一个完整的PKI基础设置,我们可以选择创建自己的证书授权中心(Certificate Authority,CA),或者使用已有的CA。在这里我们将建立自己的证书授权中心,因为这是一个简单、快速的开始。
警告:这依赖于运行在Docker宿主机上的本地CA。它也不像使用一个完整的证书授权中心那样安全。
二、建立证书授权中心
下面快速了解一下创建所需CA证书和密钥的方法,在大多数平台下这个过程都是非常标准的。
第一步:先要确保系统安装了openssl。查看命令:which openssl

第二步:默认情况下,宿主机中有一个/etc/docker/目录,待会我们用这个目录来保存我们的CA和相关资料(如果没有这个目录/etc/docker自己创建)。
- ls /etc/docker
第三步:进入上面那目录,生成一个私钥,命令如下,在创建私钥的过程中,我们需要为CA密钥设置一个密码(要自己记住这个密码123456,在新CA中,我们需要用这个秘钥来创建并对证书签名)。
- cd /etc/docker
- echo 01 | sudo tee ca.srl
- openssl genrsa -des3 -out ca-key.pem
openssl genrsa -aes256 -passout pass:$123456 -out ca-key.pem 2048
之后会生成一个名为ca-key.pem的新文件,这个文件是我们的CA的秘钥(不要把这个文件透露出去,也不能丢失这个文件)。
- 第四步:现在我们来创建一个CA证书,命令如下,回车之后会让你输入:
- 刚才创建的CA的秘钥的密码(刚才上面输入的123456)
- 然后输入城市名、组织名、邮箱等等呢个信息
- sudo openssl req -new -x509 -days 365 -key ca-key.pem -out ca.pem
- openssl req -new -x509 -passin “pass:123456” -days 3650 -key ca-key.pem -sha256 -out ca.pem

- 上面命令输入之后会创建一个ca.pem文件,这个文件是我们的CA证书,我们后面会使用这个文件来验证连接的安全性。

- 现在我们有了自己的CA,让我们用它为我们的Docker服务器创建证书和秘钥。
三、创建服务器的证书签名和秘钥
我们可以用新的CA来为Docker服务器进行证书签名请求(certificate signing request, CSR)和秘钥的签名和验证。
- 第一步:为Docker服务器创建一个秘钥,如下所示,同理也需要输入这个密钥的密码(注意:请设置一个密码,我们将会在使用之前清除这个密码)。
- openssl genrsa -des3 -out server-key.pem
- openssl genrsa -out server-key.pem 2048

- 之后会创建一个密钥server-key.pem。
- 第二步:现在让我们创建服务器的证书签名请求(CSR),如下所示:
- 同理,也要输入上面server-key.pem密钥的密码;
- 然后再输入一系列的信息,可直接回车,不输入了。
- 但是其中的Common Name比较重要,这个选项的值要么为Docker服务器(即从DNS中解析后得到的结果,完全限定域名)形式,要么为’*’ (这将允许在任何服务器上使用该服务器证书)。
- openssl req -new -key server-key.pem -out server.csr
- openssl req -new -key server-key.pem -out server.csr

- 之后生成一个server.csr文件。
- 第三步:现在让我们对CSR进行签名并生成服务器证书,如下所示,需要输入CA密钥文件的密钥(创建ca-key.pem文件时的密钥)。
- openssl x509 -req -days 365 -in server.csr -CA ca.pem -CAkey ca-key.pem -out server-cert.pem
- openssl x509 -req -days 3650 -in server.csr -CA ca.pem -CAkey ca-key.pem -passin “pass:$123456” -CAcreateserial -out server-cert.pem

- 上面命令输入完成之后会生成一个名为server-cert.pem的文件,这个文件就是我们的服务器证书。
- 第四步:现在让我们来清除服务器密钥的密码,如下所示:
- 输入命令之后,我们要输入先前设置的服务器密钥的密码(见上面第一步)。
- 我们不想在Docker守护进程启动的时候再输入一次密码,因此需要清除它。
- openssl rsa -in server-key.pem -out server-key.pem

- 第五步:现在,让我们为这些文件添加一些更为严格的权限来更好地保护它们,如下所示:
- chmod 0600 server-key.pem server-cert.pem ca.pem

- chmod 0600 server-key.pem server-cert.pem ca.pem
四、配置Docker守护进程
现在有了证书和密钥,可以来配置Docker守护进程来使用它们了。首先,我们需要修改守护进程的配置文件。在不同的系统中配置文件不同:
- Ubuntu、Debian系统:/etc/default/docker
- Upstart系统:/etc/init/docker.conf
- Red Hat、Redora系统:/etc/sysconfig/docker
- 对于那些使用了Systemd的发布版本:/usr/lib/systemd/docker.service
- 下面以centos7.9为例
- 第一步:修改/lib/systemd/system/docker.service 配置文件,修改ExecStart选项。我们添加了一个-H,让其监听在tcp的2376端口上,这样使得外网可以访问我们的Docker守护进程,从而可以调用Docker Remote API。
- 备注:上面让我们Docker守护进程监听在2376端口,这是Docker中TLS/SSL的默认端口号。对于非认证的链接,只能使用2375这个端口。
- vim /lib/systemd/system/docker.service

- 使用了 —tlsverify 标志来启动TLS,使用 —tlscacert、—tlsscert、—tlsskey这3个参数指定了CA证书、证书、密钥的位置。
- 可以使用 —tls标志来只启用TLS,而不启用客户端认证功能。
- ExecStart=/usr/bin/dockerd -H fd:// —containerd=/run/containerd/containerd.sock -H tcp://0.0.0.0:2376 —tlsverify —tlscacert=/etc/docker/ca.pem —tlscert=/etc/docker/server-cert.pem —tlskey=/etc/docker/server-key.pem
- 关于TLS还有很多其它选项可以使用,请参考: https://docs.docker.com/engine/security/protect-access/
- 第二步:之后重启Docker服务,然后再重启Docker守护进程,之后查看守护进程的状态。
- systemctl daemon-reload
- service docker restart
- service docker status

五、创建客户端证书和秘钥
服务器已经启用了TLS,下面需要为客户端创建和签名证书和密钥,以保证我们的Docker客户端的安全性。
备注:实际开发中,客户端应该是在其它机器上创建这些内容的,但是我们只有一台机器,因此都放在一个机器上操作了。
- 第一步:创建客户端的密钥,同理,也需要输入一个临时的密码。
- openssl genrsa -des3 -out client-key.pem
- openssl genrsa -out key.pem 2048

- 之后生成一个client-key.pem密钥文件。
- 第二步:现在我们来创建客户端CSR,如下所示:
需要输入上面创建client-key.pem密钥文件的密码。另外需要输入城市名一些列信息,直接回车。
- openssl req -new -key client-key.pem -out client.csr
- openssl req -new -key key.pem -out client.csr

- 第三步:现在我们需要通过添加一些扩展的客户端SSL认证属性,来开启我们的密钥的客户端身份认证,命令如下,需要切换到管理员身份,不能使用sudo来执行echo命令。
- sudo su
- echo extendedKeyUsage = clientAuth > extfile.cnf
- echo “extendedKeyUsage=clientAuth” > extfile.cnf

- 之后生成一个extfile.cnf文件。
- 第四步:现在让我们在自己的CA中对客户端CSR进行签名,如下所示:
- 此处我们使用CA密钥的密码创建另一个证书: client-cert.pem,需要输入创建ca-key.pem文件时的密码”123456”(见文章上面)。
- openssl x509 -req -days 365 -in client.csr -CA ca.pem -CAkey ca-key.pem -out client-cert.pem -extfile extfile.cnf
- openssl x509 -req -days 3650 -in client.csr -CA ca.pem -CAkey ca-key.pem -passin “pass:$123456” -CAcreateserial -out cert.pem -extfile extfile.cnf

- 之后生成一个client-cert.pem证书。
- 第五步:同理,我们需要清除client-cert.pem文件中的密码,以便在Docker客户端中使用该文件,如下所示:回车之后需要输入上面创建client-key.pem密钥文件指定的密码”111111”。
- openssl rsa -in client-key.pem -out client-key.pem

六、配置Docker客户端开启认证功能
接下来我们刻意配置我们的Docker客户端来使用我们新的TLS配置。之所以需要这么做,是因为Docker守护进程现在已经准备接收来自客户端和API的经过认证的连接。
备注:我们需要将ca.pem、client-cert.pem、client-key.pem这三个文件复制到想运行Docker客户端的宿主机上。上面提到过,实际上Docker客户端与服务端应该不在同一台机器上操作,但是此处我们只有一台机器,因此都在一台机器上操作了。
- 第一步:在/root/目录下有一个.docker目录(如果没有自己创建一个),然后将上面我们创建的客户端的ca.pem、client-cert.pem和client-key.pem复制进去。
- cp ca.pem client-cert.pem client-key.pem ~/.docker/
- ls ~/.docker/

- 第二步:现在我们就可以来测试从客户端到Docker守护进程的连接了。
- 我们使用-H来告诉客户端要连接的Docker主机(这个地方不能直接填IP,要填服务器的域名,要不然会报错的)。
- 指定了 —tlsverify选项,使我们通过TLS方式连接到Docker守护进程。
- 此处我们不需要指定任何证书或者秘钥文件,因为Docker会自己在我们的~/.docker/目录下查找这些文件。如果确实需要执行这些文件,请分别用 —tlscacert、—tlscert、—tlskey选项来指定CA证书、证书、密钥的位置。
- sudo docker -H=localhost:2376 —tlsverify info
备注: 如果在连接的时候不指定 —tlsverify标志,那么TLS连接会不通过,无法连接到服务端。
