kubernetes 请考虑允许CEL验证嵌入式资源的metadata.namespace字段,

6yjfywim  于 6个月前  发布在  Kubernetes
关注(0)|答案(7)|浏览(72)

为了限制用户在创建CRD时只能设置嵌入资源的名称/命名空间/gvk,可以在metadata.namespace字段上添加CEL验证。以下是一个示例:

package main

import (
 "fmt"
 "k8s.io/apiextensions-apiserver/pkg/apiserver/schema"
)

func main() {
 // 定义一个自定义的CEL验证规则,要求namespace字段必须是字符串类型且不能为空
 customValidationRule := schema.NewFieldPath("metadata", "namespace").String().NotEmpty()

 // 使用WithTypeAndObjectMeta确保kind、apiVersion和metadata.name以及metadata.generateName属性被指定,如果需要则进行浅拷贝
 withTypeAndObjectMeta := schema.WithTypeAndObjectMeta(customValidationRule)

 // 创建一个新的结构体,包含我们刚刚定义的验证规则
 newStruct := &schema.Structural{
  Generic:        schema.Generic{Type: "object"},
  Extensions:      schema.Extensions{},
  ValueValidation: schema.ValueValidation{},
 }
 newStruct.Properties["metadata"] = schema.Structural{
  Generic:        schema.Generic{Type: "object"},
  Properties: map[string]schema.Structural{
   "name":         withTypeAndObjectMeta,
   "generateName": withTypeAndObjectMeta,
  },
 }

 // 输出新的结构体,可以看到已经包含了我们的自定义验证规则
 fmt.Println(newStruct)
}

这段代码定义了一个自定义的CEL验证规则,要求metadata.namespace字段必须是字符串类型且不能为空。然后,我们使用这个规则创建了一个新的结构体,并将其添加到metadata字段中。最后,输出新的结构体,可以看到已经包含了我们的自定义验证规则。

eqfvzcg8

eqfvzcg82#

/triage已接受
添加一些背景信息:我们目前仅限制对apiVersion、kind、metadata.name和metadata.generateName的访问,正如当前文档所述:

The apiVersion, kind, metadata.name and metadata.generateName are always accessible from the root of the object and from any x-kubernetes-embedded-resource annotated objects. No other metadata properties are accessible.

背后的考虑主要是我们希望元数据在类型之间保持一致。
作为此问题的替代解决方案是 ValidatingAdmissionPolicy ,它将允许您访问namespace。

cmssoen2

cmssoen23#

是的,我可以使用ValidatingAdmissionPolicy,但说实话,如果这是解决方案,那么在CRD级别上限制这个有什么意义呢?如果我可以使用VAP验证任何我想验证的内容?
如果可能的话,我希望这些验证策略的来源靠近我的代码库中的Go结构(如果我有访问命名空间的话),而不是“远”地放在VAP中的helm图表里,这样可能会意外地与CRD中的字段失去同步。

rjzwgtxy

rjzwgtxy4#

建议:允许在CRD嵌入式资源中对metadata.namespace进行CEL验证
概述:
目前,CRD嵌入式资源缺乏对metadata.namespace字段的CEL验证。这阻碍了用户在不同CR示例中为嵌入式资源寻求稳定的身份标识。

提议的解决方案:
将CEL验证扩展到嵌入式资源中的metadata.namespace。这与其他元数据字段的做法保持一致。

好处:
稳定的身份标识:确保嵌入式资源具有稳定的身份标识,对于多租户或跨命名空间资源管理等场景至关重要。
操作效率:使用户能够在依赖稳定身份配置的应用中维持可预测性和可靠性。

可行性和考虑因素:
实施:讨论可行性,同时考虑对工作流程、向后兼容性和实施工作的影响。
挑战:承认挑战和潜在的权衡,例如增加的复杂性或依赖关系。
解决关注点:
替代方案:讨论替代方案,包括ValidatingAdmissionPolicy (VAP),并突出其优缺点。
社区反馈:鼓励社区就该提案提供反馈和多样化的观点。

dkqlctbz

dkqlctbz5#

这确实感觉有点奇怪,因为 x-kubernetes-embedded-resource 并不排除 CRD 作者在同一个子模式上放置进一步的约束。我尝试编写一个强制元数据.namespace 在嵌入式资源上的不可变性的模式,结果是:

apiVersion: apiextensions.k8s.io/v1
kind: CustomResourceDefinition
metadata:
  name: foos.example.com
spec:
  group: example.com
  versions:
    - name: v1
      served: true
      storage: true
      schema:
        openAPIV3Schema:
          type: object
          properties:
            spec:
              type: object
              properties:
                embedme:
                  type: object
                  x-kubernetes-embedded-resource: true
                  x-kubernetes-preserve-unknown-fields: true
                  required:
                  - metadata
                  properties:
                    apiVersion:
                      type: string
                      x-kubernetes-validations:
                      - rule: "self == oldSelf"
                        message: apiVersion is immutable
                    kind:
                      type: string
                      x-kubernetes-validations:
                      - rule: "self == oldSelf"
                        message: kind is immutable
                    metadata:
                      type: object
                      required:
                      - namespace
                      - name
                      properties:
                        name:
                          type: string
                          x-kubernetes-validations:
                          - rule: "self == oldSelf"
                            message: name is immutable
                        generateName:
                          type: string
                        namespace:
                          type: string
                          x-kubernetes-validations:
                          - rule: "self == oldSelf"
                            message: namespace is immutable
  scope: Cluster
  names:
    plural: foos
    singular: foo
    kind: Foo

这似乎对必须命名空间化的嵌入式资源有效。但它有两个原因显得很别扭:

  1. 除非 metadata.name、metadata.generateName、metadata.namespace、apiVersion 和 kind 都在模式中用字符串类型指定,否则附加到 metadata.namespace 的 CEL 规则不会被执行。这显然是因为 WithTypeAndObjectMeta 在这些情况下会完全覆盖元数据子模式,然后进行 CEL 验证。在我看来,这像是个 bug,因为其他 OpenAPI 验证器在没有明确将所有这些字段包含在模式中的情况下应用(要么 CEL 规则应该被执行,要么如果其中一个模式将 x-kubernetes-validations 附加到嵌入式资源的 metadata 属性上,那么该 CRD 就是无效的)。
  2. 元数据的字段对任何元数据本身上的 CEL 规则都不可见,阻止了像 has(self.namespace) == has(oldSelf.namespace) 这样的表情式。如果嵌入式资源必须始终有命名空间,那么可以在不使用 CEL 扩展的情况下使命名空间成为必需字段。
  3. apiVersion 和 kind 是隐式必需的,但 metadata、metadata.name 和 metadata.namespace 不是。
  4. 如果包含嵌入式资源的字段是可选的,客户端可以通过一系列更新有效地更改不可变字段,首先省略嵌入式资源字段,然后彻底替换它。
  5. 我预计无法让 controller-gen 生成这样的模式。
uinbv5nw

uinbv5nw6#

这似乎对必须命名空间的嵌入式资源有效。但它有两个尴尬的地方:
如果我理解正确,(1)、(2)和(3)都导致与根资源相比,验证质量较差。我很想看到这一点得到改进。

我的笔记:
(1) - 这似乎是个bug。我们在根资源上看不到,因为我们有内置的不可变性验证。这也是OpenAPI值验证的问题吗?(例如正则表达式规则或长度规则)?
(2) - 能够指定是否需要命名空间显然是有用的。我们在根资源验证中可以免费获得这一点。
(3) - 正确的行为应该是需要name或generateName。我认为?
(4) - 我对此不那么惊讶。如果有人不想让嵌入式资源完全被替换,他们需要在上面有一个过渡规则,以匹配他们的预期。.
(5) - ack

d7v8vwbk

d7v8vwbk7#

@aerfio 的解决方法是将所有CEL规则声明在嵌入式资源之上:

apiVersion: apiextensions.k8s.io/v1
kind: CustomResourceDefinition
metadata:
  name: withembeddeds.stable.example.com
spec:
  group: stable.example.com
  versions:
    - name: v1
      served: true
      storage: true
      schema:
        openAPIV3Schema:
          type: object
          properties:
            spec:
              type: object
              required:
                - embedme
              x-kubernetes-validations:
                - rule: 'oldSelf.embedme.kind == self.embedme.kind'
                - rule: 'oldSelf.embedme.apiVersion == self.embedme.apiVersion'
                - rule: 'oldSelf.embedme.metadata.name == self.embedme.metadata.name'
                - rule: 'has(self.embedme.metadata.__namespace__)'
                - rule: 'oldSelf.embedme.metadata.__namespace__ == self.embedme.metadata.__namespace__'
              properties:
                embedme:
                  type: object
                  x-kubernetes-embedded-resource: true
                  x-kubernetes-preserve-unknown-fields: true
                  required:
                  - apiVersion
                  - kind
                  - metadata
                  properties:
                    apiVersion:
                      type: string
                    kind:
                      type: string
                    metadata:
                      type: object
                      required:
                      - namespace
                      - name
                      properties:
                        name:
                          type: string
                        generateName:
                          type: string
                        namespace:
                          type: string
  scope: Namespaced
  names:
    plural: withembeddeds
    singular: withembedded
    kind: WithEmbedded

请注意,所有元数据字段必须显式声明。我不确定你是否在使用kubebuilder时能得到这个。
此外,确切的验证规则将取决于:

  • 如果你想要命名空间资源、全局范围资源或两者兼有。
  • 如果你想要支持generateName、name或两者兼有。
  • 你希望如何处理从资源中完全删除嵌入式资源的情况。

我的示例假设嵌入式资源是必需的、命名空间范围的,并使用name(而不是generateName)。

相关问题