安全地远程调用Docker API

安全地远程调用Docker API

引言

你也许知道如何在一台安装了 docker 的机器上创建、停止、删除容器。但是如果发号施令的程序和 docker 不在同一台机器上该怎么办?

本文将介绍如何开启 docker api 远程调用、使用 http api 或者 java sdk 操作另一台机器上的 docker、以及如何确保
docker api 不被他人调用。

开启 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 举例

使用 java sdk 远程调用 docker api

我们使用 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 被他人调用

现在我们对 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官方合作二维码免费领取哦,无偿分享!!!

如果你对网络安全入门感兴趣,那么你需要的话可以

点击这里👉网络安全重磅福利:入门&进阶全套282G学习资源包免费分享!

①网络安全学习路线
②上百份渗透测试电子书
③安全攻防357页笔记
④50份安全攻防面试指南
⑤安全红队渗透工具包
⑥HW护网行动经验总结
⑦100个漏洞实战案例
⑧安全大厂内部视频资源
⑨历年CTF夺旗赛题解析

  • 44
    点赞
  • 53
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值