验证准入策略

特性状态: Kubernetes v1.30 [稳定]

此页面提供验证准入策略的概述。

什么是验证准入策略?

验证准入策略提供了一种声明式、过程中的验证准入 Webhook 的替代方案。

验证准入策略使用通用表达式语言 (CEL) 来声明策略的验证规则。验证准入策略具有高度可配置性,使策略作者能够定义可以参数化并根据集群管理员的需求作用于资源的策略。

策略由哪些资源构成

通常,策略由三个资源构成

  • ValidatingAdmissionPolicy 描述了策略的抽象逻辑(例如:“此策略确保设置了特定标签为特定值”)。

  • 参数资源为 ValidatingAdmissionPolicy 提供信息,使其成为一个具体的语句(例如:“owner 标签必须设置为以 .company.com 结尾的内容”)。原生类型,例如 ConfigMap 或 CRD,定义了参数资源的模式。ValidatingAdmissionPolicy 对象指定了它期望其参数资源的 Kind。

  • ValidatingAdmissionPolicyBinding 将上述资源链接在一起并提供作用域。如果您只想要求为 Pods 设置 owner 标签,则绑定是指定此限制的位置。

为了使策略生效,必须定义至少一个 ValidatingAdmissionPolicy 和相应的 ValidatingAdmissionPolicyBinding

如果 ValidatingAdmissionPolicy 不需要通过参数进行配置,则只需将 spec.paramKindValidatingAdmissionPolicy 中留空。

开始使用验证准入策略

验证准入策略是集群控制平面的组成部分。您应该谨慎编写和部署它们。以下介绍了如何快速试验验证准入策略。

创建 ValidatingAdmissionPolicy

以下是一个 ValidatingAdmissionPolicy 的示例。

apiVersion: admissionregistration.k8s.io/v1
kind: ValidatingAdmissionPolicy
metadata:
  name: "demo-policy.example.com"
spec:
  failurePolicy: Fail
  matchConstraints:
    resourceRules:
    - apiGroups:   ["apps"]
      apiVersions: ["v1"]
      operations:  ["CREATE", "UPDATE"]
      resources:   ["deployments"]
  validations:
    - expression: "object.spec.replicas <= 5"

spec.validations 包含使用 通用表达式语言 (CEL) 来验证请求的 CEL 表达式。如果表达式求值为 false,则根据 spec.failurePolicy 字段强制执行验证检查。

要配置集群中使用的验证准入策略,需要一个绑定。以下是 ValidatingAdmissionPolicyBinding 的示例。

apiVersion: admissionregistration.k8s.io/v1
kind: ValidatingAdmissionPolicyBinding
metadata:
  name: "demo-binding-test.example.com"
spec:
  policyName: "demo-policy.example.com"
  validationActions: [Deny]
  matchResources:
    namespaceSelector:
      matchLabels:
        environment: test

当尝试创建一个副本数不满足验证表达式的 Deployment 时,将返回包含消息的错误

ValidatingAdmissionPolicy 'demo-policy.example.com' with binding 'demo-binding-test.example.com' denied request: failed expression: object.spec.replicas <= 5

以上提供了一个使用不配置参数的验证准入策略的简单示例。

验证操作

每个 ValidatingAdmissionPolicyBinding 必须指定一个或多个 validationActions,以声明策略的 validations 的强制执行方式。

支持的 validationActions

  • Deny:验证失败会导致请求被拒绝。
  • Warn:验证失败会向请求客户端报告为 警告
  • Audit:验证失败将包含在 API 请求的审计事件中。

例如,要同时警告客户端有关验证失败并审计验证失败,请使用

validationActions: [Warn, Audit]

DenyWarn 不能一起使用,因为这种组合会不必要地将验证失败复制到 API 响应正文中和 HTTP 警告标头中。

如果 failurePolicy 设置为 Fail(或未指定),则根据这些操作强制执行评估为 false 的 validation。否则,将忽略失败。

有关更多详细信息,请参阅 审计注释:验证失败

参数资源

参数资源允许将策略配置与定义分离。策略可以定义 paramKind,概述参数资源的 GVK,然后策略绑定通过 paramRef 将策略按名称绑定到特定的参数资源。

如果需要参数配置,以下是带有参数配置的 ValidatingAdmissionPolicy 的示例。

apiVersion: admissionregistration.k8s.io/v1
kind: ValidatingAdmissionPolicy
metadata:
  name: "replicalimit-policy.example.com"
spec:
  failurePolicy: Fail
  paramKind:
    apiVersion: rules.example.com/v1
    kind: ReplicaLimit
  matchConstraints:
    resourceRules:
    - apiGroups:   ["apps"]
      apiVersions: ["v1"]
      operations:  ["CREATE", "UPDATE"]
      resources:   ["deployments"]
  validations:
    - expression: "object.spec.replicas <= params.maxReplicas"
      reason: Invalid

ValidatingAdmissionPolicy 的 spec.paramKind 字段指定用于参数化此策略的资源的类型。对于此示例,它由 ReplicaLimit 自定义资源配置。请注意,在此示例中,CEL 表达式如何通过 CEL params 变量引用参数,例如 params.maxReplicasspec.matchConstraints 指定此策略旨在验证哪些资源。请注意,原生类型,例如 ConfigMap 也可以用作参数引用。

spec.validations 字段包含 CEL 表达式。如果表达式求值为 false,则根据 spec.failurePolicy 字段强制执行验证检查。

验证准入策略作者负责提供 ReplicaLimit 参数 CRD。

要配置集群中使用的验证准入策略,需要创建一个绑定和参数资源。以下是使用 全集群 参数的 ValidatingAdmissionPolicyBinding 的示例 - 相同的参数将用于验证与绑定匹配的每个资源请求

apiVersion: admissionregistration.k8s.io/v1
kind: ValidatingAdmissionPolicyBinding
metadata:
  name: "replicalimit-binding-test.example.com"
spec:
  policyName: "replicalimit-policy.example.com"
  validationActions: [Deny]
  paramRef:
    name: "replica-limit-test.example.com"
    namespace: "default"
    parameterNotFoundAction: Deny
  matchResources:
    namespaceSelector:
      matchLabels:
        environment: test

请注意,此绑定将参数应用于 test 环境中的所有资源。

参数资源可以是如下所示

apiVersion: rules.example.com/v1
kind: ReplicaLimit
metadata:
  name: "replica-limit-test.example.com"
  namespace: "default"
maxReplicas: 3

此策略参数资源将 Deployment 限制为最多 3 个副本。

准入策略可以有多个绑定。要将所有其他环境绑定到具有 100 个 maxReplicas 限制,请创建另一个 ValidatingAdmissionPolicyBinding

apiVersion: admissionregistration.k8s.io/v1
kind: ValidatingAdmissionPolicyBinding
metadata:
  name: "replicalimit-binding-nontest"
spec:
  policyName: "replicalimit-policy.example.com"
  validationActions: [Deny]
  paramRef:
    name: "replica-limit-prod.example.com"
    namespace: "default"
    parameterNotFoundAction: Deny
  matchResources:
    namespaceSelector:
      matchExpressions:
      - key: environment
        operator: NotIn
        values:
        - test

请注意,此绑定将不同的参数应用于不在 test 环境中的资源。

并具有一个参数资源

apiVersion: rules.example.com/v1
kind: ReplicaLimit
metadata:
  name: "replica-limit-prod.example.com"
maxReplicas: 100

对于每个准入请求,API 服务器评估与请求匹配的每个 (策略、绑定、参数) 组合的 CEL 表达式。要被允许,请求必须通过 所有 评估。

如果多个绑定匹配请求,则将针对每个绑定评估策略,并且它们都必须通过评估才能认为策略已通过。

如果多个参数匹配单个绑定,策略规则将针对每个参数进行评估,并且它们也必须全部通过才能认为绑定已通过。绑定可以具有重叠的匹配标准。策略针对每个匹配的绑定-参数组合进行评估。如果多个绑定匹配它,或者单个绑定匹配多个参数,策略甚至可能被多次评估。

表示参数资源的 params 对象在参数资源未绑定时不会被设置,因此对于需要参数资源的策略,添加一个检查以确保已绑定一个参数资源可能很有用。如果策略的 `paramKind` 或绑定的 `paramRef` 未指定,则参数资源将不会被绑定,并且 `params` 将为 null。

对于需要参数配置的使用场景,建议在 `spec.validations[0].expression` 中添加参数检查。

- expression: "params != null"
  message: "params missing but required to bind to this policy"

可选参数

能够将可选参数作为参数资源的一部分,并且仅在存在时才验证它们,这可能很方便。CEL 提供了 `has()`,它检查传递给它的键是否存在。CEL 还实现了布尔短路。如果逻辑 OR 的前半部分评估为 true,它将不会评估后半部分(因为整个 OR 的结果无论如何都将为 true)。

结合这两点,我们可以提供一种验证可选参数的方法

!has(params.optionalNumber) || (params.optionalNumber >= 5 && params.optionalNumber <= 10)

在这里,我们首先使用 `!has(params.optionalNumber)` 检查可选参数是否存在。

  • 如果 `optionalNumber` 未定义,则表达式将短路,因为 `!has(params.optionalNumber)` 将评估为 true。
  • 如果 `optionalNumber` 已定义,则 CEL 表达式的后半部分将被评估,并且将检查 optionalNumber 以确保它包含 5 到 10 之间的值(包括 5 和 10)。

按命名空间划分的参数

作为 ValidatingAdmissionPolicy 及其 ValidatingAdmissionPolicyBinding 的作者,您可以选择指定集群范围或按命名空间的参数。如果在绑定 `paramRef` 中指定了 `namespace`,则控制平面仅会在该命名空间中搜索参数。

但是,如果在 ValidatingAdmissionPolicyBinding 中未指定 `namespace`,则 API 服务器可以搜索请求针对的命名空间中的相关参数。例如,如果您发出请求以修改 `default` 命名空间中的 ConfigMap,并且存在一个没有设置 `namespace` 的相关 ValidatingAdmissionPolicyBinding,那么 API 服务器将在 `default` 中查找参数对象。此设计支持依赖于正在操作的资源的命名空间的策略配置,以实现更精细的控制。

参数选择器

除了通过 `name` 在绑定中指定参数之外,您还可以选择指定标签选择器,以便选择所有匹配标签选择器的策略的 `paramKind` 资源以及参数的 `namespace`(如果适用)。有关标签选择器如何匹配资源的更多信息,请参阅 选择器

如果发现多个参数满足条件,则策略规则将针对每个找到的参数进行评估,并且结果将进行 AND 运算。

如果提供了 `namespace`,则只有提供的命名空间中 `paramKind` 的对象才有资格被选中。否则,当 `namespace` 为空且 `paramKind` 是命名空间范围时,将使用被允许的请求中的 `namespace`。

授权检查

我们引入了参数资源的授权检查。预计用户具有对 `ValidatingAdmissionPolicy` 中 `paramKind` 引用以及 `ValidatingAdmissionPolicyBinding` 中 `paramRef` 引用资源的 `read` 访问权限。

请注意,如果在 restmapper 中解析 `paramKind` 中的资源失败,则需要对所有组的资源进行 `read` 访问权限。

paramRef

`paramRef` 字段指定策略使用的参数资源。它具有以下字段

  • name:参数资源的名称。

  • namespace:参数资源的命名空间。

  • selector:用于匹配多个参数资源的标签选择器。

  • parameterNotFoundAction:(必需)控制未找到指定参数时的行为。

    • 允许的值:
      • Allow:缺少匹配的参数被绑定视为成功的验证。
      • Deny:缺少匹配的参数受策略的 `failurePolicy` 的约束。

必须设置 `name` 或 `selector` 中的一个,但不能同时设置两者。

使用 parameterNotFoundAction 处理缺少参数

在使用带有选择器的 `paramRef` 时,可能没有参数匹配该选择器。`parameterNotFoundAction` 字段确定绑定在这种情况下如何表现。

示例

apiVersion: admissionregistration.k8s.io/v1alpha1
kind: ValidatingAdmissionPolicyBinding
metadata:
  name: example-binding
spec:
  policyName: example-policy
  paramRef:
    selector:
      matchLabels:
        environment: test
    parameterNotFoundAction: Allow
  validationActions:
  - Deny

失败策略

failurePolicy 定义了如何处理准入策略中的错误配置和 CEL 表达式评估错误。允许的值为 IgnoreFail

  • Ignore 表示调用 ValidatingAdmissionPolicy 的错误将被忽略,并且 API 请求将继续进行。
  • Fail 表示调用 ValidatingAdmissionPolicy 的错误将导致准入失败,并且 API 请求将被拒绝。

请注意,failurePolicyValidatingAdmissionPolicy 内部定义

apiVersion: admissionregistration.k8s.io/v1
kind: ValidatingAdmissionPolicy
spec:
...
failurePolicy: Ignore # The default is "Fail"
validations:
- expression: "object.spec.xyz == params.x"  

验证表达式

spec.validations[i].expression 表示将由 CEL 评估的表达式。要了解更多信息,请参阅 CEL 语言规范 CEL 表达式可以访问入站请求/响应的内容,组织为 CEL 变量以及其他一些有用的变量

  • 'object' - 来自传入请求的对象。对于 DELETE 请求,该值为 null。
  • 'oldObject' - 现有的对象。对于 CREATE 请求,该值为 null。
  • 'request' - 准入请求 的属性。
  • 'params' - 策略绑定正在评估的参数资源。如果未指定 `ParamKind`,则该值为 null。
  • namespaceObject - 入站对象所属的命名空间,作为 Kubernetes 资源。如果入站对象是集群范围的,则该值为 null。
  • authorizer - 一个 CEL Authorizer。可用于对请求的主体(经过身份验证的用户)执行授权检查。有关更多详细信息,请参阅 Kubernetes CEL 库文档中的 AuthzSelectorsAuthz
  • authorizer.requestResource - 用于配置请求资源(组、资源、(子资源)、命名空间、名称)的授权检查的快捷方式。

在 CEL 表达式中,变量如 `object` 和 `oldObject` 是强类型的。您可以访问对象模式中的任何字段,例如 `object.metadata.labels` 和 `spec` 中的字段。

对于任何 Kubernetes 对象,包括无模式的自定义资源,CEL 保证可以访问一组最小的属性:apiVersionkindmetadata.namemetadata.generateName

具有 'set' 或 'map' 列表类型的数组上的相等性忽略元素顺序,即 [1, 2] == [2, 1]。具有 x-kubernetes-list-type 的数组上的连接使用列表类型的语义

  • 'set':X + Y 执行一个并集,其中 X 中所有元素的数组位置都被保留,并且 Y 中不相交的元素被追加,保留它们的偏序。
  • 'map':X + Y 执行一个合并,其中 X 中所有键的数组位置都被保留,但当 XY 的键集相交时,值会被 Y 中的值覆盖。Y 中具有不相交键的元素被追加,保留它们的偏序。

验证表达式示例

表达式目的
object.minReplicas <= object.replicas && object.replicas <= object.maxReplicas验证定义副本的三个字段按适当的顺序排序
'Available' in object.stateCounts验证映射中是否存在带有“Available”键的条目
(size(object.list1) == 0) != (size(object.list2) == 0)验证其中一个列表为空,但不是两个列表
!('MY_KEY' in object.map1) || object['MY_KEY'].matches('^[a-zA-Z]*$')如果它在映射中,则验证映射中特定键的值
object.envars.filter(e, e.name == 'MY_ENV').all(e, e.value.matches('^[a-zA-Z]*$')验证 listMap 条目中 key 字段为 'MY_ENV' 的 'value' 字段
has(object.expired) && object.created + object.ttl < object.expired验证 'expired' 日期在 'create' 日期加上一个 'ttl' 持续时间之后
object.health.startsWith('ok')验证 'health' 字符串字段以 'ok' 前缀开头
object.widgets.exists(w, w.key == 'x' && w.foo < 10)验证 key 为 'x' 的 listMap 项的 'foo' 属性是否小于 10
type(object) == string ? object == '100%' : object == 1000验证 int-or-string 字段的 int 和 string 情况
object.metadata.name.startsWith(object.prefix)验证对象的名称是否具有另一个字段值的 前缀
object.set1.all(e, !(e in object.set2))验证两个 listSet 是否不相交
size(object.names) == size(object.details) && object.names.all(n, n in object.details)验证 'details' map 的键由 'names' listSet 中的项键入
size(object.clusters.filter(c, c.name == object.primary)) == 1验证 'primary' 属性在 'clusters' 列表Map 中恰好出现一次

阅读 CEL 上支持的评估 以获取有关 CEL 规则的更多信息。

spec.validation[i].reason 表示此验证失败的机器可读描述。如果这是列表中第一个失败的验证,则此原因以及相应的 HTTP 响应代码将用于 HTTP 响应中发送给客户端。当前支持的理由是:UnauthorizedForbiddenInvalidRequestEntityTooLarge。如果未设置,则在响应中向客户端使用 StatusReasonInvalid

匹配请求:matchConditions

你可以为 ValidatingAdmissionPolicy 定义匹配条件,以便进行细粒度的请求过滤。如果发现匹配规则、objectSelectorsnamespaceSelectors 仍然无法提供所需的过滤,这些条件会很有用。匹配条件是 CEL 表达式。所有匹配条件都必须评估为 true,资源才能被评估。

这里有一个示例,说明了匹配条件的几种不同用法

apiVersion: admissionregistration.k8s.io/v1
kind: ValidatingAdmissionPolicy
metadata:
  name: "demo-policy.example.com"
spec:
  failurePolicy: Fail
  matchConstraints:
    resourceRules:
      - apiGroups:   ["*"]
        apiVersions: ["*"]
        operations:  ["CREATE", "UPDATE"]
        resources:   ["*"]
  matchConditions:
    - name: 'exclude-leases' # Each match condition must have a unique name
      expression: '!(request.resource.group == "coordination.k8s.io" && request.resource.resource == "leases")' # Match non-lease resources.
    - name: 'exclude-kubelet-requests'
      expression: '!("system:nodes" in request.userInfo.groups)' # Match requests made by non-node users.
    - name: 'rbac' # Skip RBAC requests.
      expression: 'request.resource.group != "rbac.authorization.k8s.io"'
  validations:
    - expression: "!object.metadata.name.contains('demo') || object.metadata.namespace == 'demo'"

匹配条件可以访问与验证表达式相同的 CEL 变量。

如果在评估匹配条件时发生错误,则不会评估策略。是否拒绝请求的决定如下

  1. 如果任何匹配条件评估为 false(无论是否存在其他错误),API 服务器将跳过该策略。
  2. 否则

审计注释

auditAnnotations 可用于在 API 请求的审计事件中包含审计注释。

例如,这里有一个带有审计注释的准入策略

apiVersion: admissionregistration.k8s.io/v1
kind: ValidatingAdmissionPolicy
metadata:
  name: "demo-policy.example.com"
spec:
  failurePolicy: Fail
  matchConstraints:
    resourceRules:
    - apiGroups:   ["apps"]
      apiVersions: ["v1"]
      operations:  ["CREATE", "UPDATE"]
      resources:   ["deployments"]
  validations:
    - expression: "object.spec.replicas > 50"
      messageExpression: "'Deployment spec.replicas set to ' + string(object.spec.replicas)"
  auditAnnotations:
    - key: "high-replica-count"
      valueExpression: "'Deployment spec.replicas set to ' + string(object.spec.replicas)"

当使用此准入策略验证 API 请求时,生成的审计事件将如下所示

# the audit event recorded
{
    "kind": "Event",
    "apiVersion": "audit.k8s.io/v1",
    "annotations": {
        "demo-policy.example.com/high-replica-count": "Deployment spec.replicas set to 128"
        # other annotations
        ...
    }
    # other fields
    ...
}

在此示例中,只有当 Deployment 的 spec.replicas 大于 50 时,才会包含该注释,否则 CEL 表达式评估为 null,并且不会包含该注释。

请注意,审计注释键会以 ValidatingAdmissionPolicy 的名称和 / 作为前缀。如果另一个准入控制器(例如准入 webhook)使用完全相同的审计注释键,则第一个包含审计注释的准入控制器的值将包含在审计事件中,并且所有其他值将被忽略。

消息表达式

为了在策略拒绝请求时返回更友好的消息,我们可以使用 CEL 表达式来组合一个消息,使用 spec.validations[i].messageExpression。与验证表达式类似,消息表达式可以访问 objectoldObjectrequestparamsnamespaceObject。与验证不同,消息表达式必须评估为字符串。

例如,为了更好地告知用户拒绝的原因,当策略引用参数时,我们可以使用以下验证

apiVersion: admissionregistration.k8s.io/v1
kind: ValidatingAdmissionPolicy
metadata:
  name: "deploy-replica-policy.example.com"
spec:
  paramKind:
    apiVersion: rules.example.com/v1
    kind: ReplicaLimit
  matchConstraints:
    resourceRules:
    - apiGroups:   ["apps"]
      apiVersions: ["v1"]
      operations:  ["CREATE", "UPDATE"]
      resources:   ["deployments"]
  validations:
  - expression: "object.spec.replicas <= params.maxReplicas"
    messageExpression: "'object.spec.replicas must be no greater than ' + string(params.maxReplicas)"
    reason: Invalid

在创建将副本限制为 3 的 params 对象并设置绑定后,当我们尝试使用 5 个副本创建部署时,我们将收到以下消息。

$ kubectl create deploy --image=nginx nginx --replicas=5
error: failed to create deployment: deployments.apps "nginx" is forbidden: ValidatingAdmissionPolicy 'deploy-replica-policy.example.com' with binding 'demo-binding-test.example.com' denied request: object.spec.replicas must be no greater than 3

这比静态消息“副本过多”更有信息量。

如果同时定义了 spec.validations[i].message 中的静态消息和消息表达式,则消息表达式优先。但是,如果消息表达式评估失败,则将使用静态消息。此外,如果消息表达式评估为多行字符串,则将丢弃评估结果,如果存在静态消息,则将使用静态消息。请注意,静态消息会针对多行字符串进行验证。

类型检查

当创建或更新策略定义时,验证过程会解析其中包含的表达式,并报告任何语法错误,如果发现任何错误,则会拒绝该定义。之后,将检查引用的变量是否存在类型错误,包括缺少字段和类型混淆,与 spec.matchConstraints 中匹配的类型进行比较。可以从 status.typeChecking 中检索类型检查的结果。status.typeChecking 的存在表示类型检查已完成,并且空的 status.typeChecking 表示未检测到任何错误。

例如,给定以下策略定义

apiVersion: admissionregistration.k8s.io/v1
kind: ValidatingAdmissionPolicy
metadata:
  name: "deploy-replica-policy.example.com"
spec:
  matchConstraints:
    resourceRules:
    - apiGroups:   ["apps"]
      apiVersions: ["v1"]
      operations:  ["CREATE", "UPDATE"]
      resources:   ["deployments"]
  validations:
  - expression: "object.replicas > 1" # should be "object.spec.replicas > 1"
    message: "must be replicated"
    reason: Invalid

状态将产生以下信息

status:
  typeChecking:
    expressionWarnings:
    - fieldRef: spec.validations[0].expression
      warning: |-
        apps/v1, Kind=Deployment: ERROR: <input>:1:7: undefined field 'replicas'
         | object.replicas > 1
         | ......^        

如果 spec.matchConstraints 中匹配了多个资源,将针对所有匹配的资源进行检查。例如,以下策略定义

apiVersion: admissionregistration.k8s.io/v1
kind: ValidatingAdmissionPolicy
metadata:
  name: "replica-policy.example.com"
spec:
  matchConstraints:
    resourceRules:
    - apiGroups:   ["apps"]
      apiVersions: ["v1"]
      operations:  ["CREATE", "UPDATE"]
      resources:   ["deployments","replicasets"]
  validations:
  - expression: "object.replicas > 1" # should be "object.spec.replicas > 1"
    message: "must be replicated"
    reason: Invalid

将具有多种类型和每种类型的类型检查结果在警告消息中。

status:
  typeChecking:
    expressionWarnings:
    - fieldRef: spec.validations[0].expression
      warning: |-
        apps/v1, Kind=Deployment: ERROR: <input>:1:7: undefined field 'replicas'
         | object.replicas > 1
         | ......^
        apps/v1, Kind=ReplicaSet: ERROR: <input>:1:7: undefined field 'replicas'
         | object.replicas > 1
         | ......^        

类型检查具有以下限制

  • 不支持通配符匹配。如果 spec.matchConstraints.resourceRulesapiGroupsapiVersionsresources 中的任何一个中包含 "*",则 "*" 匹配的类型将不会被检查。
  • 匹配类型的数量限制为 10。这是为了防止手动指定过多类型的策略消耗过多的计算资源。按照组、版本和资源升序排列,第 11 个及以后的组合将被忽略。
  • 类型检查不会以任何方式影响策略行为。即使类型检查检测到错误,策略仍将继续评估。如果在评估过程中发生错误,则故障策略将决定其结果。
  • 类型检查不适用于 CRD,包括匹配的 CRD 类型和 paramKind 的引用。对 CRD 的支持将在未来的版本中提供。

变量组合

如果一个表达式变得过于复杂,或者表达式的一部分是可重用的并且计算成本很高,你可以将表达式的一部分提取到变量中。变量是一个命名的表达式,稍后可以在 variables 中的其他表达式中引用。

spec:
  variables:
    - name: foo
      expression: "'foo' in object.spec.metadata.labels ? object.spec.metadata.labels['foo'] : 'default'"
  validations:
    - expression: variables.foo == 'bar'

变量是延迟评估的,即在第一次引用时进行评估。评估过程中发生的任何错误都将在引用表达式的评估过程中报告。结果和潜在错误都会被记住,并且仅对运行时成本产生一次影响。

变量的顺序很重要,因为变量可以引用在其之前定义的其他变量。这种排序可以防止循环引用。

以下是一个更复杂的示例,用于强制镜像仓库名称与命名空间中定义的环境匹配。

# This policy enforces that all containers of a deployment has the image repo match the environment label of its namespace.
# Except for "exempt" deployments, or any containers that do not belong to the "example.com" organization (e.g. common sidecars).
# For example, if the namespace has a label of {"environment": "staging"}, all container images must be either staging.example.com/*
# or do not contain "example.com" at all, unless the deployment has {"exempt": "true"} label.
apiVersion: admissionregistration.k8s.io/v1
kind: ValidatingAdmissionPolicy
metadata:
  name: "image-matches-namespace-environment.policy.example.com"
spec:
  failurePolicy: Fail
  matchConstraints:
    resourceRules:
    - apiGroups:   ["apps"]
      apiVersions: ["v1"]
      operations:  ["CREATE", "UPDATE"]
      resources:   ["deployments"]
  variables:
  - name: environment
    expression: "'environment' in namespaceObject.metadata.labels ? namespaceObject.metadata.labels['environment'] : 'prod'"
  - name: exempt
    expression: "'exempt' in object.metadata.labels && object.metadata.labels['exempt'] == 'true'"
  - name: containers
    expression: "object.spec.template.spec.containers"
  - name: containersToCheck
    expression: "variables.containers.filter(c, c.image.contains('example.com/'))"
  validations:
  - expression: "variables.exempt || variables.containersToCheck.all(c, c.image.startsWith(variables.environment + '.'))"
    messageExpression: "'only ' + variables.environment + ' images are allowed in namespace ' + namespaceObject.metadata.name"

将策略绑定到命名空间 default,该命名空间标记为 environment: prod,以下尝试创建部署将被拒绝。

kubectl create deploy --image=dev.example.com/nginx invalid

错误消息类似于此。

error: failed to create deployment: deployments.apps "invalid" is forbidden: ValidatingAdmissionPolicy 'image-matches-namespace-environment.policy.example.com' with binding 'demo-binding-test.example.com' denied request: only prod images are allowed in namespace default

免于准入验证的 API 类型

有一些 API 类型免于准入时验证检查。例如,你无法创建一个 ValidatingAdmissionPolicy 来阻止对 ValidatingAdmissionPolicyBindings 的更改。

受豁免的 API 类型列表如下

最后修改时间为 2025 年 9 月 11 日下午 9:04 PST:澄清 ValidatingAdmissionPolicy 文档和 CEL 上下文的内容 (#52303) (877e7fa201)