保护Docker守护进程套接字

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

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

注意

给定的USERNAME必须具有访问远程机器上docker套接字的权限。请参考 以非root用户身份管理Docker 了解如何为非root用户提供对docker套接字的访问权限。

以下示例创建了一个 docker context 以通过SSH连接到host1.example.com上的远程dockerd守护进程,并以远程机器上的docker-user用户身份进行操作:

$ 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守护进程套接字

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

在守护进程模式下,它只允许来自由该CA签名的证书认证的客户端的连接。在客户端模式下,它只连接到具有由该CA签名的证书的服务器。

重要

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

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

注意

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

首先,在Docker守护进程的主机上,生成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

使用默认的umask为022时,您的密钥对您和您的组是世界可读且可写的。

为了防止您的密钥意外损坏,请移除它们的写权限。要使它们仅对您可读,请按如下方式更改文件模式:

$ 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 上运行。

警告

如上例所示,当你使用证书认证时,不需要使用sudodocker组来运行docker客户端。这意味着任何拥有密钥的人都可以向你的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 设置:验证客户端
  • 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