配置 Docker 远程访问 TLS 认证

部署 Docker 的远程访问,网上教程有些遗漏,尤其是如何设置 TLS 认证模式的相关内容,博主一一尝试过后汇总在此。

Docker,Portainer

需求

多台公网主机都安装了 Docker,如果每次 SSH 登陆再一条条命令来管理,未免烦躁,所以祭出各种炫酷的可视化容器管理工具,只需点点鼠标就可替代繁琐命令。博主这里不涉及 swarm、k8s 等复杂的集群,只是简单的批量管理多个独立 Docker 服务,暂用 portainer 这个轻量工具来操作。

环境

5 台 VPS 的系统均为 CentOS 7 x64,设置主机名 host-1 到 host-5,都有公网 IP 且会暴露在外,均安装了 Docker 19.03.14,服务已启动。现在目标是:host-1 上安装一个 portainer,且用来管理其他所有主机上的 Docker 服务。

安装 Portainer

根据 portainer 官方文档,在 host-1 中执行命令,先给 portainer 创建一个数据卷用来持久化:

docker volume create portainer_data

运行容器:

docker run -d -p 8000:8000 -p 9000:9000 --name=portainer --restart=always -v /var/run/docker.sock:/var/run/docker.sock -v portainer_data:/data portainer/portainer-ce

docker run 命令中:-d 后台守护进程方式运行容器;-p 暴露两个端口,9000 是 portainer 的网页端,8000 端口用于 edge agent 的内网穿透,如果不部署 edge agent 则可忽略;--name=portainer 给容器命名;--restart=always 设置容器自动启动;-v /var/run/docker.sock:/var/run/docker.sock 把 docker 套接字挂载到容器里;-v portainer_data:/data 挂载持久化的数据卷;portainer/portainer-ce 使用 portainer-ce 镜像,网上很多教程还是用 portainer 这个镜像,官方已说明:portainer/portainer 里是 Portainer v1.24.x 版本,现在已经被弃用了,Portainer 2.0 新版都会发布在 portainer/portainer-ce 这个仓库里。

容器启动后打开 http://ip:9999 即可访问 portainer 的网页,先设置密码,选择本地 Local 的 Docker 环境 Connect 连接,即可进入后台。

设置 Docker 远程访问

接着要在 host-1 的 portainer 后台添加其他主机的 docker 服务,当然你可以选择在每台主机中都安装 portainer ,但没这个必要。

添加前,先开启 host-2 到 host-5 中 Docker 的远程访问权限:

查看 docker.service 文件所在路径,终端命令 systemctl status docker.service

CentOS 通常是 /usr/lib/systemd/system/docker.service

vi 编辑 docker.service,找到定义 ExecStart=/usr/bin/dockerd 处的代码,修改为:ExecStart=/usr/bin/dockerd -H tcp://0.0.0.0:2375 -H fd:// --containerd=/run/containerd/containerd.sock,即添加了 -H tcp://0.0.0.0:2375

接着依次执行 systemctl daemon-reloadsystemctl restart docker,重载配置文件和重启 Docker 服务。

此时即开启了本机 Docker 所有 ipv4 地址访问,且绑定了 2375 这个端口。接着到 host-1 的 portainer 后台,SETTINGS -- Endpoints -- Add endpoint,还是选择第三项 Docker( Directly connect to the Docker API ), Environment details 下填入自定义 Name 和 Endpoint URL:需添加的服务器 IP:2375 即可。如有必要,要在系统防火墙中放行 2375 端口访问。当然也可绑定单独的外网 IP 和其他端口。

以上只适用于本地测试环境或所有主机仅在内网下使用。如果是公网环境且赤裸裸暴露 2375 端口会相当危险,博主撰写本文时为测试整个流程,几台主机开启端口半小时后就被注入了恶意挖矿程序,所以需要添加安全验证。

配置 Docker 的 TLS 认证

Docker 官方文档说明了使用基于 CA 证书的加密方法来保护 Docker 进程的网络通信,即开启带验证的 TLS 连接。

这里暂不详述关于 SSL/TLS 的认证原理,详见文末参考资料。只是简单说下配置过程,主要有三步:创建本地 CA 证书;CA 对服务器证书签名;CA 对客户端证书签名。

创建本地 CA 证书

首先要有个受信任的机构,用来给其他申请对象颁发证书,即 CA,这里直接用本机当 CA,当然签发的证书只有我们自己承认。此外 CA 也要有一个证书和私钥,在 host-2 的终端执行:

先创建一个目录放各种证书文件 mkdir docker_ca,进入目录 cd docker_ca

给 CA 生成私钥 ca-key.pem:

openssl genrsa -aes256 -out ca-key.pem 4096,需要设置个密码。

接着生成 CA 自签名证书 ca.pem,里面包含证书和公钥等信息:

openssl req -new -x509 -days 365 -key ca-key.pem -sha256 -out ca.pem

需要输入上步中设置的密码,再依次填入各种基本信息,其中 Common Name (eg, your name or your server's hostname) 建议为本机主机名或 IP 地址,博主这里是 host-2;其他项随便填。

现在服务器上有 CA 了,可以用来生成密钥和证书签名请求(CSR) 。docker_ca 目录下有 ca-key.pem、ca.pem 两个文件。

创建服务器端证书

服务器端是 host-2

生成服务器私钥 server-key.pem:

openssl genrsa -out server-key.pem 4096

生成服务器证书签名请求文件 server.csr,"/CN="后填写主机名或 IP 地址:

openssl req -subj "/CN=host-2" -sha256 -new -key server-key.pem -out server.csr

extfile.cnf 文件用于添加受信任的主机或 IP 地址,其中 host-2 和 IP 自行修改:

echo subjectAltName = DNS:host-2,IP:xxx.xxx.xxx.xxx,IP:127.0.0.1 >> extfile.cnf

将 extfile.cnf 添加为证书扩展,用来限制可用范围,其中 serverAuth 表明用于 SSL/TLS 的服务器认证:

echo extendedKeyUsage = serverAuth >> extfile.cnf

给服务器签发 CA 证书 server-cert.pem:

openssl x509 -req -days 365 -sha256 -in server.csr -CA ca.pem -CAkey ca-key.pem -CAcreateserial -out server-cert.pem -extfile extfile.cnf

此时已经可用 TLS 仅服务端单向认证来远程连接 Docker 服务了。

注意:但这并没有达到我们的需求,这种模式通常用来给客户端校验服务器的合法性,比如 HTTPS 网页。

创建客户端证书

继续在 host-2 主机上操作,步骤与创建服务器端证书差不多。

生成客户端私钥 client-key.pem:

openssl genrsa -out client-key.pem 4096

生成客户端证书签名请求文件 client.csr,这里"/CN="后填写安装 portainer 的 host-1:

openssl req -subj '/CN=host-1' -new -key client-key.pem -out client.csr

同样添加用于 SSL/TLS 客户端认证的扩展配置文件 extfile-client.cnf,这里不用添加 SAN:

echo extendedKeyUsage = clientAuth > extfile-client.cnf

给客户端颁发 CA 证书 client-cert.pem:

openssl x509 -req -days 365 -sha256 -in client.csr -CA ca.pem -CAkey ca-key.pem -CAcreateserial -out client-cert.pem -extfile extfile-client.cnf

上面把各种证书都搞定了,docker_ca 目录下要用到的文件:

ca.pem:CA 自签名证书;ca-key.pem:CA 私钥;server-cert.pem:服务器证书;server-key.pem:服务器私钥;client-cert.pem:客户端证书;client-key.pem:客户端私钥

将 CA 自签名证书 ca.pem、客户端 CA 证书 client-cert.pem、客户端私钥 client-key.pem 保存到本地。

Portainer 使用 TLS 连接 Docker

回到第四步中设置 Docker 远程访问,服务器端(host-2)和客户端(安装了 Portainer 的 host-1)此时都有几种模式。

Docker 服务端模式

1、不带客户端认证的连接:添加参数 --tls--tlscert=server-cert.pem--tlskey=server-key.pem即可,对应:服务器 CA 证书 server-cert.pem、服务器私钥 server-key.pem。

2、客户端认证连接:添加参数 --tlsverify--tlscacert=ca.pem--tlscert=server-cert.pem--tlskey=server-key.pem,比上面多了个:CA 自签名证书 ca.pem。

客户端模式

各种客户端模式对应 Portainer 添加 Endpoints 时,开启 TLS 后的各种 TLS mode。

Docker远程连接TLS模式

从右至左:

TLS only( No server/client verification ):仅开启 TLS 连接,不带认证。

TLS with server verification only(Only verify the server certificate):单向的服务端认证模式,客户端只需 TLS CA certificate 即 CA 自签名证书。服务端参数对应第一种不带客户端认证的连接。

TLS with client verification only( Use client certificates without server verification):同样单向认证,不过是客户端认证模式。服务端带 --tlsverify 参数,客户端要客户端证书和私钥。

TLS with server and client verification( Use client certificates and server verification):双向认证,相比前面一种,客户端还要多提交一个 CA 自签名证书。官方推荐使用这种。

配置文件

修改/usr/lib/systemd/system/docker.service ,开启 TLS 后,映射端口用默认的 2376,相关代码如下,注意 /root/docker_ca 为存放证书的目录:

ExecStart=/usr/bin/dockerd -H tcp://0.0.0.0:2376 -H fd:// --containerd=/run/containerd/containerd.sock --tlsverify --tlscacert=/root/docker_ca/ca.pem --tlscert=/root/docker_ca/server-cert.pem --tlskey=/root/docker_ca/server-key.pem

同样,修改完成后需要 systemctl daemon-reloadsystemctl restart docker,重载配置文件和重启 Docker 服务。

Portainer 后台添加 Endpoints 时,TLS CA certificate 选择 CA 自签名证书 ca.pem、TLS certificate 为 客户端 CA 证书 client-cert.pem、TLS key 选择客户端私钥 client-key.pem 即可。

补充

因为有多台主机,在 host-2 签发服务器证书添加 SAN 扩展时,加入其他几个主机名和 IP 地址:echo subjectAltName = DNS:host-2,DNS:host-3,DNS:host-4,IP:xxx.xxx.xxx.xxx,IP:xxx.xxx.xxx.xxx,IP:xxx.xxx.xxx.xxx,IP:127.0.0.1 >> extfile.cnf,再把 host-2 中生成的 CA 自签名证书 ca.pem、服务器 CA 证书 server-cert.pem、服务器私钥 server-key.pem 复制到其他服务器对应目录中,同样修改 docker.service 文件即可。

参考资料

» 链接地址:https://wbt5.com/docker-tls.html »英雄不问来路,转载请注明出处。

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注