容器安全管理

容器和虚拟机

容器和虚拟化都是系统虚拟化的实现技术,可以实现系统资源的共享。相较于虚拟机,容器技术是一种“轻量”的虚拟化方式,虚拟机通常在Hypervisor层实现对硬件资源的虚拟化,Hypervisor为虚拟机提供了虚拟的运行平台,管理虚拟机的操作系统运行,每个虚拟机都有自己的操作系统、系统库以及应用。而容器并没有Hypervisor 层,每个容器是和主机共享硬件资源及操作系统 ,容器技术在操作系统层面实现了对计算机系统资源的虚拟化,在操作系统中,通过对 CPU、内存和文件系统等资源的隔离、划分和控制,实现进程之间透明的资源使用。

容器的安全机制

容器因其轻量,不受运行环境的依赖、能很好的支持CI/CD(持续集成和持续部署)等特性,在快速发展的信息时代也备受开发者青睐。不同于虚拟机可以创建完全隔离的环境并实现完全虚拟化,容器共享宿主机内核和资源,在隔离性上存在一定安全风险,例如虚拟机逃逸风险,会导致对其他容器甚至是宿主机造成威胁。

容器主要通过Linux 内核的Cgroup和Namespace两大特性来实现资源限制和环境隔离。

  • Cgroups

Cgroups 是 control groups 的缩写,是 Linux 内核提供的一种可以限制、记录、隔离进程组(process groups)所使用的物理资源(如:cpu,memory,IO等等)的机制。

  • Namespace

Linux Namespace提供了一种内核级别隔离系统资源的方法,通过将系统的全局资源放在不同的Namespace中,来实现资源隔离的目的,提供了对 UTS、IPC、Mount、PID、Network、User 等的隔离机制,但Linux内核的namespace机制并不完善、不能实现完全的隔离:

- /proc、/sys等未完全隔离
- Top, free, iostat等命令展示的信息未隔离
- Root用户未隔离
- /dev设备未隔离
- 内核模块未隔离
- SELinux、time、syslog等所有现有Namespace之外的信息都未隔离

容器的安全风险面

  • 镜像安全
  • 逃逸风险
  • 网络风险
  • 拒绝服务风险
  • 生态安全

镜像安全

镜像是docker容器的静态表现形式,镜像的安全决定了容器运行时的安全,镜像的风险面主要分为如下四类:

  • 镜像漏洞:如果镜像本来就存在cve、应用组件、语言包漏洞甚至是恶意上传的后门镜像等,开发者在从仓库(如 :docker hub 、阿里云等第三方镜像仓库)拉取镜像进行开发时就会直接引入安全风险,增大了容器的风险面。
    针对容器镜像的安全扫描工具有:trivy、clair、Anchore、Quay等,可以嵌入CI流水线、和镜像仓库集成,实现在开发阶段就及时发现安全风险。
  • 镜像仓库:用于存储容器镜像的仓库,安全风险主要包括仓库本身的安全风险和镜像拉取传输过程中的风险。
    仓库本身的安全风险例如,将私有镜像仓库配置不当端口对外了、仓库存在越权漏洞可以创建管理员(CVE-2019-16097:Harbor任意管理员注册)。
    镜像传输过程中风险包括,如何确保容器镜像从镜像仓库到用户端的完整性,不被中间人劫持、篡改。Docker已在其1.8版本后采用内容校验机制解决中间人攻击的问题,但非默认配置,需主动开启(export DOCKER_CONTENT_TRUST = 1)。
  • dockerfile
    镜像构建的方式通常有两种:基于容器直接构建或基于dockerfile构建,基于dockerfile构建的镜像是“透明”的,所有指令都可以追溯,其中的安全风险在于正确使用镜像指令和敏感信息的处理:
    • 指令的正确选择:在Dockerfile中没有指定USER,Docker将默认以root用户的身份运行该Dockerfile创建的容器,如果该容器遭到攻击,那么宿主机的root访问权限也可能会被获取;若需引入外部文件,在 Dockerfile 中能用COPY 指令就不要使用ADD 指令,因为COPY 指令只是将文件从本地主机复制到容器文件系统,ADD 指令却可以从远程 URL 下载文件并执行诸如解压缩等操作,这可能会带来从 URL 添加恶意文件的风险。
    • 防止敏感信息泄露:如果在Dockerfile文件中存储了固定密码等敏感信息并对外进行发布,则可能导致数据泄露的风险。
    • 最小必要原则:在编写指令时,只添加必要的应用和服务,ssh、telnet等高危服务若不使用就不必开启。

逃逸风险

容器逃逸攻击指的是容器利用漏洞,“逃逸”出了其自身所拥有的权限,实现了对宿主机和宿主机上其他容器的访问。

  • Linux内核漏洞:CVE-2016-5195 Dirty Cow (脏牛漏洞)
    该漏洞是Linux内核的内存子系统在处理写时拷贝(Copy-on-Write)时存在条件竞争漏洞,导致可以破坏私有只读内存映射,黑客可以获取低权限的本地用户后,利用此漏洞获取其他只读内存映射的写权限,进一步获取root权限。
    Linux Kernel版本不低于2.6.22 的所有 Linux 系统(从 2007 年发布 2.6.22 版本开始,直到2016年10月18日为止,这中间发行的所有 Linux 系统都受影响),可自查Linux内核版本 uname -a

    exp:git clone https://github.com/gbonacini/CVE-2016-5195.git

  • docker软件漏洞
    a. Shocker攻击
    通过调用open_by_handle_at函数(能够读取文件的函数)对宿主机文件系统进行暴力扫描,以获取宿主机的目标文件内容。由于Docker1.0之前版本对容器能力(Capability)使用黑名单策略进行管理,并没有限制CAP_DAC_READ_SEARCH能力,赋予了shocker.c程序调用open_by_handle_at函数的能力,导致容器逃逸的发生。
    洞影响版本:Docker版本< 1.0, 存在于 Docker 1.0 之前的绝大多数版本。
    exp:https://github.com/gabrtv/shocker

    b. runC容器逃逸 CVE-2019-5736
    runc:一个基于OCI (Open Container Initiative)标准的轻量级工具,用于创建和运行容器。
    漏洞允许恶意容器(以最少的用户交互)覆盖host上的runc文件,从而在host上以root权限执行任意代码。所有使用到runc的容器服务和产品(如Docker、Kubernetes等)均受漏洞影响。
    环境安装:curl https://gist.githubusercontent.com/thinkycx/e2c9090f035d7b09156077903d6afa51/raw -o install.sh && bash install.sh
    POC: git clone https://github.com/Frichetten/CVE-2019-5736-PoC

    c.dcker cp命令逃逸 CVE-2019-14271
    当docker使用cp命令(实现容器和宿主机的文件拷贝)时,会调用在宿主机命名空间中的docker-tar,加载位于容器中的libnss_.so库,当容器被攻击者控制或存在恶意镜像时,攻击者可以通过替换libnss_.so库为恶意代码并将其注入到docker-tar中,实现docker逃逸、获得宿主机权限。

    docker-tar的原理是chroot到容器中,归档其中请求的文件及目录,然后将生成的tar文件传回Docker守护进程,该进 
    程负责将文件提取到宿主机上的目标目录中。
    docker-tar的原理其实是使用了chroot,其实就是设置了一个根目录,将要请求的文件与目录放到这个根目录中去,生成一个tar文件,然后再将这个tar文件交给docker的守护进程,由守护进程将文件复制到目标文件夹中去。
    
  • 配置不当导致逃逸

    • Docker Remote API 未授权访问
      Docker Remote API可以实现对容器的远程系统命令控制,相当于在dcoker界面执行指令;攻击者利用该未授权漏洞API能远程控制docker容器,实现容器逃逸、进而危害到宿主机,被广泛用于挖矿、蠕虫病毒等。
      复现环境 https://github.com/vulhub/vulhub/tree/master/docker/unauthorized-rce

    • docker.sock 挂载到容器内部
      是Docker守护进程(Docker daemon)默认监听的Unix域套接字(Unix domain socket),容器中的进程可以通过它与Docker守护进程进行通信,当其被挂载在容器内时,攻击者可利用 docker.sock 和docker deamon 通信,运行一个高权限的恶意容器,进而实现逃逸。

    • docker 高危启动参数
      a. privileged 特权模式
      当docker用特权模式启动时 ----privileged ,相当于放开了容器和宿主机对 Network,PID,IPC namespace命名空间的限制,攻击者可通过--volume 将宿主机根目录挂载进容器中,直接实现逃逸。

      b. 敏感目录挂载
      例如将宿主机root目录挂载至容器,写入ssh密钥后获得宿主机权限
      docker run -itd -v /root:/root ubuntu:18.04 /bin/bash

      c. 相关启动参数的安全问题
      docker通过linux namespace实现 主机名、用户权限、文件系统、网络、进程号、进程间通讯等资源的隔离,当启动时如果给予容器的权限过高就可能导致逃逸发生。

网络安全风险

 - 桥接模式(bridge):在默认的bridge网络模式下,docker主机上的容器都会使用docker0这个网关,容易造成ARP欺骗、端口嗅探等,建议是自行给容器分配网络 或使用docker swarm、kubernetes等容器集群管理平台,创建集群间的overlay网络。

  • 主机模式(host):host模式会有更好的网络性能,因为其使用了主机的本地网络堆栈,共享网络命名空间(漏洞案例:host模式容器逃逸漏洞 cve-2020-15257);但此时 容器将共享主机的网络堆栈,容器能看到主机的所有端口,使容器有了访问主机本地系统服务的全部权限。

  • none模式:在这种模式下,Docker容器拥有自己的Network Namespace,但是,并不为Docker容器进行任何网络配置。也就是说,这个Docker容器没有网卡、IP、路由等信息。需要我们自己为Docker容器添加网卡、配置IP等。

  • container模式:这个模式指定新创建的容器和已经存在的一个容器共享一个Network Namespace,而不是和宿主机共享。新创建的容器不会创建自己的网卡,配置自己的IP,而是和一个指定的容器共享IP、端口范围等。同样,两个容器除了网络方面,其他的如文件系统、进程列表等还是隔离的,两个容器进程通过lookback网卡通信。

拒绝服务攻击

由于容器和宿主机共享内核资源,因此当存在资源争抢时容易出现拒绝服务攻击,例如计算资源、存储资源、网络资源等。

  • 计算资源
    主机内核正常情况下只能支持一定数量的进程,如果某个容器内的进程组新建过多进程,消耗了主机上的所有进程资源,那其他容器就没有新资源来创建进程,甚至会危害到宿主机资源的正常使用,攻击案例 如fork bomb ,可以通过限制容器资源使用降低相关风险,--kernel-memory=#M
Fork Bomb是一类典型的针对计算资源的拒绝服务攻击手段,其可通过递归方式无限循环调用fork()系统函数快速创建大量进程。
  • 存储资源
    docker通过mount命名空间实现文件系统隔离,但没有对docker使用的AUFS文件系统做限制,导致容器可以通过无限写入文件来打满存储空间,从而造成存储资源的拒绝服务。

  • 网络资源
    攻击者使用大量的受控主机向被攻击目标(容器)发送大量的网络数据包,以占满容器的网络宽带,并消耗容器主机的网络数据处理能力,实现网络资源的拒绝服务。

生态安全

docker的广泛用于也促进了整个云原生生态的发展,包括编排系统(常见的例如k8s)、微服务、devops(devsecops)等。

参考

《容器安全风险解决方法上/下篇》
《容器安全白皮书-绿盟2018》
https://blog.fundebug.com/2017/04/17/about-docker-sock/
https://yangrz.github.io/blog/2018/04/13/docker/
https://github.com/Kutim/docker-security
https://www.secrss.com/articles/2947
https://www.dosec.cn/dosecwp.pdf
https://www.jianshu.com/p/89b329626621
https://github.com/xxg1413/docker-security/blob/master/shocker/shocker-cn.md
https://www.cnblogs.com/xiaozi/p/13423853.html
https://dockerdocs.cn/engine/security/index.html#conclusions

posted @ 2021-12-03 17:51  人间修行  阅读(555)  评论(0编辑  收藏  举报