网站搜索

如何使用 TLS 保护 Docker 的 TCP 套接字


Docker 的 API 默认情况下完全不受保护,除了其 Unix 套接字上的文件系统权限。当通过 TCP 公开 Docker API 时,您应该设置 TLS,以便 Docker 引擎和您的客户端可以验证彼此的身份。否则,任何有权访问 TCP 端口的人都可以浏览您的 Docker 容器、启动新容器并以 root 身份在您的系统上运行操作。

配置的 TLS 将要求客户端提供由服务器的证书颁发机构签名的有效证书。要让它工作,您需要创建 SSL 证书,然后设置 Docker Engine 以要求 TLS 连接。还必须调整 Docker CLI 客户端以期待 TLS 服务器。

公开 TCP 套接字

您可以通过使用 -H 标志在启动 dockerd 进程时定义一个额外的端点来公开 Docker 的 TCP 套接字。这个标志可以重复多次;在此示例中,Unix 套接字和 TCP 套接字都可用:

/usr/bin/dockerd -H unix:///var/run/docker.sock -H tcp://0.0.0.0:2375

端口 2375 通常用于未加密的 Docker 连接。设置 TLS 后,应改用端口 2376。

您可以通过修改 Docker 服务定义将 Docker 配置为自动使用这些标志。在 /etc/systemd/system/docker.service.d/override.conf 中添加一个覆盖来更改 ExecStart 行:

[Service]
ExecStart=/usr/bin/dockerd -H ...

重新加载 systemd 以应用更改:

sudo systemctl daemon-reload

创建您的证书颁发机构

首先为您的 TLS 配置创建证书颁发机构 (CA)。您将使用此 CA 来签署您的证书;服务器将拒绝与提供来自不同 CA 的证书的客户端通信。

使用 OpenSSL 在托管 Docker 服务器的机器上生成私有和公共 CA 密钥:

# Generate the private key
openssl genrsa -aes256 -out ca-private.pem 4096

# Generate a public key from the private key
openssl req -new -x509 -days 365 -key ca-private.pem -sha256 -out ca-public.pem

系统将提示您提供密码、电子邮件地址、国家代码、州和城市名称以及组织名称,以包含在您的公钥中。在您的终端中输入信息,在每行之后按回车键继续前进并创建密钥。

生成服务器密钥和证书签名请求

接下来创建服务器密钥和证书签名请求:

# Generate the server key
openssl genrsa -out server-key.pem 4096

# Generate a certificate signing request
openssl req -subj "/CN=example.com" -sha256 -new -key server-key.pm -out request.csr

证书签名请求 (CSR) 包含生成签名证书所需的所有信息。检查 CSR 中的公用名是否适合您的服务器很重要。这在 CN 字段中指定为上面的 example.com;您应该将其设置为服务器的完全限定域名 (FQDN)。

设置证书扩展

使用此 CSR 将允许通过其 FQDN 连接到服务器。如果要添加另一个域或使用 IP 地址,则需要指定证书扩展名。创建一个包含 subjectAltName 和 extendedKeyUsage 字段的扩展文件以进行设置:

echo subjectAltName = DNS:sub.example.com;IP=192.168.0.1 >> extfile.cnf
echo extendedKeyUsage = serverAuth >> extFile.cnf

此示例还允许通过 sub.example.com 和 192.168.0.1 进行连接。

生成签名证书

现在您已准备好组合所有组件并生成签名证书:

openssl x509 -req -days 365 -sha256 
    -in request.csr 
    -CA ca-public.pem 
    -CAkey ca-private.pem 
    -CAcreateserial 
    -extfile extfile.cnf 
    -out certificate.pem

这将接受证书签名请求,添加您的扩展文件,并使用您的 CA 密钥生成签名的 OpenSSL 证书。您需要提供 CA 的密码才能完成该过程。

该证书将在一年后到期。您可以调整 -days 标志以获得满足您要求的有用生命周期。您应该安排在此证书过期之前生成替换证书。

生成客户端证书

接下来,您应该生成另一个证书供您的 Docker 客户端使用。这必须由与服务器证书相同的 CA 签名。使用带有 extendedKeyUsage=clientAuth 的扩展文件来准备此证书以用于客户端场景。

# Generate a client key
openssl genrsa -out client-key.pem 4096

# Create a certificate signing request
openssl req -subj '/CN=client' -new -key client-key.pem -out client-request.csr

# Complete the signing
echo extendedKeyUsage = clientAuth >> extfile-client.cnf
openssl x509 -req -days 365 -sha256 
     -in client-request.csr  
     -CA ca-public.pem 
     -CAkey ca-private.pem 
     -CAcreateserial 
     -extfile extfile-client.cnf 
     -out client-certificate.pem

准备配置 Docker

将您的 ca-public.pem、certificate.pem 和 server-key.pem 文件复制到一个新目录中,以便在您的 Docker 中引用配置。然后,将 ca-public.pem、client-certificate.pem 和 client-key.pem 文件复制到您要安装的机器上将从连接。

您可以删除工作目录中的证书签名请求和扩展文件。小心不要丢失您的私钥,因为它们是不可恢复的。没有它们,您将无法验证证书或生成续订。

配置 Docker 守护进程

现在您可以使用引用您生成的证书和密钥的 TLS 标志启动 Docker 守护程序。 --tlscacert、--tlscert 和 --tlskey 参数指定上面生成的相应 OpenSSL 资源的路径。

/usr/bin/dockerd 
    -H unix:///var/run/docker.sock 
    -H tcp://0.0.0.0:2376 
    --tlsverify 
    --tlscacert=ca-public.pem 
    --tlscert=certificate.pem 
    --tlskey=server-key.pem

添加 --tlsverify 标志可以启用 TLS 连接。没有匹配证书的客户端将被阻止访问 Docker 的 TCP 套接字。

配置 Docker 客户端

当您使用 docker 命令时,通过提供 TLS 标志在客户端上激活 TLS。您还必须添加 -H 标志以指定要连接的远程 Docker 套接字地址。从客户端的角度来看,--tlsverify 意味着该命令将只连接到具有与其自身相同的证书颁发机构签署的 TLS 证书的服务器。

docker 
    -H tcp://0.0.0.0:2376 
    --tlsverify 
    --tlscacert=ca-public.pem 
    --tlscert=client-certificate.pem 
    --tlskey=client-key.pem 
    ps

每次使用 CLI 时都提供这些标志很快就会重复。如果您主要使用同一个受 TLS 保护的主机,请在您的 shell 配置文件中设置 DOCKER_HOST 和 DOCKER_TLS_VERIFY 环境变量。将证书文件复制到 ~/.docker 目录中的 ca、cert 和 key。这些对应于 Docker 的 --tls 标志并为客户端定义默认证书。

export DOCKER_HOST=tcp://0.0.0.0:2376
export DOCKER_TLS_VERIFY=1

通过设置 Docker 上下文,您可以混合使用本地、远程、不安全和 TLS 连接来简化与多个主机的合作。此功能允许您使用 Docker CLI 命令在目标之间切换。

Docker 客户端还支持替代验证模式。混合使用 tls、tlscacert、tlscert、tlskey 和 tlsverify 标志激活不同的 TLS 执行级别。

仅设置 tls 后,Docker 将使用默认 CA 池对服务器进行身份验证。添加没有客户端密钥的 tlscacert 和 tlsverify 标志将强制服务器使用给定的 CA,而无需任何其他检查。省略 tlscacert 和 tlsverify 但包括其他三个密钥将验证客户端的证书而不验证服务器的 CA。

结论

使用 TLS 证书保护 Docker 的 TCP 套接字可以让您通过防止来自未经授权的客户端的连接来更安全地公开 API。对您的网络进行端口扫描的参与者将被禁止连接到 Docker,从而为您提供一层保护,以防止您的计算机受到 root 级特权的损害。

生成证书后,您可以使用它们通过 Docker CLI 或您自己的 HTTP 客户端进行身份验证。例如,Curl 将接受它们作为 --cert、--key 和 --cacert 标志。

TLS 只是安全 Docker API 实例的一个组件。它提供加密和客户端可信的保证,但不是细粒度的访问控制机制。

如果你想限制允许单个客户端做什么,你应该设置一个 Docker 引擎授权插件。插件可以联系外部服务以确定是否允许继续进行特定的 API 请求。作为替代方案,您可以在 TCP 套接字前使用反向代理,以在请求到达 Docker 之前强制执行访问控制。

相关文章: