檢查資源配置是否符合策略。
驗證規(guī)則可能是您將使用的最常見和最實用的規(guī)則類型,也是 Kyverno 等準入控制器的主要用例。在一個典型的驗證規(guī)則中,定義了創(chuàng)建給定資源時應強制的屬性。當用戶或進程創(chuàng)建新資源時,Kyverno 會根據(jù)驗證規(guī)則檢查該資源的屬性。如果這些屬性得到驗證,意味著達成一致,則允許創(chuàng)建資源。如果這些屬性不同,則阻止創(chuàng)建。Kyverno 如何響應失敗的驗證檢查的行為由 validationFailureAction 字段決定。它可以被阻止(enforce)或在策略報告中記錄(audit)。無論是在初始創(chuàng)建時還是在 Kyverno 啟動 Kubernetes 資源的定期掃描時,在 audit 模式中,驗證規(guī)則也可用于獲取資源匹配時有關違反規(guī)則的情況報告。在 audit 模式中,違反現(xiàn)有規(guī)則的說明也將出現(xiàn)在相關資源的事件中。
要驗證資源數(shù)據(jù),請在驗證規(guī)則中定義一個pattern。要拒絕某些 API 請求,請在驗證規(guī)則中定義一個deny元素以及一組控制何時允許或拒絕請求的條件。
基本驗證
下面的 ClusterPolicy 是驗證新創(chuàng)建的 Namespace 是否有標簽 purpose=production。
apiVersion: kyverno.io/v1
# ClusterPolicy 類型應用于整個集群
kind: ClusterPolicy
metadata:
name: require-ns-purpose-label
# `spec` 定義了策略的屬性
spec:
# `validationFailureAction` 告知 Kyverno 當資源驗證失敗是,應該中斷(enforce)還是報告(audit)
validationFailureAction: enforce
# `rules` 是一個或多個必須為 true 的規(guī)則。
rules:
- name: require-ns-purpose-label
# `match` 設置了要檢查的范圍。在這個case中,要檢查所有的 `Namespace`
match:
any:
- resources:
kinds:
- Namespace
# The `validate` statement tries to positively check what is defined. If the statement, when compared with the requested resource, is true, it is allowed. If false, it is blocked.
validate:
# `message` 在規(guī)則驗證失敗并中斷后,給用戶展示的提示信息
message: "You must have label `purpose` with value `production` set on all new namespaces."
# `pattern` 對象定義了資源檢查的模式。在這個 case 中,會在 `metadata.labels` 中查找`purpose=production`
pattern:
metadata:
labels:
purpose: production
如果將具有以下定義的新命名空間提交給 Kyverno,則根據(jù)上面的 ClusterPolicy,它將被允許(有效)。這是因為它包含標簽 purpose=production,這是規(guī)則中唯一驗證的模式。
apiVersion: v1
kind: Namespace
metadata:
name: prod-bus-app1
labels:
purpose: production
相比之下,如果提交了具有以下定義的新命名空間,鑒于上面的 ClusterPolicy,它將被阻止(無效)。如您所見,其 purpose 標簽的值與策略中要求的值不同。但這并不是驗證失敗的唯一方式。 例如,如果請求了相同的命名空間,但沒有定義任何標簽,它也會因為同樣的原因被阻止。
apiVersion: v1
kind: Namespace
metadata:
name: prod-bus-app1
labels:
purpose: development
將上述清單另存為 ns.yaml 并嘗試使用示例 ClusterPolicy 創(chuàng)建它。
$ kubectl create -f ns.yaml
Error from server: error when creating "ns.yaml": admission webhook "validate.kyverno.svc" denied the request:
resource Namespace//prod-bus-app1 was blocked due to the following policies
require-ns-purpose-label:
require-ns-purpose-label: 'Validation error: You must have label `purpose` with value `production` set on all new namespaces.; Validation rule require-ns-purpose-label failed at path /metadata/labels/purpose/'
將 development 改為 production,然后重試。 Kyverno 允許創(chuàng)建新的命名空間資源。
驗證失敗操作
validationFailureAction 屬性控制不符合策略的資源的準入控制行為。如果將該值設置為 enforce,則資源創(chuàng)建或更新會在資源不符合要求時被阻止。當值設置為 audit 時,策略違規(guī)會記錄在 PolicyReport 或 ClusterPolicyReport 中,但允許創(chuàng)建或更新資源。對于違反新創(chuàng)建的 enforce 模式策略的現(xiàn)有資源,Kyverno 將允許對繼續(xù)違反策略的資源進行后續(xù)更新,以確?,F(xiàn)有資源不會受到影響。但是,如果對違規(guī)資源的后續(xù)更新使其符合要求,則會阻止任何會產生違規(guī)的進一步更新。
驗證失敗操作覆蓋
使用 validationFailureActionOverrides,您可以指定每個命名空間應用哪些操作。 此屬性僅適用于 ClusterPolicy。
apiVersion: kyverno.io/v1
kind: ClusterPolicy
metadata:
name: check-label-app
spec:
validationFailureAction: audit
validationFailureActionOverrides:
- action: enforce # 采取的操作
namespaces: # 受影響的命名空間列表
- default
- action: audit
namespaces:
- test
rules:
- name: check-label-app
match:
any:
- resources:
kinds:
- Pod
validate:
message: "The label `app` is required."
pattern:
metadata:
labels:
app: "?*"
上述策略,對于 default 命名空間,validationFailureAction 被設置為 enforce,而對于 test 命名空間,被設置為 audit。對于其它的命名空間,使用 validationFailureAction 中設置的操作。
Patterns
檢查資源數(shù)據(jù)的驗證規(guī)則被定義為提供所需配置的覆蓋模式。資源配置必須匹配模式中定義的字段和表達式才能通過驗證規(guī)則。處理覆蓋模式時遵循以下規(guī)則:
如果在模式中定義了字段而配置中不存在該字段,則驗證將失敗。
未定義的字段被視為通配符。
帶有通配符值“*”的驗證模式字段將匹配零個或多個字母數(shù)字字符。也匹配空值,但字段缺失時不匹配。
帶有通配符值“?”的驗證模式字段將匹配任何單個字母數(shù)字字符。 空值或缺失字段不匹配。
具有通配符值“?*”的驗證模式字段將匹配任何字母數(shù)字字符,并要求該字段存在非空值。
值為 null 或 ""(空字符串)的驗證模式字段要求該字段未定義或沒有值。
僅當字段值之一與模式中定義的值匹配時,才執(zhí)行同級的驗證。您可以使用條件錨來顯式指定必須匹配的字段值。 這允許編寫諸如“如果字段A等于 X,則字段B必須等于 Y”之類的規(guī)則。
僅當父項與模式匹配時才執(zhí)行子值的驗證。
通配符
*- 匹配零個或多個字母數(shù)字字符?- 匹配單個字母數(shù)字字符
有關通配符如何在規(guī)則中工作的幾個示例,請參閱以下內容。
該策略要求所有 Pod 中的所有容器都定義了資源請求和限制(故意省略了 CPU 限制):
apiVersion: kyverno.io/v1
kind: ClusterPolicy
metadata:
name: all-containers-need-requests-and-limits
spec:
validationFailureAction: enforce
rules:
- name: check-container-resources
match:
any:
- resources:
kinds:
- Pod
validate:
message: "All containers must have CPU and memory resource requests and limits defined."
pattern:
spec:
containers:
# 選擇 Pod 中的所有容器。 `name` field here is not specifically required but serves
# as a visual aid for instructional purposes.
- name: "*"
resources:
limits:
# '?' requires 1 alphanumeric character and '*' means that
# there can be 0 or more characters. Using them together
# e.g. '?*' requires at least one character.
memory: "?*"
requests:
memory: "?*"
cpu: "?*"
以下驗證規(guī)則檢查 Deployment、StatefulSet 和 DaemonSet 資源中的標簽:
apiVersion: kyverno.io/v1
kind: ClusterPolicy
metadata:
name: check-label-app
spec:
validationFailureAction: enforce
rules:
- name: check-label-app
match:
any:
- resources:
kinds:
- Deployment
- StatefulSet
- DaemonSet
validate:
message: "The label `app` is required."
pattern:
spec:
template:
metadata:
labels:
app: "?*"
要將通配符等特殊字符視為字面值,請參閱 JMESPath 頁面中的此部分。
運算符
除了標量值之外,從 Kyverno 1.3.6 開始支持以下列表值的運算符。一些運算符也支持持續(xù)時間(如 12h)和語義化版本(如 1.4.1)檢查。
| 運算符 | 含義 |
|---|---|
| > | 大于 |
| < | 小于 |
| >= | 大于等于 |
| <= | 小于等于 |
| ! | 不等于 |
| | | 邏輯或 |
| & | 邏輯與 |
| - | 區(qū)間內 |
| !- | 區(qū)間外 |
注意
注意:- 運算符提供了一種更簡單的方法來驗證目標值是否落在閉合區(qū)間 [a,b] 內。 因此,條件 a-b 等效于 value >= a & value <= b。
注意:!- 運算符提供了一種更簡單的方法來驗證目標值是否落在閉區(qū)間 [a,b] 之外。 因此,條件 a!-b 等效于編寫 value < a | value > b。
注意:沒有用于 equals 的運算符,因為在模式中提供字段值需要與該值相等。
錨點
錨點允許條件處理(即“if-then-else”)和驗證模式中的其他邏輯檢查。
支持以下類型的錨點:
| 錨點 | Tag | 行為 |
|---|---|---|
| Conditional | () | 如果指定了具有給定值的標簽(包括子元素),則將處理對等元素。 例如,如果鏡像具有最新標簽,則imagePullPolicy不能為IfNotPresent。 (image): “*:latest” imagePullPolicy: “!IfNotPresent” |
| Equality | =() | 如果指定了標簽,則處理繼續(xù)。對于具有標量值的標簽,該值必須匹配。對于具有子元素的標簽,子元素將進一步評估為驗證模式。 例如,如果定義了hostPath,則路徑不能為 /var/lib =(hostPath): path: “!/var/lib” |
| Existence | ^() | 僅適用于列表/數(shù)組類型。列表中至少一個元素是否滿足該模式。相反,條件錨將驗證列表中的所有元素均與模式匹配。 例如,必須至少有一個容器使用鏡像 nginx:latest。 ^(containers): - image: nginx:latest |
| Negation | X() | 無法指定標簽。不評估標記的值(使用感嘆號來否定值)。理想情況下,該值應設置為 null。 例如,不能定義 Hostpath。 X(hostPath): |
| Global | <() | 這個條件的內容如果為假,會導致整個規(guī)則被跳過。適用于驗證和戰(zhàn)略合并補丁。 |
anyPattern
在某些情況下,可以在不同級別定義內容。例如,security context 可以被定義為 Pod 或 Container 級別。如果滿足任一條件,則驗證規(guī)則應通過。
anyPattern 是對多個驗證 pattern 的邏輯或,可用于檢查列表中的任何一種模式是否匹配。
注意:規(guī)則中允許使用 pattern 或 anyPattern 之一;它們不能在同一規(guī)則中聲明。
apiVersion: kyverno.io/v1
kind: ClusterPolicy
metadata:
name: require-run-as-non-root
spec:
background: true
validationFailureAction: enforce
rules:
- name: check-containers
match:
any:
- resources:
kinds:
- Pod
validate:
message: >-
Running as root is not allowed. The fields spec.securityContext.runAsNonRoot,
spec.containers[*].securityContext.runAsNonRoot, and
spec.initContainers[*].securityContext.runAsNonRoot must be `true`.
anyPattern:
# spec.securityContext.runAsNonRoot must be set to true. If containers and/or initContainers exist which declare a securityContext field, those must have runAsNonRoot also set to true.
- spec:
securityContext:
runAsNonRoot: true
containers:
- =(securityContext):
=(runAsNonRoot): true
=(initContainers):
- =(securityContext):
=(runAsNonRoot): true
# All containers and initContainers must define (not optional) runAsNonRoot=true.
- spec:
containers:
- securityContext:
runAsNonRoot: true
=(initContainers):
- securityContext:
runAsNonRoot: true
anyPattern 方法最適合不使用否定條件的驗證案例。在上面的例子中,只有一個 spec 內容必須是有效的。
注意:由于 Kubernetes v1.23 中的一個 bug 已在 v1.23.3 中修復,因此在 v1.23 版本中使用 anyPattern 至少需要 v1.23.3。
Deny 規(guī)則
除了使用 pattern 來檢查資源之外,驗證規(guī)則還可以基于以表達式形式編寫的一組條件來拒絕請求。
你可以使用 match 和 exclude 什么時候應用策略,然后在 deny 聲明中用額外的條件進行更細粒度的控制。
注意:使用 deny 聲明時,validationFailureAction 必須被設置為 enforce 以中斷請求。
請參閱使用前置條件基于變量匹配規(guī)則。deny 可以像 preconditions 一樣使用 any 和 all 塊。
除了準入審查請求數(shù)據(jù)、用戶信息和內置變量之外,deny 規(guī)則和前置條件還可以對 ConfigMap 數(shù)據(jù)、來自 API 服務器查找的數(shù)據(jù)等進行操作
根據(jù)標簽拒絕 DELETE 請求
這個策略會拒絕所有沒有 cluster-admin 角色的用戶對于包含 pp.kubernetes.io/managed-by: kyverno 對象的 delete 操作。
apiVersion: kyverno.io/v1
kind: ClusterPolicy
metadata:
name: deny-deletes
spec:
validationFailureAction: enforce
background: false
rules:
- name: block-deletes-for-kyverno-resources
match:
any:
- resources:
selector:
matchLabels:
app.kubernetes.io/managed-by: kyverno
exclude:
any:
- clusterRoles:
- cluster-admin
validate:
message: "Deleting {{request.oldObject.kind}}/{{request.oldObject.metadata.name}} is not allowed"
deny:
conditions:
any:
- key: "{{request.operation}}"
operator: Equals
value: DELETE
阻止對自定義資源的更改
這個策略對拒絕所有對該用戶自定義資源的更新或刪除操作,除非是來自指定 ServiceAccount 或 Roles 的請求。
apiVersion: kyverno.io/v1
kind: ClusterPolicy
metadata:
name: block-updates-to-custom-resource
spec:
validationFailureAction: enforce
background: false
rules:
- name: block-updates-to-custom-resource
match:
any:
- resources:
kinds:
- SomeCustomResource
exclude:
any:
- subjects:
- kind: ServiceAccount
name: custom-controller
- clusterRoles:
- custom-controller:*
- cluster-admin
validate:
message: "Modifying or deleting this custom resource is forbidden."
deny: {}
防止更改 NetworkPolicy 資源
該策略拒絕用戶修改名稱以 -default 為后綴的 NetworkPolicy 資源。
apiVersion: kyverno.io/v1
kind: ClusterPolicy
metadata:
name: deny-netpol-changes
spec:
validationFailureAction: enforce
background: false
rules:
- name: deny-netpol-changes
match:
any:
- resources:
kinds:
- NetworkPolicy
name: "*-default"
exclude:
any:
- clusterRoles:
- cluster-admin
validate:
message: "Changing default network policies is not allowed."
deny: {}
foreach
foreach 聲明簡化了資源聲明中子元素的驗證,例如 Pod 中的容器。
一個 foreach 聲明可以包含多個條目來處理不同的子元素,例如一個處理容器列表,另一個處理 Pod 中的 initContainers 列表。
每個 foreach 條目必須包含一個 list 屬性,寫為不帶大括號的 JMESPath 表達式,它定義了它處理的子元素。例如,使用此 list 聲明執(zhí)行對 Pod 中容器列表的迭代:
list: request.object.spec.containers
處理 foreach 時,Kyverno 引擎會將 list 作為 JMESPath 表達式來處理,以檢索零個或多個子元素以進行進一步處理。list 字段的值也可以解析為一個簡單的字符串數(shù)組,例如在 context 變量中定義的字符串。list 字段的值不應包含在大括號中,即使它是 JMESPath 表達式。
每次迭代時,會將一個 element 變量加入到上下文中??梢允褂?element.<name> 引用元素中的數(shù)據(jù),這里的 name 是屬性名稱。例如,當 request.object 是一個 Pod 時,遍歷 request.object.spec.containers 列表時,可以在 foreach 里用 element.image 引用容器鏡像。
在 foreach 中允許以下子聲明:
此外,每個 foreach 聲明都可以包含以下聲明:
Context: 添加僅在每個循環(huán)迭代中可用的額外外部數(shù)據(jù)。
Preconditions: 控制何時跳過循環(huán)迭代。
elementScope: 控制是否使用當前列表元素作為驗證范圍。如果未指定,則默認為“true”。
這是一個完整的示例,用于強制所有容器映像都來自受信任的注冊表:
apiVersion : kyverno.io/v1
kind: ClusterPolicy
metadata:
name: check-images
spec:
validationFailureAction: enforce
background: false
rules:
- name: check-registry
match:
any:
- resources:
kinds:
- Pod
preconditions:
any:
- key: "{{request.operation}}"
operator: NotEquals
value: DELETE
validate:
message: "unknown registry"
foreach:
- list: "request.object.spec.initContainers"
pattern:
image: "trusted-registry.io/*"
- list: "request.object.spec.containers"
pattern:
image: "trusted-registry.io/*"
請注意,pattern 應用于 element,因此不需要指定 spec.containers 并且可以直接引用 element 的屬性,在上面的示例中它是一個 container。