【Docker】对Docker Remote Api 进行认证

将虚拟机配置docker

docker的安装,我在我的博客里有写,这里就不写了。

  • 开启认证的docker remote api
第一步
1
2
3
cd /etc/docker
echo 01 | sudo tee ca.srl
sudo openssl genrsa -des3 -out ca-key.pem
第二步

创建私钥的过程中,我们需要为CA密钥设置一个密码,我们需要牢记这个密码,并确保它的安全性。在新CA中,我们需要用这个密码来创建并对证书签名。

1
sudo openssl req -new -x509 -days 365 -key ca-key.pem -out ca.pem
第三步

注意这里Common Name (e.g. server FQDN or YOUR name) []:docker.example.com,这里填写你的服务器的域名或者IP地址。(其他的跳过就好了)

1
sudo openssl genrsa -des3 -out server-key.pem

这将为我们的服务器创建一个密钥server-key.pem。像前面一样,我们要确保此密钥的安全性,这是保证我们的Docker服务器安全的基础。

第四步
1
sudo openssl req -new -key server-key.pem -out server.csr
第五步

这将创建一个名为server.csr的文件。这也是一个请求,这个请求将为创建我们的服务器证书进行签名。在这些选项中最重要的是Common Name或CN。该项的值要么为Docker服务器(即从DNS中解析后得到的结果,比如docker.example.com)的FQDN(fully qualified domain name,完全限定的域名)形式,要么为*,这将允许在任何服务器上使用该服务器证书。
我直接输入了虚拟机的ip 192.168.73.123

1
2
sudo openssl x509 -req -days 365 -in server.csr -CA ca.pem \
-CAkey ca-key.pem -out server-cert.pem
第六步

需要输入CA密钥文件的密码,该命令会生成一个名为server-cert.pem的文件,这个文件就是我们的服务器证书

1
sudo openssl rsa -in server-key.pem -out server-key.pem
第七步
1
2
sudo chmod 0600 /etc/docker/server-key.pem /etc/docker/server-cert.pem \
/etc/docker/ca-key.pem /etc/docker/ca.pem
第八步

需要编辑/usr/lib/systemd/system/docker.service

1
vim /usr/lib/systemd/system/docker.service
1
2
3
ExecStart=/usr/bin/docker -d -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
第九步
1
sudo systemctl --system daemon-reload
第十步
    • 创建客户端证书和密钥
1
sudo openssl genrsa -des3 -out client-key.pem
第十一步

创建一个名为client-key.pem的密钥文件。我们同样需要在创建阶段设置一个临时性的密码。

1
sudo openssl req -new -key client-key.pem -out client.csr
第十二步
1
echo extendedKeyUsage = clientAuth > extfile.cnf
第十三步
1
2
sudo openssl x509 -req -days 365 -in client.csr -CA ca.pem \
-CAkey ca-key.pem -out client-cert.pem -extfile extfile.cnf
第十四步
1
sudo openssl rsa -in client-key.pem -out client-key.pem
第十五步
1
2
3
4
5
mkdir -p ~/.docker/
cp ca.pem ~/.docker/ca.pem
cp client-key.pem ~/.docker/key.pem
cp client-cert.pem ~/.docker/cert.pem
chmod 0600 ~/.docker/key.pem ~/.docker/cert.pem
第十六步
1
sudo docker -H=192.168.73.123:2376 --tlsverify info

Shell脚本自动化

要注意:这里的环境是虚拟机的环境,生产环境需要替换ip为自己服务器的公网ip和域名

下面我写了一个shell脚本进行自动化

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
#!/bin/bash
set -e
if [ -z $1 ];then
echo "请输入Docker服务器主机名"
exit 0
fi
HOST=$1
mkdir -p /opt/cert/docker
cd /opt/cert/docker
openssl genrsa -aes256 -out ca-key.pem 4096
openssl req -new -x509 -days 365 -key ca-key.pem -sha256 -out ca.pem
openssl genrsa -out server-key.pem 4096
openssl req -subj "/CN=$HOST" -sha256 -new -key server-key.pem -out server.csr
# 配置白名单,推荐配置0.0.0.0,允许所有IP连接但只有证书才可以连接成功
echo subjectAltName = DNS:$HOST,IP:0.0.0.0 > extfile.cnf
openssl x509 -req -days 365 -sha256 -in server.csr -CA ca.pem -CAkey ca-key.pem -CAcreateserial -out server-cert.pem -extfile extfile.cnf
openssl genrsa -out key.pem 4096
openssl req -subj '/CN=client' -new -key key.pem -out client.csr
echo extendedKeyUsage = clientAuth > extfile.cnf
openssl x509 -req -days 365 -sha256 -in client.csr -CA ca.pem -CAkey ca-key.pem -CAcreateserial -out cert.pem -extfile extfile.cnf
rm -v client.csr server.csr
chmod -v 0400 ca-key.pem key.pem server-key.pem
chmod -v 0444 ca.pem server-cert.pem cert.pem

保存为createcert.sh

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
#!/bin/bash

# 检查参数
if [ -z "$1" ]; then
echo "Usage: $0 <hostname>"
exit 1
fi

HOSTNAME=$1

# 定义一个错误处理函数
rollback() {
echo "An error occurred. Rolling back changes..."
if [ -f /usr/lib/systemd/system/docker.service.old ]; then
cp /usr/lib/systemd/system/docker.service.old /usr/lib/systemd/system/docker.service
systemctl daemon-reload
systemctl restart docker
fi
exit 1
}

# 捕捉错误信号并调用 rollback 函数
trap rollback ERR

chmod +x /opt/sh/createcert.sh
# 运行证书生成脚本
sh /opt/sh/createcert.sh $HOSTNAME || rollback

# 备份原始 docker.service 文件
cp /usr/lib/systemd/system/docker.service /usr/lib/systemd/system/docker.service.old || rollback

# 使用 sed 命令在 ExecStart 属性后追加参数
sed -i '/ExecStart=/ s|$| --tlsverify --tlscacert=/opt/cert/docker/ca.pem --tlscert=/opt/cert/docker/server-cert.pem --tlskey=/opt/cert/docker/server-key.pem -H tcp://0.0.0.0:2376 -H unix://var/run/docker.sock|' /usr/lib/systemd/system/docker.service || rollback

# 重新加载 systemd 配置并重启 Docker 服务
systemctl daemon-reload || rollback
systemctl restart docker || rollback

# 更新 /etc/hosts 文件
if ! grep -q "$HOSTNAME" /etc/hosts; then
echo "127.0.0.1 $HOSTNAME" >> /etc/hosts || rollback
fi

# 测试 ping 和 curl 命令
ping -c 4 $HOSTNAME || rollback
curl https://$HOSTNAME:2376/info --cert /opt/cert/docker/cert.pem --key /opt/cert/docker/key.pem --cacert /opt/cert/docker/ca.pem || rollback

echo "Script executed successfully."

上面的保存为complete-remote-protect-tls.sh

执行以下命令即可

1
2
chmod +x complete-remote-protect-tls.sh
./complete-remote-protect-tls.sh <your-host-name>

最后显示成这样就成功了。

总结

tm这个折磨我一天了,网上的资料比较少,只能自己摸索。每次输入时都要重新复制粘贴,烦死了。所以我最后搞成自动化脚本一劳永逸。还好最后有发现一个大佬写的脚本启发了我,感谢大佬。👍👍

后记

​ 我配了之后,能用了很久。但是有一天,我恢复虚拟机的快照,忽然发现连接不上了,像下图这样:

timeout 老问题了,我之前配docker的mysql的时候也遇到过,还以为是mysql配置出现了问题,然后一直在改配置。后来我才发现,虚拟机重启就能解决的了。但这次docker的重启了还是没用。折磨了一个晚上,终于在第二天发现,我虚拟机的防火墙没关。。。真是无语死了😢

参考资料