分析
一直在思考vps怎么会被挖矿,平时也没安装乱七八糟的东西,更何况也没怎么用。
然后突然想起,为了监控远程docker,我开了允许远程访问docker。具体操作参考Configure remote access for Docker daemon。
这样带来很危险的后果,只要被扫描到端口,就可以实现攻击,完全不设防。
攻击示例
简单地举个例子:
# 攻击者使用无认证的 2375 端口远程连接 Docker 并修改 /etc/hosts
docker -H tcp://<your-server-ip>:2375 run --rm \
-v /etc/hosts:/etc/hosts \
alpine sh -c "echo '1.2.3.4 example.com' >> /etc/hosts"
这样一来,还有什么不能改的呢?
改进
有两个方法:
套上TLS
生成服务器TLS证书
sudo mkdir -p /etc/docker/certs
sudo openssl genrsa -aes256 -out /etc/docker/certs/ca-key.pem 4096
sudo openssl req -new -x509 -days 365 -key /etc/docker/certs/ca-key.pem -sha256 -out /etc/docker/certs/ca.pem
sudo openssl genrsa -out /etc/docker/certs/server-key.pem 4096
sudo openssl req -subj "/CN=$(hostname)" -new -key /etc/docker/certs/server-key.pem -out /etc/docker/certs/server.csr
sudo openssl x509 -req -days 365 -sha256 -in /etc/docker/certs/server.csr -CA /etc/docker/certs/ca.pem -CAkey /etc/docker/certs/ca-key.pem -CAcreateserial -out /etc/docker/certs/server-cert.pem
sudo chmod 600 /etc/docker/certs/*
修改 /etc/docker/daemon.json
{
"tls": true,
"tlsverify": true,
"tlscacert": "/etc/docker/certs/ca.pem",
"tlscert": "/etc/docker/certs/server-cert.pem",
"tlskey": "/etc/docker/certs/server-key.pem",
"hosts": [
"unix:///var/run/docker.sock",
"tcp://0.0.0.0:2376"
]
}
重启docker
sudo systemctl daemon-reload
sudo systemctl restart docker
生成客户端证书
openssl genrsa -out client-key.pem 4096
openssl req -new -key client-key.pem -sha256 -out client.csr
openssl x509 -req -days 365 -sha256 -in client.csr -CA ca.pem -CAkey ca-key.pem \
-CAcreateserial -out client-cert.pem
客户端连接
docker --tlsverify \
--tlscacert=/path/to/ca.pem \
--tlscert=/path/to/client-cert.pem \
--tlskey=/path/to/client-key.pem \
-H=tcp://<服务器IP>:2376 info
使用 Docker Socket Proxy
使用 tecnativa/docker-socket-proxy 作为代理,限制 API 权限。
docker run -d \
--name docker_proxy \
-p 2375:2375 \
-v /var/run/docker.sock:/var/run/docker.sock \
-e CONTAINERS=1 \
-e IMAGES=1 \
-e SERVICES=0 \
tecnativa/docker-socket-proxy
常用权限控制
| 环境变量 | 默认 | 含义 |
|---|---|---|
| CONTAINERS | 0 | 允许管理容器(列表、启动) |
| IMAGES | 0 | 允许管理镜像(列出、拉取) |
| SERVICES | 0 | 允许管理 Swarm 服务 |
| TASKS | 0 | 允许管理任务 |
| VOLUMES | 0 | 允许管理数据卷 |
| NETWORKS | 0 | 允许管理网络 |
| INFO | 0 | 允许访问 Docker 信息 |
验证
-
使用 curl 进行 API 测试:
curl http://localhost:2375/containers/json仅返回正在运行的容器列表。
-
尝试删除容器:
curl -X DELETE http://localhost:2375/containers/<container-id>会被拒绝。
第二个方法更方便也更安全,最后我用了这个方案。

