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

Kubernetes 验证准入策略:一个实践示例

准入控制是 Kubernetes 控制平面的重要组成部分,其中几个内部功能取决于在 API 对象提交到服务器时批准或更改它的能力。管理员也可以定义关于哪些对象可以被允许进入集群的业务逻辑或策略。为了更好地支持该用例,Kubernetes 在 v1.7 中引入了外部准入控制

除了无数自定义的内部实现之外,许多开源项目和商业解决方案都使用用户指定的策略来实现准入控制器,包括 Kyverno 和 Open Policy Agent 的 Gatekeeper

虽然用于策略的准入控制器已被采用,但其广泛使用存在障碍。 Webhook 基础设施必须作为生产服务来维护,这需要付出所有努力。准入控制 webhook 的失败情况必须关闭,从而降低集群的可用性;或者打开,否定该功能用于策略执行。网络跳转和评估时间使得准入控制成为处理延迟的重要组成部分,例如在“无服务器”环境中启动 Pod 以响应网络请求时。

验证准入策略和通用表达式语言

Kubernetes 1.26 版本引入了一种折衷的解决方案,该方案处于 alpha 阶段。验证准入策略 是准入 webhook 的声明式进程内替代方案。它们使用 通用表达式语言 (CEL) 来声明验证规则。

CEL 由 Google 为安全和策略用例而开发,基于从 Firebase 实时数据库中获得的经验。它的设计使其可以安全地嵌入到应用程序中并在微秒内执行,计算和内存影响有限。CRD 的验证规则在 v1.23 中将 CEL 引入了 Kubernetes 生态系统,当时有人指出该语言将适用于通过准入控制进行更通用的验证实现。

使用 CEL - 一个实际示例

Kubescape 是一个 CNCF 项目,它已成为用户提高 Kubernetes 集群安全态势和验证其合规性的最流行方式之一。它的 控制(针对 API 对象的一组测试)是用 Open Policy Agent 的策略语言 Rego 构建的。

Rego 因其复杂性而闻名,这主要基于它是声明式查询语言(如 SQL)这一事实。 它被考虑用于 Kubernetes,但它不提供与 CEL 相同的沙箱约束。

该项目的一个常见功能请求是能够根据 Kubescape 的发现和输出实现策略。例如,在扫描 Pod 中是否存在到云凭证文件的已知路径后,用户希望能够强制执行策略,即这些 Pod 根本不应被允许进入。Kubescape 团队认为这将是尝试将我们现有的控件移植到 CEL 并将其作为准入策略应用的最佳机会。

给我看策略

我们没有花很长时间就转换了我们的许多控制,并构建了一个验证准入策略库。让我们看一个例子。

Kubescape 的 控制 C-0017 涵盖了容器必须具有不可变(只读)根文件系统的要求。根据 NSA Kubernetes 加固指南,这是一个最佳实践,但目前不作为任何Pod 安全标准的一部分。

这是我们在 CEL 中的实现方式

apiVersion: admissionregistration.k8s.io/v1alpha1
kind: ValidatingAdmissionPolicy
metadata:
  name: "kubescape-c-0017-deny-resources-with-mutable-container-filesystem"
spec:
  failurePolicy: Fail
  matchConstraints:
    resourceRules:
    - apiGroups:   [""]
      apiVersions: ["v1"]
      operations:  ["CREATE", "UPDATE"]
      resources:   ["pods"]
    - apiGroups:   ["apps"]
      apiVersions: ["v1"]
      operations:  ["CREATE", "UPDATE"]
      resources:   ["deployments","replicasets","daemonsets","statefulsets"]
    - apiGroups:   ["batch"]
      apiVersions: ["v1"]
      operations:  ["CREATE", "UPDATE"]
      resources:   ["jobs","cronjobs"]
  validations:
    - expression: "object.kind != 'Pod' || object.spec.containers.all(container, has(container.securityContext) && has(container.securityContext.readOnlyRootFilesystem) &&  container.securityContext.readOnlyRootFilesystem == true)"
      message: "Pods having containers with mutable filesystem not allowed! (see more at https://hub.armosec.io/docs/c-0017)"
    - expression: "['Deployment','ReplicaSet','DaemonSet','StatefulSet','Job'].all(kind, object.kind != kind) || object.spec.template.spec.containers.all(container, has(container.securityContext) && has(container.securityContext.readOnlyRootFilesystem) &&  container.securityContext.readOnlyRootFilesystem == true)"
      message: "Workloads having containers with mutable filesystem not allowed! (see more at https://hub.armosec.io/docs/c-0017)"
    - expression: "object.kind != 'CronJob' || object.spec.jobTemplate.spec.template.spec.containers.all(container, has(container.securityContext) && has(container.securityContext.readOnlyRootFilesystem) &&  container.securityContext.readOnlyRootFilesystem == true)"
      message: "CronJob having containers with mutable filesystem not allowed! (see more at https://hub.armosec.io/docs/c-0017)"

为三个可能的 API 组提供了匹配约束:Pod 的 core/v1 组、apps/v1 工作负载控制器和 batch/v1 作业控制器。

validations 包括对象的 CEL 规则。有三个不同的表达式,用于处理以下事实:Pod spec 可以位于对象的根目录(一个裸 Pod),位于 template 下(工作负载控制器或作业),或位于 jobTemplate 下(CronJob)。

如果任何 spec 没有将 readOnlyRootFilesystem 设置为 true,则该对象将不会被允许进入。

在您的集群中使用 CEL 库

策略以 Kubernetes 对象的形式提供,然后通过选择器绑定到某些资源。

Minikube 是一种快速简便的安装和配置 Kubernetes 集群以进行测试的方法。要安装启用了 ValidatingAdmissionPolicy 功能门控的 Kubernetes v1.26

minikube start --kubernetes-version=1.26.1 --extra-config=apiserver.runtime-config=admissionregistration.k8s.io/v1alpha1  --feature-gates='ValidatingAdmissionPolicy=true'

要在您的集群中安装策略

# Install configuration CRD
kubectl apply -f https://github.com/kubescape/cel-admission-library/releases/latest/download/policy-configuration-definition.yaml
# Install basic configuration
kubectl apply -f https://github.com/kubescape/cel-admission-library/releases/latest/download/basic-control-configuration.yaml
# Install policies
kubectl apply -f https://github.com/kubescape/cel-admission-library/releases/latest/download/kubescape-validating-admission-policies.yaml

要将策略应用于对象,请创建一个 ValidatingAdmissionPolicyBinding 资源。让我们将上述 Kubescape C-0017 控制应用于任何带有标签 policy=enforced 的命名空间

# Create a binding
kubectl apply -f - <<EOT
apiVersion: admissionregistration.k8s.io/v1alpha1
kind: ValidatingAdmissionPolicyBinding
metadata:
  name: c0017-binding
spec:
  policyName: kubescape-c-0017-deny-mutable-container-filesystem
  matchResources:
    namespaceSelector:
      matchLabels:
        policy: enforced
EOT

# Create a namespace for running the example
kubectl create namespace policy-example
kubectl label namespace policy-example 'policy=enforced'

现在,如果您尝试创建一个不指定 readOnlyRootFilesystem 的对象,则不会创建该对象。

# The next line should fail
kubectl -n policy-example run nginx --image=nginx --restart=Never

输出显示了我们的错误

The pods "nginx" is invalid: : ValidatingAdmissionPolicy 'kubescape-c-0017-deny-mutable-container-filesystem' with binding 'c0017-binding' denied request: Pods having containers with mutable filesystem not allowed! (see more at https://hub.armosec.io/docs/c-0017)

配置

策略对象可以包含配置,该配置在不同的对象中提供。许多 Kubescape 控制都需要配置:要要求的标签、允许或拒绝的功能、允许部署容器的注册表等。这些控制的默认值在ControlConfiguration 对象中定义。

要使用此配置对象,或使用相同格式的您自己的对象,请向您的绑定对象添加 paramRef.name

apiVersion: admissionregistration.k8s.io/v1alpha1
kind: ValidatingAdmissionPolicyBinding
metadata:
  name: c0001-binding
spec:
  policyName: kubescape-c-0001-deny-forbidden-container-registries
  paramRef:
    name: basic-control-configuration
  matchResources:
    namespaceSelector:
      matchLabels:
        policy: enforced

总结

在大多数情况下,将我们的控制转换为 CEL 很简单。我们无法移植整个 Kubescape 库,因为某些控件会检查 Kubernetes 集群之外的事物,而某些控件需要准入请求对象中不可用的数据。总的来说,我们很高兴能将这个库贡献给 Kubernetes 社区,并将继续为 Kubescape 和 Kubernetes 用户开发它。我们希望它能够有用,无论是您自己使用它,还是作为您编写自己的策略的示例。

至于验证准入策略功能本身,我们很高兴看到 Kubernetes 引入了此原生功能。我们期待着它转移到 Beta 版本,然后希望在今年年底达到 GA 版本。需要注意的是,此功能目前处于 Alpha 阶段,这意味着这是在 Minikube 等环境中进行测试并进行试驾的绝佳机会。但是,它尚未被认为是生产就绪且稳定的,并且不会在大多数托管 Kubernetes 环境中启用。在底层功能变得稳定之前,我们不会建议 Kubescape 用户在生产中使用这些策略。请密切关注KEP,当然还有本博客,以获取最终版本公告。