验证性准入策略
Kubernetes v1.30 [稳定]
本页面提供了验证准入策略的概述。
什么是验证准入策略?
验证准入策略提供了一种声明式的、进程内的替代方案,用于验证准入 webhook。
验证准入策略使用通用表达式语言 (CEL) 来声明策略的验证规则。验证准入策略是高度可配置的,使策略作者能够定义可参数化并根据集群管理员的需求限定资源范围的策略。
构成策略的资源
策略通常由三个资源组成
ValidatingAdmissionPolicy
描述了策略的抽象逻辑(例如:“此策略确保某个特定标签设置为特定值”)。参数资源向 ValidatingAdmissionPolicy 提供信息,使其成为一个具体的语句(例如“
owner
标签必须设置为以.company.com
结尾的值”)。原生类型(如 ConfigMap)或 CRD 定义了参数资源的模式。ValidatingAdmissionPolicy
对象指定了它们期望的参数资源的 Kind。ValidatingAdmissionPolicyBinding
将上述资源链接在一起并提供作用域。如果你只希望Pods
设置owner
标签,则可以在绑定中指定此限制。
至少必须定义一个 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
字段强制执行验证检查。
注意
你可以在 CEL Playground 中快速测试 CEL 表达式。要配置验证准入策略以在集群中使用,需要进行绑定。下面是 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]
Deny
和 Warn
不能同时使用,因为这种组合不必要地在 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
ValidatingAdmissionPolicy 的 spec.paramKind
字段指定了用于参数化此策略的资源的类型。对于此示例,它由 ReplicaLimit 自定义资源配置。请注意在此示例中 CEL 表达式如何通过 CEL params 变量引用参数,例如 params.maxReplicas
。spec.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
此策略参数资源将部署限制为最多 3 个副本。
一个准入策略可以有多个绑定。要将所有其他环境绑定为 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"
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(含)之间的值。
每命名空间参数
作为 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
访问权限。
请注意,如果 paramKind
中的资源通过 restmapper 解析失败,则需要对所有组资源具有 read
访问权限。
paramRef
paramRef
字段指定了策略使用的参数资源。它具有以下字段
name:参数资源的名称。
namespace:参数资源的命名空间。
selector:一个标签选择器,用于匹配多个参数资源。
parameterNotFoundAction:(必需)控制未找到指定参数时的行为。
- 允许值:
Allow
:未找到匹配参数被视为绑定成功验证。Deny
:未找到匹配参数受策略的failurePolicy
约束。
- 允许值:
name
或 selector
必须设置一个,但不能同时设置两者。
注意
paramRef
中的 parameterNotFoundAction
字段是**必需**的。它指定当没有找到与 paramRef
匹配的参数时要执行的操作。如果未指定,则策略绑定可能被视为无效并将被忽略或可能导致意外行为。
Allow
:如果设置为Allow
并且未找到参数,则绑定将参数缺失视为成功验证,并且策略被认为已通过。Deny
:如果设置为Deny
并且未找到参数,则绑定将强制执行策略的failurePolicy
。如果failurePolicy
为Fail
,则请求将被拒绝。
请确保根据参数缺失时的预期行为设置 parameterNotFoundAction
。
使用 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 表达式评估为错误时如何处理。允许的值为 Ignore
或 Fail
。
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 库文档中的 AuthzSelectors 和 Authz。authorizer.requestResource
- 用于配置有请求资源(组、资源、(子资源)、命名空间、名称)的授权检查的快捷方式。
apiVersion
、kind
、metadata.name
和 metadata.generateName
始终可以从对象的根访问。其他元数据属性均不可访问。
列表类型为“set”或“map”的数组上的相等性忽略元素顺序,即 [1, 2] == [2, 1]。数组上的连接与 x-kubernetes-list-type 使用列表类型的语义
- 'set':
X + Y
执行并集,其中X
中所有元素的数组位置保留,Y
中不相交的元素附加,保留其部分顺序。 - 'map':
X + Y
执行合并,其中X
中所有键的数组位置保留,但当X
和Y
的键集相交时,值会被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-or-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”列表映射中只出现一次 |
阅读CEL 上支持的评估,了解有关 CEL 规则的更多信息。
spec.validation[i].reason
表示此验证失败原因的机器可读描述。如果这是列表中第一个失败的验证,则此原因以及相应的 HTTP 响应代码将用于 HTTP 响应客户端。目前支持的原因有:Unauthorized
、Forbidden
、Invalid
、RequestEntityTooLarge
。如果未设置,则在响应客户端时使用 StatusReasonInvalid
。
匹配请求:matchConditions
如果你需要细粒度的请求过滤,可以为 ValidatingAdmissionPolicy
定义*匹配条件*。如果发现匹配规则、objectSelectors
和 namespaceSelectors
仍然无法提供所需的过滤功能,这些条件将很有用。匹配条件是 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 变量。
如果评估匹配条件时发生错误,则不会评估策略。是否拒绝请求的决定如下
- 如果**任何**匹配条件评估为
false
(无论其他错误如何),API 服务器将跳过该策略。 - 否则
- 对于
failurePolicy: Fail
,拒绝请求(不评估策略)。 - 对于
failurePolicy: Ignore
,继续请求但跳过策略。
- 对于
审计注解
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
组合消息。与验证表达式类似,消息表达式可以访问 object
、oldObject
、request
、params
和 namespaceObject
。与验证不同,消息表达式必须评估为字符串。
例如,为了更好地告知用户策略拒绝请求的原因(当策略引用参数时),我们可以有以下验证
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
在任何apiGroups
、apiVersions
或resources
中包含"*"
,则不会检查"*"
匹配的类型。 - 匹配类型的数量限制为 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
免于准入验证的 API 种类
某些 API 种类免于准入时间验证检查。例如,你不能创建阻止更改 ValidatingAdmissionPolicyBindings 的 ValidatingAdmissionPolicy。
免除的 API 种类列表是
- ValidatingAdmissionPolicies
- ValidatingAdmissionPolicyBindings
- MutatingAdmissionPolicies
- MutatingAdmissionPolicyBindings
- TokenReviews
- LocalSubjectAccessReviews
- SelfSubjectAccessReviews
- SelfSubjectReviews