Kyverno变量

用于重用和智能决策的数据驱动策略

变量通过启用对策略定义、准入审查请求和外部数据源(如 ConfigMaps、Kubernetes API Server 甚至 OCI image registries)中的数据的引用,使策略更加智能和可重用。

变量存储为 JSON,Kyverno 支持使用 JMESPath(发音为“James path”)来选择和转换 JSON 数据。使用 JMESPath,以 {{key1.key2.key3}} 的格式引用来自数据源的值。例如,要在 kubectl apply 操作(如命名空间)期间引用传入资源的名称,您可以将其写为变量引用:{{request.object.metadata.name}}。在处理规则之前,策略引擎将使用变量值替换任何格式为 {{ <JMESPath> }} 的值。有关专门探讨 JMESPath 在 Kyverno 中的使用的页面,请参见此处

注意:目前在 match 或 exclude 语句或 patchesJson6902.path 中不允许使用变量。

预定义变量

Kyverno 自动创建一些有用的变量并在规则中使它们可用:

  1. serviceAccountName: “userName”,它是 service account 的最后一部分(即没有前缀 system:serviceaccount:<namespace>:)。例如,在处理来自 system:serviceaccount:nirmata:user1 的请求时,Kyverno 会将值 user1 存储在变量 serviceAccountName 中。

  2. serviceAccountNamespace: serviceAccount 的 “namespace” 部分。例如,在处理来自 system:serviceaccount:nirmata:user1 的请求时,Kyverno 会将 nirmata 存储在变量 serviceAccountNamespace 中。

  3. request.roles: 存储在数组中的、给定账户可能具有的 role 列表。如["foo:dave"]。

  4. request.clusterRoles: 存储在数组中的 cluster role 列表。如 ["dave-admin","system:basic-user","system:discovery","system:public-info-viewer"]

  5. images: a map of container image information, if available. See Variables from container images for more information.

注意:request.roles 或 request.clusterRoles 之一将被替换为变量,但不能同时替换两者。

策略定义中的变量

Kyverno 策略定义可以以“快捷方式”的形式引用策略定义中的其他字段。这可能是一种分析和比较值的有用方法,而无需显式定义它们。

为了让 Kyverno 在清单中引用这些现有值,它使用符号 $(./../key_1/key_2)。这可能看起来很熟悉,因为它本质上与 Linux/Unix 系统引用相对路径的方式相同。 例如,可以看下面的策略清单片段。

validationFailureAction: enforce
rules:
- name: check-tcpSocket
  match:
    any:
    - resources:
        kinds:
        - Pod
  validate:
    message: "Port number for the livenessProbe must be less than that of the readinessProbe."
    pattern:
      spec:
        ^(containers):
        - livenessProbe:
            tcpSocket:
              port: "$(./../../../readinessProbe/tcpSocket/port)"
          readinessProbe:
            tcpSocket:
              port: "3000"

在上面的示例中,Pod Spec 中所有 container 的 readinessProbe.tcpSocket.port 字段必须为 3000,livenessProbe.tcpSocket.port 字段值也必须是相同的值。查找表达式可以被认为是一个 cd 返回三个级别并向下进入 readinessProbe 对象。

可以在查找清单变量中使用运算符,因此可以修改前面的代码片段。

- livenessProbe:
    tcpSocket:
      port: "$(<./../../../readinessProbe/tcpSocket/port)"
  readinessProbe:
    tcpSocket:
      port: "3000"

在这个示例中,livenessProbe.tcpSocket.port 的字段值必须小于 readinessProbe.tcpSocket.port 的值。

更多信息请参考Operators章节。

转义变量

在某些情况下,您希望编写一个包含变量的规则,以供另一个程序或流程执行操作,而不是供 Kyverno 使用。例如,使用 $() 表示法中的变量,从 Kyverno 1.5.0 开始,这些变量可以使用前导反斜杠 () 进行转义,并且 Kyverno 不会尝试替换值。用 JMESPath 表示法编写的变量也可以使用相同的语法进行转义,例如 {{ request.object.metadata.name }}。

下面的策略中,OTEL_RESOURCE_ATTRIBUTES 的值包含另一个环境变量的引用,例如,$(POD_NAMESPACE)。

apiVersion: kyverno.io/v1
kind: Policy
metadata:
  name: add-otel-resource-env
spec:
  background: false
  rules:
  - name: imbue-pod-spec
    match:
      any:
      - resources:
          kinds:
          - v1/Pod
    mutate:
      patchStrategicMerge:
        spec:
          containers:
          - (name): "?*"
            env:
            - name: NODE_NAME
              value: "mutated_name"
            - name: POD_IP_ADDRESS
              valueFrom:
                fieldRef:
                  fieldPath: status.podIP
            - name: POD_NAME
              valueFrom:
                fieldRef:
                  fieldPath: metadata.name
            - name: POD_NAMESPACE
              valueFrom:
                fieldRef:
                  fieldPath: metadata.namespace
            - name: POD_SERVICE_ACCOUNT
              valueFrom:
                fieldRef:
                  fieldPath: spec.serviceAccountName
            - name: OTEL_RESOURCE_ATTRIBUTES
              value: >-
                k8s.namespace.name=\$(POD_NAMESPACE),
                k8s.node.name=\$(NODE_NAME),
                k8s.pod.name=\$(POD_NAME),
                k8s.pod.primary_ip_address=\$(POD_IP_ADDRESS),
                k8s.pod.service_account.name=\$(POD_SERVICE_ACCOUNT),
                rule_applied=$(./../../../../../../../../name)                

使用如下 Pod 定义,可以对此进行测试。

apiVersion: v1
kind: Pod
metadata:
  name: test-env-vars
spec:
  containers:
  - name: test-container
    image: busybox
    command: ["sh", "-c"]
    args:
    - while true; do
      echo -en '\n';
      printenv OTEL_RESOURCE_ATTRIBUTES;
      sleep 10;
      done;
    env:
    - name: NODE_NAME
      value: "node_name"
    - name: POD_NAME
      valueFrom:
        fieldRef:
          fieldPath: metadata.name
    - name: POD_NAMESPACE
      valueFrom:
        fieldRef:
          fieldPath: metadata.namespace
    - name: POD_IP_ADDRESS
      valueFrom:
        fieldRef:
          fieldPath: status.podIP
  restartPolicy: Never

结果是 OTEL_RESOURCE_ATTRIBUTES 环境变量会被添加到 Pod 中,如下所示:

- name: OTEL_RESOURCE_ATTRIBUTES
      value: k8s.namespace.name=$(POD_NAMESPACE), k8s.node.name=$(NODE_NAME), k8s.pod.name=$(POD_NAME),
        k8s.pod.primary_ip_address=$(POD_IP_ADDRESS), k8s.pod.service_account.name=$(POD_SERVICE_ACCOUNT),
        rule_applied=imbue-pod-spec

AdmissionReview 请求变量

Kyverno 以 webhook 的方式在 Kubernetes 中运行。当 Kubernetes API Server 收到新的请求时(如创建 Pod),API Server将该信息发送给已注册的、用于监听 Pod 创建事件的 webhook。传入的数据会以 AdmissionReview 对象传给 webhook。有四种常用于获取 AdmissionReview 请求中数据属性的方式:

  • {{request.operation}}:正在执行的 API 操作的类型(CREATE、UPDATE、DELETE 或 CONNECT)。

  • {{request.object}}:正在被创建或修改的新对象。对于 DELETE 请求,该对象是null。

  • {{request.oldObject}}:被修改的旧对象。对于 CREATE 和 CONNECT 请求,该对象是null。

  • {{request.userInfo}} :包含有关谁/什么提交了请求的信息,其中包括组和用户名键。

  • {{request.namespace}}:被操作对象的命名空间。

以下是查找此数据的一些示例:

  • 引用资源名称(字符串类型)

{{request.object.metadata.name}}

  • 引用元数据(对象类型)

{{request.object.metadata}}

  • 引用正在创建的新命名空间的名称

{{request.object.name}}

  • 引用提交请求的用户名

{{request.userInfo.username}}

AdmissionReview 中的变量也可以和用户定义的字符串相结合,用于 messages 或其它字段。

  1. 从多个变量构建一个名称(字符串类型)

"ns-owner-{{request.namespace}}-{{request.userInfo.username}}-binding"

让我们看一个如何在 Kyverno 政策中使用此 AdmissionReview 数据的示例。

在下面的 ClusterPolicy 中,我们想知道哪个账户创建了一个给定的 Pod 资源。我们可以使用 AdmissionReview 包含的信息,特别是 username,将这个信息写入 label 中。如下所示:

apiVersion: kyverno.io/v1
kind: ClusterPolicy
metadata:
  name: who-created-this
spec:
  background: false
  rules:
  - name: who-created-this
    match:
      any:
      - resources:
          kinds:
          - Pod
    mutate:
      patchStrategicMerge:
        metadata:
          labels:
            created-by: "{{request.userInfo.username}}"

这个示例会修改传入的 Pod,并将 kubeconfig 中授权的用户信息写入 created-by 标签中。

创建一个简单的 Pod 资源:

kubectl run busybox --image busybox:1.28

查看新创建的 Pod busybox:

kubectl get po busybox --show-labels

NAME       READY   STATUS    RESTARTS   AGE   LABELS
busybox   0/1     Pending   0          25m   created-by=kubernetes-admin,run=busybox

在输出信息中,我们可以看到 Pod 上有一个标签 created-by=kubernetes-admin,kubernetes-admin 就是创建该 Pod 的用户。

来自容器镜像的变量

Kyverno 能从 AdmissionReview 请求中提取镜像数据,并能够在规则上下文中用 map 类型的变量 images 引用这些数据。例如:

{
  "containers": {
    "tomcat": {
      "registry": "https://ghcr.io",
      "name": "tomcat",
      "tag": "9"
    }
  },
  "initContainers": {
    "vault": {
      "registry": "https://ghcr.io",
      "name": "vault",
      "tag": "v3"
    }
  }
}

如果一个 AdmissionReview 请求中定义了 containers 或 initContainers,就可以用下面的方式通过 images 引用这些数据。

引用 tomcat 容器中镜像的属性:

  • 引用 registry URL

{{images.containers.tomcat.registry}}

  • 引用镜像名称

{{images.containers.tomcat.name}}

  • 引用镜像tag

{{images.containers.tomcat.tag}}

  • 引用摘要

{{images.containers.tomcat.digest}}

引用 vault initContainer 中镜像的属性:

  • 引用 registry URL

{{images.initContainers.vault.registry}}

  • 引用镜像名称

{{images.initContainers.vault.name}}

  • 引用镜像tag

{{images.initContainers.vault.tag}}

  • 引用摘要

{{images.initContainers.vault.digest}}

这种相同的模式和镜像变量编排也适用于临时容器。

Kyverno 默认将一个空 registry 设置为 docker.io,并将一个空 tag 设置为 latest。

注意

请注意,对于 JMESPath 中某些字符必须进行转义(如容器名中的-),可以通过使用双引号和双转义字符 \ 来完成转义,例如 {{images.containers."my-container".tag}}。更多信息请参考 JMESPath 格式化

您还可以获取所有容器的镜像属性以进行进一步处理。例如,{{ images.containers.*.name }} 创建了一个包含所有容器名称的列表。

内联变量

可以在 context 中定义变量以供 Kyverno 规则使用。这可以像静态值、另一个变量或嵌套对象一样简单。也可以使用相同的变量名重新定义变量,将使用最后设置的值。下面设置了一个值为 foo 的 context 变量。

    context:
    # 唯一的变量名称
    # 如果用户重新声明一个名称相同的变量,该变量会被重分配
    - name: foodata
      variable:
        # value 定义了变量的值,它可能包含 jmespath 变量或者任何可以用 JSON 对象表示的 YAML 对象。
        # value、default 和 jmespath 是可选的,但必须定义 value 或 jmespath。
        value: "foo"

这个片段给 context 变量设置的值为 request.object.metadata.name。如果未定义 value 字段,jmesPath 的内容将作用于整个上下文。

context:
- name: objName
  variable:
    jmesPath: request.object.metadata.name

变量可以引用其他变量,如下所示。

context:
- name: jpExpression
  variable:
    value: name
- name: objName
  variable:
    value:
      name: "{{ request.object.metadata.name }}"
    jmesPath: "{{ jpExpression }}"

来自外部数据源的变量

一些策略决策需要访问由其他 Kubernetes 控制器或外部应用程序管理的集群资源和数据。 对于这些类型的策略,Kyverno 允许对 Kubernetes API Server进行 HTTP 调用并使用 ConfigMap。

从外部来源获取的数据存储在按规则处理的上下文中,用于由策略引擎评估变量。一旦来自外部源的数据存储在上下文中,就可以像任何其他变量数据一样引用它。

要了解有关 ConfigMap 查找和 API Server 调用的更多信息,请参考 外部数据源

嵌套查找

也可以将 JMESPath 表达式嵌套在另一个表达式中,例如,当混合来自 ConfigMap 和 AdmissionReview 的数据时。通过在另一个中包含一个 JMESPath 表达式,Kyverno 将首先替换内部表达式,然后再构建外部表达式,如下例所示。

apiVersion: kyverno.io/v1
kind: ClusterPolicy
metadata:
  name: resource-annotater
spec:
  background: false
  rules:
  - name: add-resource-annotations
    context:
    - name: LabelsCM
      configMap:
        name: resource-annotater-reference
        namespace: default
    match:
      any:
      - resources:
          kinds:
          - Pod
    mutate:
      patchStrategicMerge:
        metadata:
          annotations:
            foo: "{{LabelsCM.data.{{ request.object.metadata.labels.app }}}}"

在这个示例中,首先以 {{request.object.metadata.labels.app}} 的形式将 AdmissionReview 中的数据收集在内部表达式中,而外部表达式是从名为 LabelsCM 的 ConfigMap 上下文构建的。

评估顺序

Kyverno 策略可以在以下位置使用变量:

  • 规则上下文(context)

  • 规则前置条件(preconditions)

  • 规则定义

    • Validation patterns

    • Validation deny rules

    • Mutate strategic merge patches (patchesStrategicMerge)

    • Generate resource data definitions

match 和 exclude 元素中不支持使用变量。这样规则就可以快速匹配,而无需加载和处理数据。patchesJson6902.path 中也不支持使用变量。

由于变量可以嵌套,因此了解变量的计算顺序很重要。 在准入控制期间,引擎处理规则的方式如下:

  1. 匹配规则集是通过从请求信息创建散列来确定的,以根据规则和资源类型检索所有匹配规则。

  2. 每个匹配的规则都经过进一步处理,以全面评估匹配和检索条件。

  3. 然后评估规则上下文并从数据源加载变量。

  4. 然后检查前置条件。

  5. 处理规则体。

这种排序使得在定义 context 时可以使用请求数据,并在前置条件中使用上下文变量。在 context 本身中,每个变量都按照定义的顺序进行评估。因此,如果需要,变量可以引用先前的变量,但尝试使用后续定义将导致错误。

JMESPath 自定义函数

除了 JMESPath 提供的内置功能列表之外,Kyverno 通过添加其他几个功能来增强这些功能,这使得制定 Kyverno 策略更加容易。

通用

base64_decode(string) string
base64_encode(string) string
compare(string, string) integer
equal_fold(string, string) bool
label_match(object, object) bool (object arguments must be enclosed in backticks; ex. `{{request.object.spec.template.metadata.labels}}`)
parse_json(string) any (decodes a valid JSON encoded string to the appropriate type. Opposite of `to_string` function)
parse_yaml(string) any
path_canonicalize(string) string
pattern_match(pattern string, string|number) bool ('*' matches zero or more alphanumeric characters, '?' matches a single alphanumeric character)
regex_match(string, string|number) bool
regex_replace_all(regex string, src string|number, replace string|number) string (converts all parameters to string)
regex_replace_all_literal(regex string, src string|number, replace string|number) string (converts all parameters to string)
replace(str string, old string, new string, n float64) string
replace_all(str string, old string, new string) string
semver_compare(string, string) bool (Use operators [>, <, etc] with string inputs for comparison logic)
split(str string, sep string) []string
time_since(<layout>, <time1>, <time2>) string (all inputs as string)
to_upper(string) string
to_lower(string) string
trim(str string, cutset string) string
truncate(str string, length float64) string (length argument must be enclosed in backticks; ex. "{{request.object.metadata.name | truncate(@, `9`)}}")

计算

add(number, number) number
add(quantity|number, quantity|number) quantity (returns a quantity if any of the parameters is a quantity)
add(duration|number, duration|number) duration (returns a duration if any of the parameters is a duration)
subtract(number, number) number
subtract(quantity|number, quantity|number) quantity (returns a quantity if any of the parameters is a quantity)
subtract(duration|number, duration|number) duration (returns a duration if any of the parameters is a duration)
multiply(number, number) number
multiply(quantity|number, quantity|number) quantity (returns a quantity if any of the parameters is a quantity)
multiply(duration|number, duration|number) duration (returns a duration if any of the parameters is a duration)
divide(quantity|number, quantity|number) quantity|number (returns a quantity if exactly one of the parameters is a quantity, else a number; the divisor must be non-zero)
divide(duration|number, duration|number) duration|number (returns a duration if exactly one of the parameters is a duration, else a number; the divisor must be non-zero)
modulo(number, number) number
modulo(quantity|number, quantity|number) quantity (returns a quantity if any of the parameters is a quantity; the divisor must be non-zero)
modulo(duration|number, duration|number) duration (returns a duration if any of the parameters is a duration; the divisor must be non-zero)

注意

JMESPath 算术函数适用于标量(例如,10)、资源数量(例如,10Mi)和持续时间(例如,10h)。如果输入是标量,则必须将其括在反引号中,以便将参数视为数字。资源数量和持续时间用单引号括起来,被视为字符串。

特殊变量 {{@}} 可用于引用给定字段中的当前值,这对于源值很有用。

要查找其中一些函数的实际示例,请参阅 Kyverno 策略库。有关每个自定义过滤器的更完整信息以及示例,请参阅此处的 JMESPath 页面。

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 159,569评论 4 363
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 67,499评论 1 294
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 109,271评论 0 244
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 44,087评论 0 209
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,474评论 3 287
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,670评论 1 222
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,911评论 2 313
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,636评论 0 202
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,397评论 1 246
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,607评论 2 246
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 32,093评论 1 261
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,418评论 2 254
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 33,074评论 3 237
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,092评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,865评论 0 196
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,726评论 2 276
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,627评论 2 270

推荐阅读更多精彩内容

  • 1.weak和assign区别 修饰变量类型的区别: weak 只可以修饰对象。如果修饰基本数据类型,编译器会报错...
    coderjon阅读 966评论 0 1
  • github排名https://github.com/trending,github搜索:https://gith...
    小米君的demo阅读 4,180评论 2 38
  • 用到的组件 1、通过CocoaPods安装 2、第三方类库安装 3、第三方服务 友盟社会化分享组件 友盟用户反馈 ...
    SunnyLeong阅读 14,500评论 1 180
  • 控制器管理的 Pod: 生产环境中可以用控制器创建和管理多个 pod。控制器在 pod 失败的情况下可以处理副本、...
    菜头_355f阅读 480评论 0 1
  • 如何实现蓝绿部署? 蓝绿部署中,一共有两套系统:一套是正在提供服务系统,标记为“绿色”;另一套是准备发布的系统,标...
    菜头_355f阅读 10,819评论 1 8