当前位置: 首页 > 科技观察

如何在Kubernetes中运行不受信任的容器

时间:2023-03-21 15:31:05 科技观察

IT世界每天都在越来越多地采用基于容器的基础架构。但是,其优势、劣势甚至局限性,大家就不清楚了。考虑到即使是大公司也越来越接近基于容器的基础设施,可能的攻击区域和数据泄露的潜在影响被忽视了。Docker(containerd)和LXC等技术并不是真正孤立的系统,因为它们与托管操作系统共享相同的Linux内核。对于潜在的攻击者来说,在大公司内启动他们的容器是千载难逢的机会。但是容器技术本身能不能让我们轻松自卫呢?现在的容器技术已经重复了很多次,容器是一种打包、共享和部署应用程序的新方式,而不是将所有功能打包在一个软件或操作系统中的单一应用程序。目前,容器没有利用任何新东西,但它们是在Linux名称空间和cgroups之上创建的演变。命名空间创建一个虚拟的和隔离的用户空间,并为应用程序提供隔离的系统资源,例如文件系统、网络和进程。这种抽象允许应用程序独立启动,而不会干扰同一主机上运行的其他应用程序。因此,由于命名空间和cgroup的结合,我们绝对可以在隔离环境中启动在同一主机上运行的许多应用程序。容器与虚拟机显然,与虚拟机环境相比,容器技术解决了隔离、可移植性和精益架构等问题。但我们不要忘记,虚拟机允许我们隔离我们的应用程序,尤其是在内核级别,因此黑客逃出容器并破坏系统的风险远高于逃出虚拟机。大多数Linux内核漏洞可能适用于容器,这可能允许它们升级和破坏受影响的命名空间以及同一操作系统中的其他命名空间。这些安全问题促使研究人员尝试创建与主机真正独立的名称空间。具体称为“沙盒”,现在有几种提供这些功能的解决方案:gVisor或,例如,KataContainers。Kubernetes中的容器运行时我们可以在容器编排器Kubernetes中更深入地研究此类技术。Kubernetes使用组件kubelet来管理容器。我们可以将其定义为一艘船的船长,负责按照给定的规范并准时准确地执行其操作。Kubelet将pod规范作为容器运行在分配给它们的主机上,并且可以与任何容器运行时交互,只要它符合OCI标准(其实现是RunC)容器运行时的工作原理RunC最初是嵌入式的在Docker架构中,于2015年作为独立工具发布。它已成为一个通用的、标准的、跨功能的容器运行时,DevOps团队可以将其用作容器引擎的一部分。RunC提供了与现有低级Linux特性交互的所有功能。它使用命名空间和控制组来创建和运行容器进程。在接下来的段落中,我们将介绍运行时类和核心元素。还有一个默认值为RunC的RuntimeClass处理程序(对于使用containerd作为容器运行时的Kubernetes安装)。RuntimeClass顾名思义,运行时类允许我们操作各种容器运行时。2014年,Docker是Kubernetes上唯一可用的容器运行时。从Kubernetes1.3版本开始,增加了与Rocket(RKT)的兼容性,最后在Kubernetes1.5中,引入了ContainerRuntimeIterface(CRI),它有一个标准的接口和所有容器运行时的可能性,你可以直接与这个接口标准通信免去了开发者适配各种容器运行时和担心版本维护的麻烦。事实上,CRI允许我们将容器运行时部分与Kubernetes解耦,最重要的是,允许KataContainers和gVisor等技术以containerd的形式连接到容器运行时。在Kubernetes1.14中,RuntimeClass作为内置的集群资源再次引入,其核心是处理程序属性。handler是一个接收容器创建请求的程序,对应一个containerruntime。kind:RuntimeClassapiVersion:node.k8s.io/v1metadata:name:#RuntimeClassNamehandler:#containerruntime例如:runco??verhead:podFixed:memory:""#64Micpu:""#250mscheduling:nodeSelector::#container-rt:gvisorhandler字段指向要使用的特定容器运行时或配置。声明开销允许集群(包括调度程序)在做出有关Pod和资源的决策时将其考虑在内。通过使用这些字段,您可以指定使用此RuntimeClass运行pod的开销,并确保在Kubernetes中考虑这些开销。调度字段用于确保Pod被调度到正确的节点上。默认情况下,如果我们有一个带有Docker或containerd的集群,我们的处理程序是runc,但如果我们使用gVisor,它将是runc。在Kubernetes中使用gVisor隔离Linux主机和容器现在我们将了解如何在Kubernetes集群中拥有多个容器运行时,并为敏感工作负载选择限制性更强的容器运行时。在本教程中,我使用了之前的项目,在该项目中我使用containerd安装了Kubernetes集群。https://github.com/alessandrolomanto/k8s-vanilla-containerd初始化Kubernetes集群:makevagrant-start启动机器后,验证所有组件是否已启动并运行:vagrantsshmasterkubectlgetnodesNAMESTATUSROLESAGEVERSIONmaster就绪控制-plane,master7m59sv1.21.0worker1Ready5m50sv1.21.0worker2Ready3m51sv1.21.0在worker1上安装gVisor:sshworker1#Vagrant默认密码:vagrantsudosu安装最新的gVisor版本:(set-eARCH=$(uname-m)URL=https://storage.googleapis.com/gvisor/releases/release/latest/${ARCH}wget${URL}/runsc${URL}/runsc.sha512\\${URL}/containerd-shim-runsc-v1${URL}/containerd-shim-runsc-v1.sha512sha512sum-crunsc.sha512\\-ccontainerd-shim-runsc-v1.sha512rm-f*.sha512chmoda+rxrunsccontainerd-shim-runsc-v1sudomvrunsccontainerd-shim-runsc-v1/usr/local/bin)FINISHED--2022-04-2807:24:44--总挂钟时间:5.2已下载:4个文件,62Min3.1s(20.2MB/s)runsc:OKcontainerd-shim-runsc-v1:OKConfigurecontainerruntime:cat<有关更新信息,请遵循官方文档https://监督者。dev/docs/user_guide/install/结论我们已经看到,当前的容器技术存在薄弱的隔离问题。快速修补容器和最小特权安全上下文等常见做法可以有效地限制攻击面。我们甚至应该像上面的教程一样开始实施运行时安全措施,因为现在可能有多个容器运行时。当然,这不是每个人都需要的东西,但是当您想运行不受信任的容器而不以任何方式影响主机时,它肯定会派上用场。假设你是一个容器托管服务,在同一台主机上为不同的客户启动容器。您是否通过共享上下文伤害了其他客户?开始思考如何缓解这些问题。