Kubernetes集群组件的安全

 kelvinji2009 译 分布式实验室 

Kubernetes集群组件的安全

在《保护Kubernetes for Cloud Native Applications》系列的前一篇文章中,我们讨论了在保护部署Kubernetes集群的基础设施时需要考虑的因素。这一次,我们将注意力转移到集群本身。

Kubernetes集群组件的安全


Kubernetes是一个复杂的系统,上图显示了构成一个集群的许多不同的组成部分。为了保持集群的整体完整性,需要仔细保护每一个组件中。
在本文中,我们无法涵盖集群级安全性的各个方面,但我们的目标是解决更重要的主题。正如我们稍后将看到的,可以从更广泛的社区获得帮助,包括Kubernetes集群的最佳实践安全性,以及衡量对最佳实践的遵守情况的工具。


集群安装

Kubernetes集群组件的安全

我们应该首先简要观察一下可以用来安装集群组件的许多不同工具。
从安全角度来看,Kubernetes集群组件的某些默认配置参数是次优的,需要正确设置以确保安全集群。 除非您选择托管的Kubernetes集群(例如Giant Swarm提供的集群),代表您管理整个集群,否则许多不同的集群安装工具会加剧这个问题,每个工具都会有一些微妙的不同配置。虽然大多数安装程序都提供了合理的默认设置,但我们绝不应该认为它们在安全性方面有所支持,我们的目标应该是确保我们选择使用哪种安装程序机制,并将其配置为匹配我们的要求。
让我们来看一下控制平面安全性的一些重要方面。


API Server

Kubernetes集群组件的安全

API服务器是群集中所有通信的中心,它位于应用了大部分群集安全配置的API服务器上。API服务器是群集控制平面的唯一组件,它能够直接与群集的状态存储进行交互。操作集群,其他控制平面组件以及有时集群工作负载的用户都使用服务器的基于HTTP的REST API与集群交互。
由于其在集群控制中的关键作用,因此就安全性而言,仔细管理对API服务器的访问至关重要。如果某人或某些人获得了对API的未经请求的访问权限,他们就有可能获得各种敏感信息,并获得对集群本身的控制权。因此,客户端对Kubernetes API的访问应该进行加密,验证和授权。
使用TLS进行安全通讯
为防止中间人***,应使用TLS对每个客户端和API服务器之间的通信进行加密。为此,需要使用私钥和X.509证书配置API服务器。
一般来说,发API服务器证书的根证书颁发机构(CA)的X.509证书必须可供在TLS握手期间需要向API服务器进行身份验证的任何客户端使用,这导致我们遇到群集的证书颁发机构的问题。正如我们稍后将看到的,客户端可以通过多种方式对API服务器进行身份验证,其中一种方法是通过X.509证书。 如果采用这种客户端身份验证方法,在大多数情况下(至少对于群集组件)可能都是如此,每个集群组件都应该获得自己的证书,建立集群范围的PKI功能很有意义。
有许多方法可以为集群实现PKI功能,没有说一种方法比另一种更好。它可以手动配置,可以由您选择的安装程序配置,或通过其他方式配置。实际上,可以将集群配置为具有自己的内置CA,该CA可以发出证书以响应通过API服务器提交的证书签名请求。在Giant Swarm,我们使用名为cert-operator的运算符与Hashicorp的Vault[1]一起使用。
虽然我们的主题是与API服务器进行安全通信,但请务必禁用其不安全的端口(在Kubernetes 1.13之前),该端口通过普通HTTP(--insecure-port = 0)提供API!
身份验证,授权和准入控制
现在让我们将注意力转移到控制哪些客户端可以对集群中的哪些资源执行哪些操作。我们在这里不会详细介绍,总的来说,这是下一篇文章的主题。 重要的是确保控制平面的组件配置为提供底层访问控制。

Kubernetes集群组件的安全


当API请求落在API服务器上时,它会执行一系列检查以确定是否为请求提供服务,如果它确实为请求提供服务,则是根据定义的策略验证是为请求提供服务还是改变资源对象,执行链如上图所示。
Kubernetes支持许多不同的身份验证方案,这些方案几乎总是在集群外部实现,包括X.509证书,基本身份验证,bearer令牌,用于通过可信身份提供商进行身份验证的OpenID Connect(OIDC)等。使用API服务器上的相关配置选项可以启用多种方案,因此请务必为计划使用的身份验证方案提供这些选项。例如,X.509客户端证书身份验证需要包含一个或多个CA证书( -client-ca-file)文件路径。需要记住的一点是,默认情况下,任何未通过其中一种身份验证方案验证的API请求都会被视为匿名请求。虽然匿名请求获得的访问权限可能受到授权的限制,但如果不需要,则应完全关闭它们(--anonymous-auth = false)。
验证请求后,API服务器会根据授权策略考虑请求。同样,授权模式是一个配置选项(--authorization-mode),至少应该从默认值AlwaysAllow进行更改。理想情况下,授权模式列表应包括RBAC和Node,前者用于启用RBAC API以进行细粒度访问控制,后者用于授权kubelet API请求(见下文)。
一旦API请求经过身份验证和授权,资源对象在使用admission controller持久保存到集群的状态数据库之前可能会经过验证或改变。建议使用最少的admission controller,除非有充分的理由,否则不应从列表中删除。 额外的安全相关的admission controllers值得考虑:
  • DenyEscalatingExec:如果必须允许您的Pod以增强的权限运行(例如使用主机的IPC/PID命名空间),则此admission controller将阻止用户在Pod的特权容器中执行命令。

  • PodSecurityPolicy:为所有创建的Pod提供应用各种安全机制的方法。我们将在本系列的下一篇文章中对此进行进一步讨论,但是现在确保启用此admission controller非常重要,否则我们的安全策略将无法应用。

  • NodeRestriction:用于管理kubelet必须的集群资源的访问权限,下面将详细介绍。

  • ImagePolicyWebhook:允许为Pod的容器定义的镜像,通过外部“镜像验证器”(例如Image Enforcer)检查漏洞。 Image Enforcer[2]基于Open Policy Agent(OPA)[3],与开源漏洞扫描程序Clair配合使用。


Dynamic admission control是Kubernetes中相对较新的功能,相对静态插件化admission control机制提供更大的灵活性。它是通过admission webhooks和基于控制器的初始化实现的,并且只要社区解决方案达到足够成熟的水平,就可以为集群安全做出很大贡献。


Kubelet

Kubernetes集群组件的安全

Kubelet是在集群中的每个节点上运行的代理,负责它所在节点上的所有与Pod相关的活动,包括启动/停止和重新启动Pod容器,报告Pod容器的运行状况等等。在API服务器之后,当涉及到安全性时,kubelet是下一个要考虑的最重要的集群组件。
访问Kubelet REST API
kubelet在端口10250和10255上提供小型REST API。端口10250是读/写端口,而10255是具有API端点子集的只读端口。
提供对端口10250的不受限制的访问是危险的,因为可以在Pod的容器内执行任意命令,以及启动任意Pod。 同样,这两个端口都提供对有关Pod及其容器的潜在敏感信息的读访问权,这可能会使工作负载容易受到***。
为了防止潜在的危害,应通过设置kubelet的配置--read-only-port=0来禁用只读端口。但是,端口10250需要可用于度量收集和其他重要功能。应仔细控制对此端口的访问,因此我们将讨论关键的安全配置。
客户端认证
除非特别配置,否则Kubelet API对来自客户端的未经身份验证的请求是开放的。因此,配置一种可用的身份验证方法非常重要;X.509客户端证书,或具有包含bearer令牌的授权头的请求。
对于X.509客户端证书,需要使CA bundle的内容对kubelet可用,以便它可以在TLS握手期间验证客户端提供的证书。这是作为kubelet配置(--client-ca-file)的一部分提供的。
在理想的世界中,唯一需要访问kubelet API的客户端是Kubernetes API服务器。它需要访问kubelet的API端点以获取各种功能,例如收集日志和指标,在容器中执行命令(想想kubectl exec),将端口转发到容器等等。为了通过kubelet对其进行身份验证,需要使用客户端TLS凭据(--kubelet-client-certificate和--kubelet-client-key)配置API服务器。
匿名认证
如果您已经注意并配置了API服务器对kubelet API的访问权限,那么您可能会认为已经“完成工作”了。但事实并非如此,因为任何触发kubelet的API的请求都不会尝试使用kubelet进行身份验证,这被视为匿名请求。默认情况下,kubelet会传递匿名请求以进行授权,而不是将其作为未经身份验证而拒绝。
如果在您的环境中允许匿名的kubelet API请求是必不可少的,那么就有了授权门,它可以灵活地确定API能够和不能提供什么服务。 但是,通过将kubelet的--anonymous-auth配置设置为false,完全禁止匿名API请求会更安全。通过这样的配置,API向未经授权的客户端返回401 Unauthorized响应。
授权
通过授权对kubelet API的请求,再一次可能会违反默认的Kubernetes设置。对kubelet API的授权以两种模式之一运行;AlwaysAllow(默认)或Webhook。 AlwaysAllow模式完全符合您的预期 - 它将允许所有通过身份验证门的请求成功,这也包括匿名请求。
最好的方法是使用kubelet的--authorization-mode配置选项和webhook值,将授权决策转移到Kubernetes API服务器,而不是将其打开。使用此配置,kubelet调用SubjectAcce***eview API(它是API服务器的一部分)以确定是否允许主体发出请求。


限制Kubelet的力量

Kubernetes集群组件的安全


在较旧版本的Kubernetes(1.7之前)中,即使Node和Pod对象受另一个节点上运行的另一个kubelet的控制,该kubelet也具有对所有Node和Pod API对象的读写访问权限。他们还可以读取Pod规范中包含的所有对象:Secret,ConfigMap,PersistentVolume和PersistentVolumeClaim对象。换句话说,一个kubelet可以访问和控制它不负责的众多资源。这非常强大,并且在集群节点受损的情况下,损坏可能会迅速升级到相关节点之外。
节点授权
出于这个原因,专门为kubelet引入了节点授权模式,目的是控制其对Kubernetes API的访问。 节点授权器限制kubelet读取与kubelet相关的那些对象上的操作(例如Pod,节点,服务),并对Secrets,ConfigMap,PersistentVolume和PersistentVolumeClaim对象应用进一步的只读限制,这些对象与Pod绑定到运行kubelet的节点。
NodeRestriction Admission Controller
将kubelet限制为与其相关的对象的只读访问权限是防止受损集群或工作负载的重要一步。但是,kubelet需要对其Node和Pod对象进行写访问,以此作为其正常功能的一种方式。为了实现这一点,一旦kubelet的API请求通过节点授权,它就会受到NodeRestriction Admission Controller的约束,该控制器限制了kubelet可以修改的Node和Pod对象(它自己的)。为此,kubelet用户必须是system:node:<nodeName>,它必须属于system:nodes组。当然,它是kubelet用户的nodeName组件,NodeRestriction Admission Controller使用它来允许或禁止修改Node和Pod对象的kubelet API请求。接下来,每个kubelet应具有唯一的X.509证书,用于向API服务器进行身份验证,subject的Common Name表示用户,而组织则表示该组。
同样,这些重要的配置无法自动完成,而且API服务器在启动时需要将Node添加至—authorization-mode config选项的插件清单,并以逗号隔开;同时,NodeRestriction需要由—enable-admission-plugins选项在准入控制器清单内进行指定。


最佳实践

Kubernetes集群组件的安全

特别需要强调的是我们只覆盖了集群层的安全考虑因素的子集(尽管是重要的),如果你认为这听起来非常令人生畏,那就不要担心,因为有帮助在手。
与为基础架构层的组件(如Docker)创建基准安全建议的方式相同,这个建议也适用于Kubernetes集群。互联网安全中心(CIS)已为集群的每个组件编制了一套完整的配置设置和文件系统检查,并以CIS Kubernetes Benchmark[4]的形式发布。
您可能也有兴趣知道Kubernetes社区已经开发了一个开源工具,用于审核Kubernetes集群与基准测试Kubernetes Bench for Security[5]。它是一个Golang应用程序,支持许多不同的Kubernetes版本(1.6以上),以及不同版本的基准测试。
如果您认真对待集群的正确保护,那么必须使用基准作为合规性的衡量标准。


总结

Kubernetes集群组件的安全

显而易见,采取预防措施来保护具有适当配置的集群对于保护集群中运行的工作负载至关重要。虽然Kubernetes社区非常努力地提供所有必要的安全控制来实现其安全性,但由于历史原因,一些默认配置忽略了最佳实践。如果我们忽视这些缺点,将会带来危险,所以我们必须在建立集群或者当升级到提供新功能的新版本时,由我们自己负责来处理这些缺点以缩小差距。
我们在这里讨论的一些内容为下一层铺平了道路,我们利用配置的安全机制来定义和应用安全控制,以保护在集群上运行的工作负载。下一篇文章的名字叫做《Kubernetes集群安全最佳实践》。
相关链接:

  1. https://www.vaultproject.io/

  2. https://github.com/open-policy-agent/contrib/tree/master/image_enforcer

  3. https://www.openpolicyagent.org/

  4. https://www.cisecurity.org/benchmark/kubernetes/

  5. https://github.com/aquasecurity/kube-bench


原文链接:https://blog.giantswarm.io/securing-the-configuration-of-kubernetes-cluster-components/


上一篇:k8s架构组件功能介绍


下一篇:kubernetes真要放弃docker吗?