赞
踩
你也许知道如何在一台安装了 docker 的机器上创建、停止、删除容器。但是如果发号施令的程序和 docker 不在同一台机器上该怎么办?
本文将介绍如何开启 docker api 远程调用、使用 http api 或者 java sdk 操作另一台机器上的 docker、以及如何确保
docker api 不被他人调用。
默认 docker 只允许本机使用docker
命令进行操作,我们现在来开启 http api 调用,使得其他机器可以通过 http 请求来操作
docker。
注意:这种方法不对调用者权限进行校验,也就是说互联网上任何一个人都可以控制你的 docker。我们这里为了快速体验临时使用这种方法,长期使用请务必使用
tls 来鉴权,具体方法下文会介绍。
vim /lib/systemd/system/docker.service
编辑 docker 启动命令,找到 service 模块下的
ExecStart=xxx
这一行,在其末尾添加`-H=tcp://0.0.0.0:2375
其中,0.0.0.0
意为允许任何来源的访问,docker 将会在 2375
端口监听 http 请求。(记得开放安全组或者防火墙)
重启 docker:
systemctl daemon-reload
sudo service docker restart
然后你就可以通过 http 请求远程操控 docker 了,例如通过curl http://ip:2375/images/json
来获取镜像列表。同样你也可以通过各种编程语言的 sdk 来发起请求,详见:https://docs.docker.com/engine/api/sdk/
接下来我们用 java sdk 举例
我们使用 star 最多的 sdk:https://github.com/docker-java/docker-java
我的使用的 maven 依赖如下,其他版本可能会报错:
<dependency>
<groupId>com.github.docker-java</groupId>
<artifactId>docker-java</artifactId>
<version>3.3.4</version>
</dependency>
<dependency>
<groupId>com.github.docker-java</groupId>
<artifactId>docker-java-transport-httpclient5</artifactId>
<version>3.3.4</version>
</dependency>
<dependency>
<groupId>org.apache.httpcomponents.client5</groupId>
<artifactId>httpclient5</artifactId>
<version>5.2.1</version>
</dependency>
假设我有一台安装了 docker 的 ubuntu 服务器,下面这段代码将初始化一个 dockerClient,然后通过远程调用获取 docker
的镜像列表。
DockerClientConfig config = DefaultDockerClientConfig
.createDefaultConfigBuilder()
.withDockerHost("tcp://服务端 ip 地址:2375")
.withDockerTlsVerify(false)
.build();
DockerHttpClient httpClient = new ApacheDockerHttpClient.Builder()
.dockerHost(config.getDockerHost())
.sslConfig(config.getSSLConfig())
.maxConnections(100)
.connectionTimeout(Duration.ofSeconds(30))
.responseTimeout(Duration.ofSeconds(45))
.build();
dockerClient = DockerClientImpl.getInstance(config, httpClient);
dockerClient.listImagesCmd().exec().forEach(System.out::println);
现在我们对 docker api 远程调用有了一个基本认识,接下来我们将使用 tls 自签证书为 docker api
开启鉴权,只有持有配对证书的客户端和服务端才可以通信,防止被他人调用。
找一个目录存放等下要生成的证书文件,本文以/root/docker/cert/
为例。
进入这个目录,逐一运行以下命令:
# 这里要你设定一个密码,找个地方存下来,等下运行其他命令还要再输入这个密码 openssl genrsa -aes256 -out ca-key.pem 4096 # 这一步的问题可以不回答,一路回车即可 openssl req -new -x509 -days 365 -key ca-key.pem -sha256 -out ca.pem openssl genrsa -out server-key.pem 4096 # 把$HOST替换成运行着 docker 的服务器的 ip 或者域名 openssl req -subj "/CN=$HOST" -sha256 -new -key server-key.pem -out server.csr # 把$HOST替换成运行着 docker 的服务器的域名,把$IP替换成 ip。二者至少填一个,不填的就删掉,总之你最终要通过 ip 远程调用就填 ip,通过域名调用就填域名 echo subjectAltName = DNS:$HOST,IP:$IP >> extfile.cnf 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 openssl genrsa -out key.pem 4096 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 # 可选,删除以后没用的配置文件 rm -v client.csr server.csr extfile.cnf extfile-client.cnf
现在这个目录里应该会有一些 .pem 文件,其中,ca.pem, server-cert.pem, server-key.pem
是服务端要用的,ca.pem, cert.pem, key.pem 是客户端要用的。
vim /lib/systemd/system/docker.service
编辑 docker 启动命令,找到我们之前编辑过的 service
模块下的ExecStart=xxx
这一行,把之前的-H tcp://0.0.0.0:2375
改成-H tcp://0.0.0.0:2376
,(2376是 docker 在启用 https 情况下的惯用端口),然后再在后面追加--tlsverify --tlscacert=/path/to/ca.pem tlscert=/path/to/server-cert.pem --tlskey=/path/to/server-key.pem
,以指定启用 ssl 及其用到的证书文件路径(根据自己情况修改)
下面的代码示例指定了服务端所需要的证书文件,并监听 2376 端口接收远程调用,允许所有 ip 来源(但是客户端必须持有配对的证书)
ExecStart=/usr/bin/dockerd -H fd:// --containerd=/run/containerd/containerd.sock -H tcp://0.0.0.0:2376 --tlsverify --tlscacert=/root/docker/cert/ca.pem --tlscert=/root/docker/cert/server-cert.pem --tlskey=/root/docker/cert/server-key.pem
重启 docker:
systemctl daemon-reload
sudo service docker restart
我们从服务端把ca.pem, cert.pem, key.pem这三个文件拷贝到客户端的一个目录里放下,然后修改客户端的代码:
DockerClientConfig config = DefaultDockerClientConfig
.createDefaultConfigBuilder()
.withDockerHost("tcp://服务端 ip 地址:2376")
.withDockerTlsVerify(true)
.withDockerCertPath("你存放客户端证书的目录路径")
.build();
DockerHttpClient httpClient = new ApacheDockerHttpClient.Builder()
.dockerHost(config.getDockerHost())
.sslConfig(config.getSSLConfig())
.maxConnections(100)
.connectionTimeout(Duration.ofSeconds(30))
.responseTimeout(Duration.ofSeconds(45))
.build();
dockerClient = DockerClientImpl.getInstance(config, httpClient);
dockerClient.listImagesCmd().exec().forEach(System.out::println);
如果你能够正常获取服务端的 docker 镜像列表,说明你成功地实现了安全远程调用 docker api
本文介绍了如何开启 docker api 远程调用,并用 java sdk 控制远程 docker 服务器,以及如何通过自签 tls 证书来确保
docker api 不被他人调用
https://docs.docker.com/engine/security/protect-access/#use-tls-https-to-
protect-the-docker-daemon-socket
https://www.youtube.com/watch?v=cjm_NqteLLA&ab_channel=CodeWithRajRanjan
我一共划分了六个阶段,但并不是说你得学完全部才能上手工作,对于一些初级岗位,学到第三四个阶段就足矣~
这里我整合并且整理成了一份【282G】的网络安全从零基础入门到进阶资料包,需要的小伙伴可以扫描下方CSDN官方合作二维码免费领取哦,无偿分享!!!
如果你对网络安全入门感兴趣,那么你需要的话可以
点击这里
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。