本文发表于一年多以前。较旧的文章可能包含过时的内容。请检查页面中的信息自发布以来是否已变得不正确。
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
作业控制器。
注意
matchConstraints
会将 API 对象转换为与您匹配的版本。例如,如果 API 请求是 apps/v1beta1
,并且您在 matchConstraints 中匹配 apps/v1
,则 API 请求将从 apps/v1beta1
转换为 apps/v1
,然后再进行验证。这具有有用的特性,可以使验证规则在引入新版本的 API 时保持安全,否则这将允许 API 请求通过使用新引入的版本绕过验证规则。validations
包括对象的 CEL 规则。有三个不同的表达式,考虑到 Pod spec
可能在对象的根目录(裸 Pod)、在 template
下(工作负载控制器或作业)或在 jobTemplate
下(CronJob)。
如果任何 spec
未将 readOnlyRootFilesystem
设置为 true,则该对象将不会被允许进入。
注意
在我们的初始版本中,我们将三个表达式分组到同一个策略对象中。这意味着它们可以原子地启用和禁用,因此用户不会意外地通过为某个 API 组启用策略而没有为其他 API 组启用策略而留下合规性漏洞。将它们分解为单独的策略将允许我们访问针对 1.27 版本改进的功能,包括类型检查。我们正在与 SIG API Machinery 讨论如何在 API 达到v1
之前最好地解决这个问题。在您的集群中使用 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,当然还有本博客,以了解最终的发布公告。