验证准入策略

功能状态: Kubernetes v1.30 [稳定]

本页概述了验证准入策略。

什么是验证准入策略?

验证准入策略为验证准入 Webhook 提供了一种声明性的、进程内的替代方案。

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

哪些资源构成一个策略

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

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

  • ValidatingAdmissionPolicyBinding 将上述资源链接在一起并提供范围限定。如果您只想要求为 Pod 设置 owner 标签,则绑定是您指定此限制的地方。

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

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

如果 ValidatingAdmissionPolicy 不需要通过参数进行配置,只需将 spec.paramKindValidatingAdmissionPolicy 中不指定即可。

在您开始之前

  • 确保 ValidatingAdmissionPolicy 功能开关 已启用。
  • 确保 admissionregistration.k8s.io/v1beta1 API 已启用。

验证准入策略入门

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

创建 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

当尝试创建副本集不满足验证表达式的部署时,将返回包含消息的错误

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,然后策略绑定通过名称(通过 policyName)将策略绑定到特定参数资源(通过 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

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

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

参数资源可能是以下内容

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

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

准入策略可能有多个绑定。要将所有其他环境绑定到具有 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

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

并具有参数资源

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

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

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

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

如果参数资源未绑定,则表示参数资源的参数对象将不会设置,因此对于需要参数资源的策略,添加检查以确保已绑定参数资源可能会有用。如果策略的 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(含)之间的值。

每个命名空间的参数

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

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

参数选择器

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

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

如果提供了 namespace,则只有提供的命名空间中的 paramKind 对象才有资格进行选择。否则,当 namespace 为空且 paramKind 为命名空间范围时,将使用正在承认的请求中使用的 namespace

授权检查

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

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

失败策略

failurePolicy 定义了如何处理来自准入策略的错误配置和 CEL 表达式计算结果为错误。允许的值为 IgnoreFail

  • Ignore 表示忽略调用 ValidatingAdmissionPolicy 产生的错误,并允许 API 请求继续进行。
  • Fail 表示调用 ValidatingAdmissionPolicy 产生的错误会导致准入失败,并拒绝 API 请求。

请注意,failurePolicy 定义在 ValidatingAdmissionPolicy 内部。

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 授权器。可用于对请求的委托人(已验证的用户)执行授权检查。有关更多详细信息,请参阅 Kubernetes CEL 库文档中的 Authz
  • authorizer.requestResource - 用于配置请求资源(组、资源、(子资源)、命名空间、名称)的授权检查的快捷方式。

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]*$')验证键字段 'name' 为 '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)验证具有键 'x' 的列表映射项的 'foo' 属性是否小于 10
type(object) == string ? object == '100%' : object == 1000验证 int 或字符串字段的 int 和字符串情况
object.metadata.name.startsWith(object.prefix)验证对象的名称是否具有另一个字段值的 prefix
object.set1.all(e, !(e in object.set2))验证两个列表集是否不相交
size(object.names) == size(object.details) && object.names.all(n, n in object.details)验证 'details' 映射是否以 'names' 列表集中的项为键
size(object.clusters.filter(c, c.name == object.primary)) == 1验证 'primary' 属性在 'clusters' 列表映射中只出现一次

阅读 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,并且注释将不会包含。

请注意,审计注释键以 ValidatingAdmissionWebhook 的名称和一个 / 为前缀。如果另一个准入控制器(例如准入 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"

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

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
上次修改时间:2024 年 2 月 21 日下午 5:38 PST:将 ValidatingAdmissionPolicy 提升为 GA (0fc8d236e0)