如何解决 K8s 多租户集群的安全隔离难题?

时间:2022-01-14 01:20:19

解决多租户集群的安全隔离问题对于企业上云而言至关重要。本文讨论了 Kubernetes 多租户集群的概念和常见的应用模式、企业内共享集群的业务场景以及 Kubernetes 现有的安全管理功能。

首先,我们讨论一下“租户”是什么。租户的概念不仅是集群用户,还包括构成计算、网络、存储和其他资源的工作负载集。在多租户集群中,对单个集群中不同租户进行隔离,这样恶意租户就无法攻击其他租户,共享集群资源也能合理地分配给租户。

根据隔离的安全级别,可以将集群分为软隔离(Soft Multi-tenancy)和硬隔离(Hard Multi-tenancy)。软隔离适用于企业内的多租户集群,因为默认情况下不会有恶意租户。在这种情况下,软隔离主要是保护内部团队之间的业务并防护可能的安全攻击。硬隔离适用于那些提供对外服务的服务提供商。由于业务模式,不能保证不同租户中业务用户的安全背景,所以集群中的租户和 Kubernetes 系统可能会相互攻击,这时需要严格的隔离以确保安全性。下面会对不同的多租户方案进行更详细的描述。

多租户使用场景

下面介绍两种不同隔离要求的企业多租户方案:

企业内共享集群的多租户

这种场景下,所有集群用户都来自企业,这也是许多 Kubernetes 集群客户的使用场景。由于服务用户的身份是可控的,因此这种业务模式的安全风险也相对可控,毕竟老板可以直接开掉有问题的员工。根据企业内部人员的结构,企业可以通过命名空间,按照逻辑对不同部门或团队的资源进行隔离。另外,定义具有以下角色的业务人员:

集群管理员

具有集群管理功能,例如伸缩容、添加节点等

为租户管理员创建并分配命名空间

管理各种策略,例如 RAM、RBAC、NetworkPolicy 以及 quota

租户管理员

至少拥有集群 RAM 只读权限

管理租户中相关人员的 RBAC 配置

租户用户

在租户命名空间允许范围内使用 Kubernetes 资源

除了用户角色的访问控制之外,我们还要确保命名空间之间的网络隔离,不同命名空间之间只允许白名单内的跨租户应用程序请求。

SaaS 和 KaaS 服务模型中的多租户

在 SaaS 多租户场景中,Kubernetes 集群中的租户是 SaaS 平台和 SaaS 控制平面上的服务应用程序实例。在这种场景下,平台的服务应用程序实例分为不同的命名空间。服务的最终用户无法与 Kubernetes 控制平面组件进行交互。这些最终用户可以通过自定义的 SaaS 控制平面访问和使用 SaaS 控制台,使用服务或部署业务,如下左图所示。例如,假设博客平台已部署并在多租户集群上运行。在这种情况下,租户是每个客户的博客实例和平台的控制平面。平台控制平面和每个托管博客都在不同的命名空间中运行。

KaaS 多租户方案通常与云服务提供商有关。在这种场景下,业务平台的服务通过 Kubernetes 控制平面直接暴露给不同租户的用户。最终用户可以使用服务提供商提供的 Kubernetes API 或其他扩展 API。为了满足隔离要求,不同的租户同样需要使用命名空间按照逻辑对访问进行隔离,同时确保不同租户的网络和资源配额的隔离。

与企业内的共享集群相反,这里的最终用户都来自非受信区域,所以可能会有在服务平台上运行恶意代码的恶意租户。对此,SaaS 和 KaaS 服务模型中的多租户集群需要更强的安全隔离。在这种场景下,Kubernetes 现有的原生功能还无法满足安全要求,因此需要在运行时进行内核级别的隔离来增强此业务场景中的租户安全性。

实施多租户架构

在规划和实施多租户集群时,我们首先要通过资源隔离模型来使用 Kubernetes 的资源隔离层,该模型会将集群本身、命名空间、节点、Pod 和容器分别分层。当不同租户的应用程序负载共享相同的资源模型时,就可能会产生安全风险,因此,在实施多租户时,要控制每个租户可访问的资源域。在资源调度层面,还要确保处理敏感信息的容器只能运行在独立的资源节点上。当不同租户的负载共享同一资源域时,我们可以使用运行时的资源调度控制策略来降低跨租户攻击的风险。

尽管 Kubernetes 现有安全性和调度功能不足以实现租户之间的完全安全隔离,但是可以通过命名空间隔离租户使用的资源域,并使用 RBAC、PodSecurityPolicy、NetworkPolicy 等策略模型来控制租户的资源访问范围以及资源调度功能。这种方法具有可靠的安全隔离能力。

以下部分重点介绍基于 Kubernetes 原生安全功能的多租户实践。

访问控制

NetworkPolicy

NetworkPolicy 控制不同租户业务 Pod 之间的网络流量,并通过白名单进行跨租户业务的访问控制。

PodSecurityPolicy

PodSecurityPolicies(PSP)是 Kubernetes 中原生集群维度的资源模型,可以在创建 Pod 请求的准入阶段验证该行为是否满足相应 PSP 的要求,例如检查 Pod 是否使用主机的网络、文件系统、指定端口或 PID 命名空间。另外,它能限制租户内的用户启用特权容器,还会根据绑定的策略将相应的 SecurityContext 添加到 Pod,包括容器运行时的 UID、GID 以及添加或删除的内核功能等设置。

OPA

Open Policy Agent(OPA)是一种功能强大的策略引擎,支持解耦的策略决策服务。目前,社区已经有了成熟的 Kubernetes 集成解决方案。当现有 RBAC 在命名空间级别上的隔离不能满足企业应用程序复杂的安全需求时,OPA 可以在对象模型级别提供细粒度的访问策略控制。另外,OPA 还支持 7 层 NetworkPolicy 定义以及基于标签和注释的跨命名空间访问控制,可以有效增强 Kubernetes 原生的 NetworkPolicy。

资源调度

资源配额(ResourceQuota)和限制范围(LimitRange)

在多租户场景中,不同的团队或部门会共享集群资源,这可能导致资源竞争问题,需要通过限制每个租户的资源使用配额来解决。ResourceQuota 用于限制总资源请求,以及租户对应命名空间下所有 Pod 的资源。LimitRange 用于设置租户的命名空间中 Pod 的默认资源请求和限制值。另外,我们还可以限制租户的存储资源配额和对象数量配额。

Pod 优先级(Priority)和抢占(Preemption)

从 Kubernetes 1.14 版本开始,Pod 优先级和抢占功能已成为重要组成部分。容器优先级表示调度队列中处于 pending 状态容器的优先级。由于节点资源不足或其他原因而无法调度高优先级的 Pod 时,调度程序会尝试驱逐低优先级的 Pod,来保证可以先调度、部署高优先级的 Pod。

在多租户方案中,优先级和抢占的设置可以用来保护租户中重要业务应用程序的可用性。此外,Pod 优先级与 ResourceQuota 搭配使用可将租户配额限制设为指定的优先级。

专用节点(Dedicated Nodes)

注意:恶意租户可能绕过节点 taint 和 tolerance 机制强制实施策略。以下内容仅适用于企业内受信任租户的集群,或租户无法直接访问 Kubernetes 控制平面的集群。

通过为集群中的某些节点添加 taint,可以将这些节点提供给指定租户专用。在多租户场景中,当集群中包含 GPU 节点时,可以使用 taint 为需要 GPU 资源的业务应用程序服务团队保留这些节点。集群管理员可以使用诸如 effect:“NoSchedule” 之类的标签向节点添加污点,这样就只能调度具有相应 tolerance 设置的 Pod 到该节点。

但是,恶意租户会将相同的 tolerance 设置添加到 Pod 上来访问此节点,因此,仅使用节点 taint 和 tolerance 机制无法确保目标节点在非信任多租户集群中的安全性。

保护敏感信息—REST 的 secret 加密

在多租户集群中,不同的租户用户共享一套相同的 etcd 存储。当最终用户访问 Kubernetes 控制平面时,要保护好 secret 数据,以避免访问控制策略配置不正确时导致敏感信息泄漏。

总结

在部署多租户体系架构时,首先要确定相应的应用场景,包括租户内用户和应用程序的可信度和对应的安全隔离程度。另外,为满足基本的安全隔离要求,最好执行以下几点:

启用 Kubernetes 集群默认安全配置

启用 RBAC,禁止匿名用户访问

启用 secrets encryption,保护敏感信息

根据 CIS Kubernetes 基准执行安全配置

启用准入控制器,例如 NodeRestriction、AlwaysPullImages 和 PodSecurityPolicy

使用 PSP 控制 Pod 部署的特权模式,并在 Pod 运行时控制 Pod 的安全上下文

配置 NetworkPolicy

Docker 运行时启用 Seccomp、AppArmor 和 SELinux

对监控、日志记录等服务进行多租户隔离

当使用诸如 SaaS 和 KaaS 之类的服务模型时,或者无法保证租户下用户的可信度时,可以使用以下更强力的隔离措施:

使用 OPA DENG 动态策略引擎在网络或对象级别进行细粒度的访问控制

部署安全容器,在容器运行时进行内核级隔离

对监视、日志记录、存储和其他服务实施全面的多租户隔离解决方案