引言
Docker 默认通过 Unix Socket
对外提供接口,也支持 HTTP
的方式,后者允许我们能够在本地控制远程服务器中的 Docker。如果你想让远程服务器中的 Docker 以安全的方式被访问,可为其配置 TLS,做到服务端和客户端的双向验证。本文由我的同事 @like 投稿,其中总结了他在配置 Docker TLS 过程中的实践经验。
安装 cfssl
这里我们使用 CloudFlare 的 PKI 工具集 cfssl 来创建证书。
安装 cfssl
、cfssljson
以及 cfssl-certinfo
(假设已有GoLang
环境):
go get -u github.com/cloudflare/cfssl/cmd/cfsslgo get -u github.com/cloudflare/cfssl/cmd/cfssljsongo get -u github.com/cloudflare/cfssl/cmd/cfssl-certinfo
另外也可以直接下载二进制包:
curl -o cfssl -L https://pkg.cfssl.org/R1.2/cfssl_linux-amd64
该网站上的 cfssl
好久没更新啦,建议通过 GO
方式安装。
创建证书
根证书(CA)
首先我们需要创建一个 CA 证书,后续利用它去生成其他证书。
配置文件:
cat > ca-config.json << EOF{"signing": {"default": {"expiry": "87600h"},"profiles": {"docker": {"usages": ["signing","key encipherment","server auth","client auth"],"expiry": "87600h"}}}}EOF
profiles
: 可以定义多个 profile,分别指定不同的过期时间、使用场景等参数,在签名证书时使用某个 profile;server auth
: 服务端证书,表示 client 可以用该 CA 对 server 提供的证书进行验证;client auth
: 客户端证书,表示 server 可以用该 CA 对 client 提供的证书进行验证
生成根证书
证书请求文件(CSR):
cat > ca-csr.json << EOF{"CN": "LiKe Personal CA","key": {"algo": "rsa","size": 2048},"names": [{"C": "CN","ST": "LiaoNing","L": "DaLian","O": "My Org","OU": "My Org Unit"}],"ca": {"expiry": "87600h"}}EOF
生成根证书和私钥:
cfssl gencert -initca ca-csr.json | cfssljson -bare ca
得到:
ca-key.pemca.pem
服务端证书
CSR 配置:
cat > server-csr.json << EOF{"CN": "Docker Server","hosts": ["127.0.0.1","x.x.x.x","my.docker.server",],"key": {"algo": "rsa","size": 2048},"names": [{"C": "CN","ST": "LiaoNing","L": "DaLian","O": "My Org","OU": "My Org Unit"}]}EOF
CN
: Common Name,通常为域名或服务器的FQDN(完全限定域名)
;hosts
: 如果该证书能被多域名使用,可在这里添加DNS
或IP
生成服务端证书和私钥:
cfssl gencert -ca ca.pem -ca-key ca-key.pem -config ca-config.json -profile docker server-csr.json | cfssljson -bare server
得到:
server-key.pemserver.pem
客户端证书
客户端证书的配置中除了没有 hosts
字段,其他与生成服务端证书一样。
cat > client-csr.json << EOF{"CN": "Docker Client","key": {"algo": "rsa","size": 2048},"names": [{"C": "CN","ST": "LiaoNing","L": "DaLian","O": "My Org","OU": "My Org Unit"}]}EOF
生成客户端证书和私钥:
cfssl gencert -ca ca.pem -ca-key ca-key.pem -config ca-config.json -profile docker client-csr.json | cfssljson -bare client
得到:
client-key.pemclient.pem
最后为了保护 key 文件,需要移除其写权限,并保证只有自己可读:
chmod -v 0400 ca-key.pem server-key.pem client-key.pem
另外证书是任何人都可以访问的:
chmod -v 0444 ca.pem server.pem client.pem
配置docker
修改 dockerd
的启动命令:
dockerd --tlsverify --tlscacert=ca.pem --tlscert=server.pem --tlskey=server-key.pem -H=0.0.0.0:2376
为了连接远端 Docker 并验证服务端证书,需要提供客户端 key、客户端证书以及信任的 CA:
docker --tlsverify --tlscacert=ca.pem --tlscert=client.pem --tlskey=client-key.pem -H=$HOST:2376 version
每次执行 docker
命令时都提供证书是很麻烦的,我们可以把证书和密钥放在 ~/.docker
目录下,并设置 DOCKER_HOST
和 DOCKER_TLS_VERIFY
环境变量,这样默认就走 TLS 的方式。
mkdir -p ~/.dockercp -v {ca,cert,key}.pem ~/.dockerexport DOCKER_HOST=tcp://$HOST:2376 DOCKER_TLS_VERIFY=1docker ps
注意: .docker目录下的证书文件名必须为 ca.pem, cert.pem, key.pem
另外还可以利用 curl
来发送 Docker 请求:
curl https://$HOST:2376/images/json \--cert ~/.docker/cert.pem \--key ~/.docker/key.pem \--cacert ~/.docker/ca.pem
参考内容
[1] https://coreos.com/os/docs/latest/generate-self-signed-certificates.html
[2] https://docs.docker.com/engine/security/https/




