我创建了一个 Web 应用程序,除其他外,它允许用户编写、编译和执行代码(Java、C#)。该应用程序为每个进行编译和代码执行的用户创建一个 Docker 容器。我已采取以下措施来保护容器:
- 此容器没有持久性或共享数据。
- 它无权访问 docker API(受 TLS 保护)。
- 容器中没有用户不应该知道的信息。
- 用户不会意识到编译器在容器中。
我可以认为这个容器可以安全地运行不受信任的代码吗?在这样的配置中,是否有任何已知的方法可以从容器内影响主机?
我创建了一个 Web 应用程序,除其他外,它允许用户编写、编译和执行代码(Java、C#)。该应用程序为每个进行编译和代码执行的用户创建一个 Docker 容器。我已采取以下措施来保护容器:
我可以认为这个容器可以安全地运行不受信任的代码吗?在这样的配置中,是否有任何已知的方法可以从容器内影响主机?
tl;dr:容器解决方案不会也永远不会保证提供完全隔离,如果需要,请使用虚拟化。
Docker(同样适用于类似的容器解决方案)不保证完全隔离,不应与虚拟化混淆。容器的隔离是通过在它们之间添加一些屏障来实现的,但它们仍然使用共享资源作为内核。另一方面,虚拟化的共享资源要小得多,现在更容易理解和经过良好测试,通常通过硬件功能来限制访问。Docker 本身在他们的Docker 安全文章中将其描述为
运行 Docker 容器的一个主要风险是,为容器提供的默认功能集和挂载可能会提供不完整的隔离,无论是单独使用,还是与内核漏洞结合使用时。
对于虚拟化,您从几乎完全隔离开始,并提供一些保护良好、描述良好的接口;这意味着您可以确定突破虚拟机很困难。内核不是共享的,如果你有一些内核漏洞可以让你摆脱用户限制,那么虚拟机管理程序就在你和其他虚拟机之间。
这并不意味着完美的隔离。一次又一次地发现管理程序问题,但其中大多数是非常复杂的攻击,范围有限,难以执行(但也有非常关键的“易于利用”的攻击。
使用容器,您可以从在同一个内核上运行应用程序开始,但会增加障碍(内核命名空间、cgroup...)以更好地隔离它们。虽然这提供了一些优势,例如较低的开销,但要“确定”没有忘记任何东西要困难得多,Linux 内核是一个非常庞大且复杂的软件。并且内核本身仍然是共享的,如果内核中有漏洞,您很有可能可以逃到主机(和/或其他容器)。
尤其是Docker 1.9 之前的版本,它应该获得用户命名空间,这几乎意味着“容器 root 也具有主机 root 权限”,一旦发现 Docker 机器(或内核漏洞)中另一个缺失的障碍。以前有过这样的问题,你应该期待更多的问题, Docker 建议你
注意以非特权用户(即非 root)的身份在容器内运行您的进程。
如果您对更多细节感兴趣,estep 在 http://integratedcode.us 上发布了一篇很好的文章,解释了用户命名空间。
限制 root 访问(例如,通过在创建映像时强制使用非特权用户或至少使用新的用户命名空间)是提供隔离的必要且基本的安全措施,并且可能会在容器之间提供令人满意 的隔离。使用受限用户和用户命名空间,转义到主机变得更加困难,但您仍然不应该确定是否有另一种尚未考虑的方式来突破容器(如果这包括利用内核中未修补的安全问题),并且不应该用于运行不受信任的代码。
虽然来自@jens-erat 的回答具有正确的高层次观点,即虚拟化为 docker 等容器化解决方案提供了卓越的隔离,但它并不是一个黑白设置。
一方面,虚拟化技术中出现了许多客户 --> 主机突破(例如虚拟软盘设备驱动程序中的“毒液”漏洞),因此与任何安全控制一样,虚拟化提供的隔离不是 100%。
从加强 docker 安装以提高隔离性和降低风险的角度来看,您可以采取许多步骤来帮助保护 docker 安装。
Docker 有一些很好的关于加固的安全指南。有一个(稍微过时的)CIS 安全指南和docker bench可用于查看配置
根据您的应用程序的运行方式(即代码如何在那里进行编译),您可以修改 docker 的操作以减少恶意活动的机会。例如,假设代码在主机级别运行,您可能能够拒绝对容器的网络访问(--net none
switch on docker run
)。您还可以查看是否可以删除其他功能以减少容器中运行的进程可以执行的操作。
考虑使用 AppArmor 配置文件来限制资源。AppArmor 可用于限制可以在容器中执行的操作,您可以使用bane等工具为您的应用程序生成配置文件。
此外,我建议在主机级别实施一些监控,以寻找可能的恶意访问。如您所知,容器应该/不应该做什么,进行一些相对严格的监控会提醒您任何可能的突破
另一个可以有效强化这种设置的领域是使用精简的主机操作系统和容器镜像。暴露的代码越少,攻击面就越小。CoreOS或Ubuntu Snappy Core之类的东西可能值得一看
我的解决方案类似于 SmartOS。原因是 SmartOS 支持 Docker、KVM 和区域。因此,您可以结合使用这些来防止恶意代码在 Docker 容器之外执行。毕竟,Docker 容器仍然是文件系统上的文件。