保护 Docker 守护进程套接字

默认情况下,Docker 通过非网络化的 UNIX socket 运行。它还可以 选择使用 SSH 或 TLS (HTTPS) socket 进行通信。

使用 SSH 保护 Docker 守护进程套接字

注意

指定的 USERNAME 必须拥有在远程机器上访问 Docker Socket 的权限。请参见 以非 root 用户身份管理 Docker 以了解如何授予非 root 用户访问 Docker Socket 的权限。

The following example creates a docker context to connect with a remote dockerd daemon on host1.example.com using SSH, and as the docker-user user on the remote machine:

$ docker context create \
    --docker host=ssh://docker-user@host1.example.com \
    --description="Remote engine" \
    my-remote-engine

my-remote-engine
Successfully created context "my-remote-engine"

创建上下文后,使用 docker context use 切换 docker CLI 以连接远程引擎:

$ docker context use my-remote-engine
my-remote-engine
Current context is now "my-remote-engine"

$ docker info
<prints output of the remote engine>

使用 default 上下文切换回默认(本地)守护进程:

$ docker context use default
default
Current context is now "default"

或者,使用 DOCKER_HOST 环境变量临时切换 docker CLI,以便通过 SSH 连接到远程主机。此操作无需创建上下文, 对于与不同引擎建立临时连接非常有用:

$ export DOCKER_HOST=ssh://docker-user@host1.example.com
$ docker info
<prints output of the remote engine>

SSH 提示

为了获得最佳的 SSH 用户体验,请按以下方式配置 ~/.ssh/config,以便在多次调用 docker CLI 时重用 SSH 连接:

ControlMaster     auto
ControlPath       ~/.ssh/control-%C
ControlPersist    yes

使用 TLS (HTTPS) 保护 Docker 守护进程 socket

如果您需要以安全的方式通过 HTTP(而非 SSH)访问 Docker, 您可以指定 tlsverify 标志来启用 TLS (HTTPS),并将 Docker 的 tlscacert 标志指向受信任的 CA 证书。

在守护进程模式下,它仅允许由该 CA 签名的证书进行身份验证的客户端连接。在客户端模式下,它仅连接到拥有由该 CA 签名的证书的服务器。

重要

使用 TLS 和管理 CA 是一个高级主题。在生产环境中使用之前,请先熟悉 OpenSSL、x509 和 TLS。

使用 OpenSSL 创建 CA、服务器和客户端密钥

注意

将以下示例中 $HOST 的所有出现替换为您 Docker 守护进程主机的 DNS 名称。

首先,在 Docker 守护进程(daemon)的宿主机上生成 CA 私钥和公钥:

$ openssl genrsa -aes256 -out ca-key.pem 4096
Generating RSA private key, 4096 bit long modulus
..............................................................................++
........++
e is 65537 (0x10001)
Enter pass phrase for ca-key.pem:
Verifying - Enter pass phrase for ca-key.pem:

$ openssl req -new -x509 -days 365 -key ca-key.pem -sha256 -out ca.pem
Enter pass phrase for ca-key.pem:
You are about to be asked to enter information that will be incorporated
into your certificate request.
What you are about to enter is what is called a Distinguished Name or a DN.
There are quite a few fields but you can leave some blank
For some fields there will be a default value,
If you enter '.', the field will be left blank.
-----
Country Name (2 letter code) [AU]:
State or Province Name (full name) [Some-State]:Queensland
Locality Name (eg, city) []:Brisbane
Organization Name (eg, company) [Internet Widgits Pty Ltd]:Docker Inc
Organizational Unit Name (eg, section) []:Sales
Common Name (e.g. server FQDN or YOUR name) []:$HOST
Email Address []:Sven@home.org.au

现在您已经拥有了 CA,您可以创建服务器密钥和证书签名请求(CSR)。请确保“通用名称”与您用于连接 Docker 的主机名相匹配:

注意

将以下示例中 $HOST 的所有出现替换为您 Docker 守护进程主机的 DNS 名称。

$ openssl genrsa -out server-key.pem 4096
Generating RSA private key, 4096 bit long modulus
.....................................................................++
.................................................................................................++
e is 65537 (0x10001)

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

接下来,我们将使用我们的 CA 对公钥进行签名:

由于 TLS 连接既可以通过 IP 地址也可以通过 DNS 名称建立,因此在创建证书时需要指定 IP 地址。例如,要允许使用 10.10.10.20127.0.0.1 进行连接:

$ echo subjectAltName = DNS:$HOST,IP:10.10.10.20,IP:127.0.0.1 >> extfile.cnf

将 Docker 守护进程密钥的扩展用途属性设置为仅用于服务器身份验证:

$ echo extendedKeyUsage = serverAuth >> 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
Signature ok
subject=/CN=your.host.com
Getting CA Private Key
Enter pass phrase for ca-key.pem:

授权插件 提供更细粒度的控制以补充双向 TLS 的身份验证。除了上述文档中描述的其他信息外,在 Docker 守护进程中运行的授权插件会接收连接 Docker 客户端的证书信息。

对于客户端身份验证,请创建客户端密钥和证书签名请求:

注意

为简化接下来的几个步骤,您也可以在此 Docker 守护进程的主机上执行此操作。

$ openssl genrsa -out key.pem 4096
Generating RSA private key, 4096 bit long modulus
.........................................................++
................++
e is 65537 (0x10001)

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

为使密钥适用于客户端身份验证,请创建一个新的扩展配置文件:

$ echo extendedKeyUsage = clientAuth > extfile-client.cnf

现在,生成已签名的证书:

$ openssl x509 -req -days 365 -sha256 -in client.csr -CA ca.pem -CAkey ca-key.pem \
  -CAcreateserial -out cert.pem -extfile extfile-client.cnf
Signature ok
subject=/CN=client
Getting CA Private Key
Enter pass phrase for ca-key.pem:

生成 cert.pemserver-cert.pem 后,您可以安全地删除这两个证书签名请求和扩展配置文件:

$ rm -v client.csr server.csr extfile.cnf extfile-client.cnf

With a default umask of 022, your secret keys are world-readable and writable for you and your group.

为防止密钥意外损坏,请移除其写权限。要确保仅您本人可读,请按以下方式更改文件模式:

$ chmod -v 0400 ca-key.pem key.pem server-key.pem

证书可以是世界可读的,但您可能希望移除写权限以防止意外损坏:

$ chmod -v 0444 ca.pem server-cert.pem cert.pem

现在您可以配置 Docker 守护进程,使其仅接受提供由您的 CA 信任的证书的客户端连接:

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

要连接到 Docker 并验证其证书,请提供您的客户端密钥、 证书和受信任的 CA:

提示

此步骤应在您的 Docker 客户端机器上运行。因此,您需要将 CA 证书、服务器证书和客户端证书复制到该机器。

注意

将以下示例中 $HOST 的所有出现替换为您 Docker 守护进程主机的 DNS 名称。

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

注意

Docker over TLS 应运行在 TCP 端口 2376 上。

警告

如上例所示,当您使用证书认证时,无需在运行 docker 客户端时指定 sudodocker 组。 这意味着任何拥有密钥的人都可以向您的 Docker 守护进程发送任意指令,从而获得托管该守护进程的机器的 root 权限。 请务必像保护 root 密码一样妥善保管这些密钥!

默认安全

如果您希望默认情况下保护 Docker 客户端连接,可以将文件移动到家目录中的 .docker 目录——并设置 DOCKER_HOSTDOCKER_TLS_VERIFY 变量(而不是在每次调用时传递 -H=tcp://$HOST:2376--tlsverify)。

$ mkdir -pv ~/.docker
$ cp -v {ca,cert,key}.pem ~/.docker

$ export DOCKER_HOST=tcp://$HOST:2376 DOCKER_TLS_VERIFY=1

Docker 现在默认安全连接:

$ docker ps

其他模式

如果您不希望启用完整的双向身份验证,可以通过组合不同的标志以多种其他模式运行 Docker。

守护进程模式

  • tlsverify, tlscacert, tlscert, tlskey set: 验证客户端
  • tls, tlscert, tlskey: 不验证客户端

客户端模式

  • tls: 基于公共/默认 CA 池对服务器进行身份验证
  • tlsverify, tlscacert: 基于给定的 CA 对服务器进行身份验证
  • tls, tlscert, tlskey: 使用客户端证书进行身份验证,不根据给定的CA验证服务器
  • tlsverify, tlscacert, tlscert, tlskey: 使用客户端证书进行身份验证,并基于给定的 CA 验证服务器

如果找到,客户端将发送其客户端证书,因此您只需 将您的密钥放入 ~/.docker/{ca,cert,key}.pem。或者, 如果您希望将密钥存储在另一个位置,您可以使用环境变量 DOCKER_CERT_PATH 来指定该位置。

$ export DOCKER_CERT_PATH=~/.docker/zone1/
$ docker --tlsverify ps

正在使用 curl 连接到安全的 Docker 端口

要使用 curl 发起测试 API 请求,您需要额外使用三个命令行 标志:

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