【问题标题】:How to forbid Pods in Namespaces without ResourceQuota using Gatekeeper?如何使用 Gatekeeper 在没有 ResourceQuota 的情况下禁止命名空间中的 Pod?
【发布时间】:2021-07-05 09:22:04
【问题描述】:

我想禁止在没有ResourceQuota 的命名空间中创建 Pod。如果可能的话,我希望 Gatekeeper 在允许创建 Pod 之前确保有一个设置 limits.cpulimits.memory 的 ResourceQuota。

我已经创建了以下配置,但它们并没有解决我的问题:

模板

apiVersion: templates.gatekeeper.sh/v1beta1 
kind: ConstraintTemplate 
metadata: 
  name: k8sresoucequota 
spec:
  crd:
    spec:
      names:
        kind: k8sResouceQuota
  targets:
    - target: admission.k8s.gatekeeper.sh
      rego: |
        package k8sresoucequota

        violation[{"msg": msg}] {
          input.request.kind.kind == "Pod"
          requestns := input.request.object.metadata.namespace
          existingrqs := {e | e := data.inventory.namespace[requestns]["v1beta1"]["ResourceQuota"].metadata.name}
          not ns_exists(requestns,existingrqs)
          msg := sprintf("container <%v> could not be created because the <%v> namespace does not have ResourceQuotas defined", [input.request.object.metadata.name,input.request.object.metadata.namespace])
        }

        ns_exists(ns,arr) {
          arr[_] = ns
        }

约束

apiVersion: constraints.gatekeeper.sh/v1beta1
kind: k8sResouceQuota
metadata:
  name: namespace-must-have-resourcequota
spec:
  match:
    kinds:
      - apiGroups: [""]
        kinds: ["Pod"]
    excludedNamespaces:
      - kube-system
      - kube-public
      - kube-node-lease
      - default
      - gatekeeper-system
      - kubernetes-dashboard

sync.yaml

apiVersion: config.gatekeeper.sh/v1alpha1
kind: Config
metadata:
  name: config
  namespace: "gatekeeper-system"
spec:
  sync:
    syncOnly:
      - group: ""
        version: "v1beta1"
        kind: "Pod"
      - group: ""
        version: "v1beta1"
        kind: "Namespace"
      - group: ""
        version: "v1beta1"
        kind: "ResourceQuota"

【问题讨论】:

    标签: kubernetes open-policy-agent rego


    【解决方案1】:

    第 1 部分:“没有与命名空间同名的 ResourceQuota”

    让我们一一浏览你的 Rego 的这三行。

    requestns := input.request.object.metadata.namespace
    existingrqs := {e | e := data.inventory.namespace[requestns]["v1beta1"]["ResourceQuota"].metadata.name}
    not ns_exists(requestns,existingrqs)
    
    1. 此行获取包含正在评估的 Pod 的命名空间的名称。
    requestns := input.request.object.metadata.namespace
    
    1. 此行无效。或者更确切地说,它将返回一个空集。
    existingrqs := {e | e := data.inventory.namespace[requestns]["v1beta1"]["ResourceQuota"].metadata.name}
    

    我假设您想说的是“在与 Pod 相同的命名空间中获取每个 ResourceQuota 的名称。

    回想一下the format of datadata.inventory.namespace[&lt;namespace&gt;][groupVersion][&lt;kind&gt;][&lt;name&gt;]。所以真的应该是:

    existingrqs := {e | e := data.inventory.namespace[requestns]["v1beta1"]["ResourceQuota"][_].metadata.name
    

    这将遍历 Pod 命名空间中的所有 ResourceQuota,并创建一个包含所有名称的集合。

    1. 您已将其拆分为自己的函数 (ns_exists),但您似乎正在尝试查找是否存在与命名空间同名的 ResourceQuota。相反,您应该使用:
    not existingrqs[requestns]
    

    如果存在同名的 ResourceQuota,则此语句将评估为 false,如果不存在则评估为 true。但这实际上比我们需要的要多。我们只关心 ResourceQuota 是否存在。我们可以将第 2 行和第 3 行合并为:

    not data.inventory.namespace[requestns]["v1beta1"]["ResourceQuota"][requestns]
    

    如果缺少 ResourceQuota,这将评估为 true,如果存在这样的 ResourceQuota,则评估为 false

    完成的Rego应该是:

    package k8sresoucequota
    
    violation[{"msg": msg}] {
      input.request.kind.kind == "Pod"
      requestns := input.request.object.metadata.namespace
      not data.inventory.namespace[requestns]["v1beta1"]["ResourceQuota"][requestns]
      msg := sprintf("container <%v> could not be created because the <%v> namespace does not have ResourceQuotas defined", [input.request.object.metadata.name,input.request.object.metadata.namespace])
    }
    

    在英语中,如果对象是 Pod,并且 Namespace 确实包含与 Namespace 同名的 ResourceQuota,这将造成违规。

    第 2 部分:“ResourceQuota 设置 limits.cpu 和 limits.memory”

    对于 Rego,我们使用增量规则来创建 OR 条件。尽管可能,但它被认为是一种反模式,可以规避 Rego 函数中的所有语句都被 AND-ed 在一起。所以我们需要一个不同的违规来检查 ResourceQuota 是否设置了 limits.cpulimits.memory

    violation[{"msg": msg}] {
      input.request.kind.kind == "Pod"
      requestns := input.request.object.metadata.namespace
      data.inventory.namespace[requestns]["v1beta1"]["ResourceQuota"][requestns]
      rq := data.inventory.namespace[requestns]["v1beta1"]["ResourceQuota"][requestns]
      not defines_limits(rq)
      msg := sprintf("container <%v> could not be created because the <%v> namespace does not enforce limits.cpu or limits.memory", [input.request.object.metadata.name,input.request.object.metadata.namespace])
    }
    
    defines_limits(rq) {
      rq.limits.cpu
    }
    
    defines_limits(rq) {
      rq.limits.memory
    }
    
    

    此违规检查:

    1. 存在所需名称的 ResourceQuota。
    2. ResourceQuota 未能设置limits.cpulimits.memory 之一。也就是说,我们找到的 ResourceQuota 必须同时设置才能允许创建 Pod。

    This answer 很好地解释了增量规则的工作原理。

    【讨论】:

      猜你喜欢
      • 2011-02-18
      • 2020-10-25
      • 2021-07-02
      • 2014-10-09
      • 1970-01-01
      • 2011-11-03
      • 1970-01-01
      • 1970-01-01
      • 2018-09-13
      相关资源
      最近更新 更多