验证准入策略

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

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

什么是验证准入策略?

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

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

什么资源构成策略

策略通常由三个资源组成

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

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

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

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

如果 ValidatingAdmissionPolicy 不需要通过参数进行配置,只需在 ValidatingAdmissionPolicy 中将 spec.paramKind 保留为未指定即可。

验证准入策略入门

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

创建 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 设置为 Fail(或未指定)时,才会根据这些操作强制执行 failurePolicy 定义的失败,否则会忽略这些失败。

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

参数资源

参数资源允许策略配置与其定义分离。策略可以定义 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

ValidatingAdmissionPolicy 的 spec.paramKind 字段指定用于参数化此策略的资源类型。对于此示例,它由 ReplicaLimit 自定义资源配置。请注意在此示例中 CEL 表达式如何通过 CEL 参数变量引用参数,例如 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 个 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"
  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 还实现了布尔短路。如果逻辑或的第一部分计算结果为 true,它将不会评估另一半(因为整个或的结果无论如何都将为 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(如果适用)进行评估。有关标签选择器如何匹配资源的详细信息,请参阅选择器

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

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

授权检查

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

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

失败策略

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 授权器。可以用于对请求的主体(经过身份验证的用户)执行授权检查。有关更多详细信息,请参阅 Kubernetes CEL 库文档中的 AuthzSelectorsAuthz
  • 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”的 listMap 条目的“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”的 listMap 项目的“foo”属性是否小于 10
type(object) == string ? object == '100%' : object == 1000验证 int 或字符串字段的 int 和字符串两种情况
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 定义匹配条件。如果您发现匹配规则、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 的参数对象并设置绑定后,当我们尝试创建一个包含 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: prod 的命名空间 default 时,以下创建 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
上次修改时间:2024 年 8 月 1 日 上午 9:08 PST: 删除 beta 先决条件 (d77111d096)