Policy: organization-sa-namespaces

Ensure that all namespaces created by organization serviceaccounts have a label appuio.io/organization which isn’t empty.
Category

Namespace Ownership

Minimum Kyverno version

v1

Subject

APPUiO Organizations

Policy types

mutate, validate

Implementation

component/namespace-policies.jsonnet

This policy will:

  • Check that each namespace created by a serviceaccount without cluster-admin permissions has a label appuio.io/organization which isn’t empty.

  • Check that the creating serviceaccount is part of the organization it tries to create a namespace for.

The serviceaccount’s organization membership is checked by:

  • Fetching the serviceaccount’s namespace

  • Comparing that namespace’s appuio.io/organization label value with the request’s appuio.io/organization label value.

If the label appuio.io/organization is missing or empty or the serviceaccount’s organization doesn’t match the request’s organization the request is denied.

Serviceaccounts which match an entry of component parameter bypassNamespaceRestrictions are allowed to bypass the policy.

Policy Definition

apiVersion: kyverno.io/v1
kind: ClusterPolicy
metadata:
  annotations:
    policies.kyverno.io/category: Namespace Ownership
    policies.kyverno.io/description: |
      This policy will:

      - Check that each namespace created by a serviceaccount without cluster-admin permissions has a label appuio.io/organization which isn't empty.
      - Check that the creating serviceaccount is part of the organization it tries to create a namespace for.

      The serviceaccount's organization membership is checked by:

      - Fetching the serviceaccount's namespace
      - Comparing that namespace's `appuio.io/organization` label value with the request's `appuio.io/organization` label value.

      If the label `appuio.io/organization` is missing or empty or the serviceaccount's organization doesn't match the request's organization the request is denied.

      Serviceaccounts which match an entry of xref:references/parameters#_bypassnamespacerestrictions[component parameter `bypassNamespaceRestrictions`] are allowed to bypass the policy.
    policies.kyverno.io/jsonnet: component/namespace-policies.jsonnet
    policies.kyverno.io/minversion: v1
    policies.kyverno.io/subject: APPUiO Organizations
    policies.kyverno.io/title: Ensure that all namespaces created by organization
      serviceaccounts have a label `appuio.io/organization` which isn't empty.
  labels:
    app.kubernetes.io/component: appuio-cloud
    app.kubernetes.io/managed-by: commodore
    app.kubernetes.io/name: appuio-cloud
    name: organization-sa-namespaces
  name: organization-sa-namespaces
spec:
  background: false
  rules:
    - context:
        - apiCall:
            jmesPath: '@'
            urlPath: /api/v1/namespaces/{{serviceAccountNamespace}}
          name: saNamespace
      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: cluster-logging-operator
                namespace: openshift-logging
              - kind: ServiceAccount
                name: olm-operator-serviceaccount
                namespace: openshift-operator-lifecycle-manager
              - 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
      mutate:
        patchStrategicMerge:
          metadata:
            labels:
              +(appuio.io/organization): '{{saNamespace.metadata.labels."appuio.io/organization"
                || ""}}'
      name: add-organization
      preconditions:
        all:
          - key: '{{serviceAccountName}}'
            operator: NotEquals
            value: ''
    - 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: cluster-logging-operator
                namespace: openshift-logging
              - kind: ServiceAccount
                name: olm-operator-serviceaccount
                namespace: openshift-operator-lifecycle-manager
              - 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
      name: has-organization
      preconditions:
        all:
          - key: '{{serviceAccountName}}'
            operator: NotEquals
            value: ''
      validate:
        message: Namespace must have organization
        pattern:
          metadata:
            labels:
              appuio.io/organization: ?*
    - context:
        - apiCall:
            jmesPath: '@'
            urlPath: /api/v1/namespaces/{{serviceAccountNamespace}}
          name: saNamespace
      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: cluster-logging-operator
                namespace: openshift-logging
              - kind: ServiceAccount
                name: olm-operator-serviceaccount
                namespace: openshift-operator-lifecycle-manager
              - 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
      name: is-in-organization
      preconditions:
        all:
          - key: '{{serviceAccountName}}'
            operator: NotEquals
            value: ''
          - key: '{{request.object.metadata.labels."appuio.io/organization" || ""}}'
            operator: NotEquals
            value: ''
      validate:
        deny:
          conditions:
            - key: '{{request.object.metadata.labels."appuio.io/organization"}}'
              operator: NotEquals
              value: '{{saNamespace.metadata.labels."appuio.io/organization"}}'
        message: Creating namespace for {{request.object.metadata.labels."appuio.io/organization"}}
          but {{serviceAccountName}} is not in organization
  validationFailureAction: enforce