docker安全
Docker简介
容器
容器技术最早可以追述到1979年在Unix上的 chroot
,chroot
之后的程序没法访问真实系统的的目录结构和文件。这种技术和思想经过发展,最后成为了 Linux 上的 Namespace
,Namespace
和用于管理资源的 CGroup
以及 AUFS
类的 Union FS
等技术构成了 Linux 上的容器技术
Docker
Docker 是一个开源的应用容器引擎,让开发者可以打包他们的应用以及依赖包到一个可移植的容器中,然后发布到任何流行的Linux机器上,也可以实现虚拟化,容器是完全使用沙箱机制,相互之间不会有任何接口
Docker 在容器的基础上,进行了进一步的封装,从文件系统、网络互联到进程隔离等等,极大的简化了容器的创建和维护。使得 Docker 技术比虚拟机技术更为轻便、快捷。
Docker 和传统虚拟化方式也有不同之处:
传统虚拟机技术是虚拟出一套硬件后,在其上运行一个完整操作系统,在该系统上再运行所需应用进程;而容器内的应用进程直接运行于宿主的内核,容器内没有自己的内核,而且也没有进行硬件虚拟。
Docker组成
一个完整的 Docker 有以下几个部分组成:
DockerClient
客户端Docker Daemon
守护进程Docker Image
镜像DockerContainer
容器
Docker 镜像是一个特殊的文件系统,除了提供容器运行时所需的程序、库、资源、配置等文件外,还包含了一些为运行时准备的一些配置参数(如匿名卷、环境变量、用户等)。镜像不包含任何动态数据,其内容在构建之后也不会被改变。
镜像(Image
)和容器(Container
)的关系,就像是面向对象程序设计中的 类
和 实例
一样,镜像是静态的定义,容器是镜像运行时的实体。容器可以被创建、启动、停止、删除、暂停等。
Docker架构
Docker采用 C/S
架构。Docker Daemon
作为服务端,接受来自DockerClient
客户端的请求。
服务端可以通过三种不同类型方式来监听 Docker Engine API
请求:unix
,tcp
和 fd
。
https://docs.docker.com/engine/reference/commandline/dockerd/#examples
unix
默认使用 unix domain socket /var/run/docker.sock
进行通信。
客户端只能本地访问服务端,需要 root 权限或 Docker 组成员身份。
tcp
如果想要远程访问服务端,可以启用 tcp
方式,无加密监听在 2375
端口,使用 HTTPS
加密监听在 2376
端口
无加密
all network interfaces:-H tcp://0.0.0.0:2375
指定:-H tcp://192.168.59.103:2375
使用证书加密
服务端dockerd --tlsverify --tlscacert=ca.pem --tlscert=server-cert.pem --tlskey=server-key.pem -H=0.0.0.0:2376
客户端docker --tlsverify --tlscacert=ca.pem --tlscert=cert.pem --tlskey=key.pem -H=$HOST:2376 version
具体见手册: https://docs.docker.com/engine/security/https/
fd
在基于 Systemd
的系统上,可以通过 Systemd socket activation
与服务端进行通信,
dockerd -H fd://
,dockerd -H fd://3
SSH
从 18.09 版本开始,Docker 客户端支持通过 SSH 连接到服务端
1 | docker -H ssh://me@example.com:22 ps |
Docker安全机制
Linux Kernel 从 2.2 版本开始,提供了 Capabilities 功能,它将root用户的权限细分为不同的领域,可以分别启用或禁用。把特权划分成不同单元,可以只授权程序所需的权限,而非所有特权。
http://man7.org/linux/man-pages/man7/capabilities.7.html
Linux Capability 一共有38种,分别对应着一些系统调用,Docker 默认只开启了14种,这样就避免了很多安全的问题。
Docker Remote API 未授权访问 造成逃逸
如果服务端监听方式配置为 tcp
且暴露在公网上,就能远程操作 docker
服务端配置为 -H tcp://0.0.0.0:2375
客户端就可以远程访问
docker -H tcp://192.168.214.145:2375 ps
利用方式:
- 运行一个容器,挂载
/
,/root
,/home
,web目录或者其他目录,就能任意读写服务端的文件 - 写入ssh公钥
- 写入webshell
- 写计划任务
- 修改
/etc/sudoer
,提权
配置特权模式造成逃逸
--privileged
与 --cap-add
当一个容器开启时加入了 --privileged=true
参数,就开启了所有的 Capability,允许容器内的 root 拥有宿主机的 root 权限。
而 --cap-add
则可以加入 Capability,其中 SYSADMIN
意为container进程允许执行 mount
、umount
等一系列系统管理操作
1 | docker run -itd --privileged=true ubuntu:latest |
这样开启了一个有特权模式的容器
进入容器,挂载宿主机的硬盘,就能任意读写宿主机的文件
1 | root@ddef5f76cc36:/# mkdir test |
Dirty Cow漏洞
CVE-2016-5195
- https://www.anquanke.com/post/id/84866
- https://github.com/gebl/dirtycow-docker-vdso
- https://github.com/scumjr/dirtycow-vdso
- https://wohin.me/sec/2017/11/17/DirtyCoWDockerEscape.html
runc中的容器逃逸漏洞
CVE-2019-5736
当在容器内以root(UID 0)运行进程时,该进程可以利用runc中的错误来获取运行容器的主机的root权限
- https://thinkycx.me/2019-05-23-CVE-2019-5736-docker-escape-recurrence.html
- https://bestwing.me/CVE-2019-5736-Docker-escape.html
poc: