本文属于机器翻译版本。若本译文内容与英语原文存在差异,则一律以英文原文为准。
Pod 安全
提示
通过 Amazon EKS 研讨会@@ 探索
Pod 规范包括各种不同的属性,这些属性可以增强或削弱您的整体安全状况。作为 Kubernetes 从业者,你最关心的问题应该是防止在容器中运行的进程逃离容器运行时的隔离边界并获得对底层主机的访问权限。
Linux 功能
默认情况下,在容器内运行的进程在 [Linux] root 用户的上下文中运行。尽管容器内的 root 操作受到容器运行时分配给容器的一组 Linux 功能的部分限制,但这些默认权限可能允许攻击者升级其权限and/or gain access to sensitive information bound to the host, including Secrets and ConfigMaps. Below is a list of the default capabilities assigned to containers. For additional information about each capability, see http://man7.org/linux/man-pages/man7/capabilities。7.html。
CAP_AUDIT_WRITE, CAP_CHOWN, CAP_DAC_OVERRIDE, CAP_FOWNER, CAP_FSETID, CAP_KILL, CAP_MKNOD, CAP_NET_BIND_SERVICE, CAP_NET_RAW, CAP_SETGID, CAP_SETUID, CAP_SETFCAP, CAP_SETPCAP, CAP_SYS_CHROOT
例
默认情况下,会为 EC2 和 Fargate 容器分配上述功能。此外,只能从 Fargate 吊舱中删除 Linux 功能。
以特权身份运行的 Pod 会继承主机上与 root 相关的所有 Linux 功能。如果可能,应避免这种情况。
节点授权
所有 Kubernetes 工作节点都使用一种名为 “节点授权” 的授权模式。
读取操作:
-
务
-
端点
-
节点
-
容器组(pod)
-
与绑定到 kubelet 节点的 pod 相关的机密、配置映射、永久卷声明和永久卷
写入操作:
-
节点和节点状态(启用
NodeRestriction准入插件以限制 kubelet 修改自己的节点) -
pod 和 pod 状态(启用
NodeRestriction准入插件以限制 kubelet 修改绑定到自身的 pod) -
events
与身份验证相关的操作:
-
对用于 TLS 引导的 CertificateSigningRequest (CSR) API 的读/写访问权限
-
能够创建 TokenReview 和 authentication/authorization 执行委托 SubjectAccessReview 支票
EKS 使用节点限制准入控制器,该控制器
Pod 安全解决方案
吊舱安全政策 (PSP)
过去,Pod 安全策略 (PSP)
重要
PSPs 在 Kubernetes 版本 1.21 中已被弃用
迁移到新的 pod 安全解决方案
由于从 Kubernetes v1.25 起 PSPs 已被移除,因此集群管理员和操作员必须更换这些安全控件。有两种解决方案可以满足这一需求:
-
Policy-as-code 来自 Kubernetes 生态系统的 (PAC) 解决方案
-
Kubernetes Pod 安全标准
(PSS)
PAC 和 PSS 解决方案都可以与 PSP 共存;它们可以在移除 PSP 之前在集群中使用。这样可以简化从 PSP 迁移时的采用。在考虑从 PSP 迁移到 PSS 时,请参阅此文档
Kyverno是下文概述的PAC解决方案之一,它在从其解决方案迁移 PSPs 到其解决方案时在博客文章
Policy-as-code (PAC)
Policy-as-code (PAC) 解决方案提供护栏,通过规定的自动控制来引导集群用户,防止不良行为。PAC 使用 Kubernetes 动态准入控制器
Kubernetes 有几种开源 PAC 解决方案可供选择。这些解决方案不是 Kubernetes 项目的一部分;它们来自 Kubernetes 生态系统。下面列出了一些 PAC 解决方案。
有关 PAC 解决方案以及如何帮助您选择适合您需求的解决方案的更多信息,请参阅以下链接。
吊舱安全标准 (PSS) 和吊舱安全准入 (PSA)
为了回应 PSP 的弃用以及控制容器安全的 out-of-the-box持续需求,Kubernetes Auth 特别兴趣小组
根据Kubernetes的文档,PSS “`定义了三种不同的策略来广泛涵盖安全领域。这些策略是累积性的,范围从高度允许到高度限制。 `”
这些策略定义为:
-
Privileged:不受限制(不安全)的策略,提供尽可能广泛的权限级别。此策略允许已知的权限升级。这是政策的缺失。这对于日志代理 CNIs、存储驱动程序等应用程序以及其他需要特权访问权限的系统范围的应用程序非常有用。
-
基准:限制性最低的策略,可防止已知的权限升级。允许默认(最低限度指定)Pod 配置。基准政策禁止使用 HostNetwork、HostPid、HostPid、HostPort、HostPort、无法添加 Linux 功能以及其他一些限制。
-
限制:严格限制政策,遵循当前 Pod 强化最佳实践。此策略继承了基准,并增加了更多限制,例如无法以 root 用户或根组的身份运行。受限的策略可能会影响应用程序的运行能力。它们主要针对运行安全关键型应用程序。
这些策略定义了 Pod 执行的配置文件
为了实现PSS定义的控制措施,PSA在三种模式下运行:
-
强制执行:违反策略将导致 pod 被拒绝。
-
审计:违反策略将触发在审计日志中记录的事件中添加审计注释,但除此之外是允许的。
-
警告:违反策略将触发面向用户的警告,但除此之外是允许的。
这些模式和配置文件(限制)级别是在 Kubernetes 命名空间级别使用标签配置的,如下例所示。
apiVersion: v1 kind: Namespace metadata: name: policy-test labels: pod-security.kubernetes.io/enforce: restricted
单独使用时,这些操作模式会有不同的响应,从而产生不同的用户体验。如果相应的 PodSpecs 违反了配置的限制级别,则强制模式将阻止创建 Pod。但是,在这种模式下,即使其中的 PodSpec 违反了所应用的 PSS,也不会阻止创建容器的非 Pod Kubernetes 对象(例如 Deploymentes)应用于集群。在这种情况下,将应用部署,而将阻止应用 pod。
这是一种困难的用户体验,因为没有立即迹象表明成功应用的 Deployment 对象掩盖了 pod 创建失败。违规的 PodSpecs 不会创建 pod。使用检查部署资源kubectl get deploy <DEPLOYMENT_NAME> -oyaml将显示来自失败的 pod .status.conditions 元素的消息,如下所示。
... status: conditions: - lastTransitionTime: "2022-01-20T01:02:08Z" lastUpdateTime: "2022-01-20T01:02:08Z" message: 'pods "test-688f68dc87-tw587" is forbidden: violates PodSecurity "restricted:latest": allowPrivilegeEscalation != false (container "test" must set securityContext.allowPrivilegeEscalation=false), unrestricted capabilities (container "test" must set securityContext.capabilities.drop=["ALL"]), runAsNonRoot != true (pod or container "test" must set securityContext.runAsNonRoot=true), seccompProfile (pod or container "test" must set securityContext.seccompProfile.type to "RuntimeDefault" or "Localhost")' reason: FailedCreate status: "True" type: ReplicaFailure ...
在审计和警告模式下,Pod 限制并不能阻止创建和启动违规的 Pod。但是,在这些模式下,当 Pod 以及创建 Pod 的对象包含违规的 PodSp ecs 时,会分别触发 API 服务器审核日志事件的审计注释和向 API 服务器客户端(例如 kubectl)发出的警告。kubectl警告消息如下所示。
Warning: would violate PodSecurity "restricted:latest": allowPrivilegeEscalation != false (container "test" must set securityContext.allowPrivilegeEscalation=false), unrestricted capabilities (container "test" must set securityContext.capabilities.drop=["ALL"]), runAsNonRoot != true (pod or container "test" must set securityContext.runAsNonRoot=true), seccompProfile (pod or container "test" must set securityContext.seccompProfile.type to "RuntimeDefault" or "Localhost") deployment.apps/test created
PSA 审计和警告模式在引入 PSS 时非常有用,不会对群集操作产生负面影响。
PSA 的操作模式并不相互排斥,可以累积使用。如下所示,可以在单个命名空间中配置多种模式。
apiVersion: v1 kind: Namespace metadata: name: policy-test labels: pod-security.kubernetes.io/audit: restricted pod-security.kubernetes.io/enforce: restricted pod-security.kubernetes.io/warn: restricted
在上面的示例中,在应用 Deployments 时提供了用户友好的警告和审计注释,同时还在 pod 级别提供了违规的强制执行。实际上,多个 PSA 标签可以使用不同的配置文件级别,如下所示。
apiVersion: v1 kind: Namespace metadata: name: policy-test labels: pod-security.kubernetes.io/enforce: baseline pod-security.kubernetes.io/warn: restricted
在上面的示例中,PSA 配置为允许创建满足基准配置文件级别的所有容器,然后对违反受限配置文件级别的 pod(以及创建 Pod 的对象)发出警告。这是一种有用的方法,可以确定从基线更改为受限配置文件时可能产生的影响。
现有 Pod
如果将包含现有 pod 的命名空间修改为使用限制性更强的 PSS 配置文件,则审计和警告模式将生成相应的消息;但是,强制模式不会删除 pod。警告消息如下所示。
Warning: existing pods in namespace "policy-test" violate the new PodSecurity enforce level "restricted:latest" Warning: test-688f68dc87-htm8x: allowPrivilegeEscalation != false, unrestricted capabilities, runAsNonRoot != true, seccompProfile namespace/policy-test configured
豁免
PSA 使用豁免来排除对原本适用的 pod 的违规行为的执行。这些豁免如下所列。
-
用户名:将忽略使用免除身份验证(或模仿)用户名的用户发出的请求。
-
RuntimeClassNames: 指定豁免运行时类名称的 pod 和工作负载资源将被忽略。
-
命名空间:豁免命名空间中的 Pod 和工作负载资源将被忽略。
作为 API 服务器配置的一部分,这些豁免在 PSA 准入控制器配置
在验证 Webhook 实现中,可以在作为卷挂载到容器的 Kubernetes ConfigMap
apiVersion: v1 kind: ConfigMap metadata: name: pod-security-webhook namespace: pod-security-webhook data: podsecurityconfiguration.yaml: | apiVersion: pod-security.admission.config.k8s.io/v1 kind: PodSecurityConfiguration defaults: enforce: "restricted" enforce-version: "latest" audit: "restricted" audit-version: "latest" warn: "restricted" warn-version: "latest" exemptions: # Array of authenticated usernames to exempt. usernames: [] # Array of runtime class names to exempt. runtimeClasses: [] # Array of namespaces to exempt. namespaces: ["kube-system","policy-test1"]
如上面的 ConfigMap YAML 所示,集群范围的默认 PSS 级别已设置为限制所有 PSA 模式,包括审计、强制和警告。这会影响所有命名空间,但豁免的命名空间除外:. namespaces: ["kube-system","policy-test1"] 此外,在ValidatingWebhookConfiguration资源中(如下所示),pod-security-webhook命名空间也被排除在已配置的 PSS 之外。
... webhooks: # Audit annotations will be prefixed with this name - name: "pod-security-webhook.kubernetes.io" # Fail-closed admission webhooks can present operational challenges. # You may want to consider using a failure policy of Ignore, but should # consider the security tradeoffs. failurePolicy: Fail namespaceSelector: # Exempt the webhook itself to avoid a circular dependency. matchExpressions: - key: kubernetes.io/metadata.name operator: NotIn values: ["pod-security-webhook"] ...
重要
在 Kubernetes v1.25 中,Pod Security 招生已升级到稳定版。如果您想在默认启用 Pod 安全准入功能之前使用该功能,则需要安装动态准入控制器(改变 webhook)。可以在此处
在 policy-as-code和 Pod 安全标准之间进行选择
Pod 安全标准 (PSS) 的开发是为了取代 Pod 安全政策 (PSP),它提供了一种内置于 Kubernetes 的解决方案,不需要来自 Kubernetes 生态系统的解决方案。话虽如此, policy-as-code(PAC)解决方案要灵活得多。
以下优点和缺点列表旨在帮助您对 pod 安全解决方案做出更明智的决定。
Policy-as-code (与 Pod 安全标准相比)
优点:
-
更灵活、更精细(如有必要,可细化到资源属性)
-
不只是专注于 pod,还可用于不同的资源和操作
-
不只是应用于命名空间级别
-
比 Pod 安全标准更成熟
-
决策可以基于 API 服务器请求负载中的任何内容,以及现有的集群资源和外部数据(取决于解决方案)
-
支持在验证之前更改 API 服务器请求(取决于解决方案)
-
可以生成补充策略和 Kubernetes 资源(取决于解决方案——从 pod 策略中,Kyverno 可以为更高级别的控制器(例如部署)自动生成
策略。 Kyverno 还可以使用生成规则生成额外的 Kubernetes 资源 “当创建新资源或更新源代码时”。) -
可用于在调用 Kubernetes API 服务器之前向左移动,进入 CICD 管道(取决于解决方案)
-
可用于实现不一定与安全相关的行为,例如最佳实践、组织标准等。
-
可以在非 Kubernetes 用例中使用(取决于解决方案)
-
由于灵活性,用户体验可以根据用户的需求进行调整
缺点:
-
未内置于 Kubernetes 中
-
学习、配置和支持更复杂
-
政策制定可能需要新的内容 skills/languages/capabilities
Pod 安全准入(与之相比 policy-as-code)
优点:
-
内置于 Kubernetes 中
-
配置更简单
-
没有新的语言可供使用,也没有政策可供创作
-
如果集群的默认准入级别配置为特权,则可以使用命名空间标签将命名空间选择到容器安全配置文件中。
缺点:
-
不如灵活或精细 policy-as-code
-
只有 3 个级别的限制
-
主要集中在吊舱上
Summary
如果你目前除了 PSP 之外还没有 pod 安全解决方案,并且你所需的吊舱安全态势符合 Pod 安全标准 (PSS) 中定义的模型,那么更简单的方法可能是采用 PSS 来代替解决方案。 policy-as-code但是,如果您的 pod 安全态势不符合 PSS 模型,或者您设想在 PSS 定义的控件之外添加其他控件,那么 policy-as-code解决方案似乎更合适。
建议
使用多个 Pod 安全准入 (PSA) 模式以获得更好的用户体验
如前所述,PSA 强制模式可防止应用具有 PSS 违规的 pod,但不会阻止更高级别的控制器,例如部署。实际上,部署将在没有任何迹象表明无法应用 pod 的情况下成功应用。虽然你可以使用 kubectl 来检查 Deployment 对象,并从 PSA 中发现失败的 pod 消息,但用户体验可能会更好。为了改善用户体验,应使用多种PSA模式(审计、强制执行、警告)。
apiVersion: v1 kind: Namespace metadata: name: policy-test labels: pod-security.kubernetes.io/audit: restricted pod-security.kubernetes.io/enforce: restricted pod-security.kubernetes.io/warn: restricted
在上面的示例中,在定义了强制模式的情况下,当尝试将相应 PodSpec 中存在违规的 PSS 的部署清单应用于 Kubernetes API 服务器时,部署将成功应用,但是 pod 不会成功应用。而且,由于还启用了审核和警告模式,API 服务器客户端将收到一条警告消息,API 服务器审核日志事件也将添加一条消息注释。
限制可以以特权身份运行的容器
如前所述,以特权身份运行的容器会继承主机上分配给 root 的所有 Linux 功能。容器很少需要这些类型的权限才能正常运行。有多种方法可用于限制容器的权限和功能。
重要
Fargate 是一种启动类型,可让您运行 “无服务器” 容器,其中 Pod 的容器在 AWS 管理的基础设施上运行。使用 Fargate,你无法运行特权容器,也无法将你的容器配置为使用 HostNetwork 或 HostPort。
不要以 root 用户身份在容器中运行进程
默认情况下,所有容器都以 root 身份运行。如果攻击者能够利用应用程序中的漏洞并获得 shell 访问正在运行的容器的权限,则可能会出现问题。您可以通过多种方式降低这种风险。首先,从容器镜像中移除 shell。其次,将 USER 指令添加到你的 Dockerfile 中,或者以非 root 用户身份运行容器中的容器。Kubernetes PodSpec 在下面包含一组字段spec.securityContext,允许您指定运行应用程序的用户 and/or 组。这些字段runAsGroup分别是runAsUser和。
为了强制使用及其相关元素spec.securityContext,可以将 Kubernetes PodSpec policy-as-code 或 Pod 安全标准添加到集群中。这些解决方案允许您编写和/或使用可以验证入站 Kubernetes API 服务器请求有效负载的策略或配置文件,然后再将其保存到 etcd 中。此外, policy-as-code解决方案可以改变入站请求,在某些情况下还会生成新的请求。
切勿在 Docker 中运行 Docker 或将套接字安装到容器中
虽然这可以方便地在 Docker 容器中查看 build/run 镜像,但你基本上是将对节点的完全控制权交给容器中运行的进程。如果你需要在 Kubernetes 上构建容器镜像,可以改用 Kaniko
注意
用于 CICD 处理(例如构建容器镜像)的 Kubernetes 集群应与运行更广泛的工作负载的集群隔离开来。
限制 HostPath 的使用,或者如果需要 HostPath,则限制可以使用哪些前缀并将该卷配置为只读
hostPath是一个将目录从主机直接挂载到容器的卷。Pod 很少需要这种访问权限,但如果需要,则需要注意风险。默认情况下,以 root 身份运行的 pod 将拥有对 HostPath 公开的文件系统的写入权限。这可能允许攻击者修改 kubelet 设置、创建指向 HostPath 未直接暴露的目录或文件(例如 /etc/shadow)的符号链接、安装 ssh 密钥、读取挂载到主机的机密以及其他恶意内容。要降低来自 HostPath 的风险,请将配置spec.containers.volumeMounts为readOnly,例如:
volumeMounts: - name: hostPath-volume readOnly: true mountPath: /host-path
您还应该使用 policy-as-code解决方案来限制hostPath卷可以使用的目录,或者完全禁止hostPath使用。您可以使用 Pod 安全标准基准或受限策略来防止使用hostPath。
有关特权升级危险的更多信息,请阅读塞思·阿特的博客 Ba d Pods:Kubernetes Pod
为每个容器设置请求和限制,以避免资源争用和 DoS 攻击
从理论上讲,没有请求或限制的 Pod 会消耗主机上的所有可用资源。当其他 Pod 被调度到一个节点上时,该节点可能会遇到 CPU 或内存压力,这可能导致 Kubelet 终止或将 Pod 从该节点中驱逐出去。虽然您无法阻止这种情况同时发生,但设置请求和限制将有助于最大限度地减少资源争用,并降低因应用程序编写不当而消耗过多资源所带来的风险。
podSpec允许您指定 CPU 和内存的请求和限制。CPU 被视为可压缩资源,因为它可能被超额订阅。内存是不可压缩的,也就是说,它不能在多个容器之间共享。
当你指定 CPU 或内存请求时,你实际上是在指定容器保证获得的内存量。Kubernetes 会汇总一个 Pod 中所有容器的请求,以确定将 Pod 调度到哪个节点上。如果容器超过请求的内存量,则如果节点上存在内存压力,则该容器可能会被终止。
限制是容器允许消耗的最大 CPU 和内存资源量,直接对应于为容器创建的 cgroup 的memory.limit_in_bytes值。超过内存限制的容器将被OOM杀死。如果容器超出其 CPU 限制,它将受到限制。
注意
使用容器时resources.limits,强烈建议容器资源使用量(又名资源足迹)以数据为导向,并根据负载测试进行准确。如果没有准确且值得信赖的资源占用空间,则resources.limits可以填充容器。例如,resources.limits.memory可以比可观察的最大值高 20-30%,以考虑潜在的内存资源限制不准确性。
Kubernetes 使用三个服务质量 (QoS) 类别来确定节点上运行的工作负载的优先级。这些方法包括:
-
保证
-
可爆发
-
尽力而为
如果未设置限制和请求,则将 Pod 配置为尽力而为(最低优先级)。当内存不足时,尽力而为的 pod 是第一个被杀死的。如果对 Pod 中的所有容器设置了限制,或者将请求和限制设置为相同的值而不等于 0,则该 Pod 将被配置为保证(最高优先级)。除非超过其配置的内存限制,否则保证的 pod 不会被杀死。如果限制和请求配置为不同的值且不等于 0,或者容器中的一个容器设置了限制,而其他容器没有或对不同的资源设置了限制,则这些 Pod 将被配置为可突发性(中等优先级)。这些 pod 有一些资源保证,但是一旦它们超过了请求的内存,它们就会被杀死。
重要
请求不会影响容器的 cgroup 的memory_limit_in_bytes值;cgroup 限制设置为主机上的可用内存量。尽管如此,如果节点承受内存压力,将请求值设置得太低可能会导致 kubelet 将 pod 作为终止的目标。
| 类 | 优先级 | 条件 | 击杀条件 |
|---|---|---|---|
|
能保证 |
最高 |
限制 = 请求! = 0 |
仅超过内存限制 |
|
可突增 |
medium |
极限! = 请求! = 0 |
如果超出请求内存,则可能被杀死 |
|
尽力而为 |
最低 |
限制和请求未设置 |
第一个在内存不足时被杀死 |
有关资源 QoS 的更多信息,请参阅 Kub
您可以通过在命名空间上设置资源配额
Policy-as-code 解决方案可以用来强制执行请求和限制。甚至可以在创建命名空间时创建资源配额和限制范围。
不允许权限升级
特权升级允许进程更改其运行所处的安全环境。Sudo 就是一个很好的例子,带有 SUID 或 SGID 位的二进制文件也是如此。权限升级基本上是用户以其他用户或组的权限执行文件的一种方式。您可以通过实施设置为false或在中设置securityContext.allowPrivilegeEscalation的 policy-as-code变更策略来防止容器使用特权升级。allowPrivilegeEscalation podSpec Policy-as-code 如果检测到设置不正确,也可以使用策略来防止 API 服务器请求成功。Pod 安全标准还可用于防止 Pod 使用权限升级。
禁用 ServiceAccount 令牌挂载
对于不需要访问 Kubernetes API 的 Pod,您可以禁用在容器规范上自动挂载 ServiceAccount 令牌,也可以禁用所有使用特定容器规范的容器自动挂载令牌。 ServiceAccount
例
apiVersion: v1 kind: Pod metadata: name: pod-no-automount spec: automountServiceAccountToken: false
apiVersion: v1 kind: ServiceAccount metadata: name: sa-no-automount automountServiceAccountToken: false
禁用服务发现
对于不需要查找或调用集群内服务的 Pod,您可以减少提供给 Pod 的信息量。你可以将 Pod 的 DNS 策略设置为不使用 CoreDNS,也不要将 Pod 命名空间中的服务作为环境变量公开。有关服务链接的更多信息,请参阅有关环境变量的 Kubernetes 文档
例
apiVersion: v1 kind: Pod metadata: name: pod-no-service-info spec: dnsPolicy: Default # "Default" is not the true default value enableServiceLinks: false
使用只读的根文件系统配置您的图像
使用只读根文件系统配置图像可防止攻击者覆盖应用程序使用的文件系统上的二进制文件。如果您的应用程序必须写入文件系统,请考虑写入临时目录或连接并装入一个卷。你可以通过按 SecurityContext 如下方式设置 pod 来强制执行此操作:
... securityContext: readOnlyRootFilesystem: true ...
Policy-as-code 并且 Pod 安全标准可用于强制执行此行为。
例
根据 Windows规定,true对于在Windows上运行的容器,KubernetessecurityContext.readOnlyRootFilesystem不能设置为,因为注册表和系统进程需要写入权限才能在容器内运行。
工具和资源
-
open-policy-agent/gatekeeper-library:OPA Gatekeeper 策略
库是一个 OPA/Gatekeeper 策略库,你可以用它来代替。 PSPs -
EKS 的常用 OPA 和 Kyverno 政策
的集合。 -
Pod Security Policy Migrator 是一种转换为 PSPs OPA/Gatekeeper 或 Kyverno 策略
的工具 KubeWarden -
NeuVector 由 SUSE
开源提供的零信任容器安全平台提供进程和文件系统策略以及准入控制规则。