验证准入策略

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

本页提供 Validating Admission Policy 的概述。

什么是 Validating Admission Policy?

验证准入策略(Validating Admission Policy)提供了一种声明性的、进程内的替代方案,用于替代验证准入 Webhook。

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

构成策略的资源有哪些

一个策略通常由三个资源组成

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

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

  • ValidatingAdmissionPolicyBinding 将上述资源链接在一起并提供作用域。如果你只想要求为 `Pods` 设置 `owner` 标签,可以在 Binding 中指定此限制。

一个策略必须至少定义一个 `ValidatingAdmissionPolicy` 和一个相应的 `ValidatingAdmissionPolicyBinding` 才能生效。

如果 ValidatingAdmissionPolicy 不需要通过参数配置,只需将 ValidatingAdmissionPolicy 中的 spec.paramKind 留空即可。

Validating Admission Policy 入门

Validating Admission Policy 是集群控制平面的一部分。你应该非常谨慎地编写和部署它们。以下描述了如何快速尝试 Validating Admission Policy。

创建 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` 字段强制执行验证检查。

要配置一个验证准入策略以在集群中使用,需要一个 Binding。以下是一个 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

上述提供了一个在未配置参数的情况下使用 ValidatingAdmissionPolicy 的简单示例。

验证动作

每个 ValidatingAdmissionPolicyBinding 必须指定一个或多个 validationActions 来声明如何强制执行策略的 validations。

支持的 validationActions 包括

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

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

validationActions: [Warn, Audit]

DenyWarn 不能一起使用,因为这种组合会不必要地在 API 响应体和 HTTP 警告头中重复验证失败信息。

求值结果为 false 的 `validation` 始终根据这些动作强制执行。`failurePolicy` 定义的失败仅在 `failurePolicy` 设置为 `Fail`(或未指定)时根据这些动作强制执行,否则忽略失败。

有关验证失败审计注解的更多详细信息,请参见审计注解:验证失败

参数资源

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

如果需要参数配置,以下是一个配置了参数的 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.maxReplicas`。`spec.matchConstraints` 指定此策略旨在验证哪些资源。请注意,ConfigMap 等原生类型也可以用作参数引用。

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

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

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

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"
  matchResources:
    namespaceSelector:
      matchLabels:
        environment: test

请注意,此 Binding 将参数应用于策略,对所有位于 `test` 环境的资源生效。

参数资源可以如下所示

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

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

一个准入策略可以有多个 Binding。要将所有其他环境绑定到 maxReplicas 限制为 100,请创建另一个 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"
  matchResources:
    namespaceSelector:
      matchExpressions:
      - key: environment
        operator: NotIn
        values:
        - test

请注意,此 Binding 对不位于 `test` 环境的资源应用了不同的参数。

并拥有一个参数资源

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

对于每个准入请求,API 服务器会评估匹配该请求的每个(策略、Binding、参数)组合的 CEL 表达式。要使请求被接受,它必须通过**所有**评估。

如果多个 Binding 匹配该请求,则会针对每个 Binding 评估策略,并且它们必须全部通过评估,该策略才被视为通过。

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

如果参数资源尚未绑定,则表示参数资源的 `params` 对象将不会设置,因此对于需要参数资源的策略,添加检查以确保已绑定参数会很有用。如果未指定策略的 `paramKind` 或 Binding 的 `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 之间(包含边界)。

按命名空间划分的参数

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

但是,如果在 ValidatingAdmissionPolicyBinding 中未指定 `namespace`,API 服务器可以在请求所针对的命名空间中搜索相关参数。例如,如果你请求修改 `default` 命名空间中的 ConfigMap,并且存在一个未设置 `namespace` 的相关 ValidatingAdmissionPolicyBinding,则 API 服务器会在 `default` 中查找参数对象。这种设计使得策略配置可以依赖于所操作资源的命名空间,从而实现更精细的控制。

参数选择器

除了在 Binding 中按 `name` 指定参数外,你还可以选择指定标签选择器,以便选择所有符合策略 `paramKind` 并位于参数 `namespace`(如果适用)且与标签选择器匹配的资源进行评估。有关标签选择器如何匹配资源的更多信息,请参见选择器

如果找到多个符合条件的参数,则针对找到的每个参数评估策略规则,并将结果进行逻辑与 (AND) 运算。

如果提供了 `namespace`,则只有指定命名空间中 `paramKind` 的对象才符合选择条件。否则,当 `namespace` 为空且 `paramKind` 是命名空间范围时,将使用被准入请求中的 `namespace`。

鉴权检查

我们引入了参数资源的鉴权检查。用户应具有对 ValidatingAdmissionPolicy 中 `paramKind` 和 ValidatingAdmissionPolicyBinding 中 `paramRef` 引用的资源的 `read` 访问权限。

请注意,如果在 `paramKind` 中的资源无法通过 restmapper 解析,则需要对组中的所有资源具有 `read` 访问权限。

失败策略

failurePolicy 定义了如何处理准入策略中的配置错误以及求值结果为错误的 CEL 表达式。允许的值是 `Ignore` 或 `Fail`。

  • 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' - 被评估的策略 Binding 引用的参数资源。如果未指定 ParamKind,则该值为 null。
  • namespaceObject - 入站对象所属的命名空间(作为 Kubernetes 资源)。如果入站对象是集群范围的,则该值为 null。
  • authorizer - 一个 CEL Authorizer。可用于对请求的主体(已认证用户)执行鉴权检查。有关详细信息,请参阅 Kubernetes CEL 库文档中的AuthzSelectorsAuthz
  • authorizer.requestResource - 一个快捷方式,用于使用请求资源(group、resource、(subresource)、namespace、name)配置的鉴权检查。

apiVersionkindmetadata.namemetadata.generateName 始终可从对象的根目录访问。其他元数据属性无法访问。

列表类型为 'set' 或 'map' 的数组上的相等比较会忽略元素顺序,即 [1, 2] == [2, 1]。带有 x-kubernetes-list-type 的数组上的串联使用列表类型的语义。

  • 'set':X + Y 执行并集操作,其中 X 中所有元素的数组位置得以保留,而 Y 中非交集元素被追加,保留其部分顺序。
  • 'map':X + Y 执行合并操作,其中 X 中所有键的数组位置得以保留,但当 XY 的键集相交时,Y 中的值会覆盖 X 中的值。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 条目的 'value' 字段,其中键字段 'name' 是 'MY_ENV'
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)验证键为 'x' 的 listMap 项的 'foo' 属性小于 10
type(object) == string ? object == '100%' : object == 1000验证 int 或 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' 映射以 'names' listSet 中的项为键
size(object.clusters.filter(c, c.name == object.primary)) == 1验证 'primary' 属性在 'clusters' listMap 中只出现一次

阅读 CEL 支持的求值了解有关 CEL 规则的更多信息。

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

匹配请求:matchConditions

如果需要细粒度的请求过滤,可以为 ValidatingAdmissionPolicy 定义*匹配条件*。如果你发现 Match Rules、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 的参数对象并设置了绑定后,当我们尝试创建一个副本数为 5 的 Deployment 时,我们将收到以下消息:

$ 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.resourceRules 中的任何 apiGroupsapiVersionsresources 包含 "*",则不会检查 "*" 匹配的类型。
  • 匹配类型的数量限制为 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"

将此策略绑定到标记为 environment: proddefault 命名空间后,尝试创建 Deployment 将被拒绝:

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 年 1 月 22 日 下午 6:31 PST:add exempt api kinds in mutating admission policies doc (0338db1b94)