1 概述
最近有很多关于容器安全性的讨论,尤其是当在生产环境中部署使用容器的时候。容器环境所面临的大多数安全威胁,和非容器环境存在的威胁在本质上基本是一致的。只不过基于容器的某些特性,出现了一些新的场景和攻击面。
那么对于容器环境来说,都有什么样的安全威胁呢?总结起来可以从以下三个方面来进行简单划分。
容器技术是基于容器主机操作系统内核实现的资源隔离,相比较vm来讲,容器对主机的操作系统有了更多的权限,因此诸如OS的安全补丁、API、权限、认证、隔离等问题对容器的安全性有着很大的影响。
■ 容器的镜像是否是安全
关于容器镜像的安全性,比如像镜像的漏洞、恶意程序等问题,之前的文章《容器镜像的脆弱性分析》已经进行了比较全面的分析,这里就不再过多介绍了。
■ 容器运行时是否是安全
比如容器中是否运行了非法的进程、是否遭到了DDoS攻击、是否发生了逃逸等。
2 定级原理及流程
本小节将从三个方面,简单介绍容器基础设施/运行环境的安全性。
2.1 容器逃逸容器逃逸攻击与虚拟机逃逸攻击相似,利用虚拟化软件存在的漏洞,通过容器获取主机权限入侵主机,以达到攻击主机的目的。这里通过容器入侵主机的逃逸,一方面包括在容器中获取到更多的主机权限;另一方面包括不完善的隔离存储。
具体地,一些PoC工具,如Shocker,可展示如何从Docker容器逃逸并读取到主机某个目录的文件内容。Shocker攻击的关键是执行了系统调用open_by_handle_at函数,Linux手册中特别提到调用open_by_handle_at函数需要具备CAP_DAC_READ_SEARCH能力,而Docker1.0版本对Capability使用黑名单管理策略,并且没有限制CAP_DAC_READ_SEARCH能力,因而引发了容器逃逸的风险。
2.2 容器网络
Docker默认采用预设的桥接网络驱动,一个docker0的网桥将所有容器连接该网桥,docker0网桥扮演着路由和NAT的角色,容器间通信都会经过容器主机。
默认情况下,这种桥接采用黑名单的方式,即同一主机上的容器之间是允许所有通信的,用户根据业务需求添加访问控制规则。如果各容器之间没有防火墙保护,攻击者就可以利用主机内部网络进行容器间的ARP欺骗、嗅探、广播风暴等攻击。
2.3 拒绝服务
默认情况下容器可以使用主机上的所有资源,如果某个容器以独占方式访问或消耗主机的大量资源,则该主机上的其它容器就会因为缺乏资源而无法正常运行。
DoS攻击可针对任何资源,例如计算资源、存储资源、网络资源等,下面分别以这三种资源进行说明。
■ 计算资源Fork Bomb 是一个很典型的计算型DoS攻击场景,主机内核正常情况下只能支持一定数量的进程,如果某个容器内的进程组新建过多进程,消耗了主机上的所有进程资源,那其它的容器就没有资源来创建新的进程,甚至会危及主机的正常工作。
Fork Bomb也是自2015年到现在Docker社区一直讨论的问题,目前最好的方法是限制内存的使用(--kernel-memory=#M),但是,当在与加密文件一起使用时可能会偶尔出现问题。
■ 存储资源
在容器技术的实现中,通过mount命名空间实现了文件系统的隔离。但是文件系统隔离仅仅是一个非常基本的要求。不建议使用AUFS做存储驱动,虽然AUFS创建出的容器文件系统互相隔离,但是在存储空间方面却没有任何限制。换言之,一个容器如果不断写文件,将会写满存储介质,其它容器将无法执行写操作,导致拒绝服务攻击。
■ 网络资源DoS攻击层出不穷,容器内网络带宽耗尽也是其中一种,攻击者使用大量的受控主机向被攻击目标(容器)发送大量的网络数据包,以占满容器的网络宽带,并消耗容器主机的网络数据处理能力,达到拒绝服务的目的。
3 CIS Benchmark
CIS针对Docker和Kubernetes,分别提出了安全基准文档,用于对Docker和Kubernetes运行环境进行安全审计。
下面本文将通过两个例子,介绍在默认情况下容器环境的安全风险。
3.1 Docker 默认配置风险
宿主机采用Ubuntu16.04.4 LTS(4.4.0-116-generic,x86_64),具体请参照Docker官方的安装文档安装Docker。官方文档路径如下:https://docs.docker.com/install/linux/docker-ce/ubuntu/#set-up-the-repository。版本如下图所示:
使用docker-bench-security(https://github.com/docker/docker-bench-security)对其进行检查,如下图所示:检查结果如下表所示:
从上表的结果中可以看出,检查结果总计可以划分为三类:
■ 通知提示(INFO/NOTE)
比如针对2.6的检查,要求确保配置了对Docker daemon访问的TLS认证。而测试环境默认启动的Docker daemon是没有启动TCP监听服务的,因此,对于该条目,设置为通知提示。
[INFO] 2.6 - Ensure TLS authentication for Docker daemon is configured [INFO] * Docker daemon not listening on TCP |
■ 通过(PASS)
比如针对2.2的检查,要求确保Docker日志级别设置为“INFO”,Docker默认的日志级别符合该要求,因此检查结果为PASS。
[PASS] 2.2 - Ensure the logging level is set to 'INFO' |
■ 警告(WARN)
比如针对2.1的检查,要求连接在默认网桥上Docker实例之间的网络流量,是要限制其之间的网络访问。而Docker的默认配置,是允许所有实例通信的,因此该条目提示为告警级别。
[WARN] 2.1 - Ensure network traffic is restricted between containers on the default bridge |
由于在CIS的标准中,第5章是针对Container Runtime的,在主机上没有容器实例运行时,这一大项的检测是跳过的,因此所有的数据都是0。这种情况下,针对全部的74项检测,除去通知级别的38项,剩下的36项检测中,告警的有12项,比例达到了33%。主要包括以下内容:
■ 主机配置检查
[WARN] 1.1 - Ensure a separate partition for containers has been created |
确保为存储Docker文件,创建一个单独的分区(逻辑卷)
[WARN] 1.5 - Ensure auditing is configured for the Docker daemon |
确保Docker daemon要将审计的能力进行配置,在/etc/audit/audit.rules文件中添加一条审计规则:–w/usr/bin/docker –k docker。
[WARN] 1.6 - Ensure auditing is configured for Docker files and directories - /var/lib/docker |
确保对docker文件和目录进行审计,在/etc/audit/audit.rules文件中添加一条审计规则:–w /var/lib/docker–k docker。
[WARN] 1.7 - Ensure auditing is configured for Docker files and directories - /etc/docker |
同样是对Docker文件和目录进行审计的检查,在/etc/audit/audit.rules文件中添加一条审计规则:–w /etc/docker–k docker。
■ Docker daemon配置检查
[WARN] 2.1 - Ensure network traffic is restricted between containers on the default bridge |
确保容器间在默认的桥接网络上,采用白名单方式实现通信。将docker daemon启动参数(/etc/docker/daemon.json)icc设置为false。
[WARN] 2.8 - Enable user namespace support |
确保在Docker守护进程中启用用户命名空间,将启动参数userns-remap设置为default。
[WARN] 2.11 - Ensure that authorization for Docker client commands is enabled |
确保启用Docker客户端命令的认证授权,Docker默认是没有对客户端命令进行授权管理的功能,这里需要借助第三方插件实现。Docker官方给出的插件主要包括Casbin AuthZ Plugin、HBM plugin和Twistlock AuthZ Broker这三种。可以采用以下命令运行插件:
#docker run -d -v/var/lib/authz-broker/policy.json:/var/lib/authz-broker/policy.json -v/run/docker/plugins/:/run/docker/plugins twistlock/authz-broker
然后在docker daemon启动参数(/etc/docker/daemon.json)中的authorization-plugins设置为authz-broker。
[WARN] 2.12 - Ensure centralized and remote logging is configured |
确保配置了集中式和远程的日志记录。
在docker daemon启动参数(/etc/docker/daemon.json)中的log-driver设置为syslog,log-opts设置为{ "syslog-address" :" = tcp://192.x.x.x"。
[WARN] 2.14 - Ensure live restore is Enabled |
确保容器实例可以支持无守护进程运行,也就是说,docker daemon在关闭或者恢复时,不会停止容器,并且可以在daemon重新启动后重新接管。
将docker daemon启动参数(/etc/docker/daemon.json)中的live-restore设置为true。
[WARN] 2.15 - Ensure Userland Proxy is Disabled |
Docker引擎提供了两种将主机端口转发到容器端口的方式:DNAT和Userland Proxy。默认情况下,Userland Proxy已启用。
将dockerdaemon启动参数(/etc/docker/daemon.json)中的userland-proxy设置为false。
[WARN] 2.18 - Ensure containers are restricted from acquiring new privileges |
确保限制容器获取新的权限。
将dockerdaemon启动参数(/etc/docker/daemon.json)中的no-new-privileges设置为true。
■ Docker镜像和构建文件检查
[WARN] 4.5 - Ensure Content trust for Docker is Enabled |
确保启用了Docker的内容信任,默认情况下,内容信任是被禁止的。可以通过修改环境变量来进行设置,export DOCKER_CONTENT_TRUST=1。
考虑到这里的检测,并未覆盖到第5章中Container Runtime相关的内容,因此在测试环境中,我们运行一个容器,再来进行一下测试,结果如下表所示。
# docker run -d -p 80:80--read-only -v $(pwd)/nginx-cache:/var/cache/nginx -v $(pwd)/nginx-pid:/var/runnginx(https://hub.docker.com/_/nginx/,以只读模式运行nginx)
对比这两个结果可以发现,1/2/3/6/7这五部分的结果是完全一样的,第四部分原来的2个PASS的内容变成了WARN,第五部分的内容进行了检测。至于第五部分的内容,涉及到运行时,不同的容器可能结果会不同,因此这里不再详细分析。第四部分由PASS转为WARN的2项是:
[WARN] 4.1 - Ensure a user for the container has been created [WARN] * Running as root: pensive_burnell |
默认情况下,容器以root权限运行,并且以容器中的用户root身份运行,应确保容器镜像的Dockerfile包含USER指令,或者在USER指令前通过useradd命令添加特定用户。
[WARN] 4.6 - Ensure HEALTHCHECK instructions have been added to the container image [WARN] * No Healthcheck found: [nginx:latest] |
确保将HEALTHCHECK指令添加到Docker镜像中,进而能够对运行的容器实例进行运行状况检查。默认情况下,HEALTHCHECK未进行设置。
3.2 Kubernetes 默认配置风险
采用两节点使用Kubeadm部署Kubernetes v1.12.1。
Master节点检测结果如下表所示:
Worker节点检测结果如下表所示:
由于篇幅的限制,这里就不再对结果进行详细分析了。
点击此链接,下载《2018绿盟科技容器安全技术报告》完整版:
http://blog.nsfocus.net/global-threat-analysis-container-safety
绿盟科技金融事业部微信公众号: nsfocusfbd
点击“阅读原文”阅读绿盟科技金融事业部安全月刊