提升Docker安全性

最后更新于:2022-04-01 21:48:37

## 1.Docker的核心原理 Docker容器的的本质是宿主机上的进程.通过namespace实现资源隔离,cgroups实现资源的限制,通过写时复制的机制完成高效的文件操作.docker实现的核心技术-namespace 和 cgroups,其实并不是什么新技术,准确的说namespace 和 cgroups是linux的相关技术.docker对这种技术进行了封装,提高可操作性。 ## 2.容器安全的痛点 容器经常拿来和虚拟机进行对比,容器的好处就不多说了!主要说说:容器的缺点-隔离性低导致的安全性较低. **通常来说,容器相比虚拟机还是不够安全的.**. #### 2.1为什么容器不够安全? 这就要从虚拟机和容器的底层实现机制来对比, * 虚拟机在hypervisor的基础上构建虚拟操作系统,有自己的操作系统内核.**容器与宿主机是共用同一个内核的**. * 虚拟机也不是绝对安全的.找到HyperVisor的弱点,攻克SELinux控制,就可以攻破虚拟机,染指宿主机。但这是非常难的. * 容器的隔离技术使用的是namespace,但namesapce的资源隔离仅限于以下6个方面 |namespace|隔离内容|内核版本| |---|---|---| |UTS|主机名与域名|Linux 2.6.19| |IPC|信号量,消息队列和共享内存|Linux 2.6.19| |PID|进程编号|Linux 2.6.24| |Network|网络设备,网络栈,端口|始于Linux 2.6.24 完成于 Linux 2.6.29| |Mount|文件挂载|Linux 2.4.19| |User|用户用户组| 始于 Linux 2.6.23 完成于 Linux 3.8| > 为提升安全性,您的linux内核请升级版本大于3.8 > docker1.10开始支持User namespace,但不是默认开启的.[《Docker 安全之用户资源隔离》](http://www.zimug.com/453.html) 这6种资源隔离看上去比较完备,但是仍然有很多的资源没有隔离,比如: * SELinux * Cgroups * file systems under /sys * /proc/sys, /proc/sysrq-trigger, /proc/irq, /proc/bus * /dev/mem * /dev/sd* file system devices 这将宿主机的资源暴露给了容器的访问者,会导致安全问题! **同时笔者认为,docker容器安全的痛点也仅限于互联网公有云环境下。对于企业内部私有云也算不上痛点,通过对docker进行安全加固可以达到生产环境的安全级别的要求!欢迎批判!**,第4章节,我们将看看如何提升docker容器安全! ## 3.docker容器安全也有自己的优势 容器的资源隔离程度相对虚拟机较低,与宿主机共享内核.导致容器的安全性低.那么是不是说容器相对于虚拟机,在安全性上完全没有自己的优势呢? 笔者认为,还是有的: 1. 可以禁止SSH访问,防止很多正面攻击 2. 容器暴露的端口有限,容器的本质是宿主机的进程,他只需要暴露非常有限的端口来提供服务. 3. 可以利用容器云控制容器的生命周期,使其在不影响服务的情况下,尽可能的短命.攻击短生命周期的容器意义并不大. 3. 容器的文件系统分层,镜像层是只读的,只有容器层可写.容器层文件的生命周期与容器相同(不是数据卷). ## 4.如何提升容器安全性 ### 4.1 使用User namespace **User namespace是从docker1.10开始被支持,并且不是默认开启的.** docker 使用namespace进行资源隔离,其中一种是user namespace.user namespace主要隔离了安全相关的标识符和属性,包括用户ID,用户组Id,root目录,key(密钥)以及特殊权限. 默认的情况下,docker容器使用的root用户和宿主机的root用户是同一个用户,尽管可以限制容器内root用户的权限(capability),但本质上仍然和宿主机root用户是同一个用户. 有了user namespace之后,我们就可以将宿主机上的普通用户映射为容器的root用户,这样容器中的实际用户为普通用户权限,可以将容器的安全程度提高一个等级! 关于具体的实现步骤,请查看我的这篇文章: [《Docker 安全之用户资源隔离》](http://www.zimug.com/453.html) ### 4.2 使用OpenSSL保护docker daemon 默认情况下,运行docker命令需要访问本地的Unix Socket.也可以通过HTTP的方式完成远程访问. 如果你需要以安全的方式在网络中访问docker,最好使用TLS,指定tlsverify参数,设置tlscacert参数指向一个可信的CA证书.在这种方式下,只有经过CA权限验证通过的客户端才能访问docker deamon. 具体内容请访问官网:[《Protect the Docker daemon socket》](https://docs.docker.com/engine/security/https/#connecting-to-the-secure-docker-port-using-curl) ### 4.3 安全的组网方式 我们可以将容器的服务端口分为两种 * 第一种:直接为用户提供服务的端口,如:web应用常用8080 * 第二种:为其他应用的提供服务的端口. 笔者认为安全的组网方式就是:**尽量**不使用端口映射的方式将容器端口映射到宿主机.端口暴露的越少,安全性就越高. **什么是尽量?如何尽量?** 我采用overlay的网络,或者叫应用层网络,覆盖网络,**但这绝不是唯一的方法**. docker 1.9为我们提供了官方的跨宿主机组网方式overlay(还有其他的网络工具也是这种方式).容器应用的网络构建于物理网络之上,在逻辑上又独立于物理网络. 举个例子:ZF的各个部门是都一个宿主机,容器(职能人员)之间可以跨宿主机沟通.部门级别之间的沟通是物理网络,各部门的职能人员之间的沟通是应用网络. 最后形成的沟通结论,对外发布,交给新闻发言人,这个新闻发言人是物理网络对外服务的接口. 同样: 对于第一种直接为用户提供服务的端口,可以采用端口映射的方式映射到宿主机,他就是发言人. 对于第二种端口的消息,应用网络内部处理,不对外发布。 实现方式可以参考:[《基于consul的Docker-overlay跨多宿主机容器网络》](http://www.zimug.com/364.html) ### 4.4 限制docker容器的capability **什么是capability?** 简单地说,就是执行调用操作的权限.Linux将超级用户的权限进行分组,每一组代表了所能执行的系统调用操作. 如果是root用户,剥夺它的某些capability,那么它将无法调用对应的系统操作.如果是普通用户,对它赋予某些capability,它也可以完成某些超级用户才能做的系统调用. capability为系统的权限管理,提供了更加细粒度的权限划分. **容器默认拥有的capability(能力)包括:** * CHOWN: 更改文件UID和GID的能力 * DAC_OVERRIDE:忽略文件的读,写,执行访问权限的检查的能力 * FOWNER:越过可执行文件的拥有者权限检查,执行操作的能力 * FSETID:文件修改后保留setuid/setgid标志位 * SETGID:改变进程组id的能力 * SETUID:改变进程用户ID的能力 * SETFCAP:向security.capability写入能力属性的能力 * NET_RAW:创建RAW和PACKET套接字的能力 * MKNOD:使用mknod创建特殊文件的能力 * SYS_REBOOT:允许使用reboot或者kexec_load.kexec_load功能是加载新的内核作为reboot重新启动所需的内核 * SYS_CHROOT:使用chroot的能力 * KILL:越过权限检查,发送信号的能力 * NET_BIND_SERVICE:绑定常用端口的能力(端口号小于1024) * AUDIT_WRITE:允许审计日志写入的能力 **查看容器的capability(能力)** 通过docker ps 和docker inspect 获得容器进程的id,查看容器的默认能力 ``` $ pscap |grep 165536 1411 19337 165536 top chown, dac_override, fowner, fsetid, kill, setgid, setuid, setpcap, net_bind_service, net_raw, sys_chroot, mknod, audit_write, setfcap ``` **移除容器的capability(能力)** 使用--cap-drop移除能力,运行容器 ``` docker run -it --cap-drop SETGID --cap-drop SETUID ubuntu:14.04 top ``` 通过docker ps 和docker inspect 获得容器进程的id,查看容器的现有能力.setuid和setgid的能力被移除 ``` 1411 19803 165536 top chown, dac_override, fowner, fsetid, kill, setpcap, net_bind_service, net_raw, sys_chroot, mknod, audit_write, setfcap ``` **为容器新增capability(能力)** 使用--cap-add增加能力,运行容器 ``` docker run -it --cap-add SYS_TIME ubuntu:14.04 top ``` 通过docker ps 和docker inspect 获得容器进程的id,查看容器的现有能力.新增了sys_time能力 ``` 1411 20101 165536 top chown, dac_override, fowner, fsetid, kill, setgid, setuid, setpcap, net_bind_service, net_raw, sys_chroot, sys_time, mknod, audit_write, setfcap ``` **Linux都有哪些capability(能力)?** [capabilities - overview of Linux capabilities](http://www.man7.org/linux/man-pages/man7/capabilities.7.html) ### 4.5 文件系统只读保护 Docker 可以设置容器的文件系统为只读模式.这样可以禁止,脚本注入方式的攻击,因为脚本无法保存. ``` $ docker run --rm -ti --read-only ubuntu bash ``` **注意:此方法不能与user namespace 同时使用** **……未完待续,欢迎持续关注我的博客!** ## 参考 * Docker安全部署的17条建议 http://dockone.io/article/150 * 容器相比虚拟机更为安全的十三个方面 http://dockone.io/article/1427 * Docker背后的内核知识——Namespace资源隔离 http://www.infoq.com/cn/articles/docker-kernel-knowledge-namespace-resource-isolation * Docker安全 https://segmentfault.com/a/1190000005794220
';