11 个方法避免 Kubernetes 被黑客攻击
技术
作者:Andrew Martin
译者:夏天
2018-08-06 04:37

自 Kubernetes 出现以来,它的安全性已经取得了长足的进步,但目前仍然存在一些问题。这篇文章给出了 11 个让 Kubernetes 避免被黑的方法。内容涵盖 Control Plane,通过 Workload 和网络安全构建,以及 Kubernetes 未来安全性预测,希望能帮助你加强集群安全性,增强集群的受损害恢复能力。


Control Plane 部分

Control Plane 是 Kubernetes 的“大脑”。通过 Control Plane,可以整体浏览集群上所有容器和 Pod 的运行情况 。Control Plane 可以调度新 Pod (包含具有对其 Parent Node 有 root 访问权限的容器),也可以读取集群中存储的所有 secret。但当 Control Plane 被访问时,空闲时或有流量通过网络传输进来时,就要格外小心意外损坏和恶意攻击了。


方法 1 : TLS 无处不在

应该为支持 TLS 的每个组件启用 TLS 以防止流量嗅探(traffic sniffing)、验证服务器身份,以及(对 mutual TLS)验证客户端的身份。

值得注意的是,有些组件和安装方法可以越过 HTTP 启用本地端口,管理员应该熟悉每个组件的设置,以提高自己识别潜在不安全流量的能力。

Lucas Käldström(Kubernetes 社区 SIG lead & contributor) 的这个网络图展示了应用 TLS 理想情况:清晰地列出了主服务器上的所有组件之间、Kubelet 和 API 服务器之间关系。Kelsey Hightower 大作《Kubernetes The Hard Way 》中,也给出了详细的操作说明,以及安全模型文档。 



在以前,自动伸缩 Kubernetes Node 非常困难,因为每个 Node 都需要一个 TLS Key 来连接到 Master,而把 secret 放入基本镜像不是很好实现。Kubelet TLS bootstrapping 为新的 Kubelet 提供了 创建 Certificate Signing Request(CSR)文件的能力,以便在启动时间内生成 Certificate。 


方法 2:最低权限启用 RBAC、禁用 ABAC 和监控日志 

RBAC(Role-Based Access Control ) 可以为用户访问资源提供细粒度策略管理,例如对 Namespace 的访问。



Kubernetes 1.6 发布以后,Kubernetes 的 ABAC(Attribute Based Access Control )已被 RBAC 取代,因此不应在 API 服务器上启用,应使用 RBAC 替代如下: 

或者使用这个标记在 GKE 中禁用 ABAC: 

对于集群服务和文档来说,RBAC 策略有很多很好的例子。细粒度 RBAC 策略可以通过 audit2rbac 在 Audit Log 中提取。

在 Pod 受损时,错误或过度宽松的 RBAC 策略都是安全威胁。保持最低权限,不断审查和改进 RBAC 规则,这应被视为团队在其开发生命周期中应偿还的“技术债务”(开发团队在设计或架构选型时,从短期效应的角度选择了一个易于实现的方案。但从长远来看,这种方案会带来更消极的影响,即开发团队所欠的债务)的一部分。 

Audit Logging(1.10 版本中已处于 beta 阶段)可在有效负载(例如请求和响应)以及元数据级别提供可自定义的 API 日志(log) 记录,方便组织根据安全策略进行调整 ,GKE 也提供了默认设置来帮助用户入门。 

对于 Get、List 、Watch 等读取请求来说,只有请求对象是被保存在 Audit Log 中的,而响应对象并不保存在内。 对于涉及 Secret 和 ConfigMap 等敏感数据的请求,只有元数据可被导出;所有其他请求的请求和响应对象在 Audit Log 中。 

需谨记:一旦遭遇攻击,把这些 Log 保留在集群中的行为将成为安全威胁。和其他安全敏感日志一样,这些 log 应在集群外部传输,以防止在发生破坏时被篡改。 

方法 3 :API 服务器使用第三方身份验证 

在整个组织中,集中身份验证和授权(也称为单点登录)有助于为用户提供 Onboarding,Offboarding 和一致权限。 

将 Kubernetes 与第三方 Auth 提供者(如 Google 或 GitHub ) 集成在一起,使用远程平台的标识保证(由 2FA 之类的东西支持),并防止管理员重新配置 Kubernetes API 服务器以添加或删除用户。 

Dex(CoreOS 开源项目)是一个带可插拔连接器的 OpenID Connect(OIDC)和 OAuth 2.0 的解决方案。 Pusher 通过一些自定义工具在此基础上做了一些改进,另外还有一些其他工具可用,但应用场景略有不同。 

方法 4 :为你的 etcd 设置防火墙 

etcd 是 Kubernetes 中一个存储状态和 secret 信息的关键组件,它的安全保护措施与集群其他部分略有不同。 

对 API Server 的 etcd 写访问(Write access)等同于获得整个集群的 root 权限,而读访问(Read access)甚至可以被轻易利用来升级权限。 

Kubernetes scheduler 将搜索 etcd,寻找那些没有 nodeSelector 标签的 Pod 。 然后将找到的 Pod 调度到可用的 Node 上。 提交的 Pod 验证是在写入 etcd 之前由 API 服务器执行的,因此直接写入 etcd 的恶意用户可以绕过许多安全机制,例如 PodSecurityPolicies 的许可控制。 

etcd 应配置同级的用户端 TLS 证书,并部署在专属 Node 上。 为了减少私钥被盗和或通过 Worker Node 进入,集群也可以成为 API 服务器的防火墙。 

方法 5:轮换加密密钥 

保证安全性最好的办法就是定期轮换加密密钥和证书。 

当现有的凭证到期时,Kubernetes 会通过创建新的 CSRs 来自动轮换某些证书(特别是 kubelet 用户端和服务器证书)。 

但是,API  server 用于加密 etcd 值的对称加密密钥(Symmetric encryption keys)并不能进行自动轮换,必须手动执行。 主访问确实需要这种轮换机制,因此很多托管服务(例如 GKE 或 AKS)把这个问题从运维人员那单独抽取出来。 

Workload 部分  

我们一般对 Control Plane 的最低要求就是能保障集群安全地运行。但是,就像载满货物的船一样,船上的集装箱必须在发生意外事故或险情时保护好这些货物。 

Kubernetes workload(Pod、Deployment、Job、Set 等)也是如此。在部署时,他们可能备受信任,可一旦它们暴露在互联网上,就存在被恶意利用的风险。以最低权限运行 workload 并加强其运行时配置,有助于降低此风险。 

方法 6:使用 Linux 安全功能和 podsecuritypolicy 

Linux 具有许多重叠的安全扩展功能(如 Capabilities 机制,SELinux,AppArmor,seccomp-bpf),都可以向应用程序提供最低权限的配置。 

像 bane (由 Docker 的核心维护者之一,Jessie Frazelle 创建以简化配置文件的编写难度的工具) 这样的工具可以帮助生成 AppArmor 配置文件,和 seccomp 配置文件的 docker-slim,但值得注意的是,在验证应用这些策略的副作用时,最好对在应用程序中运行所有代码路径进行综合测试。 

PodSecurityPolicies 可用于强制使用安全扩展和其他 Kubernetes 安全指令。PodSecurityPolicies 可以保证 Pod 在满足一定条件时,才能提交到 API server,包括安全配置文件,权限标记(Privileged flag)以及主机网络、进程或 IPC namespace 共享。这些指令可以有效防止容器化进程“逃离”其隔离边界,因此非常重要。 

方法 7:静态分析 YAML 文件 

当 PodSecurityPolicies 拒绝对 API server 进行访问的情况下,静态分析代码在开发流程中,也可以用来模拟一个组织的合规性要求或风险偏好。 

敏感信息不应存储在 Pod 类型的 YAML 资源(Deployment、Pods、Sets 等)中,敏感的 configmap 和 secret 应使用诸如 Vault(CoreOS 运营),git-crypt,sealed secret 或云提供商提供 KMS 服务等进行加密。 

YAML 配置的静态分析常用来为运行时安全建立基线。kubesec 可为资源生成风险评分: 

kubetest 是 Kubernetes 配置的一个单元测试框架: 

这些工具适用于“左移测试”(在开发周期的早期进行检查和验证)。开发阶段的安全测试为用户提供了关于代码和配置的快速反馈,虽然这些反馈可能会被以后的手动或自动检查拒绝,但是确实会减少引入更多安全操作时产生的摩擦。 

方法 8:使用 Non-Root  User 运行容器 

以 root 身份运行的容器,通常具有比其 workload 更大的权限,一旦受到损害,它就会帮助攻击者发起进一步的攻击。 

目前,容器仍然依赖于传统的 Unix 安全模型(称为自主访问控制或 DAC),以文件形式为主,权限授予 User 和组。 

User Namespace 在 Kubernetes 上不可用。 这意味着容器的 User ID 表会映射到主机 User 表上,并且容器内的 root user 在运行进程时也会在主机上以 root 身份运行。 虽然我们有多层安全机制来防止容器中断,但仍不推荐在容器内以 root 身份运行。 

许多容器镜像都使用 root user 运行 PID 1 ,如果该进程受到攻击,攻击者就会在容器中拥有 root 权限,此时任何错误配置都非常容易被利用。 

为了将容器镜像移动给 non-root user(OpenShift 上是默认设置的 ),BitNami 做了很多努力,这确实可以简化向 non-root 容器镜像迁移过程。 

以下 PodSecurityPolicy 可防止使用 root user 在容器内运行进程,并升级到 root: 

Non-root 容器是无法绑定到 1024 以下的特权端口的(这是由 CAP_NET_BIND_SERVICE 内核功能限制的),但 Services 可用来来掩盖这一事实。 在这个例子中,虚构的 MyApp 应用程序绑定到其容器中 8443 端口上,但是 Service 通过将请求代理到 targetPort,在 443 上进行暴露: 

如果必须使用 non-root user 运行 Workload, 那就直到用户 Namespace 可用也不改变、在容器运行时中运行没有 root 的容器也能保持持续工作。 

方法 9:使用网络策略(Policy) 

默认情况下,Kubernetes 网络允许所有 Pod 到 Pod 的流量,也可以使用网络策略进行限制。 


传统 Service 受防火墙限制,每个 Service 都必须使用静态 IP 和端口范围(Port ranges)。 正因为这些 IP 很少发生变化,所以它们长期被用作一种确认身份的形式。但是容器很少有静态 IP,它们迅速迭代,迅速重建,Service Discovery 也替代了静态 IP 地址。 这些特点都意味着防火墙的配置和审查变得更加困难。 

由于 Kubernetes 将其所有系统状态都存储在 etcd 中,如果 CNI 网络插件可行的话,它就可以配置动态防火墙。事实上 Calico,Cilium,kube-router,Romana 和 Weave Net 都支持网络策略。 

应该注意的是在这里标记的策略是失败关闭的,因为它缺少一个 podSelector  作为默认通配符: 

下面是一个  NetworkPolicy  示例,它拒绝除  UDP 53(DNS)之外的所有出口,同时阻止到应用程序入站连接。但  NetworkPolicies  是有状态的网络隔离,因此对出站请求的回复仍然会到达应用程序。 

Kubernetes 网络策略不能用于 DNS 域名。这是因为 DNS 可以解决许多 IP loop,或者基于调用 IP 动态地解决问题,所以网络策略只能应用于固定的 IP 或 podSelector (对于动态的 Kubernetes IP)。 

最佳做法是首先拒绝 Namespace 的所有流量,然后递增添加路由以允许应用程序通过验收测试。 这个过程会比较复杂,因为 Control Plane 会为了高度并行化的 nmap DevSecOps 工作流将 netassert-network 的安全测试一并攻击: 

云提供商 Metadata APIs 是不断升级的,为了防止意外错误配置产生, 确认 API 在容器网络上被阻止的特定测试是有必要的。 

Kubernetes 通过一系列的 Admission Controller 允许 Pod 进入集群,这些 Controller 应用于 Pod 和其他资源中,如 Deployment。 这些 Controller 可以验证每个 Pod 的入口或更改其内容,现在它们支持后端 Webhook。 


容器镜像扫描工具可以利用这些 Webhook,在镜像被部署到集群之前,对镜像进行验证。验证失败的镜像会被拒绝访问。 

根据已知漏洞,扫描容器镜像可以缩短攻击者攻击暴露 CVE 的时间。可以在部署 Pipeline 中使用 CoreOS 家的 Clair 和 Aqua 家的 Micro Scanner 等免费工具,以防止在部署时关键镜像有漏洞。

像 Grafeas 这样的工具可以存储镜像元数据,以便针对容器的唯一签名(内容可寻址 hash)进行持续合规性漏洞检查。这意味着使用该 hash 扫描容器镜像与扫描生产中部署的镜像相同,这个过程可以持续完成而无需访问生产环境。 

未知的 “Zero Day attack” 始终存在,因此应在 Kubernetes 中部署入侵检测工具,如 Twistlock,Aqua 和 Sysdig Secure。 IDS 可以检测容器中的异常行为并暂停或将其扼杀,另外 Sysdig 的 Falco (一个开源规则引擎)也可用。 

 未来发展  

Kubernetes 安全“云原生演化”的下一阶段看起来是 Service Mesh,尽管距离大规模采用还需要一段时间。采用的难点将从现在的应用程序转移到 Mesh 基础架构上,目前很多组织都热衷于了解最佳实践。 


Service Mesh 是一个加密的长链接(Persistent connections)网络,通常在 Envoy 和 Linkerd 等高性能 “sidecar” 代理服务器之间建立。它增加了流量管理、监控和策略,所有这些都没有微服务化。  

Linkerd 目前能够卸载微服务安全协议、共享网络代码,具有“久经沙场” 的库(Library )设置,而 Google,IBM 和 Lyft 共同开发的 Istio 为我们提供了另一个选择。 Istio 通过添加 SPIFEE 为每个 Pod 加密身份和其他冗余功能,简化下一代网络安全部署。

因为每次交互都发生在 mTLS(Mutual TLS)上,所以这不仅可以确保双方通信安全,而且知道彼此的身份,所以在这个“零信任”的网络中,也许不再需要传统的防火墙或 Kubernetes 网络策略。

这种从传统网络到云原生安全规则的转变,对我们这些具有传统安全思维方式的人来说并不简单,在此我为那些渴望触碰“美丽新世界”的人们强烈推荐,Evan Gilman 所著的 《Zero Trust Networking》 一书。 

目前,Istio 0.8 LTS 已经过时,该项目正在迅速接近 1.0 版本(2018 年 8 月 1 日 0:00 已发布)。 它的稳定版本与 Kubernetes 模型相同:具有一个稳定的核心,各个 API 在自己的 alpha / beta 阶段稳定的 Namespace 下标识自己。 预计未来几个月 Istio 的采用率将会上升。 

结语 

云原生应用程序拥有更精细的轻量级安全原语集,可锁定 Workload 和基础设施。 这些工具的强大功能和灵活性是一把双刃剑。由于自动化不足,暴露不安全的 Workload 将变得更容易。 

虽然,我们拥有比以往更多的防御工具,但仍要注意减少攻击面和潜在错误配置问题。一个安全性功能交付速度不高的企业,永远不会站在行业的第一梯队。 一个企业(组织)想要实现合规性、持续审计和在不影响生产前提下进行强制治理,就必须将持续交付原则应用于软件供应链上。

53 comCount 0