使用 Kyverno 在亚马逊 EKS 上管理 Pod 安全

作者:吉米·雷 |

这篇博文由Nirmata联合创始人兼首席执行官吉姆·布格瓦迪亚共同撰写。

这篇文章是我们之前的博客《 在亚马逊 EKS 中 实施 Pod 安全标准 》的后续 文章

简介

在 Kubernetes 中,Pod 是执行的基本单位。在这篇文章中,我们将通过新的 Kubernetes Pod 安全准入和 Pod 安全标准功能,探讨如何使用 Kyverno 来管理 亚马逊弹性 Kubernetes 服务 (亚马逊 EKS)的容器安全。

Pod 安全准入

Kubernetes Pod 安全准入 (PSA) 功能在 Kubernetes 1.23 中进入测试阶段,在 1.25 版本中处于稳定状态。它实现了 Pod 安全标准 (PSS) 中定义的一组安全 控制。PSS 为 Pod 配置定义了 17 个安全控件,分为三个级别: 特权 (不安全)、 基准 (安全)和 限制 (高度安全)。PSA 是 Kubernetes 的一项功能,它提供了 PSS 的实现。该实现由一个准入控制器组成,该准入控制器针对每个命名空间的三个安全级别之一验证 Pod 的准入,该安全级别通常基于静态配置文件和命名空间标签。PSA 使用三种操作模式:

  • 强制执行 :违反政策将导致 Pod 被拒绝。
  • 审计 :违反策略会触发向审计日志中记录的事件添加审计注释,但在其他方面是允许的。
  • 警告 :违反政策将触发面向用户的警告,但在其他方面是允许的。

Kubernetes API 服务器静态配置提供了定义其他 PSA/PSS 设置的功能,例如基于 用户名 、运行时类和命名空间的豁免。 自亚马逊 EKS 1.23 起可用(测试版),PSA/PSS 实现不包括自定义 PSA/PSS 静态配置的功能。这是一个有意识的决定,旨在降低 Kubernetes API 服务器的复杂性并保持默认设置。

注意: 为了确保操作稳定性并维护我们的 SLA,Amazon EKS 不允许对 API 服务器设置进行自定义配置。Amazon EKS 会根据具体情况评估自定义配置请求,如果有足够的客户需求,则可能允许配置设置。例如,亚马逊 EKS API 支持 OpenID Connect (OIDC) 用户身份验证,然后在集群启动时将其作为 API 服务器标志传递。客户可以使用 容器路线图 来打开和监控问题,并增加他们对现有问题的影响。

Amazon EKS 1.23 及更高版本使用的默认配置为集群中的所有 Pod 启用特权 PSS 配置文件,使用 最新 版本的 PSA 模式,无需配置豁免。

...
    defaults:
      enforce: "privileged"
      enforce-version: "latest"
      audit: "privileged"
      audit-version: "latest"
      warn: "privileged"
      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: []
...

使用这种模型,亚马逊 EKS 1.23 及更高版本中的 Kubernetes 命名空间可以使用 PSA/PSS 标签选择更严格的容器安全设置。

# The per-mode level label indicates which policy level to apply for the mode.
#
# MODE must be one of `enforce`, `audit`, or `warn`.
# LEVEL must be one of `privileged`, `baseline`, or `restricted`.
pod-security.kubernetes.io/<MODE>: <LEVEL>

# Optional: per-mode version label that can be used to pin the policy to the
# version that shipped with a given Kubernetes minor version (for example v1.24).
#
# MODE must be one of `enforce`, `audit`, or `warn`.
# VERSION must be a valid Kubernetes minor version, or `latest`.
pod-security.kubernetes.io/<MODE>-version: <VERSION>

虽然在 Amazon EKS 1.23 及更高版本中内置并默认启用 PSA,但它也被配置为默认使用 特权 PSS 级别。这意味着默认情况下不强制执行安全措施,除非使用命名空间标签来选择更安全的设置;默认情况下,可以使用 root 权限执行 pod。

PSA 的另一个常见挑战是,配置的安全级别适用于命名空间中的所有 Pod。这样做的理由是,命名空间中的所有 Pod 都可以访问该命名空间中的所有服务账号和其他敏感资源。但是,使用精细命名空间并不总是可行的,通常需要为命名空间中的单个 pod 或容器提供策略例外,同时限制同一命名空间中的其他 Pod 或容器的访问。使用 Kyverno,用户可以强制执行其他行为,以补充 PSA/PSS 设置,提高 pod 安全性,并为 Amazon EKS 提供更好的用户体验。

Kyverno

Kyverno 是 云原生计算基金会 (CNCF) 的 孵化项目,是一个策略即代码 (PaC) 解决方案,其中包括专为 Kubernetes 设计的策略引擎。 Kyverno 策略引擎安装在 Kubernetes 集群中,并作为动态准入控制器集成到 Kubernetes API 服务器中。 这允许在请求将更改保存到内部 Kubernetes etcd 数据存储库之前,使用 Kyverno 策略来变更和验证入站 Kubernetes API 服务器请求。

注意: Kubernetes 动态准入控制器使用 webhook 集成来调用验证和变更服务。这些呼叫具有超时设置(默认为 10 秒),用于设置呼叫在超时之前将等待多长时间。webhook 配置还包括 FailurePolic y 设置,用于配置当 Webhook 调用未在配置的超时时间内返回时 API 服务器应如何响应。webhook 要么失效打开(允许 API 服务器请求继续),要么失败关闭(API 服务器请求被阻止)。每种故障情景都需要权衡取舍。尽管失效开放场景可能被视为潜在的安全问题,但失效关闭场景可能会导致集群出现操作问题。有关这些场景以及如何在 Kyverno 中配置它们的更多信息,请参阅 Kyverno 安全性 与可操作性文档。

Kyverno 政策是声明性的 Kubernetes 资源,用 YAML 编写,没有新的政策语言可供学习。策略结果也可以作为 Kubernetes 资源和事件提供。Kyverno 策略可用于验证、变更和生成资源配置,以及验证图像签名和认证。

正在安装 Kyverno

要行使 Kyverno 提供的新 pod 安全功能,我们必须将 Kyverno 策略引擎和相关配置安装到现有的 Amazon EKS 集群中。你可以使用这个 Helm 命令安装最新版本的 Kyverno:

helm repo add kyverno https://kyverno.github.io/kyverno/
helm repo update
helm install kyverno --namespace kyverno kyverno/kyverno --create-namespace

由于 Kyverno 是为 Kubernetes 构建的,因此它可以用来补充和增强 Kubernetes PSA 功能。在本文的以下部分中,我们将讨论如何使用 Kyverno 将 PSS 设置应用到您的 Amazon EKS 集群。

强制执行 pod 安全标签

如前所述,使用亚马逊 EKS 中的默认 PSA/PSS 设置,命名空间必须选择使用带有 PSA/PSS 标签的更严格的 pod 安全。你可以使用 Kyverno 通过强制使用这些 pod 安全标签来帮助管理 pod 安全。以下 Kyverno 策略更改创建命名空间的入站 Kubernetes API 服务器请求,并添加 pod 安全强制模式标签(如果尚未定义)。

apiVersion: kyverno.io/v1
kind: ClusterPolicy
metadata:
  name: mutate-pss-labels    
spec:
  rules:
  - name: add-restricted
    match:
      resources:
        kinds:
        - Namespace
    mutate:
      patchStrategicMerge:
        metadata:
          labels:
            +(pod-security.kubernetes.io/enforce): restricted

这种突变的结果是命名空间被正确标记为使用具有 PSS 限制级别的 PS A 强制 模式。 在命名空间中运行的所有受此策略变更的 pod 都将具有 PSA/PSS 设置中最严格的容器安全性。要更新现有命名空间,您可以参考此示例突变策略向现有命名空间 添加特权标签。

变更后,验证入站 Kubernetes API 服务器请求、确保请求负载中存在所需设置并防止请求进行不必要的集群更改仍然是一种很好的零信任做法。 为此,以下 Kyverno 验证策略规则可以将 PSA 强制 模式的值限制在 PSS 基准 或限制级别。

apiVersion: kyverno.io/v1
kind: ClusterPolicy
metadata:
  name: validate-pss-labels
spec:
  validationFailureAction: enforce
  background: true
  rules:
  - name: check-restricted
    match:
      resources:
        kinds:
        - Namespace
    validate:
      message: "the privileged pod security level is not allowed"
      pattern:
        metadata:
          labels:
            pod-security.kubernetes.io/enforce: "baseline | restricted"

有了这些策略,将在所有新的命名空间上强制执行 PSS,无论是 基准 级别 还是 限制 级别,从而提供比默认 PSA 设置更好的安全态势。

管理 Pod 安全级别和异常

在 Kyverno 版本 1.8 中,引入了新的验证规则类型 validate .podSecurity。该声明直接使用树内 Kubernetes PSS 实现,同时提供了更大的灵活性。以下是一些主要的好处:

  • 集群范围的 Pod 安全默认值不需要更新静态配置文件
  • 命名空间级别 pod 安全应用程序不需要标签
  • Pod 安全检查会自动应用于 Pod 控制器(例如,部署)
  • 可以在容器映像级别配置粒度豁免
  • 集群内报告违规行为
  • 无需集群即可通过 Kyverno 命令行界面 (CLI) 执行静态验证和测试

以下示例集群策略将 受限 PSS 级别应用于除 kube-system 命名空间之外的所有命名空间。 在每个命名空间中,除 kube-system 外,所有 Pod 都具有相同的 pod 安全设置,该设置设置为 PSS 限制级别。 此验证策略用作深度防御 (DiD) 策略的一部分,该策略增强了先前的命名空间突变和验证策略。

apiVersion: kyverno.io/v1
kind: ClusterPolicy
metadata:
  name: psa
spec:
  background: true
  validationFailureAction: enforce
  rules:
  - name: restricted
    match:
      any:
      - resources:
          kinds:
          - Pod
    exclude:
      all:
      - resources:
          namespaces:
          - kube-system
    validate:
      podSecurity:
        level: restricted
        version: latest

现有的命名空间标签被忽略

关于新的 Kyverno validate.podSecur ity 规则,需要记住的重要一点是,它既不要求也不考虑现有的 PSA/PSS 命名空间标签。 例如,假定下面的命名空间配置已经包含 特权 PSS 级别的 PSA/PSS 标签,如果容器和容器级别的 S ecurit yContext 元素组合违反了受限 PSS 控制,则上述 Kyverno 策略会阻止创建容器。

apiVersion: v1
kind: Namespace
metadata:
  name: policy-test
  labels: 
    pod-security.kubernetes.io/enforce: privileged
    pod-security.kubernetes.io/audit: privileged
    pod-security.kubernetes.io/warn: privileged

在这种情况下,使用 v alidate.podSecur ity 规则的 Kyverno 策略会覆盖 PSA/PSS 命名空间标签。

额外的粒度,包含 pod 特定的豁免

如上文提到和演示,可以在命名空间级别指定 PSA/PSS Pod 安全的命名空间选择加入模型,其各自命名空间中的每个 Pod 都获得相同的应用容器安全性。但是,如果您需要在同一命名空间中的各个 pod 之间设置不同的 PSA/PSS,则可以使用 Kyverno 策略来提供这种粒度。

将 pod 特定的豁免应用于命名空间 PSA/PSS 设置可提供子命名空间粒度。 以下 Kyverno 策略应用 受限 PSS 级别,并在豁免命名空间中使用 nginx: 1.23.1-alpin e 镜像为容器配置豁免。 同一命名空间或任何其他命名空间中的所有其他 Pod 都受 限制 PSS 级别的约 束。

apiVersion: kyverno.io/v1
kind: ClusterPolicy
metadata:
  name: exempt-run-as-non-root
spec:
  validationFailureAction: enforce
  applyRules: One
  rules:
  - name: exempt-run-as-non-root
    match:
      all:
      - resources:
          kinds:
          - Pod
          namespaces:
          - exempt
    validate:
      podSecurity:
         level: restricted
         exclude:
          - controlName: "Running as Non-root"
            images:
            - nginx:1.23.1-alpine
  - name: restricted
    match:
      all:
      - resources:
          kinds:
          - Pod
    validate:
      podSecurity:
         level: restricted

规则处理-控制应用了多少规则

在上述政策中,有两条明确的规则: 豁免以非根身份运行和受 限。 ApplyRules 的使用:上述策略中的一条 指令指示 Kyverno 在应用第一条匹配规则后停止处理其他策略规则。否则,默认行为是处理策略中声明的所有规则。在此示例中,此指令用于创建适用于在 除命名空间中使用 nginx: 1.23.1-alpine 镜像的单个工作负载的异常,同时提供适用于所有其他 p od 的默认规则,无论 命名空间如何。

使用上面的 2 规则策略,实现了流程(如下所示)。

  • 向 Kubernetes API 服务器提交创建 Pod 的请求
    • 如果请求中的命名空间不是 豁免 命名空间,则将 强制执行 PS A 模式的 受限 PSS 安全配置文件应用于该
    • 容器
    • 如果请求中的命名空间是 豁免 命名空间,则检查 pod 中的容器镜像
      • 如果容器镜像是 nginx: 1.23.1-alpine,不要使用 PSA/PSS 组合

自动生成的策略

PSA 在 pod 级别上运行,但实际上 pod 通常由 Pod 控制器管理,例如 Deployments。在容器控制器级别上没有出现 Pod 安全错误的迹象会使问题变得很复杂。PSA 强制 模式是唯一阻止创建 Pod 的 PSA 模式;但是,PSA 强制 不作用于创建 Pod 的控制器资源。为了改善用户体验,我们建议将 PSA 警告 审核 模式与 强制 模式一起使用 ;PSA 警告 审核 模式至少会表明创建 Pod 的控制器资源正在尝试创建 Pod,否则这些容器将无法达到应用的 PSS 级别。这种用户体验可能会给 PSA/PSS 功能的采用者带来挑战。

在 Kubernetes 中使用 PaC 解决方案会带来另一个挑战:编写和维护涵盖集群中使用的所有不同 Kubernetes 资源的策略。使用 容器控制器的 Kyverno 自动生成规则 功能,上述容器策略会自动生成关联的 Pod 控制器(部署、DaemonSet 等)策略。这个 Kyverno 功能增强了策略的表达性,减少了维护相关资源策略的工作量。这些额外的自动生成的策略还改善了上述 PSA 用户体验,即不会阻止 Pod 创建资源的进展,而底层 Pod 也会被阻止。

如下所示,自动生成的控制器策略显示在原始 Pod 策略的状态字段中。

...
status:
  autogen:
    rules:
    - exclude:
        all:
        - resources:
            namespaces:
            - kube-system
        resources: {}
      generate:
        clone: {}
        cloneList: {}
      match:
        any:
        - resources:
            kinds:
            - DaemonSet
            - Deployment
            - Job
            - StatefulSet
        resources: {}
      mutate: {}
      name: autogen-restricted
      validate:
        podSecurity:
          level: restricted
          version: latest
    - exclude:
        all:
        - resources:
            namespaces:
            - kube-system
        resources: {}
      generate:
        clone: {}
        cloneList: {}
      match:
        any:
        - resources:
            kinds:
            - CronJob
        resources: {}
      mutate: {}
      name: autogen-cronjob-restricted
      validate:
        podSecurity:
          level: restricted
          version: latest
...

注意: Kyverno 项目提供了一个 托管在其 项目站点 上的大量 策略库 ,包括与 pod 安全相关的特定策略。

用户友好的报告

Kyverno 包括使用由 K ubernet es 策略工作组定义的开放格式的策略报告 。 当执行准入操作( 创建 更新 删除 )时,Kyverno 会发出这些策略报告。这些报告也是通过对现有资源应用策略的后台扫描生成的。可以使用以下 kubectl 命令找到报告:

kubectl -n kyverno get policyreports.wgpolicyk8s.io

NAME       PASS   FAIL   WARN   ERROR   SKIP   AGE
cpol-psa   2      0      0      0       0      4h19m

在上面的输出中,psa 群集策略表示两次通过。整个报告可以在下面看到。

kubectl -n kyverno get policyreports.wgpolicyk8s.io

NAME       PASS   FAIL   WARN   ERROR   SKIP   AGE
cpol-psa   2      0      0      0       0      4h19m
In the output above, the psa cluster policy indicates two passes. The entire report can be seen below.
kubectl -n kyverno get policyreports.wgpolicyk8s.io cpol-psa -o yaml

apiVersion: wgpolicyk8s.io/v1alpha2
kind: PolicyReport
metadata:
  creationTimestamp: "2022-11-01T13:03:23Z"
  generation: 1
  labels:
    app.kubernetes.io/managed-by: kyverno
  name: cpol-psa
  namespace: kyverno
  resourceVersion: "3787"
  uid: eec4d26f-c276-47dc-ae8f-033ba4dc1dcb
results:
- message: Validation rule 'autogen-restricted' passed.
  policy: psa
  resources:
  - apiVersion: apps/v1
    kind: Deployment
    name: kyverno
    namespace: kyverno
    uid: c6635d26-5abb-4e2c-8d2a-802c72eeb777
  result: pass
  rule: autogen-restricted
  scored: true
  source: kyverno
  timestamp:
    nanos: 0
    seconds: 1667307788
- message: Validation rule 'restricted' passed.
  policy: psa
  resources:
  - apiVersion: v1
    kind: Pod
    name: kyverno-6d488fd94b-2f42v
    namespace: kyverno
    uid: ac769e05-84ab-40ea-a939-c4802aa689bf
  result: pass
  rule: restricted
  scored: true
  source: kyverno
  timestamp:
    nanos: 0
    seconds: 1667307788
summary:
  error: 0
  fail: 0
  pass: 2
  skip: 0
  warn: 0

Kyverno CLI 将政策评估向左移动

在 Kubernetes 集群中测试策略评估并不总是最佳选择。在自动化 DevOps 管道中发现 Kubernetes 上游的潜在政策问题(违规、错误等)更便宜(时间和金钱)。为了将策略测试向左移动(以减少成本和开销),在接触集群之前,我们可以使用 Kyverno 命令行接口 (CLI) 将策略应用于 Kubernetes 资源 YAML 文件。

安装 Kyverno 命令行界面的方法有多种。 例如,可以使用 krew 将其作为 kubectl 插件安装:

kubectl krew install kyverno

安装 Kyverno CLI 后,可以使用以下命令将 Kyverno 策略应用于 Kubernetes 资源 YAML 文件(不需要 Kubernetes 集群):

kubectl kyverno apply policies/pod-restricted.yaml --resource=tests/2-dep-sec-cont.yaml

Applying 1 policy rule to 1 resource...

policy psa -> resource policy-test/Deployment/test failed:
1. autogen-restricted: Validation rule 'autogen-restricted' failed. It violates PodSecurity "restricted:latest": ({Allowed:false ForbiddenReason:allowPrivilegeEscalation != false ForbiddenDetail:container "test" must set securityContext.allowPrivilegeEscalation=false})
({Allowed:false ForbiddenReason:allowPrivilegeEscalation != false ForbiddenDetail:container "test" must set securityContext.allowPrivilegeEscalation=false})
({Allowed:false ForbiddenReason:unrestricted capabilities ForbiddenDetail:container "test" must set securityContext.capabilities.drop=["ALL"]})
({Allowed:false ForbiddenReason:unrestricted capabilities ForbiddenDetail:container "test" must set securityContext.capabilities.drop=["ALL"]})
({Allowed:false ForbiddenReason:runAsNonRoot != true ForbiddenDetail:pod or container "test" must set securityContext.runAsNonRoot=true})
({Allowed:false ForbiddenReason:seccompProfile ForbiddenDetail:pod or container "test" must set securityContext.seccompProfile.type to "RuntimeDefault" or "Localhost"})
({Allowed:false ForbiddenReason:seccompProfile ForbiddenDetail:pod or container "test" must set securityContext.seccompProfile.type to "RuntimeDefault" or "Localhost"})


pass: 0, fail: 1, warn: 0, error: 0, skip: 2

上面的命令根据本文前面提到的示例 pod 策略对 Kubernetes 部署资源 YAML 文件进行了评估。即使在 Kyverno CLI 中,自动生成功能也基于 pod 策略创建了部署策略,该策略与策略评估一致。

正在清理

要从集群中删除 Kyverno,你可以按照 卸载 说明进行操作。 helm 卸载命令如下所示:

helm uninstall kyverno kyverno/kyverno --namespace kyverno

正如 Kyverno 文档中提到的那样,Kyverno 将尝试删除其所有 webhook 配置。这可以手动完成,也可以使用以下 kubectl 命令作为最后一步完成:

kubectl delete mutatingwebhookconfigurations kyverno-policy-mutating-webhook-cfg kyverno-resource-mutating-webhook-cfg kyverno-verify-mutating-webhook-cfg
kubectl delete validatingwebhookconfigurations kyverno-policy-validating-webhook-cfg kyverno-resource-validating-webhook-cfg

结论

在这篇文章中,我们向你展示了如何使用 Kyverno 增强 Kubernetes PSA/PSS 配置。Pod 安全标准 (PSS) 和这些标准的 Kubernetes 树内实现,即 Pod 安全准入 (PSA),为管理 pod 安全性提供了良好的构建模块。大多数从 Kubernetes Pod 安全策略 (PSP) 切换的用户都应该成功使用 PSA/PSS 功能。

Kyverno 通过利用树内的 Kubernetes 容器安全实现,并提供几项有用的可操作性增强功能,增强了 PSA/PSS 创建的用户体验。你可以使用 Kyverno 来管理 pod 安全标签的正确使用。此外,你可以使用新的 Kyverno validate.podSec urity 规则来轻松管理 Pod 安全标准,从而提高灵活性并增强用户体验。而且,使用 Kyverno CLI,您可以在集群的上游自动进行策略评估。

要了解有关 Kyverno 的更多信息,请访问 https://kyverno.io。

Jimmy Ray

吉米·雷

吉米·雷是 亚马逊云科技 Kubernetes 团队的开发者倡导者。他专注于容器和软件供应链安全以及政策即代码。


*前述特定亚马逊云科技生成式人工智能相关的服务仅在亚马逊云科技海外区域可用,亚马逊云科技中国仅为帮助您发展海外业务和/或了解行业前沿技术选择推荐该服务。