Ubuntu 下安全地远程访问 Docker

按照官方提供的方式在 Ubuntu 操作系统上安装的 Docker 只开启 unix socket 通信,不支持远程访问。


一、启用远程访问

  1. 找到 docker 的配置文件:

Ubuntu 下 docker 的配置文件通常为:/lib/systemd/system/docker.service

$ service docker status
● docker.service - Docker Application Container Engine
   Loaded: loaded (/lib/systemd/system/docker.service; enabled; vendor preset: enabled)
   Active: active (running) since Tue 2020-07-07 21:42:00 CST; 12h ago
     Docs: https://docs.docker.com
 Main PID: 1198 (dockerd)
    Tasks: 45
   CGroup: /system.slice/docker.service
           ├─1198 /usr/bin/dockerd -H fd:// --containerd=/run/containerd/containerd.sock
           ├─1551 /usr/bin/docker-proxy -proto tcp -host-ip 0.0.0.0 -host-port 50000 -container-ip 172.17.0.2 -container-port 50000
           └─1567 /usr/bin/docker-proxy -proto tcp -host-ip 0.0.0.0 -host-port 8080 -container-ip 172.17.0.2 -container-port 8080
  1. 修改启动配置文件

可以直接在文件内修改:

[Service]
Type=notify
# the default is not to use systemd for cgroups because the delegate issues still
# exists and systemd currently does not support the cgroup feature set required
# for containers run by docker
ExecStart=/usr/bin/dockerd -H tcp://0.0.0.0:2375 -H fd:// --containerd=/run/containerd/containerd.sock
ExecReload=/bin/kill -s HUP $MAINPID

修改结束保存即可。

  1. 使设置生效:
$ sudo systemctl daemon-reload
$ sudo systemctl restart docker.service
  1. 验证可用:
$ docker -H localhost:2375 ps

二、启用 TLS 访问

按照上述方法配置的远程访问并不安全,因为使用者掌握目标主机的IP地址和端口号即可全功能操纵 docker 服务。如果您需要以安全的方式通过网络访问Docker,可以通过指定tlsverify标志并将Docker的tlscacert标志指向受信任的CA证书来启用TLS。

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

使用TLS和管理CA是一个高级主题。 在生产中使用OpenSSL,x509和TLS之前,请先熟悉一下它们。接下来的文章假设您已经知晓相关技术。

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

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

首先,在Docker守护程序的主机上,生成CA私钥和公钥:

$ openssl genrsa -aes256 -out ca-key.pem 4096
Generating RSA private key, 4096 bit long modulus (2 primes)
............................................++++
....++++
e is 65537 (0x010001)
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:
Can't load /home/vistart/.rnd into RNG
139847851139520:error:2406F079:random number generator:RAND_load_file:Cannot open file:../crypto/rand/randfile.c:88:Filename=/home/vistart/.rnd
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]:CN
State or Province Name (full name) [Some-State]:Shanghai
Locality Name (eg, city) []:Yangpu
Organization Name (eg, company) [Internet Widgits Pty Ltd]:vistart
Organizational Unit Name (eg, section) []:vistart
Common Name (e.g. server FQDN or YOUR name) []:vistart
Email Address []:xxx@xxx.xxx

现在您已经有了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签署公钥:

由于可以通过IP地址和DNS名称建立TLS连接,因此在创建证书时需要指定IP地址。 例如,要允许使用10.10.10.20和127.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

注意:基于TLS的Docker应该在TCP端口2376上运行。

警告:如上例所示,使用证书身份验证时,您无需使用sudo或docker组运行docker客户端。 这意味着拥有密钥的任何人都可以向您的Docker守护程序提供任何指令,从而赋予他们对托管该守护程序的计算机的根访问权限。 像使用root密码一样保护这些密钥!

默认安全

如果您想默认保护 Docker 客户端连接的安全,您可以将文件移到您的 home 目录下的的 .docker 目录内。然后再设置 DOCKER_HOST 和 DOCKER_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。

守护模式

  • tlsverifytlscacerttlscerttlskey 参数集合:验证客户端
  • tlstlscerttlskey:不能验证客户端

客户端模式

  • tls:根据公开/默认 CA 池验证服务器
  • tlsverifytlscacert:根据给定 CA 验证服务器
  • tlstlscerttlskey:验证客户端证书,不根据给定 CA 验证服务器
  • tlsverifytlscacerttlscerttlskey:验证客户端证书,也根据给定 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

此站点使用Akismet来减少垃圾评论。了解我们如何处理您的评论数据