本文超过一年。较旧的文章可能包含过时的内容。请检查页面中的信息自发布以来是否已变得不正确。

Kubernetes 部署的安全最佳实践

注意:本文中的一些建议已不再适用。当前的集群强化选项在本文档中进行了描述。

编者按:今天的文章由 Aqua Security 的 Amir Jerbi 和 Michael Cherny 撰写,描述了 Kubernetes 部署的安全最佳实践,基于他们从本地和云部署中看到的各种用例收集的数据。

Kubernetes 提供了许多可以极大地提高应用程序安全性的控件。配置它们需要深入了解 Kubernetes 和部署的安全要求。我们在此重点介绍的最佳实践与容器生命周期(构建、交付和运行)相一致,并且专门针对 Kubernetes 部署进行了定制。我们在我们自己的 SaaS 部署中采用了这些最佳实践,该部署在 Google Cloud Platform 上运行 Kubernetes。

以下是我们关于部署安全的 Kubernetes 应用程序的建议

**确保镜像没有漏洞**
运行具有漏洞的容器会使您的环境面临容易受到攻击的风险。许多攻击都可以通过确保没有已知漏洞的软件组件来mitigated 。

  • **实施持续安全漏洞扫描**——容器可能包含具有已知漏洞 (CVE) 的过时软件包。这不可能是“一次性”的过程,因为每天都会发布新的漏洞。持续评估镜像的持续过程对于确保所需的安全状态至关重要。

  • **定期将安全更新应用到您的环境**——一旦在运行的容器中发现漏洞,您应该始终更新源镜像并重新部署容器。尽量避免直接更新(例如“apt-update”)正在运行的容器,因为这可能会破坏镜像与容器的关系。使用 Kubernetes 滚动更新功能可以非常轻松地升级容器 - 这允许通过将其镜像升级到最新版本来逐步更新正在运行的应用程序。

确保您的环境中仅使用授权镜像
如果没有一个流程来确保只允许符合组织策略的镜像运行,那么组织就面临运行易受攻击甚至恶意容器的风险。从未知来源下载和运行镜像非常危险。这相当于在生产服务器上运行来自未知供应商的软件。不要那样做。

使用私有注册表来存储您批准的镜像 - 确保您只将批准的镜像推送到这些注册表。仅此一项就已经缩小了范围,将进入您管道的潜在镜像数量减少到公开可用的数十万个镜像的一小部分。构建一个集成安全评估(如漏洞扫描)的 CI 管道,使其成为构建过程的一部分。

CI 管道应确保仅使用经过审查的代码(批准用于生产)来构建镜像。构建镜像后,应扫描其是否存在安全漏洞,并且只有在未发现问题时,才能将镜像推送到私有注册表,然后从中进行生产部署。安全评估失败应导致管道失败,从而防止将安全质量差的镜像推送到镜像注册表。

Kubernetes 中正在进行图像授权插件的工作(预计在 Kubernetes 1.4 中),这将允许阻止未经授权的图像的交付。有关更多信息,请参阅此拉取请求

限制对 Kubernetes 节点的直接访问
您应该限制对 Kubernetes 节点的 SSH 访问,降低未经授权访问主机资源的风险。相反,您应该要求用户使用“kubectl exec”,这将提供对容器环境的直接访问,而无需访问主机。

您可以使用 Kubernetes 授权插件来进一步控制用户对资源的访问。这允许为特定命名空间、容器和操作定义细粒度访问控制规则。

在资源之间创建管理边界
限制用户权限的范围可以减少错误或恶意活动的影响。Kubernetes 命名空间允许您将创建的资源划分为逻辑命名的组。在一个命名空间中创建的资源可以对其他命名空间隐藏。默认情况下,用户在 Kubernetes 集群中创建的每个资源都在一个名为 default 的默认命名空间中运行。您可以创建其他命名空间并将资源和用户附加到它们。您可以使用 Kubernetes 授权插件来创建策略,以隔离不同用户之间对命名空间资源的访问。

例如:以下策略将允许“alice”从命名空间“fronto”读取 pod。

{

  "apiVersion": "abac.authorization.kubernetes.io/v1beta1",

  "kind": "Policy",

  "spec": {

    "user": "alice",

    "namespace": "fronto",

    "resource": "pods",

    "readonly": true

  }

}

定义资源配额
运行资源不受限的容器的选项会使您的系统面临 DoS 或“嘈杂邻居”场景的风险。为了防止和最大程度地降低这些风险,您应该定义资源配额。默认情况下,Kubernetes 集群中的所有资源都是使用无限制的 CPU 和内存请求/限制创建的。您可以创建附加到 Kubernetes 命名空间的资源配额策略,以限制 pod 允许消耗的 CPU 和内存。

以下是一个命名空间资源配额定义示例,它将命名空间中的 pod 数量限制为 4 个,将其 CPU 请求限制在 1 到 2 之间,内存请求限制在 1GB 到 2GB 之间。

compute-resources.yaml

apiVersion: v1  
kind: ResourceQuota  
metadata:  
  name: compute-resources  
spec:  
  hard:  
    pods: "4"  
    requests.cpu: "1"  
    requests.memory: 1Gi  
    limits.cpu: "2"  
    limits.memory: 2Gi

将资源配额分配给命名空间

kubectl create -f ./compute-resources.yaml --namespace=myspace

实施网络分段

在同一个 Kubernetes 集群上运行不同的应用程序会造成一个受感染的应用程序攻击相邻应用程序的风险。网络分段对于确保容器只能与其应该通信的容器进行通信非常重要。

Kubernetes 部署中的挑战之一是在 pod、服务和容器之间创建网络分段。由于容器网络身份(IP)的“动态”性质,以及容器可以在同一节点内或节点之间进行通信这一事实,这是一个挑战。

Google Cloud Platform 用户可以受益于自动防火墙规则,防止跨集群通信。可以使用网络防火墙或 SDN 解决方案在本地部署类似的实现。Kubernetes 网络 SIG正在这方面开展工作,这将极大地改进 pod 到 pod 的通信策略。新的网络策略 API 应该解决围绕 pod 创建防火墙规则的需求,限制容器化可以具有的网络访问。

以下是一个网络策略示例,该策略控制“后端”pod 的网络,仅允许来自“前端”pod 的入站网络访问

POST /apis/net.alpha.kubernetes.io/v1alpha1/namespaces/tenant-a/networkpolicys  
{  
  "kind": "NetworkPolicy",

  "metadata": {

    "name": "pol1"

  },

  "spec": {

    "allowIncoming": {

      "from": [{

        "pods": { "segment": "frontend" }

      }],

      "toPorts": [{

        "port": 80,

        "protocol": "TCP"

      }]

    },

    "podSelector": {

      "segment": "backend"

    }

  }

}

在此处阅读有关网络策略的更多信息此处

将安全上下文应用于您的 Pod 和容器

在设计容器和 pod 时,请确保为 pod、容器和卷配置安全上下文。安全上下文是在部署 yaml 中定义的属性。它控制将分配给 pod/容器/卷的安全参数。一些重要的参数是

安全上下文设置描述
SecurityContext->runAsNonRoot指示容器应以非 root 用户身份运行
SecurityContext->Capabilities控制分配给容器的 Linux 功能。
SecurityContext->readOnlyRootFilesystem控制容器是否能够写入根文件系统。
PodSecurityContext->runAsNonRoot防止以“root”用户身份运行容器作为 pod 的一部分

以下是具有安全上下文参数的 pod 定义示例

apiVersion: v1  
kind: Pod  
metadata:  
  name: hello-world  
spec:  
  containers:  
  # specification of the pod’s containers  
  # ...  
  securityContext:  
    readOnlyRootFilesystem: true  
    runAsNonRoot: true

参考此处

如果您正在运行具有提升权限的容器(--privileged),您应该考虑使用“DenyEscalatingExec”准入控制。此控件拒绝对以允许主机访问的提升权限运行的 pod 执行 exec 和 attach 命令。这包括以特权方式运行的 pod、可以访问主机 IPC 命名空间的 pod 以及可以访问主机 PID 命名空间的 pod。有关准入控制的更多详细信息,请参阅 Kubernetes 文档

记录一切

Kubernetes 提供基于集群的日志记录,允许将容器活动记录到中央日志中心。创建集群后,可以使用在每个节点上运行的 Fluentd 代理将每个容器的标准输出和标准错误输出提取到 Google Stackdriver Logging 或 Elasticsearch 中,并使用 Kibana 查看。

摘要

Kubernetes 提供了许多创建安全部署的选项。没有一种通用的解决方案可以适用于所有情况,因此需要对这些选项有一定程度的了解,并理解它们如何增强应用程序的安全性。

我们建议实施本博客中重点介绍的最佳实践,并利用 Kubernetes 灵活的配置功能将安全流程融入持续集成流水线,自动化整个流程,将安全性无缝地“融入”其中。