一、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

      1. ![image.png](https://cdn.nlark.com/yuque/0/2022/png/2735310/1657335670203-0170202d-8d6b-405a-a4be-ee738df7b7b3.png#clientId=u48d09c9a-7a7a-4&crop=0&crop=0&crop=1&crop=1&from=paste&height=48&id=u716d45d7&margin=%5Bobject%20Object%5D&name=image.png&originHeight=48&originWidth=272&originalType=binary&ratio=1&rotation=0&showTitle=false&size=17471&status=done&style=none&taskId=ua486e50c-c577-48f8-a6d7-3718d2b98dc&title=&width=272)
    • 第二步:默认情况下,宿主机中有一个/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

          ![image.png](https://cdn.nlark.com/yuque/0/2022/png/2735310/1657344626800-e73ee9ea-2165-49c8-ac94-2c3270a0da0e.png#clientId=u48d09c9a-7a7a-4&crop=0&crop=0&crop=1&crop=1&from=paste&height=259&id=uab505a86&margin=%5Bobject%20Object%5D&name=image.png&originHeight=259&originWidth=534&originalType=binary&ratio=1&rotation=0&showTitle=false&size=171157&status=done&style=none&taskId=u94ba80f2-eaa4-4a48-ad2a-a7866608b2f&title=&width=534)
        
      • 之后会生成一个名为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
      • image.png
      • 上面命令输入之后会创建一个ca.pem文件,这个文件是我们的CA证书,我们后面会使用这个文件来验证连接的安全性。image.png
      • 现在我们有了自己的CA,让我们用它为我们的Docker服务器创建证书和秘钥。

    三、创建服务器的证书签名和秘钥
    我们可以用新的CA来为Docker服务器进行证书签名请求(certificate signing request, CSR)和秘钥的签名和验证。

    • 第一步:为Docker服务器创建一个秘钥,如下所示,同理也需要输入这个密钥的密码(注意:请设置一个密码,我们将会在使用之前清除这个密码)。
      • openssl genrsa -des3 -out server-key.pem
      • openssl genrsa -out server-key.pem 2048image.png
      • 之后会创建一个密钥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
      • image.png
      • 之后生成一个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.pemimage.png
      • 上面命令输入完成之后会生成一个名为server-cert.pem的文件,这个文件就是我们的服务器证书。
    • 第四步:现在让我们来清除服务器密钥的密码,如下所示:
      • 输入命令之后,我们要输入先前设置的服务器密钥的密码(见上面第一步)。
      • 我们不想在Docker守护进程启动的时候再输入一次密码,因此需要清除它。
      • openssl rsa -in server-key.pem -out server-key.pem
      • image.png
    • 第五步:现在,让我们为这些文件添加一些更为严格的权限来更好地保护它们,如下所示:
      • chmod 0600 server-key.pem server-cert.pem ca.pemimage.png

    四、配置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.serviceimage.png
      • 使用了 —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 statusimage.png

    五、创建客户端证书和秘钥
    服务器已经启用了TLS,下面需要为客户端创建和签名证书和密钥,以保证我们的Docker客户端的安全性。
    备注:实际开发中,客户端应该是在其它机器上创建这些内容的,但是我们只有一台机器,因此都放在一个机器上操作了。

    • 第一步:创建客户端的密钥,同理,也需要输入一个临时的密码。
      • openssl genrsa -des3 -out client-key.pem
      • openssl genrsa -out key.pem 2048image.png
      • 之后生成一个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.csrimage.png
      • 第三步:现在我们需要通过添加一些扩展的客户端SSL认证属性,来开启我们的密钥的客户端身份认证,命令如下,需要切换到管理员身份,不能使用sudo来执行echo命令。
    • sudo su
    • echo extendedKeyUsage = clientAuth > extfile.cnf
    • echo “extendedKeyUsage=clientAuth” > extfile.cnfimage.png
    • 之后生成一个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.cnfimage.png
    • 之后生成一个client-cert.pem证书。
      • 第五步:同理,我们需要清除client-cert.pem文件中的密码,以便在Docker客户端中使用该文件,如下所示:回车之后需要输入上面创建client-key.pem密钥文件指定的密码”111111”。
    • openssl rsa -in client-key.pem -out client-key.pemimage.png

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

    备注: 如果在连接的时候不指定 —tlsverify标志,那么TLS连接会不通过,无法连接到服务端。