我正在尝试设置一个 docker swarm。
我需要我的节点通过 TLS 进行通信。
我已经为管理器节点创建了一个证书,其 extendedKeyUsage = serverAuth
我已经使用以下 daemon.json 配置了管理器节点:
{
"hosts": ["unix:///var/run/docker.sock", "tcp://0.0.0.0:2376"],
"tlscacert": "/var/docker/ca.pem",
"tlscert": "/var/docker/server-cert.pem",
"tlskey": "/var/docker/server-key.pem",
"tlsverify": true
}
为了测试这一点,我创建了一个客户端证书,用它从我的笔记本电脑连接到 docker api,并且我能够成功连接。
现在我需要向集群添加一个工作节点。
我已按照与管理节点相同的方式对其进行了设置;使用类似的 daemon.json。我已使用具有 extendedKeyUsage = serverAuth 的 SSL 密钥,并以与管理节点相同的方式验证了客户端连接。
然后在管理器中运行 docker swarm init
要将工作节点加入集群,我使用以下命令:docker swarm join --token XXX dockman.myhost.com:2376
但是我收到一个错误:
Error response from daemon: rpc error: code = Unavailable desc = all SubConns are in TransientFailure, latest connection error: connection error: desc = "transport: authentication handshake failed: remote error: tls: bad certificate"
我想我可以通过尝试从工作节点连接到管理器节点上的 docker API 来进一步测试它:
sudo docker --tlsverify --tlscacert=/var/docker/ca.pem --tlscert=./server-cert.pem --tlskey=./server-key.pem -H=127.0.0.1:2376 version
结果是:
Client: Docker Engine - Community
Version: 19.03.5
API version: 1.40
Go version: go1.12.12
Git commit: 633a0ea838
Built: Wed Nov 13 07:29:52 2019
OS/Arch: linux/amd64
Experimental: false
The server probably has client authentication (--tlsverify) enabled. Please check your TLS client certification settings: Get https://127.0.0.1:2376/v1.40/version: remote error: tls: bad certificate
第二次测试让我思考了很多。当然,它会失败,因为我尝试连接服务器证书而不是客户端证书,但这不正是 docker swarm join 试图做的事情吗?将客户端证书放入 daemon.json 对我来说毫无意义。我在 Google 上搜索了如何为服务器和客户端制作一个证书,虽然这是可行的,但似乎不是个好习惯。我以为如果需要的话,教程中会介绍它。
我一直卡在这儿。我不知道需要设置什么证书。
我一直在关注 https://github.com/docker/docker.github.io/blob/master/swarm/configure-tls.md 这描述了证书的创建,但根本没有提及客户端或服务器身份验证。
更新 1
我发现一份文件说证书需要是客户端和服务器
https://hub.docker.com/_/swarm/
因此,我重新制作了节点证书,使其既是客户端又是服务器。现在,docker version 命令在从节点运行时有效,但 swarm join 无效。
答案1
docker swarm
您将 Swarm Mode(和类似的 CLI)与基于容器的经典 Swarm(作为容器托管在 docker hub 上)混淆了。这是两种不同的工具。
对于这两套文档,请参阅:
- 群体模式:https://docs.docker.com/engine/swarm/
- 经典群体:https://github.com/docker/classicswarm(先前的文档已从docker网站上删除)
使用 Swarm Mode 无需进行任何手动 TLS 配置,一切都是内置的,并且 Swarm Mode 的端口与 docker API 套接字的端口不同。如果没有充分的理由,您不会想在网络上公开 docker API(这是黑客攻击的常见来源),而 Swarm Mode 不是理由。
因此,您应该删除命令-H
的选项dockerd
以及其中的任何 TLS 选项。然后docker swarm init
在第一个管理器上运行,它将生成 TLS 凭据并提供包含自签名证书哈希值的令牌。然后其他管理器和工作者运行docker swarm join
以生成客户端证书,连接到管理器,从令牌验证管理器证书的哈希值,并使用加入令牌的秘密部分向管理器验证自身身份。
以上操作将加密管理者和工作者之间的管理平面。要加密工作者之间在覆盖网络上传输的数据,您需要在创建的覆盖网络上启用 IPSec:
docker network create --opt encrypted --driver overlay app-overlay-net
关于此功能的文档位于:https://docs.docker.com/v17.09/engine/userguide/networking/overlay-security-model/
答案2
我是正确的,所有证书必须同时是客户端证书和服务器证书才能起作用。
然后我又遇到了其他问题,最主要的是,我使用的主机上的虚拟机禁止使用端口 4789,因为该端口由 VMWare 使用。这是覆盖网络使用的默认数据路径端口。
我必须从群中完全删除所有节点和管理器(有效地删除它)并使用数据路径端口参数重新启动它:
docker swarm init --data-path-port=7777
(我还指定了广告地址作为每个节点的 IP,但我不认为这是必需的)
当然,我的所有 docker 机密、docker 配置和一些 docker 网络都在此过程中丢失,必须重新创建。
一旦我完成此操作并更改防火墙以允许使用数据路径端口在节点之间进行 UDP 通信,一切就可以再次正常工作。
因为群体网络是加密的,我认为它应该都可以正常工作。