Policy: check-namespace-quota

Check and enforce namespace quotas for organizations
Category

Namespace Management

Minimum Kyverno version

v1

Subject

APPUiO Organizations

Policy types

validate

Implementation

component/namespace-quota.jsonnet

This policy will deny creation of the new namespace if the number of existing namespaces for the requester’s organization is greater or equal a certain number.

The number of allowed namespaces is either the default defined in this component, or it can be overridden for a specific organization.

To create an override, create a config map in the component namespace with name pattern override-<organization-name> with .data.namespaceOverride being the number. For example, to set the namespace quota for organization foo to 4:

kubectl -n appuio-cloud create cm override-foo --from-literal=namespaceQuota=4

The default number of allowed namespaces per organization is configured with component parameter maxNamespaceQuota.

Users which match an entry of component parameter bypassNamespaceRestrictions are allowed to bypass this policy.

Policy Definition

apiVersion: kyverno.io/v1
kind: ClusterPolicy
metadata:
  annotations:
    pod-policies.kyverno.io/autogen-controllers: none
    policies.kyverno.io/category: Namespace Management
    policies.kyverno.io/description: 'This policy will deny creation of the new namespace
      if the number of existing namespaces for the requester''s organization is greater
      or equal a certain number.


      The number of allowed namespaces is either the default defined in this component,
      or it can be overridden for a specific organization.


      To create an override, create a config map in the component namespace with name
      pattern `override-<organization-name>` with `.data.namespaceOverride` being
      the number.

      For example, to set the namespace quota for organization foo to `4`:


      [source,bash]

      ----

      kubectl -n appuio-cloud create cm override-foo --from-literal=namespaceQuota=4

      ----


      The default number of allowed namespaces per organization is configured with
      xref:references/parameters#_maxnamespacequota[component parameter `maxNamespaceQuota`].


      Users which match an entry of xref:references/parameters#_bypassnamespacerestrictions[component
      parameter `bypassNamespaceRestrictions`] are allowed to bypass this policy.

      '
    policies.kyverno.io/jsonnet: component/namespace-quota.jsonnet
    policies.kyverno.io/minversion: v1
    policies.kyverno.io/subject: APPUiO Organizations
    policies.kyverno.io/title: Check and enforce namespace quotas for organizations
  labels:
    app.kubernetes.io/component: appuio-cloud
    app.kubernetes.io/managed-by: commodore
    app.kubernetes.io/name: appuio-cloud
    name: check-namespace-quota
  name: check-namespace-quota
spec:
  background: false
  rules:
    - context:
        - apiCall:
            jmesPath: items[?metadata.name == 'override-{{request.object.metadata.labels."appuio.io/organization"}}'].data.namespaceQuota
              | [0]
            urlPath: /api/v1/namespaces/appuio-cloud/configmaps
          name: override
        - apiCall:
            jmesPath: items[?metadata.labels."appuio.io/organization" == '{{request.object.metadata.labels."appuio.io/organization"}}']
              | length(@)
            urlPath: /api/v1/namespaces
          name: nsCount
      exclude:
        any:
          - clusterRoles:
              - cluster-admin
              - cluster-image-registry-operator
              - cluster-node-tuning-operator
              - kyverno:generatecontroller
              - kyverno:policycontroller
              - multus-admission-controller-webhook
              - openshift-dns-operator
              - openshift-ingress-operator
              - syn-admin
              - syn-argocd-application-controller
              - syn-argocd-server
              - system:controller:generic-garbage-collector
              - system:controller:operator-lifecycle-manager
              - system:master
              - system:openshift:controller:namespace-security-allocation-controller
              - system:openshift:controller:podsecurity-admission-label-syncer-controller
          - subjects:
              - kind: ServiceAccount
                name: argocd-application-controller
                namespace: argocd
              - kind: ServiceAccount
                name: namespace-openshift-config-2c8343f13594d63-manager
                namespace: syn-resource-locker
              - kind: ServiceAccount
                name: namespace-default-d6a0af6dd07e8a3-manager
                namespace: syn-resource-locker
              - kind: ServiceAccount
                name: namespace-openshift-monitoring-c4273dc15ddfdf7-manager
                namespace: syn-resource-locker
      match:
        all:
          - resources:
              kinds:
                - Namespace
              selector:
                matchExpressions:
                  - key: appuio.io/organization
                    operator: Exists
      name: check-namespace-count
      preconditions:
        all:
          - key: '{{request.operation}}'
            operator: In
            value:
              - CREATE
      validate:
        deny:
          conditions:
            any:
              - key: '{{nsCount}}'
                operator: GreaterThanOrEquals
                value: '{{override || `3`}}'
        message: 'You cannot create more than {{override || `3`}} namespaces for organization
          ''{{request.object.metadata.labels."appuio.io/organization"}}''.

          Please contact support to have your quota raised.'
    - context:
        - apiCall:
            jmesPath: metadata.annotations."appuio.io/default-organization" || ""
            urlPath: /apis/user.openshift.io/v1/users/{{request.userInfo.username}}
          name: organization
        - apiCall:
            jmesPath: items[?metadata.name == 'override-{{organization}}'].data.namespaceQuota
              | [0]
            urlPath: /api/v1/namespaces/appuio-cloud/configmaps
          name: override
        - apiCall:
            jmesPath: items[?metadata.labels."appuio.io/organization" == '{{organization}}']
              | length(@)
            urlPath: /api/v1/namespaces
          name: nsCount
      exclude:
        any:
          - clusterRoles:
              - cluster-admin
              - cluster-image-registry-operator
              - cluster-node-tuning-operator
              - kyverno:generatecontroller
              - kyverno:policycontroller
              - multus-admission-controller-webhook
              - openshift-dns-operator
              - openshift-ingress-operator
              - syn-admin
              - syn-argocd-application-controller
              - syn-argocd-server
              - system:controller:generic-garbage-collector
              - system:controller:operator-lifecycle-manager
              - system:master
              - system:openshift:controller:namespace-security-allocation-controller
              - system:openshift:controller:podsecurity-admission-label-syncer-controller
          - subjects:
              - kind: ServiceAccount
                name: argocd-application-controller
                namespace: argocd
              - kind: ServiceAccount
                name: namespace-openshift-config-2c8343f13594d63-manager
                namespace: syn-resource-locker
              - kind: ServiceAccount
                name: namespace-default-d6a0af6dd07e8a3-manager
                namespace: syn-resource-locker
              - kind: ServiceAccount
                name: namespace-openshift-monitoring-c4273dc15ddfdf7-manager
                namespace: syn-resource-locker
      match:
        all:
          - resources:
              kinds:
                - ProjectRequest
      name: check-project-count
      preconditions:
        all:
          - key: '{{request.operation}}'
            operator: In
            value:
              - CREATE
      validate:
        deny:
          conditions:
            any:
              - key: '{{nsCount}}'
                operator: GreaterThanOrEquals
                value: '{{override || `3`}}'
        message: 'You cannot create more than {{override || `3`}} namespaces for organization
          ''{{organization}}''.

          Please contact support to have your quota raised.'
  validationFailureAction: enforce