【注意】最后更新于 May 22, 2019,文中内容可能已过时,请谨慎使用。
引言
Docker采用C/S
架构,包括客户端和服务端。Docker守护进程(Daemon)作为服务端接受来自客户端的请求,并处理这些请求( 创建、 运行、 分发容器)。Docker从 0.5.2 之后使用本地Unix套接字机制强制代替了原先绑定在127.0.0.1 上的套接字,以加强服务端的防护。用户任然可以使用HTTP提供REST API 访问。建议使用安全机制,确保只有可行的网络或VPN,或证书保护机制(例如受保护的stunnel和ssl认证)下的访问可以进行。
这里简单说明开启 REST API的过程。
安装环境
操作系统:ubuntu 16.04
Docker版本: 18.03.0-ce
开启REST API
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
|
$ systemctl show --property=FragmentPath docker
FragmentPath=/lib/systemd/system/docker.service
# 修改 ExecStart=/usr/bin/dockerd -H fd:// 为 ExecStart=/usr/bin/dockerd -H unix:///var/run/docker.sock -H tcp://0.0.0.0:2376
$ sudo vi /lib/systemd/system/docker.service
$ sudo systemctl daemon-reload
$ sudo systemctl restart docker
$ docker -H tcp://127.0.0.1:2376 version
Client:
Version: 18.03.0-ce
API version: 1.37
Go version: go1.9.4
Git commit: 0520e24
Built: Wed Mar 21 23:10:01 2018
OS/Arch: linux/amd64
Experimental: false
Orchestrator: swarm
Server:
Engine:
Version: 18.03.0-ce
API version: 1.37 (minimum version 1.12)
Go version: go1.9.4
Git commit: 0520e24
Built: Wed Mar 21 23:08:31 2018
OS/Arch: linux/amd64
Experimental: false
|
由上面的结果可以看出, REST API 已经开启,但是没有使用加密,docker 不安全
前面的方式可以完成任务但是对原有脚本修改较大。可以使用下面的方式:
修改 /etc/default/docker
, 将 DOCKER_OPTS
修改为 "-H=unix:///var/run/docker.sock -H=0.0.0.0:2375"
。 然后执行 sudo service docker restart
即可。
在Ubuntu16.04 LTS 下 DOCKER_OPTS有可能不生效,需要做一下修改:
- 修改文件
/lib/systemd/system/docker.service
在 ExecStart=/usr/bin/dockerd
前增加一行(-代表ignore error)。
1
|
EnvironmentFile=-/etc/default/docker
|
-
修改文件 /lib/systemd/system/docker.service
,将 ExecStart=/usr/bin/docker daemon -H fd://
修改为ExecStart=/usr/bin/docker daemon -H fd:// $DOCKER_OPTS
-
执行systemctl daemon-reload
重载默认配置
开启REST API 使用SSL加密
创建SSL证书,这里可以参考官方文档Protect the Docker daemon socket。 在参考文档中有已经写好的脚本,更加方便。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
|
#/bin/bash
# @author: anyesu
if [ $# != 1 ] ; then
echo "USAGE: $0 [HOST_IP]"
exit 1;
fi
#============================================#
# 下面为证书密钥及相关信息配置,注意修改 #
#============================================#
PASSWORD="8#QBD2$!EmED&QxK"
COUNTRY=CN
PROVINCE=yourprovince
CITY=yourcity
ORGANIZATION=yourorganization
GROUP=yourgroup
NAME=yourname
HOST=$1
SUBJ="/C=$COUNTRY/ST=$PROVINCE/L=$CITY/O=$ORGANIZATION/OU=$GROUP/CN=$HOST"
echo "your host is: $1"
# 1.生成根证书RSA私钥,PASSWORD作为私钥文件的密码
openssl genrsa -passout pass:$PASSWORD -aes256 -out ca-key.pem 4096
# 2.用根证书RSA私钥生成自签名的根证书
openssl req -passin pass:$PASSWORD -new -x509 -days 365 -key ca-key.pem -sha256 -out ca.pem -subj $SUBJ
#============================================#
# 用根证书签发server端证书 #
#============================================#
# 3.生成服务端私钥
openssl genrsa -out server-key.pem 4096
# 4.生成服务端证书请求文件
openssl req -new -sha256 -key server-key.pem -out server.csr -subj "/CN=$HOST"
# 5.使tls连接能通过ip地址方式,绑定IP
echo subjectAltName = IP:127.0.0.1,IP:$HOST > extfile.cnf
# 6.使用根证书签发服务端证书
openssl x509 -passin pass:$PASSWORD -req -days 365 -sha256 -in server.csr -CA ca.pem -CAkey ca-key.pem -CAcreateserial -out server-cert.pem -extfile extfile.cnf
#============================================#
# 用根证书签发client端证书 #
#============================================#
# 7.生成客户端私钥
openssl genrsa -out key.pem 4096
# 8.生成客户端证书请求文件
openssl req -subj '/CN=client' -new -key key.pem -out client.csr
# 9.客户端证书配置文件
echo extendedKeyUsage = clientAuth > extfile.cnf
# 10.使用根证书签发客户端证书
openssl x509 -passin pass:$PASSWORD -req -days 365 -sha256 -in client.csr -CA ca.pem -CAkey ca-key.pem -CAcreateserial -out cert.pem -extfile extfile.cnf
#============================================#
# 清理 #
#============================================#
# 删除中间文件
rm -f client.csr server.csr ca.srl extfile.cnf
# 转移目录
mkdir client server
cp {ca,cert,key}.pem client
cp {ca,server-cert,server-key}.pem server
rm {cert,key,server-cert,server-key}.pem
# 设置私钥权限为只读
chmod -f 0400 ca-key.pem server/server-key.pem client/key.pem
|
执行服务端配置
1
2
3
4
5
6
7
8
9
10
11
|
chmod +x tlscert.sh
HOST_IP=127.0.0.1
./tlscert.sh $HOST_IP
# 客户端需要的证书保存在client目录下, 服务端需要的证书保存在server目录下
sudo cp server/* /etc/docker
# 修改配置
sudo vi /etc/default/docker
# 改为 DOCKER_OPTS="--selinux-enabled --tlsverify --tlscacert=/etc/docker/ca.pem --tlscert=/etc/docker/server-cert.pem --tlskey=/etc/docker/server-key.pem -H=unix:///var/run/docker.sock -H=0.0.0.0:2375"
# 重启docker
sudo service docker restart
|
在Ubuntu16.04 LTS 下 DOCKER_OPTS有可能不生效,参见上面的修改或参考文档
客户端访问方式
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
|
# 客户端加tls参数访问
docker --tlsverify --tlscacert=client/ca.pem --tlscert=client/cert.pem --tlskey=client/key.pem -H tcp://127.0.0.1:2375 version
# Docker API方式访问
curl https://127.0.0.1:2375/images/json --cert client/cert.pem --key client/key.pem --cacert client/ca.pem
# 简化客户端调用参数配置
sudo cp client/* ~/.docker
# 方式一
docker --tlsverify -H tcp://127.0.0.1:2375 version
# 方式二
# 追加环境变量
echo -e "export DOCKER_HOST=tcp://$HOST_IP:2375 DOCKER_TLS_VERIFY=1" >> ~/.bashrc
sudo docker version
|
参考资料
- Docker Daemon连接方式详解
- Docker 配置文件配置无效 /etc/default/docker