成为Kubernetes黑客的11种方法(不是)

注意事项 佩雷夫 :本文的原文发布在Kubernetes官方博客上,由年轻的英国公司Control Plane的创始人之一安德鲁·马丁(Andrew Martin)撰写,专门研究在K8上运行的云本机应用程序的安全性。



自项目到达以来,Kubernetes的安全性已经走了很长一段路,但仍然存在陷阱。 我们提供了一系列有关如何保护集群并在黑客入侵时提高其稳定性的有用建议:我们将从控制平面开始,继续进行工作负载和网络安全,最后评估未来的安全性。

第1部分:控制平面


控制平面是Kubernetes的大脑。 他对集群中运行的每个容器和Pod有一个大致的了解,可以计划新的Pod(其中可以包含对父节点具有根访问权限的容器),并且可以读取存储在集群中的所有机密信息。 这是一个非常重要的组件,需要不断提供保护,以防止意外的数据泄漏和恶意行为:无论何时访问数据,什么都没有发生以及何时通过网络传输数据。

1.无处不在的TLS


对于每个支持TLS的组件,必须将其启用-以防止流量监听,服务器身份验证和(对于相互TLS)客户端身份验证。

“请注意,某些组件和安装方法可能会激活HTTP的本地端口,因此管理员需要熟悉每个组件的设置,以识别不安全流量的可能路径。”

从Kubernetes文档

下面来自LucasKäldström的网络图显示了理想情况下需要TLS的位置:向导中每个组件之间,以及Kubelet与API服务器之间。 经典的Kelsey Hightower Kubernetes The Hard Wayetcd上安全文档提供了实现这些目标的详细说明。



从历史上看,Kubernetes节点的自动缩放并不容易,因为每个节点都需要一个TLS密钥才能连接到主节点,而在基本映像中保守秘密是不明智的做法。 Kubelet TLS引导允许新的Kubelet创建证书签名请求,以便在引导时生成证书:



2. RBAC中的最低特权,禁用ABAC,日志监视


基于角色的访问控制(RBAC)提供了细粒度的策略管理,用户可以通过该策略访问资源(例如名称空间)。



自K8s 1.6起,Kubernetes中的基于属性的访问控制(ABAC)已由RBAC取代,并且不应在API的服务器端启用。 请改用RBAC: --no-enable-legacy-authorization --authorization-mode=RBAC (或GKE的此标志:-- --no-enable-legacy-authorization )。

对于群集中的各种服务,有很多很好的 RBAC策略 示例 ,以及文档 。 但不要到此为止:可以使用audit2rbacaudit日志中获取RBAC策略的有效设置。

如果炉膛受到损害,不正确或过于宽松的RBAC策略会带来安全风险。 维护具有最小特权的RBAC规则,对其进行不断审核并对其进行改进,应该成为团队在开发生命周期中应用的“债务的技术卫生”的一部分。

审核日志记录 (Kubernetes 1.10中的beta)提供了用于工作负载(例如请求和响应)以及元数据级别的自定义日志记录API。 可以根据组织的安全策略配置日志记录级别-GKE将合理的默认值应用于刚开始使用它的人员。

对于诸如getlistwatch的读取请求,只有请求的对象存储在审核日志中,而没有响应对象。 对于涉及诸如SecretConfigMap之类的敏感数据的查询,仅导出元数据。 对于所有其他请求,两个对象都记录在审核日志中:请求和响应。

别忘了:将这些日志存储在群集中会带来安全隐患。 与其他任何对安全敏感的日志一样,这些日志应放置在群集外部,以避免在出现漏洞时产生负面影响。

3.对API服务器使用第三方身份验证


整个组织(即单点登录)的身份验证和授权的集中化有助于接受和离开新员工的过程,从而确保一致的访问权限。

Kubernetes与第三方身份验证提供程序(例如Google或GitHub)的集成提供了来自远程平台的身份保证(具有两因素身份验证之类的保护),并且无需管理员在Kubernetes中重新配置API服务器来添加/删除用户。

Dex是带有插件的OpenID Connect身份(OIDC)和OAuth 2.0提供程序。 Pusher通过提供可自定义的工具而进一步发展,此外,还有一些 其他帮助者专注于其他应用程序。

4.分离群集etcd并将其放置在防火墙后面


etcd存储有关Kubernetes状态和秘密的信息,是K8的关键组成部分-必须与集群的其余部分分开保护。

在API服务器上对etcd的写访问权限等同于向整个集群颁发根权限,甚至可以通过读访问权限轻松地提升特权。

etcd中的Kubernetes调度程序搜索没有节点的pod定义。 然后,他将找到的所有吊舱发送到可用的Kubelet进行规划。 这些pod的验证工作是由API服务器完成的,然后再将它们写入etcd,因此,直接写入etcd的攻击者可以绕过许多安全机制,例如PodSecurityPolicies

应该使用TLS证书客户端对等方 )配置etcd并将其部署到专用节点。 为了降低从工作节点盗窃和使用私钥的风险,还可以限制API Server群集的防火墙。

5.加密密钥的轮换


安全密钥和证书的定期轮换是最佳的安全实践,允许您在密钥被泄露时限制“销毁半径”。

在当前证书过期后,Kubernetes将通过创建新的CSR来自动轮换某些证书(特别是Kubelet客户端和服务器证书)。

但是,API服务器用来加密etcd值的对称密钥不会自动旋转-必须手动完成 。 此操作需要主访问权限,因此托管服务(如GKE和AKS)对用户隐藏了问题。

第2部分:工作负载


在控制平面级别使用最小的安全性,集群就可以安全地运行。 但是,与带有潜在危险货物的船舶一样,这种容器必须在意外事故或泄漏的情况下保护货物。 Kubernetes工作负载(容器, 部署作业集合等)也是如此-在部署时可以信任它们,但是如果可以从外部访问它们,则始终存在被攻击者利用的风险。 通过以最小权限及其安全配置运行工作负载可以减轻这种风险。

6.使用Linux安全功能和PodSecurityPolicies


Linux内核具有许多部分重叠的安全扩展(功能,SELinux,AppArmor,seccomp-bpf),可以将其配置为为应用程序提供最小的特权。

诸如bane之类的实用工具将帮助您生成AppArmor的配置文件,而docker -slim则将帮助您生成seccomp配置文件,但要小心:要确定应用这些策略的所有副作用,您需要一个全面的测试套件来检查整个应用程序代码。

PodSecurityPolicies控制这些安全扩展以及其他Kubernetes安全指令的使用。 他们负责达到API服务器所必须满足的最低要求,包括安全配置文件,特权标志,共享的主机网络,IPC的进程或名称空间。

这些指令非常重要,因为它们有助于防止容器化进程逃离其隔离的边界。 蒂姆·阿克莱尔(Tim Allclair)的PodSecurityPolicy示例非常多才多艺-您可以将其作为基础并针对您的情况进行自定义。

7.对YAML进行静态分析


如果PodSecurityPolicies限制对API服务器的访问,则在开发过程中也可以使用静态分析来对组织的监管要求和风险承受能力进行建模。

敏感信息不应存储在诸如炉床( PodsDeploymentsSet等)的YAML资源中,敏感的ConfigMapSecrets必须使用Vault (由CoreOS的操作员使用), git-crypt密封的 SecretsKMS云之类的实用程序加密提供者

YAML配置的静态分析可以用作启动期间安全性的基础。 kubesec为资源生成风险评估:

 { "score": -30, "scoring": { "critical": [{ "selector": "containers[] .securityContext .privileged == true", "reason": "Privileged containers can allow almost completely unrestricted host access" }], "advise": [{ "selector": "containers[] .securityContext .runAsNonRoot == true", "reason": "Force the running image to run as a non-root user to ensure least privilege" }, { "selector": "containers[] .securityContext .capabilities .drop", "reason": "Reducing kernel capabilities available to a container limits its attack surface", "href": "https://kubernetes.io/docs/tasks/configure-pod-container/security-context/" }] } } 

kubetest是用于单元测试Kubernetes配置的框架:

 #// vim: set ft=python: def test_for_team_label(): if spec["kind"] == "Deployment": labels = spec["spec"]["template"]["metadata"]["labels"] assert_contains(labels, "team", "should indicate which team owns the deployment") test_for_team_label() 

这些实用程序实施左移方法(即,将验证和验证移至开发周期的早期阶段)。 在开发阶段的安全测试为用户提供了有关代码和配置的快速反馈,这些反馈随后可以被手动或自动验证拒绝,并且还可以促进引入其他安全实践。

8.运行容器而不是root


以root用户身份运行的容器通常具有比其工作负载所需的权限更多的权限,如果这些容器受到威胁,它们可以帮助攻击者获得强大的功能。

容器仍然依赖于传统的UNIX安全模型(称为DAC, 自由访问控制 )-一切都是文件,并且权限被授予用户和组。

用户名称空间在Kubernetes中不起作用。 这意味着容器中的用户ID表已映射到主机用户表,并且以容器内的root特权启动进程会导致其以root特权在主机上运行。 尽管所有机制都添加了防止退出容器的机制,但不建议在容器内部以root用户身份运行。

许多容器映像使用root用户来运行PID 1:如果此进程被破坏,则攻击者会在容器中获得root权限,并且由于任何配置错误,问题的操作变得更加容易。

Bitnami 将其容器映像转换为普通(非root)用户 (这也是默认的OpenShift要求)方面做得很好,这也可以简化向非root映像的迁移。

此PodSecurityPolicy片段可防止根进程在容器中运行并升级为根:

 # Required to prevent escalations to root. allowPrivilegeEscalation: false runAsUser: # Require the container to run without root privileges. rule: 'MustRunAsNonRoot' 

不使用root的容器不能占用特权端口,即 最多1024个(Linux内核中的相应功能CAP_NET_BIND_SERVICE对此负责),但是,使用服务有助于避免此限制。 这是MyApp应用程序的示例,该应用程序在容器中占用端口8443,但是Service使其在端口443上可用,从而代理对targetPort请求:

 kind: Service apiVersion: v1 metadata: name: my-service spec: selector: app: MyApp ports: - protocol: TCP port: 443 targetPort: 8443 

在不使用root用户的情况下运行工作负载的需求将一直保持到容器运行时中包含用于启动不具有root用户的容器的用户名称空间或操作时间

9.使用网络策略


默认情况下,Kubernetes网络允许Pod之间的所有流量。 可以通过网络策略NetworkPolicy限制此设置。



传统服务仅限于使用静态IP地址和每种服务的端口范围的防火墙。 由于这些IP地址的更改非常少,因此历史上一直将它们用作身份验证的一种形式。 容器很少具有静态IP-容器的性质暗示了快速丢弃和重新创建的可能性,因为容器使用服务发现而不是静态IP地址。 这些功能使防火墙的配置和验证大大复杂化。

由于Kubernetes在etcd中存储了有关系统状态的所有数据,因此可以配置动态防火墙-如果CNI网络插件中有必要的支持,则可以配置。 Calico,Cilium,kube-router,Romana和Weave Net-所有这些插件都支持网络策略。

重要的是要注意,策略按照失效关闭原则工作,也就是说,默认情况下此处没有podSelector等于所有可能的值(通配符):

 apiVersion: networking.k8s.io/v1 kind: NetworkPolicy metadata: name: default-deny spec: podSelector: 

以下是NetworkPolicy的示例,该示例禁止UDP 53(DNS)之外的所有内容外发,UDP 53(DNS)也阻止与应用程序的传入连接。 NetworkPolicies 是有状态的策略,因此应用程序仍将接收对传出连接的响应。

 apiVersion: networking.k8s.io/v1 kind: NetworkPolicy metadata: name: myapp-deny-external-egress spec: podSelector: matchLabels: app: myapp policyTypes: - Egress egress: - ports: - port: 53 protocol: UDP - to: - namespaceSelector: {} 

Kubernetes网络策略无法应用于DNS名称。 原因是DNS支持循环访问多个IP地址以及取决于访问IP的动态响应,因此网络策略仅适用于固定IP地址或podSelector (对于Kubernetes动态IP地址)。

最佳实践是从禁止命名空间的所有流量开始,然后逐步添加应用程序通过验收测试所需的路由。 该过程可能很困难,因此ControlPlane开发了netassert ,该实用程序用于在具有高度并行nmap的DevSecOps脚本中测试网络安全性:

 k8s: # used for Kubernetes pods deployment: # only deployments currently supported test-frontend: # pod name, defaults to `default` namespace test-microservice: 80 # `test-microservice` is the DNS name of the target service test-database: -80 # `test-frontend` should not be able to access test-database's port 80 169.254.169.254: -80, -443 # AWS metadata API metadata.google.internal: -80, -443 # GCP metadata API new-namespace:test-microservice: # `new-namespace` is the namespace name test-database.new-namespace: 80 # longer DNS names can be used for other namespaces test-frontend.default: 80 169.254.169.254: -80, -443 # AWS metadata API metadata.google.internal: -80, -443 # GCP metadata API 

来自云提供商的带有元数据的API一直是潜在升级的源泉( 由Shopify的最新漏洞赏金证明),因此特殊测试确认该API在容器网络上被阻止将有助于防止配置错误。

10.扫描图像并运行IDS


Web服务器是攻击它们所连接的网络的跳板。 扫描安装在映像中的文件,可以验证攻击者没有可用来获取对容器的远程访问的已知漏洞。 入侵检测系统(IDS)会记录这些事件(如果发生)。

Kubernetes允许通过一组控制检查(在准入控制器中 )向集群提交内容,这些控制检查不仅适用于Pod,而且适用于其他资源(如Deployments) 。 在它们中,除了现在还支持后端侧的网络钩子之外,可以验证每个子项的准入或更改其内容。



容器映像扫描工具可以使用这些webhooks来验证映像,然后再将它们部署到群集中。 验证失败的图像将不会获得控制器批准。

扫描容器映像中的已知漏洞有助于减少攻击者利用开放CVE的时间。 为了防止在部署管道中推出具有严重漏洞的映像,您可以使用免费的实用程序,例如CoreOS的Clair和Aqua的Micro Scanner

借助Grafeas等工具,您可以使用唯一的容器签名(或特殊的内容寻址哈希)存储图像元数据,以进行持续的合规性和漏洞检查。 使用此哈希值扫描容器映像无异于扫描生产中部署的映像,并且可以连续执行而无需访问生产环境。

未知的0day漏洞将始终存在,因此Kubernetes应该部署诸如TwistlockAquaSysdig Secure的入侵检测系统。 IDS检测到容器中的异常行为,然后停止或终止它。 Sysdig的Falco是一个开源规则引擎,也是该生态系统的起点。

第三部分:未来


尽管无法立即采用,但“云原生”演变中的下一阶段安全性似乎是服务网格:这种迁移需要将应用程序的复杂性转移到网格基础架构,而组织必须实现这一最佳实践。



11.启动服务网格


服务网格是在“侧面连接” (类似于“ sidecar”) ,高性能代理(如Envoy和Linkerd 之间建立的持久加密连接网络。 它带来了流量管理,监视和策略-所有这些都无需更改微服务。

Linkerd已经可以将安全性和与网络相关的代码从微服务转移到经过测试的共享库集,而Google,IBM和Lyft的Istio为该领域带来了替代方案。 通过添加用于每个Pod的加密身份的SPIFFE和许多其他功能,Istio可以简化下一代网络安全性的部署。

在“零信任”网络中,可能不需要传统的防火墙或Kubernetes网络策略,因为每次交互都使用mTLS(相互TLS)进行,这不仅保证了交互的安全性,还确认了这两种服务的身份。

从传统的网络方法到Cloud Native的世界安全原则的转变对于那些具有传统安全思想的人来说并不容易。 作为对这个新世界的介绍,我们强烈推荐SPIFFE的Evan Gilman撰写的《零信任网络》一书

Istio 0.8 LTS当前可用,该项目正在快速接近其1.0版本。 就稳定性而言,该项目的版本控制与Kubernetes模型类似地进行:具有单独API的稳定内核,使用名称空间指示其alpha或beta状态。 期望在未来几个月内看到Istio扩展。

结论


Cloud Native应用程序具有一组更详细的轻量级安全性原语,可帮助保护工作负载和基础架构。 这样的工具的强大功能和灵活性既是福也是祸:如果没有足够的自动化(供其使用),将不安全的应用程序暴露于容器之外或使其隔离模型变得更加容易。

用于保护的实用程序比以往任何时候都更易于访问,但是,为了减少攻击的可能性和配置错误的可能性,您必须谨慎使用它们。

如果安全性降低了组织交付变更的速度,那么它将永远不会成为优先事项。 使用与软件供应链相关的持续交付原则,可使组织实现法规遵从性,持续审核和增强的管理,而不会影响业务绩效。

使用全面的测试套件,最快速的增量安全性改进是最简单的方法。 Continuous Security — pipeline', , , .

译者的PS


另请参阅我们的博客:

Source: https://habr.com/ru/post/zh-CN417905/


All Articles