验证准入策略

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

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

什么是验证准入策略?

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

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

构成策略的资源

策略通常由三种资源组成

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

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

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

为了使策略生效,必须至少定义一个 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

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 表达式。为了使请求被准入,它必须通过所有评估。

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

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

如果未绑定参数资源,则不会设置表示参数资源的 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 之间(含)的值。

每个命名空间的参数

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

但是,如果在 ValidatingAdmissionPolicyBinding 中未指定 namespace,API 服务器可以搜索与请求针对的命名空间相关的参数。例如,如果您发出一个修改 default 命名空间中的 ConfigMap 的请求,并且存在一个相关的 ValidatingAdmissionPolicyBinding 且未设置 namespace,那么 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 请求。

请注意,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 库文档中的 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 或 string 字段的 int 和 string 情况
object.metadata.name.startsWith(object.prefix)验证对象的名称是否具有另一个字段值的 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 个副本的部署时,我们将收到以下消息。

$ 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"

如果将策略绑定到 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
上次修改于 2024 年 8 月 1 日下午 9:08 PST:删除 beta 先决条件 (d77111d096)