Docker安全配置建议

作者:技术拾光

时间:2026-07-26

浏览:343

容器安全,你真的想简单了 不少开发者习惯将Docker这类容器视为沙盒(sandbox)应用,以为用root权限在容器里运行任何程序都没问题,Docker自带的机制就能保护宿主系统。例如,有人觉得容器里的进程和虚拟机里的进程一样安全;有人随便找个源就下载没有验证过的Docker镜像,看都不看内容就在

文章目录

容器安全,你真的想简单了

不少开发者习惯将Docker这类容器视为沙盒(sandbox)应用,以为用root权限在容器里运行任何程序都没问题,Docker自带的机制就能保护宿主系统。例如,有人觉得容器里的进程和虚拟机里的进程一样安全;有人随便找个源就下载没有验证过的Docker镜像,看都不看内容就在本地尝试、学习、研究;更夸张的是,一些提供PaaS服务的公司竟然允许用户向多租户系统中提交自己定制的Docker镜像。请注意,这些行为统统不安全。

本文就来聊聊Docker的隔离性和安全性,以及为什么它在隔离和安全上确实不如传统虚拟机。这不是危言耸听,而是底层技术决定的。

何谓安全性?

就Docker而言,安全性可以概括为两点:

  • 不会对主机造成影响
  • 不会对其他容器造成影响

所以安全性问题90%以上可以归结为隔离性问题。而Docker的安全问题本质上就是容器技术的安全性问题,这里面有两个核心痛点:共用内核,以及Namespace还不够完善的限制。具体来说:

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

当然,镜像本身不安全也会导致安全性问题,那是另一回事。

真的不如虚拟机安全?

传统虚拟机系统也并非100%安全,攻破Hypervisor就能让整个虚拟机毁于一旦。问题在于,有谁能随随便便就攻破吗?Docker的隔离性主要靠Namespace技术,传统Linux中PID是唯一且独立的,用户不会看见重复的PID。Docker用了Namespace,相同的PID可以在不同容器里独立存在。比如A容器里PID=1是A程序,B容器里PID=1同样是A程序,完全没问题。但核心问题在于:Linux内核(Kernel)不能被Namespace。也就是说,即使有多个容器,所有的system call实际上都经过主机的内核处理——这为Docker留下了不可否认的安全隐患。

传统虚拟机呢?很多操作也需要经过内核处理,但那是虚拟机的内核,不是宿主主机的内核。万一出问题,最多影响到虚拟系统本身。当然你可以说黑客可以先攻破虚拟机内核,再找Hypervisor漏洞,同时不被发现,再破SELinux,最后攻击主机内核——文字描述都嫌复杂,实际执行更是难上加难。所以Docker很好用,但在迁移业务系统时,请务必把安全性放在第一位。

如何解决?

接受“容器并不是全封闭”这个事实之后,开源社区(尤其是红帽公司)和Docker团队一直在改进安全性,主要方向是保护宿主不受容器入侵,以及防止容器之间互相破坏。社区在这方面的努力包括不少提案,但很多最终没有合入,原因很现实:

Audit namespace

作用:隔离审计功能。未合入原因:意义不大,而且会增加audit复杂度,难以维护。

Syslognamespace

作用:隔离系统日志。未合入原因:很难完美区分哪些log属于某个容器。

Device namespace

作用:隔离设备(支持设备同时在多个容器中使用)。未合入原因:几乎要修改所有驱动,改动太大。

Time namespace

作用:使每个容器有自己的系统时间。未合入原因:设计细节未达成一致,且应用场景不多。

Task count cgroup

作用:限制cgroup中的进程数,可以解决fork bomb问题。未合入原因:不太必要,增加了复杂性,kmemlimit可以实现类似效果(近期可能会被合入)。

隔离/proc/meminfo的信息显示

作用:在容器中看到属于自己的meminfo信息。未合入原因:cgroupfs已经导出所有信息,/proc展现的工作可以由用户态实现,比如fuse。

从2008年cgroup/ns基本成型至今,内核没有加入任何新namespace,cgroup子系统也只是做了简单补充。内核社区对容器技术隔离性的原则是:够用就好,不能把内核搞得太复杂。听起来保守,但确实是现实。

除了社区,一些企业也做了不少工作,比如采用层叠式的安全机制。下面是几种主流方案:

文件系统级防护

  • 文件系统只读:有些文件系统必须mount到容器里才能正常运行,但这给恶意进程很大便利。大部分App其实不需要写入文件系统,所以mount时可以用只读模式。比如:/sys、/proc/sys、/proc/sysrq-trigger、/proc/irq、/proc/bus。
  • 写入时复制(Copy-On-Write):Docker本身就用的这个文件系统。所有容器先共享一个基本镜像,需要写数据时,引导到与自己相关的特定文件系统中。这样避免一个容器看到另一个容器的数据,也无法通过修改文件系统去影响其他容器。

Capability机制

Linux的Capability机制很清楚:传统UNIX把进程分为高权限(root)和低权限(非root)两种,高权限完全绕过权限检查,低权限接受所有检查。从2.2内核开始,Linux把超级用户权限拆分成了不同单元(Capability),可以独立使能或禁止。对Docker而言,既要安全又要可用,必须从功能、可用性、安全性上综合权衡Capability设置。目前默认开启的列表一直是社区争议焦点,普通开发者可以通过命令行调整默认值。

NameSpace机制

Docker的命名空间也在某种程度上提供了保护。比如PID命名空间,它会把不在当前容器里的进程全部隐藏——恶意程序连进程都看不见,攻击难度自然提升。另外,终止PID为1的命名空间,容器里所有进程会被自动终止,管理员可以很轻松地关停容器。网络命名空间也很有用,管理员可以通过路由规则和iptable构建网络环境,容器内进程只能使用管理员许可的特定网络(比如只能访问公网、只能访问本地,或者两个容器之间做过滤)。

Cgroups机制

主要针对拒绝服务攻击。恶意进程会通过抢占全部系统资源来攻击,Cgroups可以避免这种情况。例如CPU的cgroups可以在某个容器试图耗尽CPU时登录并制止。管理员需要设计更多cgroups来控制打开文件数、子进程数等资源。

SELinux

SELinux是一个标签系统:进程有标签,文件、目录、系统对象都有标签。通过撰写访问规则来保护安全,实现的是MAC(强制访问控制)系统——对象的所有者不能控制别人访问对象,这种机制比传统权限更严格。

安全建议

最简单的建议:不要把Docker容器当成可以完全替代虚拟机的东西。跑在容器中的应用在很长一段时间内都要有选择性,通常只跑测试系统或可信业务。

门槛再高一点,对系统做减法——通过各种限制来达到安全性。这是最主流的有效方法,比如前面介绍的那几种安全机制。同时一定要保证内核的安全和稳定,外部监控、容错系统也必不可少。

总之,通过适配和加固的Docker容器方案,安全性完全可以达到商用标准。只是对实施人员的技术要求比较高,门槛摆在那里。但话说回来,如果团队愿意投入,这个成本是值得的。

实用工具推荐

电子包浆

绿化、压缩、噪点和虚拟水印,自由调节做旧程度。

使用 ›
图片压缩

选择画质和输出格式,预览压缩前后的大小。

使用 ›
相关文章