为 Docker 配置 TLS

引言

Docker 默认通过 Unix Socket 对外提供接口,也支持 HTTP 的方式,后者允许我们能够在本地控制远程服务器中的 Docker。如果你想让远程服务器中的 Docker 以安全的方式被访问,可为其配置 TLS,做到服务端和客户端的双向验证。本文由我的同事 @like 投稿,其中总结了他在配置 Docker TLS 过程中的实践经验。

安装 cfssl

这里我们使用 CloudFlare 的 PKI 工具集 cfssl 来创建证书。

安装 cfsslcfssljson 以及 cfssl-certinfo(假设已有GoLang环境):

1
2
3
go get -u github.com/cloudflare/cfssl/cmd/cfssl
go get -u github.com/cloudflare/cfssl/cmd/cfssljson
go get -u github.com/cloudflare/cfssl/cmd/cfssl-certinfo

另外也可以直接下载二进制包:

1
curl -o cfssl -L https://pkg.cfssl.org/R1.2/cfssl_linux-amd64

该网站上的 cfssl 好久没更新啦,建议通过 GO 方式安装。

创建证书

根证书(CA)

首先我们需要创建一个 CA 证书,后续利用它去生成其他证书。

配置文件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
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):

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
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

生成根证书和私钥:

1
cfssl gencert -initca ca-csr.json | cfssljson -bare ca

得到:

1
2
ca-key.pem
ca.pem

服务端证书

CSR 配置:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
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: 如果该证书能被多域名使用,可在这里添加 DNSIP

生成服务端证书和私钥:

1
cfssl gencert -ca ca.pem -ca-key ca-key.pem -config ca-config.json -profile docker server-csr.json | cfssljson -bare server

得到:

1
2
server-key.pem
server.pem

客户端证书

客户端证书的配置中除了没有 hosts 字段,其他与生成服务端证书一样。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
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

生成客户端证书和私钥:

1
cfssl gencert -ca ca.pem -ca-key ca-key.pem -config ca-config.json -profile docker client-csr.json | cfssljson -bare client

得到:

1
2
client-key.pem
client.pem

最后为了保护 key 文件,需要移除其写权限,并保证只有自己可读:

1
chmod -v 0400 ca-key.pem server-key.pem client-key.pem

另外证书是任何人都可以访问的:

1
chmod -v 0444 ca.pem server.pem client.pem

配置docker

修改 dockerd 的启动命令:

1
dockerd --tlsverify --tlscacert=ca.pem --tlscert=server.pem --tlskey=server-key.pem -H=0.0.0.0:2376

为了连接远端 Docker 并验证服务端证书,需要提供客户端 key、客户端证书以及信任的 CA:

1
docker --tlsverify --tlscacert=ca.pem --tlscert=client.pem --tlskey=client-key.pem -H=$HOST:2376 version

每次执行 docker 命令时都提供证书是很麻烦的,我们可以把证书和密钥放在 ~/.docker 目录下,并设置 DOCKER_HOSTDOCKER_TLS_VERIFY 环境变量,这样默认就走 TLS 的方式。

1
2
3
4
5
mkdir -p ~/.docker
cp -v {ca,cert,key}.pem ~/.docker
export DOCKER_HOST=tcp://$HOST:2376 DOCKER_TLS_VERIFY=1

docker ps

注意: .docker目录下的证书文件名必须为 ca.pem, cert.pem, key.pem

另外还可以利用 curl 来发送 Docker 请求:

1
2
3
4
curl https://$HOST:2376/images/json \
--cert ~/.docker/cert.pem \
--key ~/.docker/key.pem \
--cacert ~/.docker/ca.pem

参考内容

[1] generate-self-signed-certificates
[2] Docker security

贝克街的流浪猫 wechat
您的打赏将鼓励我继续分享!
  • 本文作者: 贝克街的流浪猫
  • 本文链接: https://www.beikejiedeliulangmao.top/container/docker/config-tls-4-docker/
  • 版权声明: 本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!
  • 创作声明: 本文基于上述所有参考内容进行创作,其中可能涉及复制、修改或者转换,图片均来自网络,如有侵权请联系我,我会第一时间进行删除。