use-the-tls-protect-docker-api
使用TLS保护docker daemon的API。
前言
如果不使用TLS和不使用相关客户端证书对客户端身份进行验证,那么能够于服务器进行通信的任何主机(假设未进行其他防护措施),都可以访问该服务器上的docker daemon的TCP API(下称API)。
▲ 未对客户端进行验证,API暴露
其实这是一个非常危险的行为,拥有API的访问权相当拥有了整个docker client(甚至更多)的功能。比如说通过API使用mount bind
将服务器的某些重要目录(/
,/etc/
…)挂载到一个容器内部,通过容器就可以直接的对挂载进来的文件(夹)进行操作。
使用 openssl 创建证书
首先是创建一个私有的CA根证书,然后使用此证书分别对服务端证书和客户端证书进行签名。
证书请求文件资料
缩写 | 含义 |
---|---|
C | Country Name |
S | State or Province Name |
L | Locality Name |
O | Organization Name |
OU | Organization Unit Name |
CN | Common Name |
emailAddress | Email Address |
CN设置哪个主机可以使用这个证书(客户端好像没这个限制)。
默认情况下,OpenSSL创建的证书只包含一个CN而且只能设置一个主机名。
例子(不同服务情况可以不一样)
如果服务器IP为1.1.1.1,并且申请一个证书,其CN为1.1.1.1。
那么将只能通过1.1.1.1访问服务器中使用此证书的服务。
如果在内部通过127.0.0.1、localhost,或者是主机的域名,访问服务器的中使用此证书的服务,会有如下指示:
unable to communicate securely with peer: requested domain name does not match the server’s certificate.
因为这个限制,即便你有其他相关联的站点,也不得不为每个站点生成一张单独的证书。解决方案是使用多域名的证书,实现方法有X.509
的SAN
(subjectalternative name)和泛域名(类似使用通配符)。
需要注意的是,如果使用SAN
,CN将不生效。
创建CA根证书
- 生成CA私钥【ca-key.pem】
- 通过CA私钥【ca-key.pem】生成证书签名请求文件【ca.csr】
- 对证书签名请求文件【ca.csr】进行自签名生成CA根证书【ca.pem】
1 | # 生成CA私钥【ca-key.pem】 |
创建服务端证书
- 生成server私钥【server-key.pem】
- 通过server私钥【server-key.pem】生成证书签名请求文件【server.csr】
- 使用CA根证书【ca.pem】对服务端的证书签名请求文件【server.csr】进行签名生成服务端证书【server.pem】
先创建一个X509V3扩展文件【extfile.cnf】,说明证书的用途,还有设置SAN
,使一个证书可能支持多个主机。
1 | extendedKeyUsage = serverAuth |
1 | # 生成server私钥【server-key.pem】 |
创建客户端证书
客户端证书和服务端证书的创建流程基本一样。
X509V3扩展文件【extfile.cnf】
1 | extendedKeyUsage = clientAuth |
在客户端中,客户端证书好像不受的CN及SAN
的限制,这里就不设置了(有问题可以联系我)。
最后列下所需要的文件。
- CA根证书【ca.pem】
- 服务端证书【server.pem】
- 服务端私钥【server-key.pem】
- 客户端证书【clent.pem】
- 客户端端私钥【client-key.pem】
如果需要在像windows上面浏览器上面使用客户端的证书和私钥,需要将客户端证书和客户端私钥打包成一个证书文件。
1 | openssl pkcs12 -export -clcerts -in client.pem -inkey client-key.pem -out client.p12 |
对于CA根证书可以直接修改其后缀为.cer
或者.crt
。
配置docker daemon使用TSL
Daemon配置
tlsverify, tlscacert, tlscert, tlskey set: Authenticate clients
双向验证
要求验证客户端,其中包含的选项为ca、服务器证书、服务器私钥,且指定要求对客户端进行验证。tls, tlscert, tlskey: Do not authenticate clients
单向验证(通常不使用这个模式)
不要求验证客户端,其中包含的选项为ca、服务器证书、服务器私钥。
dockerd v18.09的配置配置文件路径为/etc/docker/daemon.json
。因为是设置双向验证的模式,所以需要在配置的选项有tlsverify
、tlscacert
、tlscert
、tlskey
。
1 | { |
需要注意的是,如果是使用systemd
的系统,不能够在daemon.json
中设置hosts
,因为docker在systemd
的启动脚本中已经使用了-H
选项(与hosts
作用一样),重复使用的话,将导致dockerd启动失败。
原文:
Note: You cannot set options in daemon.json that have already been set on daemon startup as a flag. On systems that use systemd to start the Docker daemon, -H is already set, so you cannot use the hosts key in daemon.json to add listening addresses. See https://docs.docker.com/engine/admin/systemd/#custom-docker-daemon-options for how to accomplish this task with a systemd drop-in file.
在使用systemd
的系统中配置-H
(hosts
)的方法是配置docker的systemd
启动脚本。
1 | systemtcl edit docker.service |
1 | [Service] |
注意前面留空的ExecStart
不能省略。
关于2376
和2375
端口,通常2376
是在使用TSL时的API时使用的端口,而2375
是没有使用TSL时的API端口,虽然不是硬性规定,不过还是应该遵循规范。
重启dockerd生效。
测试docker daemon TSL API
▲ 只安装CA根证书,不使用客户端证书
在没有客户端证书的情况下,服务端对客户端的身份验证不通过,访问API失败。
▲ 安装客户端证书,访问服务端时要求验证客户端身份,选择证书
▲ 验证成功,成功访问API
参考
- Blog Link: https://unihon.github.io/2019-04/use-the-tls-protect-docker-api/
- Copyright Declaration: The author owns the copyright. Please indicate the source reproduced!