From 48fe8ce9ccdd2fc7ef34bd3a5fdc436782425ccc Mon Sep 17 00:00:00 2001 From: Jaydip Gabani Date: Wed, 22 May 2024 21:17:14 +0000 Subject: [PATCH 1/7] adding cel for psp/volume and pss/selinux Signed-off-by: Jaydip Gabani --- .../selinux/1.1.0/artifacthub-pkg.yml | 22 ++ .../selinux/1.1.0/kustomization.yaml | 2 + .../samples/psp-selinux-v2/constraint.yaml | 15 ++ .../psp-selinux-v2/disallowed_ephemeral.yaml | 16 ++ .../psp-selinux-v2/example_allowed.yaml | 16 ++ .../psp-selinux-v2/example_disallowed.yaml | 16 ++ .../1.1.0/samples/psp-selinux-v2/update.yaml | 21 ++ .../selinux/1.1.0/suite.yaml | 25 ++ .../selinux/1.1.0/template.yaml | 198 +++++++++++++++ .../volumes/1.1.0/artifacthub-pkg.yml | 22 ++ .../volumes/1.1.0/kustomization.yaml | 2 + .../samples/psp-volume-types/constraint.yaml | 20 ++ .../psp-volume-types/example_allowed.yaml | 23 ++ .../psp-volume-types/example_disallowed.yaml | 24 ++ .../samples/psp-volume-types/update.yaml | 29 +++ .../volumes/1.1.0/suite.yaml | 21 ++ .../volumes/1.1.0/template.yaml | 78 ++++++ .../pod-security-policy/selinux/template.yaml | 204 ++++++++++------ .../pod-security-policy/volumes/template.yaml | 64 +++-- .../selinux/constraint.tmpl | 22 +- src/pod-security-policy/selinux/src.cel | 49 ++++ .../volumes/constraint.tmpl | 18 +- src/pod-security-policy/volumes/src.cel | 9 + website/docs/validation/selinux.md | 228 +++++++++++------- website/docs/validation/volumes.md | 76 +++--- 25 files changed, 988 insertions(+), 232 deletions(-) create mode 100644 artifacthub/library/pod-security-policy/selinux/1.1.0/artifacthub-pkg.yml create mode 100644 artifacthub/library/pod-security-policy/selinux/1.1.0/kustomization.yaml create mode 100644 artifacthub/library/pod-security-policy/selinux/1.1.0/samples/psp-selinux-v2/constraint.yaml create mode 100644 artifacthub/library/pod-security-policy/selinux/1.1.0/samples/psp-selinux-v2/disallowed_ephemeral.yaml create mode 100644 artifacthub/library/pod-security-policy/selinux/1.1.0/samples/psp-selinux-v2/example_allowed.yaml create mode 100644 artifacthub/library/pod-security-policy/selinux/1.1.0/samples/psp-selinux-v2/example_disallowed.yaml create mode 100644 artifacthub/library/pod-security-policy/selinux/1.1.0/samples/psp-selinux-v2/update.yaml create mode 100644 artifacthub/library/pod-security-policy/selinux/1.1.0/suite.yaml create mode 100644 artifacthub/library/pod-security-policy/selinux/1.1.0/template.yaml create mode 100644 artifacthub/library/pod-security-policy/volumes/1.1.0/artifacthub-pkg.yml create mode 100644 artifacthub/library/pod-security-policy/volumes/1.1.0/kustomization.yaml create mode 100644 artifacthub/library/pod-security-policy/volumes/1.1.0/samples/psp-volume-types/constraint.yaml create mode 100644 artifacthub/library/pod-security-policy/volumes/1.1.0/samples/psp-volume-types/example_allowed.yaml create mode 100644 artifacthub/library/pod-security-policy/volumes/1.1.0/samples/psp-volume-types/example_disallowed.yaml create mode 100644 artifacthub/library/pod-security-policy/volumes/1.1.0/samples/psp-volume-types/update.yaml create mode 100644 artifacthub/library/pod-security-policy/volumes/1.1.0/suite.yaml create mode 100644 artifacthub/library/pod-security-policy/volumes/1.1.0/template.yaml create mode 100644 src/pod-security-policy/selinux/src.cel create mode 100644 src/pod-security-policy/volumes/src.cel diff --git a/artifacthub/library/pod-security-policy/selinux/1.1.0/artifacthub-pkg.yml b/artifacthub/library/pod-security-policy/selinux/1.1.0/artifacthub-pkg.yml new file mode 100644 index 000000000..ca721aa92 --- /dev/null +++ b/artifacthub/library/pod-security-policy/selinux/1.1.0/artifacthub-pkg.yml @@ -0,0 +1,22 @@ +version: 1.1.0 +name: k8spspselinuxv2 +displayName: SELinux V2 +createdAt: "2024-05-20T18:10:16Z" +description: Defines an allow-list of seLinuxOptions configurations for pod containers. Corresponds to a PodSecurityPolicy requiring SELinux configs. For more information, see https://kubernetes.io/docs/concepts/policy/pod-security-policy/#selinux +digest: eba35fa7bc8ccf1110732549d7eeabaee17bc8d3f100aac7cba42913578285a2 +license: Apache-2.0 +homeURL: https://open-policy-agent.github.io/gatekeeper-library/website/selinux +keywords: + - gatekeeper + - open-policy-agent + - policies +readme: |- + # SELinux V2 + Defines an allow-list of seLinuxOptions configurations for pod containers. Corresponds to a PodSecurityPolicy requiring SELinux configs. For more information, see https://kubernetes.io/docs/concepts/policy/pod-security-policy/#selinux +install: |- + ### Usage + ```shell + kubectl apply -f https://raw.githubusercontent.com/open-policy-agent/gatekeeper-library/master/artifacthub/library/pod-security-policy/selinux/1.1.0/template.yaml + ``` +provider: + name: Gatekeeper Library diff --git a/artifacthub/library/pod-security-policy/selinux/1.1.0/kustomization.yaml b/artifacthub/library/pod-security-policy/selinux/1.1.0/kustomization.yaml new file mode 100644 index 000000000..7d70d11b7 --- /dev/null +++ b/artifacthub/library/pod-security-policy/selinux/1.1.0/kustomization.yaml @@ -0,0 +1,2 @@ +resources: + - template.yaml diff --git a/artifacthub/library/pod-security-policy/selinux/1.1.0/samples/psp-selinux-v2/constraint.yaml b/artifacthub/library/pod-security-policy/selinux/1.1.0/samples/psp-selinux-v2/constraint.yaml new file mode 100644 index 000000000..f88bbcd69 --- /dev/null +++ b/artifacthub/library/pod-security-policy/selinux/1.1.0/samples/psp-selinux-v2/constraint.yaml @@ -0,0 +1,15 @@ +apiVersion: constraints.gatekeeper.sh/v1beta1 +kind: K8sPSPSELinuxV2 +metadata: + name: psp-selinux-v2 +spec: + match: + kinds: + - apiGroups: [""] + kinds: ["Pod"] + parameters: + allowedSELinuxOptions: + - level: s0:c123,c456 + role: object_r + type: svirt_sandbox_file_t + user: system_u diff --git a/artifacthub/library/pod-security-policy/selinux/1.1.0/samples/psp-selinux-v2/disallowed_ephemeral.yaml b/artifacthub/library/pod-security-policy/selinux/1.1.0/samples/psp-selinux-v2/disallowed_ephemeral.yaml new file mode 100644 index 000000000..3a35fc737 --- /dev/null +++ b/artifacthub/library/pod-security-policy/selinux/1.1.0/samples/psp-selinux-v2/disallowed_ephemeral.yaml @@ -0,0 +1,16 @@ +apiVersion: v1 +kind: Pod +metadata: + name: nginx-selinux-disallowed + labels: + app: nginx-selinux +spec: + ephemeralContainers: + - name: nginx + image: nginx + securityContext: + seLinuxOptions: + level: s1:c234,c567 + user: sysadm_u + role: sysadm_r + type: svirt_lxc_net_t diff --git a/artifacthub/library/pod-security-policy/selinux/1.1.0/samples/psp-selinux-v2/example_allowed.yaml b/artifacthub/library/pod-security-policy/selinux/1.1.0/samples/psp-selinux-v2/example_allowed.yaml new file mode 100644 index 000000000..4eaf2dc92 --- /dev/null +++ b/artifacthub/library/pod-security-policy/selinux/1.1.0/samples/psp-selinux-v2/example_allowed.yaml @@ -0,0 +1,16 @@ +apiVersion: v1 +kind: Pod +metadata: + name: nginx-selinux-allowed + labels: + app: nginx-selinux +spec: + containers: + - name: nginx + image: nginx + securityContext: + seLinuxOptions: + level: s0:c123,c456 + role: object_r + type: svirt_sandbox_file_t + user: system_u diff --git a/artifacthub/library/pod-security-policy/selinux/1.1.0/samples/psp-selinux-v2/example_disallowed.yaml b/artifacthub/library/pod-security-policy/selinux/1.1.0/samples/psp-selinux-v2/example_disallowed.yaml new file mode 100644 index 000000000..7eb7fee11 --- /dev/null +++ b/artifacthub/library/pod-security-policy/selinux/1.1.0/samples/psp-selinux-v2/example_disallowed.yaml @@ -0,0 +1,16 @@ +apiVersion: v1 +kind: Pod +metadata: + name: nginx-selinux-disallowed + labels: + app: nginx-selinux +spec: + containers: + - name: nginx + image: nginx + securityContext: + seLinuxOptions: + level: s1:c234,c567 + user: sysadm_u + role: sysadm_r + type: svirt_lxc_net_t diff --git a/artifacthub/library/pod-security-policy/selinux/1.1.0/samples/psp-selinux-v2/update.yaml b/artifacthub/library/pod-security-policy/selinux/1.1.0/samples/psp-selinux-v2/update.yaml new file mode 100644 index 000000000..581419e9d --- /dev/null +++ b/artifacthub/library/pod-security-policy/selinux/1.1.0/samples/psp-selinux-v2/update.yaml @@ -0,0 +1,21 @@ +kind: AdmissionReview +apiVersion: admission.k8s.io/v1beta1 +request: + operation: "UPDATE" + object: + apiVersion: v1 + kind: Pod + metadata: + name: nginx-selinux-disallowed + labels: + app: nginx-selinux + spec: + containers: + - name: nginx + image: nginx + securityContext: + seLinuxOptions: + level: s1:c234,c567 + user: sysadm_u + role: sysadm_r + type: svirt_lxc_net_t diff --git a/artifacthub/library/pod-security-policy/selinux/1.1.0/suite.yaml b/artifacthub/library/pod-security-policy/selinux/1.1.0/suite.yaml new file mode 100644 index 000000000..1bbaf360e --- /dev/null +++ b/artifacthub/library/pod-security-policy/selinux/1.1.0/suite.yaml @@ -0,0 +1,25 @@ +kind: Suite +apiVersion: test.gatekeeper.sh/v1alpha1 +metadata: + name: selinux +tests: +- name: require-matching-selinux-options + template: template.yaml + constraint: samples/psp-selinux-v2/constraint.yaml + cases: + - name: example-disallowed + object: samples/psp-selinux-v2/example_disallowed.yaml + assertions: + - violations: yes + - name: example-allowed + object: samples/psp-selinux-v2/example_allowed.yaml + assertions: + - violations: no + - name: disallowed-ephemeral + object: samples/psp-selinux-v2/disallowed_ephemeral.yaml + assertions: + - violations: yes + - name: update + object: samples/psp-selinux-v2/update.yaml + assertions: + - violations: no diff --git a/artifacthub/library/pod-security-policy/selinux/1.1.0/template.yaml b/artifacthub/library/pod-security-policy/selinux/1.1.0/template.yaml new file mode 100644 index 000000000..d558968b0 --- /dev/null +++ b/artifacthub/library/pod-security-policy/selinux/1.1.0/template.yaml @@ -0,0 +1,198 @@ +apiVersion: templates.gatekeeper.sh/v1 +kind: ConstraintTemplate +metadata: + name: k8spspselinuxv2 + annotations: + metadata.gatekeeper.sh/title: "SELinux V2" + metadata.gatekeeper.sh/version: 1.1.0 + description: >- + Defines an allow-list of seLinuxOptions configurations for pod + containers. Corresponds to a PodSecurityPolicy requiring SELinux configs. + For more information, see + https://kubernetes.io/docs/concepts/policy/pod-security-policy/#selinux +spec: + crd: + spec: + names: + kind: K8sPSPSELinuxV2 + validation: + # Schema for the `parameters` field + openAPIV3Schema: + type: object + description: >- + Defines an allow-list of seLinuxOptions configurations for pod + containers. Corresponds to a PodSecurityPolicy requiring SELinux configs. + For more information, see + https://kubernetes.io/docs/concepts/policy/pod-security-policy/#selinux + properties: + exemptImages: + description: >- + Any container that uses an image that matches an entry in this list will be excluded + from enforcement. Prefix-matching can be signified with `*`. For example: `my-image-*`. + + It is recommended that users use the fully-qualified Docker image name (e.g. start with a domain name) + in order to avoid unexpectedly exempting images from an untrusted repository. + type: array + items: + type: string + allowedSELinuxOptions: + type: array + description: "An allow-list of SELinux options configurations." + items: + type: object + description: "An allowed configuration of SELinux options for a pod container." + properties: + level: + type: string + description: "An SELinux level." + role: + type: string + description: "An SELinux role." + type: + type: string + description: "An SELinux type." + user: + type: string + description: "An SELinux user." + targets: + - target: admission.k8s.gatekeeper.sh + code: + - engine: K8sNativeValidation + source: + variables: + - name: notViolatingSELinuxOptions + expression: | + has(object.spec.securityContext) && has(object.spec.securityContext.seLinuxOptions) ? + (has(variables.params.allowedSELinuxOptions) ? + ( + (has(variables.params.allowedSELinuxOptions.level) && has(object.spec.securityContext.seLinuxOptions.level) && (object.spec.securityContext.seLinuxOptions.level == variables.params.allowedSELinuxOptions.level)) && + (has(variables.params.allowedSELinuxOptions.role) && has(object.spec.securityContext.seLinuxOptions.role) && (object.spec.securityContext.seLinuxOptions.role == variables.params.allowedSELinuxOptions.role)) && + (has(variables.params.allowedSELinuxOptions.type) && has(object.spec.securityContext.seLinuxOptions.type) && (object.spec.securityContext.seLinuxOptions.type == variables.params.allowedSELinuxOptions.type)) && + (has(variables.params.allowedSELinuxOptions.user) && has(object.spec.securityContext.seLinuxOptions.user) && (object.spec.securityContext.seLinuxOptions.user == variables.params.allowedSELinuxOptions.user)) + ) : + (!has(object.spec.securityContext.seLinuxOptions.level) && !has(object.spec.securityContext.seLinuxOptions.role) && !has(object.spec.securityContext.seLinuxOptions.type) && !has(object.spec.securityContext.seLinuxOptions.user))) + : true + - name: containers + expression: 'has(object.spec.containers) ? object.spec.containers.filter(c, has(c.securityContext) && has(c.securityContext.seLinuxOptions)) : []' + - name: initContainers + expression: 'has(object.spec.initContainers) ? object.spec.initContainers.filter(c, has(c.securityContext) && has(c.securityContext.seLinuxOptions)) : []' + - name: ephemeralContainers + expression: 'has(object.spec.ephemeralContainers) ? object.spec.ephemeralContainers.filter(c, has(c.securityContext) && has(c.securityContext.seLinuxOptions)) : []' + - name: exemptImagePrefixes + expression: | + !has(variables.params.exemptImages) ? [] : + variables.params.exemptImages.filter(image, image.endsWith("*")).map(image, string(image).replace("*", "")) + - name: exemptImageExplicit + expression: | + !has(variables.params.exemptImages) ? [] : + variables.params.exemptImages.filter(image, !image.endsWith("*")) + - name: exemptImages + expression: | + (variables.containers + variables.initContainers + variables.ephemeralContainers).filter(container, + container.image in variables.exemptImageExplicit || + variables.exemptImagePrefixes.exists(exemption, string(container.image).startsWith(exemption))) + - name: badContainers + expression: | + (variables.containers + variables.initContainers + variables.ephemeralContainers).filter(c, !(c.image in variables.exemptImages) && (has(c.securityContext.seLinuxOptions) ? ( + has(variables.params.allowedSELinuxOptions) ? + ( + !(has(variables.params.allowedSELinuxOptions.level) && has(c.securityContext.seLinuxOptions.level) && (c.securityContext.seLinuxOptions.level == variables.params.allowedSELinuxOptions.level)) || + !(has(variables.params.allowedSELinuxOptions.role) && has(c.securityContext.seLinuxOptions.role) && (c.securityContext.seLinuxOptions.role == variables.params.allowedSELinuxOptions.role)) || + !(has(variables.params.allowedSELinuxOptions.type) && has(c.securityContext.seLinuxOptions.type) && (c.securityContext.seLinuxOptions.type == variables.params.allowedSELinuxOptions.type)) || + !(has(variables.params.allowedSELinuxOptions.user) && has(c.securityContext.seLinuxOptions.user) && (c.securityContext.seLinuxOptions.user == variables.params.allowedSELinuxOptions.user)) + ) : (has(c.securityContext.seLinuxOptions.level) || has(c.securityContext.seLinuxOptions.role) || has(c.securityContext.seLinuxOptions.type) || has(c.securityContext.seLinuxOptions.user)) + ) : false + )) + validations: + - expression: '(has(request.operation) && request.operation == "UPDATE") || variables.notViolatingSELinuxOptions' + messageExpression: '"SELinux options is not allowed, pod: " + object.metadata.name + ". Allowed options: " + variables.params.allowedSELinuxOptions' + - expression: '(has(request.operation) && request.operation == "UPDATE") || size(variables.badContainers) == 0' + messageExpression: '"SELinux options is not allowed, pod: " + object.metadata.name + ", container: " + variables.badContainers.map(c, c.name).join(", ")' + - engine: Rego + source: + rego: | + package k8spspselinux + + import data.lib.exclude_update.is_update + import data.lib.exempt_container.is_exempt + + # Disallow top level custom SELinux options + violation[{"msg": msg, "details": {}}] { + # spec.securityContext.seLinuxOptions field is immutable. + not is_update(input.review) + + has_field(input.review.object.spec.securityContext, "seLinuxOptions") + not input_seLinuxOptions_allowed(input.review.object.spec.securityContext.seLinuxOptions) + msg := sprintf("SELinux options is not allowed, pod: %v. Allowed options: %v", [input.review.object.metadata.name, input.parameters.allowedSELinuxOptions]) + } + # Disallow container level custom SELinux options + violation[{"msg": msg, "details": {}}] { + # spec.containers.securityContext.seLinuxOptions field is immutable. + not is_update(input.review) + + c := input_security_context[_] + not is_exempt(c) + has_field(c.securityContext, "seLinuxOptions") + not input_seLinuxOptions_allowed(c.securityContext.seLinuxOptions) + msg := sprintf("SELinux options is not allowed, pod: %v, container: %v. Allowed options: %v", [input.review.object.metadata.name, c.name, input.parameters.allowedSELinuxOptions]) + } + + input_seLinuxOptions_allowed(options) { + params := input.parameters.allowedSELinuxOptions[_] + field_allowed("level", options, params) + field_allowed("role", options, params) + field_allowed("type", options, params) + field_allowed("user", options, params) + } + + field_allowed(field, options, params) { + params[field] == options[field] + } + field_allowed(field, options, _) { + not has_field(options, field) + } + + input_security_context[c] { + c := input.review.object.spec.containers[_] + has_field(c.securityContext, "seLinuxOptions") + } + input_security_context[c] { + c := input.review.object.spec.initContainers[_] + has_field(c.securityContext, "seLinuxOptions") + } + input_security_context[c] { + c := input.review.object.spec.ephemeralContainers[_] + has_field(c.securityContext, "seLinuxOptions") + } + + # has_field returns whether an object has a field + has_field(object, field) = true { + object[field] + } + libs: + - | + package lib.exclude_update + + is_update(review) { + review.operation == "UPDATE" + } + - | + package lib.exempt_container + + is_exempt(container) { + exempt_images := object.get(object.get(input, "parameters", {}), "exemptImages", []) + img := container.image + exemption := exempt_images[_] + _matches_exemption(img, exemption) + } + + _matches_exemption(img, exemption) { + not endswith(exemption, "*") + exemption == img + } + + _matches_exemption(img, exemption) { + endswith(exemption, "*") + prefix := trim_suffix(exemption, "*") + startswith(img, prefix) + } diff --git a/artifacthub/library/pod-security-policy/volumes/1.1.0/artifacthub-pkg.yml b/artifacthub/library/pod-security-policy/volumes/1.1.0/artifacthub-pkg.yml new file mode 100644 index 000000000..28b97d66f --- /dev/null +++ b/artifacthub/library/pod-security-policy/volumes/1.1.0/artifacthub-pkg.yml @@ -0,0 +1,22 @@ +version: 1.1.0 +name: k8spspvolumetypes +displayName: Volume Types +createdAt: "2024-05-14T00:55:44Z" +description: Restricts mountable volume types to those specified by the user. Corresponds to the `volumes` field in a PodSecurityPolicy. For more information, see https://kubernetes.io/docs/concepts/policy/pod-security-policy/#volumes-and-file-systems +digest: f27f6759e3fc2969cddea91ad3b1b0d06554d63c6b9137e35e89a5e8dbd458d9 +license: Apache-2.0 +homeURL: https://open-policy-agent.github.io/gatekeeper-library/website/volumes +keywords: + - gatekeeper + - open-policy-agent + - policies +readme: |- + # Volume Types + Restricts mountable volume types to those specified by the user. Corresponds to the `volumes` field in a PodSecurityPolicy. For more information, see https://kubernetes.io/docs/concepts/policy/pod-security-policy/#volumes-and-file-systems +install: |- + ### Usage + ```shell + kubectl apply -f https://raw.githubusercontent.com/open-policy-agent/gatekeeper-library/master/artifacthub/library/pod-security-policy/volumes/1.1.0/template.yaml + ``` +provider: + name: Gatekeeper Library diff --git a/artifacthub/library/pod-security-policy/volumes/1.1.0/kustomization.yaml b/artifacthub/library/pod-security-policy/volumes/1.1.0/kustomization.yaml new file mode 100644 index 000000000..7d70d11b7 --- /dev/null +++ b/artifacthub/library/pod-security-policy/volumes/1.1.0/kustomization.yaml @@ -0,0 +1,2 @@ +resources: + - template.yaml diff --git a/artifacthub/library/pod-security-policy/volumes/1.1.0/samples/psp-volume-types/constraint.yaml b/artifacthub/library/pod-security-policy/volumes/1.1.0/samples/psp-volume-types/constraint.yaml new file mode 100644 index 000000000..0638df7cb --- /dev/null +++ b/artifacthub/library/pod-security-policy/volumes/1.1.0/samples/psp-volume-types/constraint.yaml @@ -0,0 +1,20 @@ +apiVersion: constraints.gatekeeper.sh/v1beta1 +kind: K8sPSPVolumeTypes +metadata: + name: psp-volume-types +spec: + match: + kinds: + - apiGroups: [""] + kinds: ["Pod"] + parameters: + volumes: + # - "*" # * may be used to allow all volume types + - configMap + - emptyDir + - projected + - secret + - downwardAPI + - persistentVolumeClaim + #- hostPath #required for allowedHostPaths + - flexVolume #required for allowedFlexVolumes diff --git a/artifacthub/library/pod-security-policy/volumes/1.1.0/samples/psp-volume-types/example_allowed.yaml b/artifacthub/library/pod-security-policy/volumes/1.1.0/samples/psp-volume-types/example_allowed.yaml new file mode 100644 index 000000000..df6251e7d --- /dev/null +++ b/artifacthub/library/pod-security-policy/volumes/1.1.0/samples/psp-volume-types/example_allowed.yaml @@ -0,0 +1,23 @@ +apiVersion: v1 +kind: Pod +metadata: + name: nginx-volume-types-allowed + labels: + app: nginx-volume-types +spec: + containers: + - name: nginx + image: nginx + volumeMounts: + - mountPath: /cache + name: cache-volume + - name: nginx2 + image: nginx + volumeMounts: + - mountPath: /cache2 + name: demo-vol + volumes: + - name: cache-volume + emptyDir: {} + - name: demo-vol + emptyDir: {} diff --git a/artifacthub/library/pod-security-policy/volumes/1.1.0/samples/psp-volume-types/example_disallowed.yaml b/artifacthub/library/pod-security-policy/volumes/1.1.0/samples/psp-volume-types/example_disallowed.yaml new file mode 100644 index 000000000..562cf59d8 --- /dev/null +++ b/artifacthub/library/pod-security-policy/volumes/1.1.0/samples/psp-volume-types/example_disallowed.yaml @@ -0,0 +1,24 @@ +apiVersion: v1 +kind: Pod +metadata: + name: nginx-volume-types-disallowed + labels: + app: nginx-volume-types +spec: + containers: + - name: nginx + image: nginx + volumeMounts: + - mountPath: /cache + name: cache-volume + - name: nginx2 + image: nginx + volumeMounts: + - mountPath: /cache2 + name: demo-vol + volumes: + - name: cache-volume + hostPath: + path: /tmp # directory location on host + - name: demo-vol + emptyDir: {} diff --git a/artifacthub/library/pod-security-policy/volumes/1.1.0/samples/psp-volume-types/update.yaml b/artifacthub/library/pod-security-policy/volumes/1.1.0/samples/psp-volume-types/update.yaml new file mode 100644 index 000000000..f25f07267 --- /dev/null +++ b/artifacthub/library/pod-security-policy/volumes/1.1.0/samples/psp-volume-types/update.yaml @@ -0,0 +1,29 @@ +kind: AdmissionReview +apiVersion: admission.k8s.io/v1beta1 +request: + operation: "UPDATE" + object: + apiVersion: v1 + kind: Pod + metadata: + name: nginx-volume-types-disallowed + labels: + app: nginx-volume-types + spec: + containers: + - name: nginx + image: nginx + volumeMounts: + - mountPath: /cache + name: cache-volume + - name: nginx2 + image: nginx + volumeMounts: + - mountPath: /cache2 + name: demo-vol + volumes: + - name: cache-volume + hostPath: + path: /tmp # directory location on host + - name: demo-vol + emptyDir: {} diff --git a/artifacthub/library/pod-security-policy/volumes/1.1.0/suite.yaml b/artifacthub/library/pod-security-policy/volumes/1.1.0/suite.yaml new file mode 100644 index 000000000..083aad6eb --- /dev/null +++ b/artifacthub/library/pod-security-policy/volumes/1.1.0/suite.yaml @@ -0,0 +1,21 @@ +kind: Suite +apiVersion: test.gatekeeper.sh/v1alpha1 +metadata: + name: volumes +tests: +- name: host-path-disallowed + template: template.yaml + constraint: samples/psp-volume-types/constraint.yaml + cases: + - name: example-disallowed + object: samples/psp-volume-types/example_disallowed.yaml + assertions: + - violations: yes + - name: example-allowed + object: samples/psp-volume-types/example_allowed.yaml + assertions: + - violations: no + - name: update + object: samples/psp-volume-types/update.yaml + assertions: + - violations: no diff --git a/artifacthub/library/pod-security-policy/volumes/1.1.0/template.yaml b/artifacthub/library/pod-security-policy/volumes/1.1.0/template.yaml new file mode 100644 index 000000000..4e6233966 --- /dev/null +++ b/artifacthub/library/pod-security-policy/volumes/1.1.0/template.yaml @@ -0,0 +1,78 @@ +apiVersion: templates.gatekeeper.sh/v1 +kind: ConstraintTemplate +metadata: + name: k8spspvolumetypes + annotations: + metadata.gatekeeper.sh/title: "Volume Types" + metadata.gatekeeper.sh/version: 1.1.0 + description: >- + Restricts mountable volume types to those specified by the user. + Corresponds to the `volumes` field in a PodSecurityPolicy. For more + information, see + https://kubernetes.io/docs/concepts/policy/pod-security-policy/#volumes-and-file-systems +spec: + crd: + spec: + names: + kind: K8sPSPVolumeTypes + validation: + # Schema for the `parameters` field + openAPIV3Schema: + type: object + description: >- + Restricts mountable volume types to those specified by the user. + Corresponds to the `volumes` field in a PodSecurityPolicy. For more + information, see + https://kubernetes.io/docs/concepts/policy/pod-security-policy/#volumes-and-file-systems + properties: + volumes: + description: "`volumes` is an array of volume types. All volume types can be enabled using `*`." + type: array + items: + type: string + targets: + - target: admission.k8s.gatekeeper.sh + code: + - engine: K8sNativeValidation + source: + variables: + - name: volumes + expression: 'has(object.spec.volumes) && has(request.operation) && request.operation != "UPDATE" ? object.spec.volumes : []' + - name: badVolumes + expression: | + variables.params.volumes.exists(entry, entry == "*") ? [] : variables.volumes.map(e, e.map(k, k != "name", k)).map(k, k[0]).filter(entry, !(entry in variables.params.volumes)) + validations: + - expression: 'size(variables.badVolumes) == 0' + messageExpression: '"The volume type " + variables.badVolumes.join(", ") + " is not allowed, pod: " + object.metadata.name + ". Allowed volume types: " + variables.params.volumes.join(", ")' + - engine: Rego + source: + rego: | + package k8spspvolumetypes + + import data.lib.exclude_update.is_update + + violation[{"msg": msg, "details": {}}] { + # spec.volumes field is immutable. + not is_update(input.review) + + volume_fields := {x | input.review.object.spec.volumes[_][x]; x != "name"} + field := volume_fields[_] + not input_volume_type_allowed(field) + msg := sprintf("The volume type %v is not allowed, pod: %v. Allowed volume types: %v", [field, input.review.object.metadata.name, input.parameters.volumes]) + } + + # * may be used to allow all volume types + input_volume_type_allowed(_) { + input.parameters.volumes[_] == "*" + } + + input_volume_type_allowed(field) { + field == input.parameters.volumes[_] + } + libs: + - | + package lib.exclude_update + + is_update(review) { + review.operation == "UPDATE" + } diff --git a/library/pod-security-policy/selinux/template.yaml b/library/pod-security-policy/selinux/template.yaml index 6ecc70675..d558968b0 100644 --- a/library/pod-security-policy/selinux/template.yaml +++ b/library/pod-security-policy/selinux/template.yaml @@ -4,7 +4,7 @@ metadata: name: k8spspselinuxv2 annotations: metadata.gatekeeper.sh/title: "SELinux V2" - metadata.gatekeeper.sh/version: 1.0.3 + metadata.gatekeeper.sh/version: 1.1.0 description: >- Defines an allow-list of seLinuxOptions configurations for pod containers. Corresponds to a PodSecurityPolicy requiring SELinux configs. @@ -56,89 +56,143 @@ spec: description: "An SELinux user." targets: - target: admission.k8s.gatekeeper.sh - rego: | - package k8spspselinux + code: + - engine: K8sNativeValidation + source: + variables: + - name: notViolatingSELinuxOptions + expression: | + has(object.spec.securityContext) && has(object.spec.securityContext.seLinuxOptions) ? + (has(variables.params.allowedSELinuxOptions) ? + ( + (has(variables.params.allowedSELinuxOptions.level) && has(object.spec.securityContext.seLinuxOptions.level) && (object.spec.securityContext.seLinuxOptions.level == variables.params.allowedSELinuxOptions.level)) && + (has(variables.params.allowedSELinuxOptions.role) && has(object.spec.securityContext.seLinuxOptions.role) && (object.spec.securityContext.seLinuxOptions.role == variables.params.allowedSELinuxOptions.role)) && + (has(variables.params.allowedSELinuxOptions.type) && has(object.spec.securityContext.seLinuxOptions.type) && (object.spec.securityContext.seLinuxOptions.type == variables.params.allowedSELinuxOptions.type)) && + (has(variables.params.allowedSELinuxOptions.user) && has(object.spec.securityContext.seLinuxOptions.user) && (object.spec.securityContext.seLinuxOptions.user == variables.params.allowedSELinuxOptions.user)) + ) : + (!has(object.spec.securityContext.seLinuxOptions.level) && !has(object.spec.securityContext.seLinuxOptions.role) && !has(object.spec.securityContext.seLinuxOptions.type) && !has(object.spec.securityContext.seLinuxOptions.user))) + : true + - name: containers + expression: 'has(object.spec.containers) ? object.spec.containers.filter(c, has(c.securityContext) && has(c.securityContext.seLinuxOptions)) : []' + - name: initContainers + expression: 'has(object.spec.initContainers) ? object.spec.initContainers.filter(c, has(c.securityContext) && has(c.securityContext.seLinuxOptions)) : []' + - name: ephemeralContainers + expression: 'has(object.spec.ephemeralContainers) ? object.spec.ephemeralContainers.filter(c, has(c.securityContext) && has(c.securityContext.seLinuxOptions)) : []' + - name: exemptImagePrefixes + expression: | + !has(variables.params.exemptImages) ? [] : + variables.params.exemptImages.filter(image, image.endsWith("*")).map(image, string(image).replace("*", "")) + - name: exemptImageExplicit + expression: | + !has(variables.params.exemptImages) ? [] : + variables.params.exemptImages.filter(image, !image.endsWith("*")) + - name: exemptImages + expression: | + (variables.containers + variables.initContainers + variables.ephemeralContainers).filter(container, + container.image in variables.exemptImageExplicit || + variables.exemptImagePrefixes.exists(exemption, string(container.image).startsWith(exemption))) + - name: badContainers + expression: | + (variables.containers + variables.initContainers + variables.ephemeralContainers).filter(c, !(c.image in variables.exemptImages) && (has(c.securityContext.seLinuxOptions) ? ( + has(variables.params.allowedSELinuxOptions) ? + ( + !(has(variables.params.allowedSELinuxOptions.level) && has(c.securityContext.seLinuxOptions.level) && (c.securityContext.seLinuxOptions.level == variables.params.allowedSELinuxOptions.level)) || + !(has(variables.params.allowedSELinuxOptions.role) && has(c.securityContext.seLinuxOptions.role) && (c.securityContext.seLinuxOptions.role == variables.params.allowedSELinuxOptions.role)) || + !(has(variables.params.allowedSELinuxOptions.type) && has(c.securityContext.seLinuxOptions.type) && (c.securityContext.seLinuxOptions.type == variables.params.allowedSELinuxOptions.type)) || + !(has(variables.params.allowedSELinuxOptions.user) && has(c.securityContext.seLinuxOptions.user) && (c.securityContext.seLinuxOptions.user == variables.params.allowedSELinuxOptions.user)) + ) : (has(c.securityContext.seLinuxOptions.level) || has(c.securityContext.seLinuxOptions.role) || has(c.securityContext.seLinuxOptions.type) || has(c.securityContext.seLinuxOptions.user)) + ) : false + )) + validations: + - expression: '(has(request.operation) && request.operation == "UPDATE") || variables.notViolatingSELinuxOptions' + messageExpression: '"SELinux options is not allowed, pod: " + object.metadata.name + ". Allowed options: " + variables.params.allowedSELinuxOptions' + - expression: '(has(request.operation) && request.operation == "UPDATE") || size(variables.badContainers) == 0' + messageExpression: '"SELinux options is not allowed, pod: " + object.metadata.name + ", container: " + variables.badContainers.map(c, c.name).join(", ")' + - engine: Rego + source: + rego: | + package k8spspselinux - import data.lib.exclude_update.is_update - import data.lib.exempt_container.is_exempt + import data.lib.exclude_update.is_update + import data.lib.exempt_container.is_exempt - # Disallow top level custom SELinux options - violation[{"msg": msg, "details": {}}] { - # spec.securityContext.seLinuxOptions field is immutable. - not is_update(input.review) + # Disallow top level custom SELinux options + violation[{"msg": msg, "details": {}}] { + # spec.securityContext.seLinuxOptions field is immutable. + not is_update(input.review) - has_field(input.review.object.spec.securityContext, "seLinuxOptions") - not input_seLinuxOptions_allowed(input.review.object.spec.securityContext.seLinuxOptions) - msg := sprintf("SELinux options is not allowed, pod: %v. Allowed options: %v", [input.review.object.metadata.name, input.parameters.allowedSELinuxOptions]) - } - # Disallow container level custom SELinux options - violation[{"msg": msg, "details": {}}] { - # spec.containers.securityContext.seLinuxOptions field is immutable. - not is_update(input.review) + has_field(input.review.object.spec.securityContext, "seLinuxOptions") + not input_seLinuxOptions_allowed(input.review.object.spec.securityContext.seLinuxOptions) + msg := sprintf("SELinux options is not allowed, pod: %v. Allowed options: %v", [input.review.object.metadata.name, input.parameters.allowedSELinuxOptions]) + } + # Disallow container level custom SELinux options + violation[{"msg": msg, "details": {}}] { + # spec.containers.securityContext.seLinuxOptions field is immutable. + not is_update(input.review) - c := input_security_context[_] - not is_exempt(c) - has_field(c.securityContext, "seLinuxOptions") - not input_seLinuxOptions_allowed(c.securityContext.seLinuxOptions) - msg := sprintf("SELinux options is not allowed, pod: %v, container: %v. Allowed options: %v", [input.review.object.metadata.name, c.name, input.parameters.allowedSELinuxOptions]) - } + c := input_security_context[_] + not is_exempt(c) + has_field(c.securityContext, "seLinuxOptions") + not input_seLinuxOptions_allowed(c.securityContext.seLinuxOptions) + msg := sprintf("SELinux options is not allowed, pod: %v, container: %v. Allowed options: %v", [input.review.object.metadata.name, c.name, input.parameters.allowedSELinuxOptions]) + } - input_seLinuxOptions_allowed(options) { - params := input.parameters.allowedSELinuxOptions[_] - field_allowed("level", options, params) - field_allowed("role", options, params) - field_allowed("type", options, params) - field_allowed("user", options, params) - } + input_seLinuxOptions_allowed(options) { + params := input.parameters.allowedSELinuxOptions[_] + field_allowed("level", options, params) + field_allowed("role", options, params) + field_allowed("type", options, params) + field_allowed("user", options, params) + } - field_allowed(field, options, params) { - params[field] == options[field] - } - field_allowed(field, options, _) { - not has_field(options, field) - } + field_allowed(field, options, params) { + params[field] == options[field] + } + field_allowed(field, options, _) { + not has_field(options, field) + } - input_security_context[c] { - c := input.review.object.spec.containers[_] - has_field(c.securityContext, "seLinuxOptions") - } - input_security_context[c] { - c := input.review.object.spec.initContainers[_] - has_field(c.securityContext, "seLinuxOptions") - } - input_security_context[c] { - c := input.review.object.spec.ephemeralContainers[_] - has_field(c.securityContext, "seLinuxOptions") - } + input_security_context[c] { + c := input.review.object.spec.containers[_] + has_field(c.securityContext, "seLinuxOptions") + } + input_security_context[c] { + c := input.review.object.spec.initContainers[_] + has_field(c.securityContext, "seLinuxOptions") + } + input_security_context[c] { + c := input.review.object.spec.ephemeralContainers[_] + has_field(c.securityContext, "seLinuxOptions") + } - # has_field returns whether an object has a field - has_field(object, field) = true { - object[field] - } - libs: - - | - package lib.exclude_update + # has_field returns whether an object has a field + has_field(object, field) = true { + object[field] + } + libs: + - | + package lib.exclude_update - is_update(review) { - review.operation == "UPDATE" - } - - | - package lib.exempt_container + is_update(review) { + review.operation == "UPDATE" + } + - | + package lib.exempt_container - is_exempt(container) { - exempt_images := object.get(object.get(input, "parameters", {}), "exemptImages", []) - img := container.image - exemption := exempt_images[_] - _matches_exemption(img, exemption) - } + is_exempt(container) { + exempt_images := object.get(object.get(input, "parameters", {}), "exemptImages", []) + img := container.image + exemption := exempt_images[_] + _matches_exemption(img, exemption) + } - _matches_exemption(img, exemption) { - not endswith(exemption, "*") - exemption == img - } + _matches_exemption(img, exemption) { + not endswith(exemption, "*") + exemption == img + } - _matches_exemption(img, exemption) { - endswith(exemption, "*") - prefix := trim_suffix(exemption, "*") - startswith(img, prefix) - } + _matches_exemption(img, exemption) { + endswith(exemption, "*") + prefix := trim_suffix(exemption, "*") + startswith(img, prefix) + } diff --git a/library/pod-security-policy/volumes/template.yaml b/library/pod-security-policy/volumes/template.yaml index 74165c8f4..4e6233966 100644 --- a/library/pod-security-policy/volumes/template.yaml +++ b/library/pod-security-policy/volumes/template.yaml @@ -4,7 +4,7 @@ metadata: name: k8spspvolumetypes annotations: metadata.gatekeeper.sh/title: "Volume Types" - metadata.gatekeeper.sh/version: 1.0.2 + metadata.gatekeeper.sh/version: 1.1.0 description: >- Restricts mountable volume types to those specified by the user. Corresponds to the `volumes` field in a PodSecurityPolicy. For more @@ -32,33 +32,47 @@ spec: type: string targets: - target: admission.k8s.gatekeeper.sh - rego: | - package k8spspvolumetypes + code: + - engine: K8sNativeValidation + source: + variables: + - name: volumes + expression: 'has(object.spec.volumes) && has(request.operation) && request.operation != "UPDATE" ? object.spec.volumes : []' + - name: badVolumes + expression: | + variables.params.volumes.exists(entry, entry == "*") ? [] : variables.volumes.map(e, e.map(k, k != "name", k)).map(k, k[0]).filter(entry, !(entry in variables.params.volumes)) + validations: + - expression: 'size(variables.badVolumes) == 0' + messageExpression: '"The volume type " + variables.badVolumes.join(", ") + " is not allowed, pod: " + object.metadata.name + ". Allowed volume types: " + variables.params.volumes.join(", ")' + - engine: Rego + source: + rego: | + package k8spspvolumetypes - import data.lib.exclude_update.is_update + import data.lib.exclude_update.is_update - violation[{"msg": msg, "details": {}}] { - # spec.volumes field is immutable. - not is_update(input.review) + violation[{"msg": msg, "details": {}}] { + # spec.volumes field is immutable. + not is_update(input.review) - volume_fields := {x | input.review.object.spec.volumes[_][x]; x != "name"} - field := volume_fields[_] - not input_volume_type_allowed(field) - msg := sprintf("The volume type %v is not allowed, pod: %v. Allowed volume types: %v", [field, input.review.object.metadata.name, input.parameters.volumes]) - } + volume_fields := {x | input.review.object.spec.volumes[_][x]; x != "name"} + field := volume_fields[_] + not input_volume_type_allowed(field) + msg := sprintf("The volume type %v is not allowed, pod: %v. Allowed volume types: %v", [field, input.review.object.metadata.name, input.parameters.volumes]) + } - # * may be used to allow all volume types - input_volume_type_allowed(_) { - input.parameters.volumes[_] == "*" - } + # * may be used to allow all volume types + input_volume_type_allowed(_) { + input.parameters.volumes[_] == "*" + } - input_volume_type_allowed(field) { - field == input.parameters.volumes[_] - } - libs: - - | - package lib.exclude_update + input_volume_type_allowed(field) { + field == input.parameters.volumes[_] + } + libs: + - | + package lib.exclude_update - is_update(review) { - review.operation == "UPDATE" - } + is_update(review) { + review.operation == "UPDATE" + } diff --git a/src/pod-security-policy/selinux/constraint.tmpl b/src/pod-security-policy/selinux/constraint.tmpl index 425904ec6..0c93d4500 100644 --- a/src/pod-security-policy/selinux/constraint.tmpl +++ b/src/pod-security-policy/selinux/constraint.tmpl @@ -4,7 +4,7 @@ metadata: name: k8spspselinuxv2 annotations: metadata.gatekeeper.sh/title: "SELinux V2" - metadata.gatekeeper.sh/version: 1.0.3 + metadata.gatekeeper.sh/version: 1.1.0 description: >- Defines an allow-list of seLinuxOptions configurations for pod containers. Corresponds to a PodSecurityPolicy requiring SELinux configs. @@ -56,10 +56,16 @@ spec: description: "An SELinux user." targets: - target: admission.k8s.gatekeeper.sh - rego: | -{{ file.Read "src/pod-security-policy/selinux/src.rego" | strings.Indent 8 | strings.TrimSuffix "\n" }} - libs: - - | -{{ file.Read "src/pod-security-policy/selinux/lib_exclude_update.rego" | strings.Indent 10 | strings.TrimSuffix "\n" }} - - | -{{ file.Read "src/pod-security-policy/selinux/lib_exempt_container.rego" | strings.Indent 10 | strings.TrimSuffix "\n" }} + code: + - engine: K8sNativeValidation + source: +{{ file.Read "src/pod-security-policy/selinux/src.cel" | strings.Indent 10 | strings.TrimSuffix "\n" }} + - engine: Rego + source: + rego: | +{{ file.Read "src/pod-security-policy/selinux/src.rego" | strings.Indent 12 | strings.TrimSuffix "\n" }} + libs: + - | +{{ file.Read "src/pod-security-policy/selinux/lib_exclude_update.rego" | strings.Indent 14 | strings.TrimSuffix "\n" }} + - | +{{ file.Read "src/pod-security-policy/selinux/lib_exempt_container.rego" | strings.Indent 14 | strings.TrimSuffix "\n" }} diff --git a/src/pod-security-policy/selinux/src.cel b/src/pod-security-policy/selinux/src.cel new file mode 100644 index 000000000..0a0d04a79 --- /dev/null +++ b/src/pod-security-policy/selinux/src.cel @@ -0,0 +1,49 @@ +variables: +- name: notViolatingSELinuxOptions + expression: | + has(object.spec.securityContext) && has(object.spec.securityContext.seLinuxOptions) ? + (has(variables.params.allowedSELinuxOptions) ? + ( + (has(variables.params.allowedSELinuxOptions.level) && has(object.spec.securityContext.seLinuxOptions.level) && (object.spec.securityContext.seLinuxOptions.level == variables.params.allowedSELinuxOptions.level)) && + (has(variables.params.allowedSELinuxOptions.role) && has(object.spec.securityContext.seLinuxOptions.role) && (object.spec.securityContext.seLinuxOptions.role == variables.params.allowedSELinuxOptions.role)) && + (has(variables.params.allowedSELinuxOptions.type) && has(object.spec.securityContext.seLinuxOptions.type) && (object.spec.securityContext.seLinuxOptions.type == variables.params.allowedSELinuxOptions.type)) && + (has(variables.params.allowedSELinuxOptions.user) && has(object.spec.securityContext.seLinuxOptions.user) && (object.spec.securityContext.seLinuxOptions.user == variables.params.allowedSELinuxOptions.user)) + ) : + (!has(object.spec.securityContext.seLinuxOptions.level) && !has(object.spec.securityContext.seLinuxOptions.role) && !has(object.spec.securityContext.seLinuxOptions.type) && !has(object.spec.securityContext.seLinuxOptions.user))) + : true +- name: containers + expression: 'has(object.spec.containers) ? object.spec.containers.filter(c, has(c.securityContext) && has(c.securityContext.seLinuxOptions)) : []' +- name: initContainers + expression: 'has(object.spec.initContainers) ? object.spec.initContainers.filter(c, has(c.securityContext) && has(c.securityContext.seLinuxOptions)) : []' +- name: ephemeralContainers + expression: 'has(object.spec.ephemeralContainers) ? object.spec.ephemeralContainers.filter(c, has(c.securityContext) && has(c.securityContext.seLinuxOptions)) : []' +- name: exemptImagePrefixes + expression: | + !has(variables.params.exemptImages) ? [] : + variables.params.exemptImages.filter(image, image.endsWith("*")).map(image, string(image).replace("*", "")) +- name: exemptImageExplicit + expression: | + !has(variables.params.exemptImages) ? [] : + variables.params.exemptImages.filter(image, !image.endsWith("*")) +- name: exemptImages + expression: | + (variables.containers + variables.initContainers + variables.ephemeralContainers).filter(container, + container.image in variables.exemptImageExplicit || + variables.exemptImagePrefixes.exists(exemption, string(container.image).startsWith(exemption))) +- name: badContainers + expression: | + (variables.containers + variables.initContainers + variables.ephemeralContainers).filter(c, !(c.image in variables.exemptImages) && (has(c.securityContext.seLinuxOptions) ? ( + has(variables.params.allowedSELinuxOptions) ? + ( + !(has(variables.params.allowedSELinuxOptions.level) && has(c.securityContext.seLinuxOptions.level) && (c.securityContext.seLinuxOptions.level == variables.params.allowedSELinuxOptions.level)) || + !(has(variables.params.allowedSELinuxOptions.role) && has(c.securityContext.seLinuxOptions.role) && (c.securityContext.seLinuxOptions.role == variables.params.allowedSELinuxOptions.role)) || + !(has(variables.params.allowedSELinuxOptions.type) && has(c.securityContext.seLinuxOptions.type) && (c.securityContext.seLinuxOptions.type == variables.params.allowedSELinuxOptions.type)) || + !(has(variables.params.allowedSELinuxOptions.user) && has(c.securityContext.seLinuxOptions.user) && (c.securityContext.seLinuxOptions.user == variables.params.allowedSELinuxOptions.user)) + ) : (has(c.securityContext.seLinuxOptions.level) || has(c.securityContext.seLinuxOptions.role) || has(c.securityContext.seLinuxOptions.type) || has(c.securityContext.seLinuxOptions.user)) + ) : false + )) +validations: +- expression: '(has(request.operation) && request.operation == "UPDATE") || variables.notViolatingSELinuxOptions' + messageExpression: '"SELinux options is not allowed, pod: " + object.metadata.name + ". Allowed options: " + variables.params.allowedSELinuxOptions' +- expression: '(has(request.operation) && request.operation == "UPDATE") || size(variables.badContainers) == 0' + messageExpression: '"SELinux options is not allowed, pod: " + object.metadata.name + ", container: " + variables.badContainers.map(c, c.name).join(", ")' diff --git a/src/pod-security-policy/volumes/constraint.tmpl b/src/pod-security-policy/volumes/constraint.tmpl index 0fe0567fe..34d61aeb0 100644 --- a/src/pod-security-policy/volumes/constraint.tmpl +++ b/src/pod-security-policy/volumes/constraint.tmpl @@ -4,7 +4,7 @@ metadata: name: k8spspvolumetypes annotations: metadata.gatekeeper.sh/title: "Volume Types" - metadata.gatekeeper.sh/version: 1.0.2 + metadata.gatekeeper.sh/version: 1.1.0 description: >- Restricts mountable volume types to those specified by the user. Corresponds to the `volumes` field in a PodSecurityPolicy. For more @@ -32,8 +32,14 @@ spec: type: string targets: - target: admission.k8s.gatekeeper.sh - rego: | -{{ file.Read "src/pod-security-policy/volumes/src.rego" | strings.Indent 8 | strings.TrimSuffix "\n" }} - libs: - - | -{{ file.Read "src/pod-security-policy/volumes/lib_exclude_update.rego" | strings.Indent 10 | strings.TrimSuffix "\n" }} + code: + - engine: K8sNativeValidation + source: +{{ file.Read "src/pod-security-policy/volumes/src.cel" | strings.Indent 10 | strings.TrimSuffix "\n" }} + - engine: Rego + source: + rego: | +{{ file.Read "src/pod-security-policy/volumes/src.rego" | strings.Indent 12 | strings.TrimSuffix "\n" }} + libs: + - | +{{ file.Read "src/pod-security-policy/volumes/lib_exclude_update.rego" | strings.Indent 14 | strings.TrimSuffix "\n" }} diff --git a/src/pod-security-policy/volumes/src.cel b/src/pod-security-policy/volumes/src.cel new file mode 100644 index 000000000..cc51735a6 --- /dev/null +++ b/src/pod-security-policy/volumes/src.cel @@ -0,0 +1,9 @@ +variables: +- name: volumes + expression: 'has(object.spec.volumes) && has(request.operation) && request.operation != "UPDATE" ? object.spec.volumes : []' +- name: badVolumes + expression: | + variables.params.volumes.exists(entry, entry == "*") ? [] : variables.volumes.map(e, e.map(k, k != "name", k)).map(k, k[0]).filter(entry, !(entry in variables.params.volumes)) +validations: +- expression: 'size(variables.badVolumes) == 0' + messageExpression: '"The volume type " + variables.badVolumes.join(", ") + " is not allowed, pod: " + object.metadata.name + ". Allowed volume types: " + variables.params.volumes.join(", ")' diff --git a/website/docs/validation/selinux.md b/website/docs/validation/selinux.md index ddf97c740..247a7afac 100644 --- a/website/docs/validation/selinux.md +++ b/website/docs/validation/selinux.md @@ -16,7 +16,7 @@ metadata: name: k8spspselinuxv2 annotations: metadata.gatekeeper.sh/title: "SELinux V2" - metadata.gatekeeper.sh/version: 1.0.3 + metadata.gatekeeper.sh/version: 1.1.0 description: >- Defines an allow-list of seLinuxOptions configurations for pod containers. Corresponds to a PodSecurityPolicy requiring SELinux configs. @@ -68,92 +68,146 @@ spec: description: "An SELinux user." targets: - target: admission.k8s.gatekeeper.sh - rego: | - package k8spspselinux - - import data.lib.exclude_update.is_update - import data.lib.exempt_container.is_exempt - - # Disallow top level custom SELinux options - violation[{"msg": msg, "details": {}}] { - # spec.securityContext.seLinuxOptions field is immutable. - not is_update(input.review) - - has_field(input.review.object.spec.securityContext, "seLinuxOptions") - not input_seLinuxOptions_allowed(input.review.object.spec.securityContext.seLinuxOptions) - msg := sprintf("SELinux options is not allowed, pod: %v. Allowed options: %v", [input.review.object.metadata.name, input.parameters.allowedSELinuxOptions]) - } - # Disallow container level custom SELinux options - violation[{"msg": msg, "details": {}}] { - # spec.containers.securityContext.seLinuxOptions field is immutable. - not is_update(input.review) - - c := input_security_context[_] - not is_exempt(c) - has_field(c.securityContext, "seLinuxOptions") - not input_seLinuxOptions_allowed(c.securityContext.seLinuxOptions) - msg := sprintf("SELinux options is not allowed, pod: %v, container: %v. Allowed options: %v", [input.review.object.metadata.name, c.name, input.parameters.allowedSELinuxOptions]) - } - - input_seLinuxOptions_allowed(options) { - params := input.parameters.allowedSELinuxOptions[_] - field_allowed("level", options, params) - field_allowed("role", options, params) - field_allowed("type", options, params) - field_allowed("user", options, params) - } - - field_allowed(field, options, params) { - params[field] == options[field] - } - field_allowed(field, options, _) { - not has_field(options, field) - } - - input_security_context[c] { - c := input.review.object.spec.containers[_] - has_field(c.securityContext, "seLinuxOptions") - } - input_security_context[c] { - c := input.review.object.spec.initContainers[_] - has_field(c.securityContext, "seLinuxOptions") - } - input_security_context[c] { - c := input.review.object.spec.ephemeralContainers[_] - has_field(c.securityContext, "seLinuxOptions") - } - - # has_field returns whether an object has a field - has_field(object, field) = true { - object[field] - } - libs: - - | - package lib.exclude_update - - is_update(review) { - review.operation == "UPDATE" - } - - | - package lib.exempt_container - - is_exempt(container) { - exempt_images := object.get(object.get(input, "parameters", {}), "exemptImages", []) - img := container.image - exemption := exempt_images[_] - _matches_exemption(img, exemption) - } - - _matches_exemption(img, exemption) { - not endswith(exemption, "*") - exemption == img - } - - _matches_exemption(img, exemption) { - endswith(exemption, "*") - prefix := trim_suffix(exemption, "*") - startswith(img, prefix) - } + code: + - engine: K8sNativeValidation + source: + variables: + - name: notViolatingSELinuxOptions + expression: | + has(object.spec.securityContext) && has(object.spec.securityContext.seLinuxOptions) ? + (has(variables.params.allowedSELinuxOptions) ? + ( + (has(variables.params.allowedSELinuxOptions.level) && has(object.spec.securityContext.seLinuxOptions.level) && (object.spec.securityContext.seLinuxOptions.level == variables.params.allowedSELinuxOptions.level)) && + (has(variables.params.allowedSELinuxOptions.role) && has(object.spec.securityContext.seLinuxOptions.role) && (object.spec.securityContext.seLinuxOptions.role == variables.params.allowedSELinuxOptions.role)) && + (has(variables.params.allowedSELinuxOptions.type) && has(object.spec.securityContext.seLinuxOptions.type) && (object.spec.securityContext.seLinuxOptions.type == variables.params.allowedSELinuxOptions.type)) && + (has(variables.params.allowedSELinuxOptions.user) && has(object.spec.securityContext.seLinuxOptions.user) && (object.spec.securityContext.seLinuxOptions.user == variables.params.allowedSELinuxOptions.user)) + ) : + (!has(object.spec.securityContext.seLinuxOptions.level) && !has(object.spec.securityContext.seLinuxOptions.role) && !has(object.spec.securityContext.seLinuxOptions.type) && !has(object.spec.securityContext.seLinuxOptions.user))) + : true + - name: containers + expression: 'has(object.spec.containers) ? object.spec.containers.filter(c, has(c.securityContext) && has(c.securityContext.seLinuxOptions)) : []' + - name: initContainers + expression: 'has(object.spec.initContainers) ? object.spec.initContainers.filter(c, has(c.securityContext) && has(c.securityContext.seLinuxOptions)) : []' + - name: ephemeralContainers + expression: 'has(object.spec.ephemeralContainers) ? object.spec.ephemeralContainers.filter(c, has(c.securityContext) && has(c.securityContext.seLinuxOptions)) : []' + - name: exemptImagePrefixes + expression: | + !has(variables.params.exemptImages) ? [] : + variables.params.exemptImages.filter(image, image.endsWith("*")).map(image, string(image).replace("*", "")) + - name: exemptImageExplicit + expression: | + !has(variables.params.exemptImages) ? [] : + variables.params.exemptImages.filter(image, !image.endsWith("*")) + - name: exemptImages + expression: | + (variables.containers + variables.initContainers + variables.ephemeralContainers).filter(container, + container.image in variables.exemptImageExplicit || + variables.exemptImagePrefixes.exists(exemption, string(container.image).startsWith(exemption))) + - name: badContainers + expression: | + (variables.containers + variables.initContainers + variables.ephemeralContainers).filter(c, !(c.image in variables.exemptImages) && (has(c.securityContext.seLinuxOptions) ? ( + has(variables.params.allowedSELinuxOptions) ? + ( + !(has(variables.params.allowedSELinuxOptions.level) && has(c.securityContext.seLinuxOptions.level) && (c.securityContext.seLinuxOptions.level == variables.params.allowedSELinuxOptions.level)) || + !(has(variables.params.allowedSELinuxOptions.role) && has(c.securityContext.seLinuxOptions.role) && (c.securityContext.seLinuxOptions.role == variables.params.allowedSELinuxOptions.role)) || + !(has(variables.params.allowedSELinuxOptions.type) && has(c.securityContext.seLinuxOptions.type) && (c.securityContext.seLinuxOptions.type == variables.params.allowedSELinuxOptions.type)) || + !(has(variables.params.allowedSELinuxOptions.user) && has(c.securityContext.seLinuxOptions.user) && (c.securityContext.seLinuxOptions.user == variables.params.allowedSELinuxOptions.user)) + ) : (has(c.securityContext.seLinuxOptions.level) || has(c.securityContext.seLinuxOptions.role) || has(c.securityContext.seLinuxOptions.type) || has(c.securityContext.seLinuxOptions.user)) + ) : false + )) + validations: + - expression: '(has(request.operation) && request.operation == "UPDATE") || variables.notViolatingSELinuxOptions' + messageExpression: '"SELinux options is not allowed, pod: " + object.metadata.name + ". Allowed options: " + variables.params.allowedSELinuxOptions' + - expression: '(has(request.operation) && request.operation == "UPDATE") || size(variables.badContainers) == 0' + messageExpression: '"SELinux options is not allowed, pod: " + object.metadata.name + ", container: " + variables.badContainers.map(c, c.name).join(", ")' + - engine: Rego + source: + rego: | + package k8spspselinux + + import data.lib.exclude_update.is_update + import data.lib.exempt_container.is_exempt + + # Disallow top level custom SELinux options + violation[{"msg": msg, "details": {}}] { + # spec.securityContext.seLinuxOptions field is immutable. + not is_update(input.review) + + has_field(input.review.object.spec.securityContext, "seLinuxOptions") + not input_seLinuxOptions_allowed(input.review.object.spec.securityContext.seLinuxOptions) + msg := sprintf("SELinux options is not allowed, pod: %v. Allowed options: %v", [input.review.object.metadata.name, input.parameters.allowedSELinuxOptions]) + } + # Disallow container level custom SELinux options + violation[{"msg": msg, "details": {}}] { + # spec.containers.securityContext.seLinuxOptions field is immutable. + not is_update(input.review) + + c := input_security_context[_] + not is_exempt(c) + has_field(c.securityContext, "seLinuxOptions") + not input_seLinuxOptions_allowed(c.securityContext.seLinuxOptions) + msg := sprintf("SELinux options is not allowed, pod: %v, container: %v. Allowed options: %v", [input.review.object.metadata.name, c.name, input.parameters.allowedSELinuxOptions]) + } + + input_seLinuxOptions_allowed(options) { + params := input.parameters.allowedSELinuxOptions[_] + field_allowed("level", options, params) + field_allowed("role", options, params) + field_allowed("type", options, params) + field_allowed("user", options, params) + } + + field_allowed(field, options, params) { + params[field] == options[field] + } + field_allowed(field, options, _) { + not has_field(options, field) + } + + input_security_context[c] { + c := input.review.object.spec.containers[_] + has_field(c.securityContext, "seLinuxOptions") + } + input_security_context[c] { + c := input.review.object.spec.initContainers[_] + has_field(c.securityContext, "seLinuxOptions") + } + input_security_context[c] { + c := input.review.object.spec.ephemeralContainers[_] + has_field(c.securityContext, "seLinuxOptions") + } + + # has_field returns whether an object has a field + has_field(object, field) = true { + object[field] + } + libs: + - | + package lib.exclude_update + + is_update(review) { + review.operation == "UPDATE" + } + - | + package lib.exempt_container + + is_exempt(container) { + exempt_images := object.get(object.get(input, "parameters", {}), "exemptImages", []) + img := container.image + exemption := exempt_images[_] + _matches_exemption(img, exemption) + } + + _matches_exemption(img, exemption) { + not endswith(exemption, "*") + exemption == img + } + + _matches_exemption(img, exemption) { + endswith(exemption, "*") + prefix := trim_suffix(exemption, "*") + startswith(img, prefix) + } ``` diff --git a/website/docs/validation/volumes.md b/website/docs/validation/volumes.md index d829de620..b15db2af3 100644 --- a/website/docs/validation/volumes.md +++ b/website/docs/validation/volumes.md @@ -16,7 +16,7 @@ metadata: name: k8spspvolumetypes annotations: metadata.gatekeeper.sh/title: "Volume Types" - metadata.gatekeeper.sh/version: 1.0.2 + metadata.gatekeeper.sh/version: 1.1.0 description: >- Restricts mountable volume types to those specified by the user. Corresponds to the `volumes` field in a PodSecurityPolicy. For more @@ -44,36 +44,50 @@ spec: type: string targets: - target: admission.k8s.gatekeeper.sh - rego: | - package k8spspvolumetypes - - import data.lib.exclude_update.is_update - - violation[{"msg": msg, "details": {}}] { - # spec.volumes field is immutable. - not is_update(input.review) - - volume_fields := {x | input.review.object.spec.volumes[_][x]; x != "name"} - field := volume_fields[_] - not input_volume_type_allowed(field) - msg := sprintf("The volume type %v is not allowed, pod: %v. Allowed volume types: %v", [field, input.review.object.metadata.name, input.parameters.volumes]) - } - - # * may be used to allow all volume types - input_volume_type_allowed(_) { - input.parameters.volumes[_] == "*" - } - - input_volume_type_allowed(field) { - field == input.parameters.volumes[_] - } - libs: - - | - package lib.exclude_update - - is_update(review) { - review.operation == "UPDATE" - } + code: + - engine: K8sNativeValidation + source: + variables: + - name: volumes + expression: 'has(object.spec.volumes) && has(request.operation) && request.operation != "UPDATE" ? object.spec.volumes : []' + - name: badVolumes + expression: | + variables.params.volumes.exists(entry, entry == "*") ? [] : variables.volumes.map(e, e.map(k, k != "name", k)).map(k, k[0]).filter(entry, !(entry in variables.params.volumes)) + validations: + - expression: 'size(variables.badVolumes) == 0' + messageExpression: '"The volume type " + variables.badVolumes.join(", ") + " is not allowed, pod: " + object.metadata.name + ". Allowed volume types: " + variables.params.volumes.join(", ")' + - engine: Rego + source: + rego: | + package k8spspvolumetypes + + import data.lib.exclude_update.is_update + + violation[{"msg": msg, "details": {}}] { + # spec.volumes field is immutable. + not is_update(input.review) + + volume_fields := {x | input.review.object.spec.volumes[_][x]; x != "name"} + field := volume_fields[_] + not input_volume_type_allowed(field) + msg := sprintf("The volume type %v is not allowed, pod: %v. Allowed volume types: %v", [field, input.review.object.metadata.name, input.parameters.volumes]) + } + + # * may be used to allow all volume types + input_volume_type_allowed(_) { + input.parameters.volumes[_] == "*" + } + + input_volume_type_allowed(field) { + field == input.parameters.volumes[_] + } + libs: + - | + package lib.exclude_update + + is_update(review) { + review.operation == "UPDATE" + } ``` From 9e3281f281ec8e36568c505d4046a816a97a55a5 Mon Sep 17 00:00:00 2001 From: Jaydip Gabani Date: Sat, 25 May 2024 00:09:52 +0000 Subject: [PATCH 2/7] using anyObject Signed-off-by: Jaydip Gabani --- .../selinux/1.1.0/artifacthub-pkg.yml | 2 +- .../selinux/1.1.0/template.yaml | 22 +++++++++---------- .../volumes/1.1.0/artifacthub-pkg.yml | 2 +- .../volumes/1.1.0/template.yaml | 4 ++-- .../pod-security-policy/selinux/template.yaml | 22 +++++++++---------- .../pod-security-policy/volumes/template.yaml | 4 ++-- src/pod-security-policy/selinux/src.cel | 22 +++++++++---------- src/pod-security-policy/volumes/src.cel | 4 ++-- website/docs/validation/selinux.md | 22 +++++++++---------- website/docs/validation/volumes.md | 4 ++-- 10 files changed, 54 insertions(+), 54 deletions(-) diff --git a/artifacthub/library/pod-security-policy/selinux/1.1.0/artifacthub-pkg.yml b/artifacthub/library/pod-security-policy/selinux/1.1.0/artifacthub-pkg.yml index ca721aa92..7c7cfa8ef 100644 --- a/artifacthub/library/pod-security-policy/selinux/1.1.0/artifacthub-pkg.yml +++ b/artifacthub/library/pod-security-policy/selinux/1.1.0/artifacthub-pkg.yml @@ -3,7 +3,7 @@ name: k8spspselinuxv2 displayName: SELinux V2 createdAt: "2024-05-20T18:10:16Z" description: Defines an allow-list of seLinuxOptions configurations for pod containers. Corresponds to a PodSecurityPolicy requiring SELinux configs. For more information, see https://kubernetes.io/docs/concepts/policy/pod-security-policy/#selinux -digest: eba35fa7bc8ccf1110732549d7eeabaee17bc8d3f100aac7cba42913578285a2 +digest: 896e8db9085d4346d6ad611b60932ce2b5a4c16126cf8f747f6eca14ff00bb1b license: Apache-2.0 homeURL: https://open-policy-agent.github.io/gatekeeper-library/website/selinux keywords: diff --git a/artifacthub/library/pod-security-policy/selinux/1.1.0/template.yaml b/artifacthub/library/pod-security-policy/selinux/1.1.0/template.yaml index d558968b0..c4452e137 100644 --- a/artifacthub/library/pod-security-policy/selinux/1.1.0/template.yaml +++ b/artifacthub/library/pod-security-policy/selinux/1.1.0/template.yaml @@ -62,22 +62,22 @@ spec: variables: - name: notViolatingSELinuxOptions expression: | - has(object.spec.securityContext) && has(object.spec.securityContext.seLinuxOptions) ? + has(variables.anyObject.spec.securityContext) && has(variables.anyObject.spec.securityContext.seLinuxOptions) ? (has(variables.params.allowedSELinuxOptions) ? ( - (has(variables.params.allowedSELinuxOptions.level) && has(object.spec.securityContext.seLinuxOptions.level) && (object.spec.securityContext.seLinuxOptions.level == variables.params.allowedSELinuxOptions.level)) && - (has(variables.params.allowedSELinuxOptions.role) && has(object.spec.securityContext.seLinuxOptions.role) && (object.spec.securityContext.seLinuxOptions.role == variables.params.allowedSELinuxOptions.role)) && - (has(variables.params.allowedSELinuxOptions.type) && has(object.spec.securityContext.seLinuxOptions.type) && (object.spec.securityContext.seLinuxOptions.type == variables.params.allowedSELinuxOptions.type)) && - (has(variables.params.allowedSELinuxOptions.user) && has(object.spec.securityContext.seLinuxOptions.user) && (object.spec.securityContext.seLinuxOptions.user == variables.params.allowedSELinuxOptions.user)) + (has(variables.params.allowedSELinuxOptions.level) && has(variables.anyObject.spec.securityContext.seLinuxOptions.level) && (variables.anyObject.spec.securityContext.seLinuxOptions.level == variables.params.allowedSELinuxOptions.level)) && + (has(variables.params.allowedSELinuxOptions.role) && has(variables.anyObject.spec.securityContext.seLinuxOptions.role) && (variables.anyObject.spec.securityContext.seLinuxOptions.role == variables.params.allowedSELinuxOptions.role)) && + (has(variables.params.allowedSELinuxOptions.type) && has(variables.anyObject.spec.securityContext.seLinuxOptions.type) && (variables.anyObject.spec.securityContext.seLinuxOptions.type == variables.params.allowedSELinuxOptions.type)) && + (has(variables.params.allowedSELinuxOptions.user) && has(variables.anyObject.spec.securityContext.seLinuxOptions.user) && (variables.anyObject.spec.securityContext.seLinuxOptions.user == variables.params.allowedSELinuxOptions.user)) ) : - (!has(object.spec.securityContext.seLinuxOptions.level) && !has(object.spec.securityContext.seLinuxOptions.role) && !has(object.spec.securityContext.seLinuxOptions.type) && !has(object.spec.securityContext.seLinuxOptions.user))) + (!has(variables.anyObject.spec.securityContext.seLinuxOptions.level) && !has(variables.anyObject.spec.securityContext.seLinuxOptions.role) && !has(variables.anyObject.spec.securityContext.seLinuxOptions.type) && !has(variables.anyObject.spec.securityContext.seLinuxOptions.user))) : true - name: containers - expression: 'has(object.spec.containers) ? object.spec.containers.filter(c, has(c.securityContext) && has(c.securityContext.seLinuxOptions)) : []' + expression: 'has(variables.anyObject.spec.containers) ? variables.anyObject.spec.containers.filter(c, has(c.securityContext) && has(c.securityContext.seLinuxOptions)) : []' - name: initContainers - expression: 'has(object.spec.initContainers) ? object.spec.initContainers.filter(c, has(c.securityContext) && has(c.securityContext.seLinuxOptions)) : []' + expression: 'has(variables.anyObject.spec.initContainers) ? variables.anyObject.spec.initContainers.filter(c, has(c.securityContext) && has(c.securityContext.seLinuxOptions)) : []' - name: ephemeralContainers - expression: 'has(object.spec.ephemeralContainers) ? object.spec.ephemeralContainers.filter(c, has(c.securityContext) && has(c.securityContext.seLinuxOptions)) : []' + expression: 'has(variables.anyObject.spec.ephemeralContainers) ? variables.anyObject.spec.ephemeralContainers.filter(c, has(c.securityContext) && has(c.securityContext.seLinuxOptions)) : []' - name: exemptImagePrefixes expression: | !has(variables.params.exemptImages) ? [] : @@ -105,9 +105,9 @@ spec: )) validations: - expression: '(has(request.operation) && request.operation == "UPDATE") || variables.notViolatingSELinuxOptions' - messageExpression: '"SELinux options is not allowed, pod: " + object.metadata.name + ". Allowed options: " + variables.params.allowedSELinuxOptions' + messageExpression: '"SELinux options is not allowed, pod: " + variables.anyObject.metadata.name + ". Allowed options: " + variables.params.allowedSELinuxOptions' - expression: '(has(request.operation) && request.operation == "UPDATE") || size(variables.badContainers) == 0' - messageExpression: '"SELinux options is not allowed, pod: " + object.metadata.name + ", container: " + variables.badContainers.map(c, c.name).join(", ")' + messageExpression: '"SELinux options is not allowed, pod: " + variables.anyObject.metadata.name + ", container: " + variables.badContainers.map(c, c.name).join(", ")' - engine: Rego source: rego: | diff --git a/artifacthub/library/pod-security-policy/volumes/1.1.0/artifacthub-pkg.yml b/artifacthub/library/pod-security-policy/volumes/1.1.0/artifacthub-pkg.yml index 28b97d66f..ca79b7c88 100644 --- a/artifacthub/library/pod-security-policy/volumes/1.1.0/artifacthub-pkg.yml +++ b/artifacthub/library/pod-security-policy/volumes/1.1.0/artifacthub-pkg.yml @@ -3,7 +3,7 @@ name: k8spspvolumetypes displayName: Volume Types createdAt: "2024-05-14T00:55:44Z" description: Restricts mountable volume types to those specified by the user. Corresponds to the `volumes` field in a PodSecurityPolicy. For more information, see https://kubernetes.io/docs/concepts/policy/pod-security-policy/#volumes-and-file-systems -digest: f27f6759e3fc2969cddea91ad3b1b0d06554d63c6b9137e35e89a5e8dbd458d9 +digest: cf81297bf562f15dc11e9c56a6e78c7e0345934cea0ae6285735d9bc66a366f1 license: Apache-2.0 homeURL: https://open-policy-agent.github.io/gatekeeper-library/website/volumes keywords: diff --git a/artifacthub/library/pod-security-policy/volumes/1.1.0/template.yaml b/artifacthub/library/pod-security-policy/volumes/1.1.0/template.yaml index 4e6233966..28a7db6f4 100644 --- a/artifacthub/library/pod-security-policy/volumes/1.1.0/template.yaml +++ b/artifacthub/library/pod-security-policy/volumes/1.1.0/template.yaml @@ -37,13 +37,13 @@ spec: source: variables: - name: volumes - expression: 'has(object.spec.volumes) && has(request.operation) && request.operation != "UPDATE" ? object.spec.volumes : []' + expression: 'has(variables.anyObject.spec.volumes) && has(request.operation) && request.operation != "UPDATE" ? variables.anyObject.spec.volumes : []' - name: badVolumes expression: | variables.params.volumes.exists(entry, entry == "*") ? [] : variables.volumes.map(e, e.map(k, k != "name", k)).map(k, k[0]).filter(entry, !(entry in variables.params.volumes)) validations: - expression: 'size(variables.badVolumes) == 0' - messageExpression: '"The volume type " + variables.badVolumes.join(", ") + " is not allowed, pod: " + object.metadata.name + ". Allowed volume types: " + variables.params.volumes.join(", ")' + messageExpression: '"The volume type " + variables.badVolumes.join(", ") + " is not allowed, pod: " + variables.anyObject.metadata.name + ". Allowed volume types: " + variables.params.volumes.join(", ")' - engine: Rego source: rego: | diff --git a/library/pod-security-policy/selinux/template.yaml b/library/pod-security-policy/selinux/template.yaml index d558968b0..c4452e137 100644 --- a/library/pod-security-policy/selinux/template.yaml +++ b/library/pod-security-policy/selinux/template.yaml @@ -62,22 +62,22 @@ spec: variables: - name: notViolatingSELinuxOptions expression: | - has(object.spec.securityContext) && has(object.spec.securityContext.seLinuxOptions) ? + has(variables.anyObject.spec.securityContext) && has(variables.anyObject.spec.securityContext.seLinuxOptions) ? (has(variables.params.allowedSELinuxOptions) ? ( - (has(variables.params.allowedSELinuxOptions.level) && has(object.spec.securityContext.seLinuxOptions.level) && (object.spec.securityContext.seLinuxOptions.level == variables.params.allowedSELinuxOptions.level)) && - (has(variables.params.allowedSELinuxOptions.role) && has(object.spec.securityContext.seLinuxOptions.role) && (object.spec.securityContext.seLinuxOptions.role == variables.params.allowedSELinuxOptions.role)) && - (has(variables.params.allowedSELinuxOptions.type) && has(object.spec.securityContext.seLinuxOptions.type) && (object.spec.securityContext.seLinuxOptions.type == variables.params.allowedSELinuxOptions.type)) && - (has(variables.params.allowedSELinuxOptions.user) && has(object.spec.securityContext.seLinuxOptions.user) && (object.spec.securityContext.seLinuxOptions.user == variables.params.allowedSELinuxOptions.user)) + (has(variables.params.allowedSELinuxOptions.level) && has(variables.anyObject.spec.securityContext.seLinuxOptions.level) && (variables.anyObject.spec.securityContext.seLinuxOptions.level == variables.params.allowedSELinuxOptions.level)) && + (has(variables.params.allowedSELinuxOptions.role) && has(variables.anyObject.spec.securityContext.seLinuxOptions.role) && (variables.anyObject.spec.securityContext.seLinuxOptions.role == variables.params.allowedSELinuxOptions.role)) && + (has(variables.params.allowedSELinuxOptions.type) && has(variables.anyObject.spec.securityContext.seLinuxOptions.type) && (variables.anyObject.spec.securityContext.seLinuxOptions.type == variables.params.allowedSELinuxOptions.type)) && + (has(variables.params.allowedSELinuxOptions.user) && has(variables.anyObject.spec.securityContext.seLinuxOptions.user) && (variables.anyObject.spec.securityContext.seLinuxOptions.user == variables.params.allowedSELinuxOptions.user)) ) : - (!has(object.spec.securityContext.seLinuxOptions.level) && !has(object.spec.securityContext.seLinuxOptions.role) && !has(object.spec.securityContext.seLinuxOptions.type) && !has(object.spec.securityContext.seLinuxOptions.user))) + (!has(variables.anyObject.spec.securityContext.seLinuxOptions.level) && !has(variables.anyObject.spec.securityContext.seLinuxOptions.role) && !has(variables.anyObject.spec.securityContext.seLinuxOptions.type) && !has(variables.anyObject.spec.securityContext.seLinuxOptions.user))) : true - name: containers - expression: 'has(object.spec.containers) ? object.spec.containers.filter(c, has(c.securityContext) && has(c.securityContext.seLinuxOptions)) : []' + expression: 'has(variables.anyObject.spec.containers) ? variables.anyObject.spec.containers.filter(c, has(c.securityContext) && has(c.securityContext.seLinuxOptions)) : []' - name: initContainers - expression: 'has(object.spec.initContainers) ? object.spec.initContainers.filter(c, has(c.securityContext) && has(c.securityContext.seLinuxOptions)) : []' + expression: 'has(variables.anyObject.spec.initContainers) ? variables.anyObject.spec.initContainers.filter(c, has(c.securityContext) && has(c.securityContext.seLinuxOptions)) : []' - name: ephemeralContainers - expression: 'has(object.spec.ephemeralContainers) ? object.spec.ephemeralContainers.filter(c, has(c.securityContext) && has(c.securityContext.seLinuxOptions)) : []' + expression: 'has(variables.anyObject.spec.ephemeralContainers) ? variables.anyObject.spec.ephemeralContainers.filter(c, has(c.securityContext) && has(c.securityContext.seLinuxOptions)) : []' - name: exemptImagePrefixes expression: | !has(variables.params.exemptImages) ? [] : @@ -105,9 +105,9 @@ spec: )) validations: - expression: '(has(request.operation) && request.operation == "UPDATE") || variables.notViolatingSELinuxOptions' - messageExpression: '"SELinux options is not allowed, pod: " + object.metadata.name + ". Allowed options: " + variables.params.allowedSELinuxOptions' + messageExpression: '"SELinux options is not allowed, pod: " + variables.anyObject.metadata.name + ". Allowed options: " + variables.params.allowedSELinuxOptions' - expression: '(has(request.operation) && request.operation == "UPDATE") || size(variables.badContainers) == 0' - messageExpression: '"SELinux options is not allowed, pod: " + object.metadata.name + ", container: " + variables.badContainers.map(c, c.name).join(", ")' + messageExpression: '"SELinux options is not allowed, pod: " + variables.anyObject.metadata.name + ", container: " + variables.badContainers.map(c, c.name).join(", ")' - engine: Rego source: rego: | diff --git a/library/pod-security-policy/volumes/template.yaml b/library/pod-security-policy/volumes/template.yaml index 4e6233966..28a7db6f4 100644 --- a/library/pod-security-policy/volumes/template.yaml +++ b/library/pod-security-policy/volumes/template.yaml @@ -37,13 +37,13 @@ spec: source: variables: - name: volumes - expression: 'has(object.spec.volumes) && has(request.operation) && request.operation != "UPDATE" ? object.spec.volumes : []' + expression: 'has(variables.anyObject.spec.volumes) && has(request.operation) && request.operation != "UPDATE" ? variables.anyObject.spec.volumes : []' - name: badVolumes expression: | variables.params.volumes.exists(entry, entry == "*") ? [] : variables.volumes.map(e, e.map(k, k != "name", k)).map(k, k[0]).filter(entry, !(entry in variables.params.volumes)) validations: - expression: 'size(variables.badVolumes) == 0' - messageExpression: '"The volume type " + variables.badVolumes.join(", ") + " is not allowed, pod: " + object.metadata.name + ". Allowed volume types: " + variables.params.volumes.join(", ")' + messageExpression: '"The volume type " + variables.badVolumes.join(", ") + " is not allowed, pod: " + variables.anyObject.metadata.name + ". Allowed volume types: " + variables.params.volumes.join(", ")' - engine: Rego source: rego: | diff --git a/src/pod-security-policy/selinux/src.cel b/src/pod-security-policy/selinux/src.cel index 0a0d04a79..96028c4c4 100644 --- a/src/pod-security-policy/selinux/src.cel +++ b/src/pod-security-policy/selinux/src.cel @@ -1,22 +1,22 @@ variables: - name: notViolatingSELinuxOptions expression: | - has(object.spec.securityContext) && has(object.spec.securityContext.seLinuxOptions) ? + has(variables.anyObject.spec.securityContext) && has(variables.anyObject.spec.securityContext.seLinuxOptions) ? (has(variables.params.allowedSELinuxOptions) ? ( - (has(variables.params.allowedSELinuxOptions.level) && has(object.spec.securityContext.seLinuxOptions.level) && (object.spec.securityContext.seLinuxOptions.level == variables.params.allowedSELinuxOptions.level)) && - (has(variables.params.allowedSELinuxOptions.role) && has(object.spec.securityContext.seLinuxOptions.role) && (object.spec.securityContext.seLinuxOptions.role == variables.params.allowedSELinuxOptions.role)) && - (has(variables.params.allowedSELinuxOptions.type) && has(object.spec.securityContext.seLinuxOptions.type) && (object.spec.securityContext.seLinuxOptions.type == variables.params.allowedSELinuxOptions.type)) && - (has(variables.params.allowedSELinuxOptions.user) && has(object.spec.securityContext.seLinuxOptions.user) && (object.spec.securityContext.seLinuxOptions.user == variables.params.allowedSELinuxOptions.user)) + (has(variables.params.allowedSELinuxOptions.level) && has(variables.anyObject.spec.securityContext.seLinuxOptions.level) && (variables.anyObject.spec.securityContext.seLinuxOptions.level == variables.params.allowedSELinuxOptions.level)) && + (has(variables.params.allowedSELinuxOptions.role) && has(variables.anyObject.spec.securityContext.seLinuxOptions.role) && (variables.anyObject.spec.securityContext.seLinuxOptions.role == variables.params.allowedSELinuxOptions.role)) && + (has(variables.params.allowedSELinuxOptions.type) && has(variables.anyObject.spec.securityContext.seLinuxOptions.type) && (variables.anyObject.spec.securityContext.seLinuxOptions.type == variables.params.allowedSELinuxOptions.type)) && + (has(variables.params.allowedSELinuxOptions.user) && has(variables.anyObject.spec.securityContext.seLinuxOptions.user) && (variables.anyObject.spec.securityContext.seLinuxOptions.user == variables.params.allowedSELinuxOptions.user)) ) : - (!has(object.spec.securityContext.seLinuxOptions.level) && !has(object.spec.securityContext.seLinuxOptions.role) && !has(object.spec.securityContext.seLinuxOptions.type) && !has(object.spec.securityContext.seLinuxOptions.user))) + (!has(variables.anyObject.spec.securityContext.seLinuxOptions.level) && !has(variables.anyObject.spec.securityContext.seLinuxOptions.role) && !has(variables.anyObject.spec.securityContext.seLinuxOptions.type) && !has(variables.anyObject.spec.securityContext.seLinuxOptions.user))) : true - name: containers - expression: 'has(object.spec.containers) ? object.spec.containers.filter(c, has(c.securityContext) && has(c.securityContext.seLinuxOptions)) : []' + expression: 'has(variables.anyObject.spec.containers) ? variables.anyObject.spec.containers.filter(c, has(c.securityContext) && has(c.securityContext.seLinuxOptions)) : []' - name: initContainers - expression: 'has(object.spec.initContainers) ? object.spec.initContainers.filter(c, has(c.securityContext) && has(c.securityContext.seLinuxOptions)) : []' + expression: 'has(variables.anyObject.spec.initContainers) ? variables.anyObject.spec.initContainers.filter(c, has(c.securityContext) && has(c.securityContext.seLinuxOptions)) : []' - name: ephemeralContainers - expression: 'has(object.spec.ephemeralContainers) ? object.spec.ephemeralContainers.filter(c, has(c.securityContext) && has(c.securityContext.seLinuxOptions)) : []' + expression: 'has(variables.anyObject.spec.ephemeralContainers) ? variables.anyObject.spec.ephemeralContainers.filter(c, has(c.securityContext) && has(c.securityContext.seLinuxOptions)) : []' - name: exemptImagePrefixes expression: | !has(variables.params.exemptImages) ? [] : @@ -44,6 +44,6 @@ variables: )) validations: - expression: '(has(request.operation) && request.operation == "UPDATE") || variables.notViolatingSELinuxOptions' - messageExpression: '"SELinux options is not allowed, pod: " + object.metadata.name + ". Allowed options: " + variables.params.allowedSELinuxOptions' + messageExpression: '"SELinux options is not allowed, pod: " + variables.anyObject.metadata.name + ". Allowed options: " + variables.params.allowedSELinuxOptions' - expression: '(has(request.operation) && request.operation == "UPDATE") || size(variables.badContainers) == 0' - messageExpression: '"SELinux options is not allowed, pod: " + object.metadata.name + ", container: " + variables.badContainers.map(c, c.name).join(", ")' + messageExpression: '"SELinux options is not allowed, pod: " + variables.anyObject.metadata.name + ", container: " + variables.badContainers.map(c, c.name).join(", ")' diff --git a/src/pod-security-policy/volumes/src.cel b/src/pod-security-policy/volumes/src.cel index cc51735a6..fbadb8135 100644 --- a/src/pod-security-policy/volumes/src.cel +++ b/src/pod-security-policy/volumes/src.cel @@ -1,9 +1,9 @@ variables: - name: volumes - expression: 'has(object.spec.volumes) && has(request.operation) && request.operation != "UPDATE" ? object.spec.volumes : []' + expression: 'has(variables.anyObject.spec.volumes) && has(request.operation) && request.operation != "UPDATE" ? variables.anyObject.spec.volumes : []' - name: badVolumes expression: | variables.params.volumes.exists(entry, entry == "*") ? [] : variables.volumes.map(e, e.map(k, k != "name", k)).map(k, k[0]).filter(entry, !(entry in variables.params.volumes)) validations: - expression: 'size(variables.badVolumes) == 0' - messageExpression: '"The volume type " + variables.badVolumes.join(", ") + " is not allowed, pod: " + object.metadata.name + ". Allowed volume types: " + variables.params.volumes.join(", ")' + messageExpression: '"The volume type " + variables.badVolumes.join(", ") + " is not allowed, pod: " + variables.anyObject.metadata.name + ". Allowed volume types: " + variables.params.volumes.join(", ")' diff --git a/website/docs/validation/selinux.md b/website/docs/validation/selinux.md index 247a7afac..2fcb34c6a 100644 --- a/website/docs/validation/selinux.md +++ b/website/docs/validation/selinux.md @@ -74,22 +74,22 @@ spec: variables: - name: notViolatingSELinuxOptions expression: | - has(object.spec.securityContext) && has(object.spec.securityContext.seLinuxOptions) ? + has(variables.anyObject.spec.securityContext) && has(variables.anyObject.spec.securityContext.seLinuxOptions) ? (has(variables.params.allowedSELinuxOptions) ? ( - (has(variables.params.allowedSELinuxOptions.level) && has(object.spec.securityContext.seLinuxOptions.level) && (object.spec.securityContext.seLinuxOptions.level == variables.params.allowedSELinuxOptions.level)) && - (has(variables.params.allowedSELinuxOptions.role) && has(object.spec.securityContext.seLinuxOptions.role) && (object.spec.securityContext.seLinuxOptions.role == variables.params.allowedSELinuxOptions.role)) && - (has(variables.params.allowedSELinuxOptions.type) && has(object.spec.securityContext.seLinuxOptions.type) && (object.spec.securityContext.seLinuxOptions.type == variables.params.allowedSELinuxOptions.type)) && - (has(variables.params.allowedSELinuxOptions.user) && has(object.spec.securityContext.seLinuxOptions.user) && (object.spec.securityContext.seLinuxOptions.user == variables.params.allowedSELinuxOptions.user)) + (has(variables.params.allowedSELinuxOptions.level) && has(variables.anyObject.spec.securityContext.seLinuxOptions.level) && (variables.anyObject.spec.securityContext.seLinuxOptions.level == variables.params.allowedSELinuxOptions.level)) && + (has(variables.params.allowedSELinuxOptions.role) && has(variables.anyObject.spec.securityContext.seLinuxOptions.role) && (variables.anyObject.spec.securityContext.seLinuxOptions.role == variables.params.allowedSELinuxOptions.role)) && + (has(variables.params.allowedSELinuxOptions.type) && has(variables.anyObject.spec.securityContext.seLinuxOptions.type) && (variables.anyObject.spec.securityContext.seLinuxOptions.type == variables.params.allowedSELinuxOptions.type)) && + (has(variables.params.allowedSELinuxOptions.user) && has(variables.anyObject.spec.securityContext.seLinuxOptions.user) && (variables.anyObject.spec.securityContext.seLinuxOptions.user == variables.params.allowedSELinuxOptions.user)) ) : - (!has(object.spec.securityContext.seLinuxOptions.level) && !has(object.spec.securityContext.seLinuxOptions.role) && !has(object.spec.securityContext.seLinuxOptions.type) && !has(object.spec.securityContext.seLinuxOptions.user))) + (!has(variables.anyObject.spec.securityContext.seLinuxOptions.level) && !has(variables.anyObject.spec.securityContext.seLinuxOptions.role) && !has(variables.anyObject.spec.securityContext.seLinuxOptions.type) && !has(variables.anyObject.spec.securityContext.seLinuxOptions.user))) : true - name: containers - expression: 'has(object.spec.containers) ? object.spec.containers.filter(c, has(c.securityContext) && has(c.securityContext.seLinuxOptions)) : []' + expression: 'has(variables.anyObject.spec.containers) ? variables.anyObject.spec.containers.filter(c, has(c.securityContext) && has(c.securityContext.seLinuxOptions)) : []' - name: initContainers - expression: 'has(object.spec.initContainers) ? object.spec.initContainers.filter(c, has(c.securityContext) && has(c.securityContext.seLinuxOptions)) : []' + expression: 'has(variables.anyObject.spec.initContainers) ? variables.anyObject.spec.initContainers.filter(c, has(c.securityContext) && has(c.securityContext.seLinuxOptions)) : []' - name: ephemeralContainers - expression: 'has(object.spec.ephemeralContainers) ? object.spec.ephemeralContainers.filter(c, has(c.securityContext) && has(c.securityContext.seLinuxOptions)) : []' + expression: 'has(variables.anyObject.spec.ephemeralContainers) ? variables.anyObject.spec.ephemeralContainers.filter(c, has(c.securityContext) && has(c.securityContext.seLinuxOptions)) : []' - name: exemptImagePrefixes expression: | !has(variables.params.exemptImages) ? [] : @@ -117,9 +117,9 @@ spec: )) validations: - expression: '(has(request.operation) && request.operation == "UPDATE") || variables.notViolatingSELinuxOptions' - messageExpression: '"SELinux options is not allowed, pod: " + object.metadata.name + ". Allowed options: " + variables.params.allowedSELinuxOptions' + messageExpression: '"SELinux options is not allowed, pod: " + variables.anyObject.metadata.name + ". Allowed options: " + variables.params.allowedSELinuxOptions' - expression: '(has(request.operation) && request.operation == "UPDATE") || size(variables.badContainers) == 0' - messageExpression: '"SELinux options is not allowed, pod: " + object.metadata.name + ", container: " + variables.badContainers.map(c, c.name).join(", ")' + messageExpression: '"SELinux options is not allowed, pod: " + variables.anyObject.metadata.name + ", container: " + variables.badContainers.map(c, c.name).join(", ")' - engine: Rego source: rego: | diff --git a/website/docs/validation/volumes.md b/website/docs/validation/volumes.md index b15db2af3..070f152ee 100644 --- a/website/docs/validation/volumes.md +++ b/website/docs/validation/volumes.md @@ -49,13 +49,13 @@ spec: source: variables: - name: volumes - expression: 'has(object.spec.volumes) && has(request.operation) && request.operation != "UPDATE" ? object.spec.volumes : []' + expression: 'has(variables.anyObject.spec.volumes) && has(request.operation) && request.operation != "UPDATE" ? variables.anyObject.spec.volumes : []' - name: badVolumes expression: | variables.params.volumes.exists(entry, entry == "*") ? [] : variables.volumes.map(e, e.map(k, k != "name", k)).map(k, k[0]).filter(entry, !(entry in variables.params.volumes)) validations: - expression: 'size(variables.badVolumes) == 0' - messageExpression: '"The volume type " + variables.badVolumes.join(", ") + " is not allowed, pod: " + object.metadata.name + ". Allowed volume types: " + variables.params.volumes.join(", ")' + messageExpression: '"The volume type " + variables.badVolumes.join(", ") + " is not allowed, pod: " + variables.anyObject.metadata.name + ". Allowed volume types: " + variables.params.volumes.join(", ")' - engine: Rego source: rego: | From 833ed630198ae6a247bc85078696aa6f916001a1 Mon Sep 17 00:00:00 2001 From: Jaydip Gabani Date: Thu, 30 May 2024 01:16:47 +0000 Subject: [PATCH 3/7] fixing SElinux CEL Signed-off-by: Jaydip Gabani --- .../selinux/1.1.0/artifacthub-pkg.yml | 2 +- .../selinux/1.1.0/template.yaml | 28 +++++++++++-------- .../pod-security-policy/selinux/template.yaml | 28 +++++++++++-------- src/pod-security-policy/selinux/src.cel | 28 +++++++++++-------- website/docs/validation/selinux.md | 28 +++++++++++-------- 5 files changed, 65 insertions(+), 49 deletions(-) diff --git a/artifacthub/library/pod-security-policy/selinux/1.1.0/artifacthub-pkg.yml b/artifacthub/library/pod-security-policy/selinux/1.1.0/artifacthub-pkg.yml index 7c7cfa8ef..faf470b72 100644 --- a/artifacthub/library/pod-security-policy/selinux/1.1.0/artifacthub-pkg.yml +++ b/artifacthub/library/pod-security-policy/selinux/1.1.0/artifacthub-pkg.yml @@ -3,7 +3,7 @@ name: k8spspselinuxv2 displayName: SELinux V2 createdAt: "2024-05-20T18:10:16Z" description: Defines an allow-list of seLinuxOptions configurations for pod containers. Corresponds to a PodSecurityPolicy requiring SELinux configs. For more information, see https://kubernetes.io/docs/concepts/policy/pod-security-policy/#selinux -digest: 896e8db9085d4346d6ad611b60932ce2b5a4c16126cf8f747f6eca14ff00bb1b +digest: fc1b59a39438cd81c6e376bfa5370afbfca109c31d67b2f14e6e2bfa4fa64960 license: Apache-2.0 homeURL: https://open-policy-agent.github.io/gatekeeper-library/website/selinux keywords: diff --git a/artifacthub/library/pod-security-policy/selinux/1.1.0/template.yaml b/artifacthub/library/pod-security-policy/selinux/1.1.0/template.yaml index c4452e137..171a6b5b7 100644 --- a/artifacthub/library/pod-security-policy/selinux/1.1.0/template.yaml +++ b/artifacthub/library/pod-security-policy/selinux/1.1.0/template.yaml @@ -65,12 +65,14 @@ spec: has(variables.anyObject.spec.securityContext) && has(variables.anyObject.spec.securityContext.seLinuxOptions) ? (has(variables.params.allowedSELinuxOptions) ? ( - (has(variables.params.allowedSELinuxOptions.level) && has(variables.anyObject.spec.securityContext.seLinuxOptions.level) && (variables.anyObject.spec.securityContext.seLinuxOptions.level == variables.params.allowedSELinuxOptions.level)) && - (has(variables.params.allowedSELinuxOptions.role) && has(variables.anyObject.spec.securityContext.seLinuxOptions.role) && (variables.anyObject.spec.securityContext.seLinuxOptions.role == variables.params.allowedSELinuxOptions.role)) && - (has(variables.params.allowedSELinuxOptions.type) && has(variables.anyObject.spec.securityContext.seLinuxOptions.type) && (variables.anyObject.spec.securityContext.seLinuxOptions.type == variables.params.allowedSELinuxOptions.type)) && - (has(variables.params.allowedSELinuxOptions.user) && has(variables.anyObject.spec.securityContext.seLinuxOptions.user) && (variables.anyObject.spec.securityContext.seLinuxOptions.user == variables.params.allowedSELinuxOptions.user)) + variables.params.allowedSELinuxOptions.exists(opts, + (has(opts.level) ? has(variables.anyObject.spec.securityContext.seLinuxOptions.level) && (variables.anyObject.spec.securityContext.seLinuxOptions.level == opts.level) : !has(variables.anyObject.spec.securityContext.seLinuxOptions.level)) && + (has(opts.role) ? has(variables.anyObject.spec.securityContext.seLinuxOptions.role) && (variables.anyObject.spec.securityContext.seLinuxOptions.role == opts.role) : !has(variables.anyObject.spec.securityContext.seLinuxOptions.role)) && + (has(opts.type) ? has(variables.anyObject.spec.securityContext.seLinuxOptions.type) && (variables.anyObject.spec.securityContext.seLinuxOptions.type == opts.type) : !has(variables.anyObject.spec.securityContext.seLinuxOptions.type)) && + (has(opts.user) ? has(variables.anyObject.spec.securityContext.seLinuxOptions.user) && (variables.anyObject.spec.securityContext.seLinuxOptions.user == opts.user) : !has(variables.anyObject.spec.securityContext.seLinuxOptions.user)) + ) ) : - (!has(variables.anyObject.spec.securityContext.seLinuxOptions.level) && !has(variables.anyObject.spec.securityContext.seLinuxOptions.role) && !has(variables.anyObject.spec.securityContext.seLinuxOptions.type) && !has(variables.anyObject.spec.securityContext.seLinuxOptions.user))) + true) : true - name: containers expression: 'has(variables.anyObject.spec.containers) ? variables.anyObject.spec.containers.filter(c, has(c.securityContext) && has(c.securityContext.seLinuxOptions)) : []' @@ -96,13 +98,15 @@ spec: (variables.containers + variables.initContainers + variables.ephemeralContainers).filter(c, !(c.image in variables.exemptImages) && (has(c.securityContext.seLinuxOptions) ? ( has(variables.params.allowedSELinuxOptions) ? ( - !(has(variables.params.allowedSELinuxOptions.level) && has(c.securityContext.seLinuxOptions.level) && (c.securityContext.seLinuxOptions.level == variables.params.allowedSELinuxOptions.level)) || - !(has(variables.params.allowedSELinuxOptions.role) && has(c.securityContext.seLinuxOptions.role) && (c.securityContext.seLinuxOptions.role == variables.params.allowedSELinuxOptions.role)) || - !(has(variables.params.allowedSELinuxOptions.type) && has(c.securityContext.seLinuxOptions.type) && (c.securityContext.seLinuxOptions.type == variables.params.allowedSELinuxOptions.type)) || - !(has(variables.params.allowedSELinuxOptions.user) && has(c.securityContext.seLinuxOptions.user) && (c.securityContext.seLinuxOptions.user == variables.params.allowedSELinuxOptions.user)) - ) : (has(c.securityContext.seLinuxOptions.level) || has(c.securityContext.seLinuxOptions.role) || has(c.securityContext.seLinuxOptions.type) || has(c.securityContext.seLinuxOptions.user)) - ) : false - )) + !variables.params.allowedSELinuxOptions.exists(opts, + (has(opts.level) ? has(c.securityContext.seLinuxOptions.level) && (c.securityContext.seLinuxOptions.level == opts.level) : !has(c.securityContext.seLinuxOptions.level)) && + (has(opts.role) ? has(c.securityContext.seLinuxOptions.role) && (c.securityContext.seLinuxOptions.role == opts.role) : !has(c.securityContext.seLinuxOptions.role)) && + (has(opts.type) ? has(c.securityContext.seLinuxOptions.type) && (c.securityContext.seLinuxOptions.type == opts.type) : !has(c.securityContext.seLinuxOptions.type)) && + (has(opts.user) ? has(c.securityContext.seLinuxOptions.user) && (c.securityContext.seLinuxOptions.user == opts.user) : !has(c.securityContext.seLinuxOptions.user)) + ) + ) : false) + : false) + ) validations: - expression: '(has(request.operation) && request.operation == "UPDATE") || variables.notViolatingSELinuxOptions' messageExpression: '"SELinux options is not allowed, pod: " + variables.anyObject.metadata.name + ". Allowed options: " + variables.params.allowedSELinuxOptions' diff --git a/library/pod-security-policy/selinux/template.yaml b/library/pod-security-policy/selinux/template.yaml index c4452e137..171a6b5b7 100644 --- a/library/pod-security-policy/selinux/template.yaml +++ b/library/pod-security-policy/selinux/template.yaml @@ -65,12 +65,14 @@ spec: has(variables.anyObject.spec.securityContext) && has(variables.anyObject.spec.securityContext.seLinuxOptions) ? (has(variables.params.allowedSELinuxOptions) ? ( - (has(variables.params.allowedSELinuxOptions.level) && has(variables.anyObject.spec.securityContext.seLinuxOptions.level) && (variables.anyObject.spec.securityContext.seLinuxOptions.level == variables.params.allowedSELinuxOptions.level)) && - (has(variables.params.allowedSELinuxOptions.role) && has(variables.anyObject.spec.securityContext.seLinuxOptions.role) && (variables.anyObject.spec.securityContext.seLinuxOptions.role == variables.params.allowedSELinuxOptions.role)) && - (has(variables.params.allowedSELinuxOptions.type) && has(variables.anyObject.spec.securityContext.seLinuxOptions.type) && (variables.anyObject.spec.securityContext.seLinuxOptions.type == variables.params.allowedSELinuxOptions.type)) && - (has(variables.params.allowedSELinuxOptions.user) && has(variables.anyObject.spec.securityContext.seLinuxOptions.user) && (variables.anyObject.spec.securityContext.seLinuxOptions.user == variables.params.allowedSELinuxOptions.user)) + variables.params.allowedSELinuxOptions.exists(opts, + (has(opts.level) ? has(variables.anyObject.spec.securityContext.seLinuxOptions.level) && (variables.anyObject.spec.securityContext.seLinuxOptions.level == opts.level) : !has(variables.anyObject.spec.securityContext.seLinuxOptions.level)) && + (has(opts.role) ? has(variables.anyObject.spec.securityContext.seLinuxOptions.role) && (variables.anyObject.spec.securityContext.seLinuxOptions.role == opts.role) : !has(variables.anyObject.spec.securityContext.seLinuxOptions.role)) && + (has(opts.type) ? has(variables.anyObject.spec.securityContext.seLinuxOptions.type) && (variables.anyObject.spec.securityContext.seLinuxOptions.type == opts.type) : !has(variables.anyObject.spec.securityContext.seLinuxOptions.type)) && + (has(opts.user) ? has(variables.anyObject.spec.securityContext.seLinuxOptions.user) && (variables.anyObject.spec.securityContext.seLinuxOptions.user == opts.user) : !has(variables.anyObject.spec.securityContext.seLinuxOptions.user)) + ) ) : - (!has(variables.anyObject.spec.securityContext.seLinuxOptions.level) && !has(variables.anyObject.spec.securityContext.seLinuxOptions.role) && !has(variables.anyObject.spec.securityContext.seLinuxOptions.type) && !has(variables.anyObject.spec.securityContext.seLinuxOptions.user))) + true) : true - name: containers expression: 'has(variables.anyObject.spec.containers) ? variables.anyObject.spec.containers.filter(c, has(c.securityContext) && has(c.securityContext.seLinuxOptions)) : []' @@ -96,13 +98,15 @@ spec: (variables.containers + variables.initContainers + variables.ephemeralContainers).filter(c, !(c.image in variables.exemptImages) && (has(c.securityContext.seLinuxOptions) ? ( has(variables.params.allowedSELinuxOptions) ? ( - !(has(variables.params.allowedSELinuxOptions.level) && has(c.securityContext.seLinuxOptions.level) && (c.securityContext.seLinuxOptions.level == variables.params.allowedSELinuxOptions.level)) || - !(has(variables.params.allowedSELinuxOptions.role) && has(c.securityContext.seLinuxOptions.role) && (c.securityContext.seLinuxOptions.role == variables.params.allowedSELinuxOptions.role)) || - !(has(variables.params.allowedSELinuxOptions.type) && has(c.securityContext.seLinuxOptions.type) && (c.securityContext.seLinuxOptions.type == variables.params.allowedSELinuxOptions.type)) || - !(has(variables.params.allowedSELinuxOptions.user) && has(c.securityContext.seLinuxOptions.user) && (c.securityContext.seLinuxOptions.user == variables.params.allowedSELinuxOptions.user)) - ) : (has(c.securityContext.seLinuxOptions.level) || has(c.securityContext.seLinuxOptions.role) || has(c.securityContext.seLinuxOptions.type) || has(c.securityContext.seLinuxOptions.user)) - ) : false - )) + !variables.params.allowedSELinuxOptions.exists(opts, + (has(opts.level) ? has(c.securityContext.seLinuxOptions.level) && (c.securityContext.seLinuxOptions.level == opts.level) : !has(c.securityContext.seLinuxOptions.level)) && + (has(opts.role) ? has(c.securityContext.seLinuxOptions.role) && (c.securityContext.seLinuxOptions.role == opts.role) : !has(c.securityContext.seLinuxOptions.role)) && + (has(opts.type) ? has(c.securityContext.seLinuxOptions.type) && (c.securityContext.seLinuxOptions.type == opts.type) : !has(c.securityContext.seLinuxOptions.type)) && + (has(opts.user) ? has(c.securityContext.seLinuxOptions.user) && (c.securityContext.seLinuxOptions.user == opts.user) : !has(c.securityContext.seLinuxOptions.user)) + ) + ) : false) + : false) + ) validations: - expression: '(has(request.operation) && request.operation == "UPDATE") || variables.notViolatingSELinuxOptions' messageExpression: '"SELinux options is not allowed, pod: " + variables.anyObject.metadata.name + ". Allowed options: " + variables.params.allowedSELinuxOptions' diff --git a/src/pod-security-policy/selinux/src.cel b/src/pod-security-policy/selinux/src.cel index 96028c4c4..7509e97ea 100644 --- a/src/pod-security-policy/selinux/src.cel +++ b/src/pod-security-policy/selinux/src.cel @@ -4,12 +4,14 @@ variables: has(variables.anyObject.spec.securityContext) && has(variables.anyObject.spec.securityContext.seLinuxOptions) ? (has(variables.params.allowedSELinuxOptions) ? ( - (has(variables.params.allowedSELinuxOptions.level) && has(variables.anyObject.spec.securityContext.seLinuxOptions.level) && (variables.anyObject.spec.securityContext.seLinuxOptions.level == variables.params.allowedSELinuxOptions.level)) && - (has(variables.params.allowedSELinuxOptions.role) && has(variables.anyObject.spec.securityContext.seLinuxOptions.role) && (variables.anyObject.spec.securityContext.seLinuxOptions.role == variables.params.allowedSELinuxOptions.role)) && - (has(variables.params.allowedSELinuxOptions.type) && has(variables.anyObject.spec.securityContext.seLinuxOptions.type) && (variables.anyObject.spec.securityContext.seLinuxOptions.type == variables.params.allowedSELinuxOptions.type)) && - (has(variables.params.allowedSELinuxOptions.user) && has(variables.anyObject.spec.securityContext.seLinuxOptions.user) && (variables.anyObject.spec.securityContext.seLinuxOptions.user == variables.params.allowedSELinuxOptions.user)) + variables.params.allowedSELinuxOptions.exists(opts, + (has(opts.level) ? has(variables.anyObject.spec.securityContext.seLinuxOptions.level) && (variables.anyObject.spec.securityContext.seLinuxOptions.level == opts.level) : !has(variables.anyObject.spec.securityContext.seLinuxOptions.level)) && + (has(opts.role) ? has(variables.anyObject.spec.securityContext.seLinuxOptions.role) && (variables.anyObject.spec.securityContext.seLinuxOptions.role == opts.role) : !has(variables.anyObject.spec.securityContext.seLinuxOptions.role)) && + (has(opts.type) ? has(variables.anyObject.spec.securityContext.seLinuxOptions.type) && (variables.anyObject.spec.securityContext.seLinuxOptions.type == opts.type) : !has(variables.anyObject.spec.securityContext.seLinuxOptions.type)) && + (has(opts.user) ? has(variables.anyObject.spec.securityContext.seLinuxOptions.user) && (variables.anyObject.spec.securityContext.seLinuxOptions.user == opts.user) : !has(variables.anyObject.spec.securityContext.seLinuxOptions.user)) + ) ) : - (!has(variables.anyObject.spec.securityContext.seLinuxOptions.level) && !has(variables.anyObject.spec.securityContext.seLinuxOptions.role) && !has(variables.anyObject.spec.securityContext.seLinuxOptions.type) && !has(variables.anyObject.spec.securityContext.seLinuxOptions.user))) + true) : true - name: containers expression: 'has(variables.anyObject.spec.containers) ? variables.anyObject.spec.containers.filter(c, has(c.securityContext) && has(c.securityContext.seLinuxOptions)) : []' @@ -35,13 +37,15 @@ variables: (variables.containers + variables.initContainers + variables.ephemeralContainers).filter(c, !(c.image in variables.exemptImages) && (has(c.securityContext.seLinuxOptions) ? ( has(variables.params.allowedSELinuxOptions) ? ( - !(has(variables.params.allowedSELinuxOptions.level) && has(c.securityContext.seLinuxOptions.level) && (c.securityContext.seLinuxOptions.level == variables.params.allowedSELinuxOptions.level)) || - !(has(variables.params.allowedSELinuxOptions.role) && has(c.securityContext.seLinuxOptions.role) && (c.securityContext.seLinuxOptions.role == variables.params.allowedSELinuxOptions.role)) || - !(has(variables.params.allowedSELinuxOptions.type) && has(c.securityContext.seLinuxOptions.type) && (c.securityContext.seLinuxOptions.type == variables.params.allowedSELinuxOptions.type)) || - !(has(variables.params.allowedSELinuxOptions.user) && has(c.securityContext.seLinuxOptions.user) && (c.securityContext.seLinuxOptions.user == variables.params.allowedSELinuxOptions.user)) - ) : (has(c.securityContext.seLinuxOptions.level) || has(c.securityContext.seLinuxOptions.role) || has(c.securityContext.seLinuxOptions.type) || has(c.securityContext.seLinuxOptions.user)) - ) : false - )) + !variables.params.allowedSELinuxOptions.exists(opts, + (has(opts.level) ? has(c.securityContext.seLinuxOptions.level) && (c.securityContext.seLinuxOptions.level == opts.level) : !has(c.securityContext.seLinuxOptions.level)) && + (has(opts.role) ? has(c.securityContext.seLinuxOptions.role) && (c.securityContext.seLinuxOptions.role == opts.role) : !has(c.securityContext.seLinuxOptions.role)) && + (has(opts.type) ? has(c.securityContext.seLinuxOptions.type) && (c.securityContext.seLinuxOptions.type == opts.type) : !has(c.securityContext.seLinuxOptions.type)) && + (has(opts.user) ? has(c.securityContext.seLinuxOptions.user) && (c.securityContext.seLinuxOptions.user == opts.user) : !has(c.securityContext.seLinuxOptions.user)) + ) + ) : false) + : false) + ) validations: - expression: '(has(request.operation) && request.operation == "UPDATE") || variables.notViolatingSELinuxOptions' messageExpression: '"SELinux options is not allowed, pod: " + variables.anyObject.metadata.name + ". Allowed options: " + variables.params.allowedSELinuxOptions' diff --git a/website/docs/validation/selinux.md b/website/docs/validation/selinux.md index 2fcb34c6a..6f3f70ee9 100644 --- a/website/docs/validation/selinux.md +++ b/website/docs/validation/selinux.md @@ -77,12 +77,14 @@ spec: has(variables.anyObject.spec.securityContext) && has(variables.anyObject.spec.securityContext.seLinuxOptions) ? (has(variables.params.allowedSELinuxOptions) ? ( - (has(variables.params.allowedSELinuxOptions.level) && has(variables.anyObject.spec.securityContext.seLinuxOptions.level) && (variables.anyObject.spec.securityContext.seLinuxOptions.level == variables.params.allowedSELinuxOptions.level)) && - (has(variables.params.allowedSELinuxOptions.role) && has(variables.anyObject.spec.securityContext.seLinuxOptions.role) && (variables.anyObject.spec.securityContext.seLinuxOptions.role == variables.params.allowedSELinuxOptions.role)) && - (has(variables.params.allowedSELinuxOptions.type) && has(variables.anyObject.spec.securityContext.seLinuxOptions.type) && (variables.anyObject.spec.securityContext.seLinuxOptions.type == variables.params.allowedSELinuxOptions.type)) && - (has(variables.params.allowedSELinuxOptions.user) && has(variables.anyObject.spec.securityContext.seLinuxOptions.user) && (variables.anyObject.spec.securityContext.seLinuxOptions.user == variables.params.allowedSELinuxOptions.user)) + variables.params.allowedSELinuxOptions.exists(opts, + (has(opts.level) ? has(variables.anyObject.spec.securityContext.seLinuxOptions.level) && (variables.anyObject.spec.securityContext.seLinuxOptions.level == opts.level) : !has(variables.anyObject.spec.securityContext.seLinuxOptions.level)) && + (has(opts.role) ? has(variables.anyObject.spec.securityContext.seLinuxOptions.role) && (variables.anyObject.spec.securityContext.seLinuxOptions.role == opts.role) : !has(variables.anyObject.spec.securityContext.seLinuxOptions.role)) && + (has(opts.type) ? has(variables.anyObject.spec.securityContext.seLinuxOptions.type) && (variables.anyObject.spec.securityContext.seLinuxOptions.type == opts.type) : !has(variables.anyObject.spec.securityContext.seLinuxOptions.type)) && + (has(opts.user) ? has(variables.anyObject.spec.securityContext.seLinuxOptions.user) && (variables.anyObject.spec.securityContext.seLinuxOptions.user == opts.user) : !has(variables.anyObject.spec.securityContext.seLinuxOptions.user)) + ) ) : - (!has(variables.anyObject.spec.securityContext.seLinuxOptions.level) && !has(variables.anyObject.spec.securityContext.seLinuxOptions.role) && !has(variables.anyObject.spec.securityContext.seLinuxOptions.type) && !has(variables.anyObject.spec.securityContext.seLinuxOptions.user))) + true) : true - name: containers expression: 'has(variables.anyObject.spec.containers) ? variables.anyObject.spec.containers.filter(c, has(c.securityContext) && has(c.securityContext.seLinuxOptions)) : []' @@ -108,13 +110,15 @@ spec: (variables.containers + variables.initContainers + variables.ephemeralContainers).filter(c, !(c.image in variables.exemptImages) && (has(c.securityContext.seLinuxOptions) ? ( has(variables.params.allowedSELinuxOptions) ? ( - !(has(variables.params.allowedSELinuxOptions.level) && has(c.securityContext.seLinuxOptions.level) && (c.securityContext.seLinuxOptions.level == variables.params.allowedSELinuxOptions.level)) || - !(has(variables.params.allowedSELinuxOptions.role) && has(c.securityContext.seLinuxOptions.role) && (c.securityContext.seLinuxOptions.role == variables.params.allowedSELinuxOptions.role)) || - !(has(variables.params.allowedSELinuxOptions.type) && has(c.securityContext.seLinuxOptions.type) && (c.securityContext.seLinuxOptions.type == variables.params.allowedSELinuxOptions.type)) || - !(has(variables.params.allowedSELinuxOptions.user) && has(c.securityContext.seLinuxOptions.user) && (c.securityContext.seLinuxOptions.user == variables.params.allowedSELinuxOptions.user)) - ) : (has(c.securityContext.seLinuxOptions.level) || has(c.securityContext.seLinuxOptions.role) || has(c.securityContext.seLinuxOptions.type) || has(c.securityContext.seLinuxOptions.user)) - ) : false - )) + !variables.params.allowedSELinuxOptions.exists(opts, + (has(opts.level) ? has(c.securityContext.seLinuxOptions.level) && (c.securityContext.seLinuxOptions.level == opts.level) : !has(c.securityContext.seLinuxOptions.level)) && + (has(opts.role) ? has(c.securityContext.seLinuxOptions.role) && (c.securityContext.seLinuxOptions.role == opts.role) : !has(c.securityContext.seLinuxOptions.role)) && + (has(opts.type) ? has(c.securityContext.seLinuxOptions.type) && (c.securityContext.seLinuxOptions.type == opts.type) : !has(c.securityContext.seLinuxOptions.type)) && + (has(opts.user) ? has(c.securityContext.seLinuxOptions.user) && (c.securityContext.seLinuxOptions.user == opts.user) : !has(c.securityContext.seLinuxOptions.user)) + ) + ) : false) + : false) + ) validations: - expression: '(has(request.operation) && request.operation == "UPDATE") || variables.notViolatingSELinuxOptions' messageExpression: '"SELinux options is not allowed, pod: " + variables.anyObject.metadata.name + ". Allowed options: " + variables.params.allowedSELinuxOptions' From 8de47638a85ed4a065686572c4d9601ff5824adb Mon Sep 17 00:00:00 2001 From: Jaydip Gabani Date: Mon, 3 Jun 2024 22:06:05 +0000 Subject: [PATCH 4/7] fixing psp-selinux Signed-off-by: Jaydip Gabani --- .../pod-security-policy/selinux/1.1.0/artifacthub-pkg.yml | 2 +- .../pod-security-policy/selinux/1.1.0/template.yaml | 8 ++++---- library/pod-security-policy/selinux/template.yaml | 8 ++++---- src/pod-security-policy/selinux/src.cel | 8 ++++---- website/docs/validation/selinux.md | 8 ++++---- 5 files changed, 17 insertions(+), 17 deletions(-) diff --git a/artifacthub/library/pod-security-policy/selinux/1.1.0/artifacthub-pkg.yml b/artifacthub/library/pod-security-policy/selinux/1.1.0/artifacthub-pkg.yml index faf470b72..78545c52f 100644 --- a/artifacthub/library/pod-security-policy/selinux/1.1.0/artifacthub-pkg.yml +++ b/artifacthub/library/pod-security-policy/selinux/1.1.0/artifacthub-pkg.yml @@ -3,7 +3,7 @@ name: k8spspselinuxv2 displayName: SELinux V2 createdAt: "2024-05-20T18:10:16Z" description: Defines an allow-list of seLinuxOptions configurations for pod containers. Corresponds to a PodSecurityPolicy requiring SELinux configs. For more information, see https://kubernetes.io/docs/concepts/policy/pod-security-policy/#selinux -digest: fc1b59a39438cd81c6e376bfa5370afbfca109c31d67b2f14e6e2bfa4fa64960 +digest: 918674d346e8a939fb19033fd15a2044fdf05d929c35d9ce66ceae3545129ba8 license: Apache-2.0 homeURL: https://open-policy-agent.github.io/gatekeeper-library/website/selinux keywords: diff --git a/artifacthub/library/pod-security-policy/selinux/1.1.0/template.yaml b/artifacthub/library/pod-security-policy/selinux/1.1.0/template.yaml index 171a6b5b7..edab318d5 100644 --- a/artifacthub/library/pod-security-policy/selinux/1.1.0/template.yaml +++ b/artifacthub/library/pod-security-policy/selinux/1.1.0/template.yaml @@ -60,12 +60,12 @@ spec: - engine: K8sNativeValidation source: variables: - - name: notViolatingSELinuxOptions + - name: usingAllowedSELinuxOptions expression: | has(variables.anyObject.spec.securityContext) && has(variables.anyObject.spec.securityContext.seLinuxOptions) ? (has(variables.params.allowedSELinuxOptions) ? ( - variables.params.allowedSELinuxOptions.exists(opts, + variables.params.allowedSELinuxOptions.all(opts, (has(opts.level) ? has(variables.anyObject.spec.securityContext.seLinuxOptions.level) && (variables.anyObject.spec.securityContext.seLinuxOptions.level == opts.level) : !has(variables.anyObject.spec.securityContext.seLinuxOptions.level)) && (has(opts.role) ? has(variables.anyObject.spec.securityContext.seLinuxOptions.role) && (variables.anyObject.spec.securityContext.seLinuxOptions.role == opts.role) : !has(variables.anyObject.spec.securityContext.seLinuxOptions.role)) && (has(opts.type) ? has(variables.anyObject.spec.securityContext.seLinuxOptions.type) && (variables.anyObject.spec.securityContext.seLinuxOptions.type == opts.type) : !has(variables.anyObject.spec.securityContext.seLinuxOptions.type)) && @@ -98,7 +98,7 @@ spec: (variables.containers + variables.initContainers + variables.ephemeralContainers).filter(c, !(c.image in variables.exemptImages) && (has(c.securityContext.seLinuxOptions) ? ( has(variables.params.allowedSELinuxOptions) ? ( - !variables.params.allowedSELinuxOptions.exists(opts, + !variables.params.allowedSELinuxOptions.all(opts, (has(opts.level) ? has(c.securityContext.seLinuxOptions.level) && (c.securityContext.seLinuxOptions.level == opts.level) : !has(c.securityContext.seLinuxOptions.level)) && (has(opts.role) ? has(c.securityContext.seLinuxOptions.role) && (c.securityContext.seLinuxOptions.role == opts.role) : !has(c.securityContext.seLinuxOptions.role)) && (has(opts.type) ? has(c.securityContext.seLinuxOptions.type) && (c.securityContext.seLinuxOptions.type == opts.type) : !has(c.securityContext.seLinuxOptions.type)) && @@ -108,7 +108,7 @@ spec: : false) ) validations: - - expression: '(has(request.operation) && request.operation == "UPDATE") || variables.notViolatingSELinuxOptions' + - expression: '(has(request.operation) && request.operation == "UPDATE") || variables.usingAllowedSELinuxOptions' messageExpression: '"SELinux options is not allowed, pod: " + variables.anyObject.metadata.name + ". Allowed options: " + variables.params.allowedSELinuxOptions' - expression: '(has(request.operation) && request.operation == "UPDATE") || size(variables.badContainers) == 0' messageExpression: '"SELinux options is not allowed, pod: " + variables.anyObject.metadata.name + ", container: " + variables.badContainers.map(c, c.name).join(", ")' diff --git a/library/pod-security-policy/selinux/template.yaml b/library/pod-security-policy/selinux/template.yaml index 171a6b5b7..edab318d5 100644 --- a/library/pod-security-policy/selinux/template.yaml +++ b/library/pod-security-policy/selinux/template.yaml @@ -60,12 +60,12 @@ spec: - engine: K8sNativeValidation source: variables: - - name: notViolatingSELinuxOptions + - name: usingAllowedSELinuxOptions expression: | has(variables.anyObject.spec.securityContext) && has(variables.anyObject.spec.securityContext.seLinuxOptions) ? (has(variables.params.allowedSELinuxOptions) ? ( - variables.params.allowedSELinuxOptions.exists(opts, + variables.params.allowedSELinuxOptions.all(opts, (has(opts.level) ? has(variables.anyObject.spec.securityContext.seLinuxOptions.level) && (variables.anyObject.spec.securityContext.seLinuxOptions.level == opts.level) : !has(variables.anyObject.spec.securityContext.seLinuxOptions.level)) && (has(opts.role) ? has(variables.anyObject.spec.securityContext.seLinuxOptions.role) && (variables.anyObject.spec.securityContext.seLinuxOptions.role == opts.role) : !has(variables.anyObject.spec.securityContext.seLinuxOptions.role)) && (has(opts.type) ? has(variables.anyObject.spec.securityContext.seLinuxOptions.type) && (variables.anyObject.spec.securityContext.seLinuxOptions.type == opts.type) : !has(variables.anyObject.spec.securityContext.seLinuxOptions.type)) && @@ -98,7 +98,7 @@ spec: (variables.containers + variables.initContainers + variables.ephemeralContainers).filter(c, !(c.image in variables.exemptImages) && (has(c.securityContext.seLinuxOptions) ? ( has(variables.params.allowedSELinuxOptions) ? ( - !variables.params.allowedSELinuxOptions.exists(opts, + !variables.params.allowedSELinuxOptions.all(opts, (has(opts.level) ? has(c.securityContext.seLinuxOptions.level) && (c.securityContext.seLinuxOptions.level == opts.level) : !has(c.securityContext.seLinuxOptions.level)) && (has(opts.role) ? has(c.securityContext.seLinuxOptions.role) && (c.securityContext.seLinuxOptions.role == opts.role) : !has(c.securityContext.seLinuxOptions.role)) && (has(opts.type) ? has(c.securityContext.seLinuxOptions.type) && (c.securityContext.seLinuxOptions.type == opts.type) : !has(c.securityContext.seLinuxOptions.type)) && @@ -108,7 +108,7 @@ spec: : false) ) validations: - - expression: '(has(request.operation) && request.operation == "UPDATE") || variables.notViolatingSELinuxOptions' + - expression: '(has(request.operation) && request.operation == "UPDATE") || variables.usingAllowedSELinuxOptions' messageExpression: '"SELinux options is not allowed, pod: " + variables.anyObject.metadata.name + ". Allowed options: " + variables.params.allowedSELinuxOptions' - expression: '(has(request.operation) && request.operation == "UPDATE") || size(variables.badContainers) == 0' messageExpression: '"SELinux options is not allowed, pod: " + variables.anyObject.metadata.name + ", container: " + variables.badContainers.map(c, c.name).join(", ")' diff --git a/src/pod-security-policy/selinux/src.cel b/src/pod-security-policy/selinux/src.cel index 7509e97ea..d9ad22d13 100644 --- a/src/pod-security-policy/selinux/src.cel +++ b/src/pod-security-policy/selinux/src.cel @@ -1,10 +1,10 @@ variables: -- name: notViolatingSELinuxOptions +- name: usingAllowedSELinuxOptions expression: | has(variables.anyObject.spec.securityContext) && has(variables.anyObject.spec.securityContext.seLinuxOptions) ? (has(variables.params.allowedSELinuxOptions) ? ( - variables.params.allowedSELinuxOptions.exists(opts, + variables.params.allowedSELinuxOptions.all(opts, (has(opts.level) ? has(variables.anyObject.spec.securityContext.seLinuxOptions.level) && (variables.anyObject.spec.securityContext.seLinuxOptions.level == opts.level) : !has(variables.anyObject.spec.securityContext.seLinuxOptions.level)) && (has(opts.role) ? has(variables.anyObject.spec.securityContext.seLinuxOptions.role) && (variables.anyObject.spec.securityContext.seLinuxOptions.role == opts.role) : !has(variables.anyObject.spec.securityContext.seLinuxOptions.role)) && (has(opts.type) ? has(variables.anyObject.spec.securityContext.seLinuxOptions.type) && (variables.anyObject.spec.securityContext.seLinuxOptions.type == opts.type) : !has(variables.anyObject.spec.securityContext.seLinuxOptions.type)) && @@ -37,7 +37,7 @@ variables: (variables.containers + variables.initContainers + variables.ephemeralContainers).filter(c, !(c.image in variables.exemptImages) && (has(c.securityContext.seLinuxOptions) ? ( has(variables.params.allowedSELinuxOptions) ? ( - !variables.params.allowedSELinuxOptions.exists(opts, + !variables.params.allowedSELinuxOptions.all(opts, (has(opts.level) ? has(c.securityContext.seLinuxOptions.level) && (c.securityContext.seLinuxOptions.level == opts.level) : !has(c.securityContext.seLinuxOptions.level)) && (has(opts.role) ? has(c.securityContext.seLinuxOptions.role) && (c.securityContext.seLinuxOptions.role == opts.role) : !has(c.securityContext.seLinuxOptions.role)) && (has(opts.type) ? has(c.securityContext.seLinuxOptions.type) && (c.securityContext.seLinuxOptions.type == opts.type) : !has(c.securityContext.seLinuxOptions.type)) && @@ -47,7 +47,7 @@ variables: : false) ) validations: -- expression: '(has(request.operation) && request.operation == "UPDATE") || variables.notViolatingSELinuxOptions' +- expression: '(has(request.operation) && request.operation == "UPDATE") || variables.usingAllowedSELinuxOptions' messageExpression: '"SELinux options is not allowed, pod: " + variables.anyObject.metadata.name + ". Allowed options: " + variables.params.allowedSELinuxOptions' - expression: '(has(request.operation) && request.operation == "UPDATE") || size(variables.badContainers) == 0' messageExpression: '"SELinux options is not allowed, pod: " + variables.anyObject.metadata.name + ", container: " + variables.badContainers.map(c, c.name).join(", ")' diff --git a/website/docs/validation/selinux.md b/website/docs/validation/selinux.md index 6f3f70ee9..e46efae86 100644 --- a/website/docs/validation/selinux.md +++ b/website/docs/validation/selinux.md @@ -72,12 +72,12 @@ spec: - engine: K8sNativeValidation source: variables: - - name: notViolatingSELinuxOptions + - name: usingAllowedSELinuxOptions expression: | has(variables.anyObject.spec.securityContext) && has(variables.anyObject.spec.securityContext.seLinuxOptions) ? (has(variables.params.allowedSELinuxOptions) ? ( - variables.params.allowedSELinuxOptions.exists(opts, + variables.params.allowedSELinuxOptions.all(opts, (has(opts.level) ? has(variables.anyObject.spec.securityContext.seLinuxOptions.level) && (variables.anyObject.spec.securityContext.seLinuxOptions.level == opts.level) : !has(variables.anyObject.spec.securityContext.seLinuxOptions.level)) && (has(opts.role) ? has(variables.anyObject.spec.securityContext.seLinuxOptions.role) && (variables.anyObject.spec.securityContext.seLinuxOptions.role == opts.role) : !has(variables.anyObject.spec.securityContext.seLinuxOptions.role)) && (has(opts.type) ? has(variables.anyObject.spec.securityContext.seLinuxOptions.type) && (variables.anyObject.spec.securityContext.seLinuxOptions.type == opts.type) : !has(variables.anyObject.spec.securityContext.seLinuxOptions.type)) && @@ -110,7 +110,7 @@ spec: (variables.containers + variables.initContainers + variables.ephemeralContainers).filter(c, !(c.image in variables.exemptImages) && (has(c.securityContext.seLinuxOptions) ? ( has(variables.params.allowedSELinuxOptions) ? ( - !variables.params.allowedSELinuxOptions.exists(opts, + !variables.params.allowedSELinuxOptions.all(opts, (has(opts.level) ? has(c.securityContext.seLinuxOptions.level) && (c.securityContext.seLinuxOptions.level == opts.level) : !has(c.securityContext.seLinuxOptions.level)) && (has(opts.role) ? has(c.securityContext.seLinuxOptions.role) && (c.securityContext.seLinuxOptions.role == opts.role) : !has(c.securityContext.seLinuxOptions.role)) && (has(opts.type) ? has(c.securityContext.seLinuxOptions.type) && (c.securityContext.seLinuxOptions.type == opts.type) : !has(c.securityContext.seLinuxOptions.type)) && @@ -120,7 +120,7 @@ spec: : false) ) validations: - - expression: '(has(request.operation) && request.operation == "UPDATE") || variables.notViolatingSELinuxOptions' + - expression: '(has(request.operation) && request.operation == "UPDATE") || variables.usingAllowedSELinuxOptions' messageExpression: '"SELinux options is not allowed, pod: " + variables.anyObject.metadata.name + ". Allowed options: " + variables.params.allowedSELinuxOptions' - expression: '(has(request.operation) && request.operation == "UPDATE") || size(variables.badContainers) == 0' messageExpression: '"SELinux options is not allowed, pod: " + variables.anyObject.metadata.name + ", container: " + variables.badContainers.map(c, c.name).join(", ")' From cd2a491598a9d55cbf32c1ead2f6ebea490ec546 Mon Sep 17 00:00:00 2001 From: Jaydip Gabani Date: Tue, 3 Sep 2024 21:55:46 +0000 Subject: [PATCH 5/7] fixing validation message Signed-off-by: Jaydip Gabani --- .../pod-security-policy/selinux/1.1.0/artifacthub-pkg.yml | 2 +- .../library/pod-security-policy/selinux/1.1.0/template.yaml | 4 ++-- library/pod-security-policy/selinux/template.yaml | 4 ++-- src/pod-security-policy/selinux/src.cel | 4 ++-- website/docs/validation/selinux.md | 4 ++-- 5 files changed, 9 insertions(+), 9 deletions(-) diff --git a/artifacthub/library/pod-security-policy/selinux/1.1.0/artifacthub-pkg.yml b/artifacthub/library/pod-security-policy/selinux/1.1.0/artifacthub-pkg.yml index 78545c52f..a1692a116 100644 --- a/artifacthub/library/pod-security-policy/selinux/1.1.0/artifacthub-pkg.yml +++ b/artifacthub/library/pod-security-policy/selinux/1.1.0/artifacthub-pkg.yml @@ -3,7 +3,7 @@ name: k8spspselinuxv2 displayName: SELinux V2 createdAt: "2024-05-20T18:10:16Z" description: Defines an allow-list of seLinuxOptions configurations for pod containers. Corresponds to a PodSecurityPolicy requiring SELinux configs. For more information, see https://kubernetes.io/docs/concepts/policy/pod-security-policy/#selinux -digest: 918674d346e8a939fb19033fd15a2044fdf05d929c35d9ce66ceae3545129ba8 +digest: 15d870eec167f92a25cc85e9751bc2980d11457b3caab60d3ff2794a277c63c5 license: Apache-2.0 homeURL: https://open-policy-agent.github.io/gatekeeper-library/website/selinux keywords: diff --git a/artifacthub/library/pod-security-policy/selinux/1.1.0/template.yaml b/artifacthub/library/pod-security-policy/selinux/1.1.0/template.yaml index edab318d5..853b8777a 100644 --- a/artifacthub/library/pod-security-policy/selinux/1.1.0/template.yaml +++ b/artifacthub/library/pod-security-policy/selinux/1.1.0/template.yaml @@ -109,9 +109,9 @@ spec: ) validations: - expression: '(has(request.operation) && request.operation == "UPDATE") || variables.usingAllowedSELinuxOptions' - messageExpression: '"SELinux options is not allowed, pod: " + variables.anyObject.metadata.name + ". Allowed options: " + variables.params.allowedSELinuxOptions' + messageExpression: '"SELinux options is not allowed, pod: " + variables.anyObject.metadata.name + ". Allowed options: [" + variables.params.allowedSELinuxOptions.map(opts, "{ level: " + opts.level + ", role: " + opts.role + ", type: " + opts.type + ", user: " + opts.user + "}").join(", ") + "]"' - expression: '(has(request.operation) && request.operation == "UPDATE") || size(variables.badContainers) == 0' - messageExpression: '"SELinux options is not allowed, pod: " + variables.anyObject.metadata.name + ", container: " + variables.badContainers.map(c, c.name).join(", ")' + messageExpression: '"SELinux options is not allowed, pod: " + variables.anyObject.metadata.name + ", container: " + variables.badContainers.map(c, c.name).join(", ") + ". Allowed options: [" + variables.params.allowedSELinuxOptions.map(opts, "{ level: " + opts.level + ", role: " + opts.role + ", type: " + opts.type + ", user: " + opts.user + "}").join(", ") + "]"' - engine: Rego source: rego: | diff --git a/library/pod-security-policy/selinux/template.yaml b/library/pod-security-policy/selinux/template.yaml index edab318d5..853b8777a 100644 --- a/library/pod-security-policy/selinux/template.yaml +++ b/library/pod-security-policy/selinux/template.yaml @@ -109,9 +109,9 @@ spec: ) validations: - expression: '(has(request.operation) && request.operation == "UPDATE") || variables.usingAllowedSELinuxOptions' - messageExpression: '"SELinux options is not allowed, pod: " + variables.anyObject.metadata.name + ". Allowed options: " + variables.params.allowedSELinuxOptions' + messageExpression: '"SELinux options is not allowed, pod: " + variables.anyObject.metadata.name + ". Allowed options: [" + variables.params.allowedSELinuxOptions.map(opts, "{ level: " + opts.level + ", role: " + opts.role + ", type: " + opts.type + ", user: " + opts.user + "}").join(", ") + "]"' - expression: '(has(request.operation) && request.operation == "UPDATE") || size(variables.badContainers) == 0' - messageExpression: '"SELinux options is not allowed, pod: " + variables.anyObject.metadata.name + ", container: " + variables.badContainers.map(c, c.name).join(", ")' + messageExpression: '"SELinux options is not allowed, pod: " + variables.anyObject.metadata.name + ", container: " + variables.badContainers.map(c, c.name).join(", ") + ". Allowed options: [" + variables.params.allowedSELinuxOptions.map(opts, "{ level: " + opts.level + ", role: " + opts.role + ", type: " + opts.type + ", user: " + opts.user + "}").join(", ") + "]"' - engine: Rego source: rego: | diff --git a/src/pod-security-policy/selinux/src.cel b/src/pod-security-policy/selinux/src.cel index d9ad22d13..c8f1e86fb 100644 --- a/src/pod-security-policy/selinux/src.cel +++ b/src/pod-security-policy/selinux/src.cel @@ -48,6 +48,6 @@ variables: ) validations: - expression: '(has(request.operation) && request.operation == "UPDATE") || variables.usingAllowedSELinuxOptions' - messageExpression: '"SELinux options is not allowed, pod: " + variables.anyObject.metadata.name + ". Allowed options: " + variables.params.allowedSELinuxOptions' + messageExpression: '"SELinux options is not allowed, pod: " + variables.anyObject.metadata.name + ". Allowed options: [" + variables.params.allowedSELinuxOptions.map(opts, "{ level: " + opts.level + ", role: " + opts.role + ", type: " + opts.type + ", user: " + opts.user + "}").join(", ") + "]"' - expression: '(has(request.operation) && request.operation == "UPDATE") || size(variables.badContainers) == 0' - messageExpression: '"SELinux options is not allowed, pod: " + variables.anyObject.metadata.name + ", container: " + variables.badContainers.map(c, c.name).join(", ")' + messageExpression: '"SELinux options is not allowed, pod: " + variables.anyObject.metadata.name + ", container: " + variables.badContainers.map(c, c.name).join(", ") + ". Allowed options: [" + variables.params.allowedSELinuxOptions.map(opts, "{ level: " + opts.level + ", role: " + opts.role + ", type: " + opts.type + ", user: " + opts.user + "}").join(", ") + "]"' diff --git a/website/docs/validation/selinux.md b/website/docs/validation/selinux.md index e46efae86..f116145a0 100644 --- a/website/docs/validation/selinux.md +++ b/website/docs/validation/selinux.md @@ -121,9 +121,9 @@ spec: ) validations: - expression: '(has(request.operation) && request.operation == "UPDATE") || variables.usingAllowedSELinuxOptions' - messageExpression: '"SELinux options is not allowed, pod: " + variables.anyObject.metadata.name + ". Allowed options: " + variables.params.allowedSELinuxOptions' + messageExpression: '"SELinux options is not allowed, pod: " + variables.anyObject.metadata.name + ". Allowed options: [" + variables.params.allowedSELinuxOptions.map(opts, "{ level: " + opts.level + ", role: " + opts.role + ", type: " + opts.type + ", user: " + opts.user + "}").join(", ") + "]"' - expression: '(has(request.operation) && request.operation == "UPDATE") || size(variables.badContainers) == 0' - messageExpression: '"SELinux options is not allowed, pod: " + variables.anyObject.metadata.name + ", container: " + variables.badContainers.map(c, c.name).join(", ")' + messageExpression: '"SELinux options is not allowed, pod: " + variables.anyObject.metadata.name + ", container: " + variables.badContainers.map(c, c.name).join(", ") + ". Allowed options: [" + variables.params.allowedSELinuxOptions.map(opts, "{ level: " + opts.level + ", role: " + opts.role + ", type: " + opts.type + ", user: " + opts.user + "}").join(", ") + "]"' - engine: Rego source: rego: | From 3ac9a5fcb2653f97165edd98ed12cea6b117300b Mon Sep 17 00:00:00 2001 From: Jaydip Gabani Date: Thu, 5 Sep 2024 01:35:13 +0000 Subject: [PATCH 6/7] adding allowed example without fields Signed-off-by: Jaydip Gabani --- .../example_allowed_without_selinux_opts.yaml | 10 ++++++++ .../selinux/1.1.0/suite.yaml | 4 +++ .../example_allowed_no_volume.yaml | 12 +++++++++ .../volumes/1.1.0/suite.yaml | 4 +++ .../example_allowed_without_selinux_opts.yaml | 10 ++++++++ .../pod-security-policy/selinux/suite.yaml | 4 +++ .../example_allowed_no_volume.yaml | 12 +++++++++ .../pod-security-policy/volumes/suite.yaml | 4 +++ website/docs/validation/selinux.md | 24 ++++++++++++++++++ website/docs/validation/volumes.md | 25 +++++++++++++++++++ 10 files changed, 109 insertions(+) create mode 100644 artifacthub/library/pod-security-policy/selinux/1.1.0/samples/psp-selinux-v2/example_allowed_without_selinux_opts.yaml create mode 100644 artifacthub/library/pod-security-policy/volumes/1.1.0/samples/psp-volume-types/example_allowed_no_volume.yaml create mode 100644 library/pod-security-policy/selinux/samples/psp-selinux-v2/example_allowed_without_selinux_opts.yaml create mode 100644 library/pod-security-policy/volumes/samples/psp-volume-types/example_allowed_no_volume.yaml diff --git a/artifacthub/library/pod-security-policy/selinux/1.1.0/samples/psp-selinux-v2/example_allowed_without_selinux_opts.yaml b/artifacthub/library/pod-security-policy/selinux/1.1.0/samples/psp-selinux-v2/example_allowed_without_selinux_opts.yaml new file mode 100644 index 000000000..f47cb90b2 --- /dev/null +++ b/artifacthub/library/pod-security-policy/selinux/1.1.0/samples/psp-selinux-v2/example_allowed_without_selinux_opts.yaml @@ -0,0 +1,10 @@ +apiVersion: v1 +kind: Pod +metadata: + name: nginx-selinux-allowed-without-selinux-opts + labels: + app: nginx-selinux +spec: + containers: + - name: nginx + image: nginx diff --git a/artifacthub/library/pod-security-policy/selinux/1.1.0/suite.yaml b/artifacthub/library/pod-security-policy/selinux/1.1.0/suite.yaml index 1bbaf360e..11ef74285 100644 --- a/artifacthub/library/pod-security-policy/selinux/1.1.0/suite.yaml +++ b/artifacthub/library/pod-security-policy/selinux/1.1.0/suite.yaml @@ -15,6 +15,10 @@ tests: object: samples/psp-selinux-v2/example_allowed.yaml assertions: - violations: no + - name: example-allowed-wihtout-selinux-opts + object: samples/psp-selinux-v2/example_allowed_without_selinux_opts.yaml + assertions: + - violations: no - name: disallowed-ephemeral object: samples/psp-selinux-v2/disallowed_ephemeral.yaml assertions: diff --git a/artifacthub/library/pod-security-policy/volumes/1.1.0/samples/psp-volume-types/example_allowed_no_volume.yaml b/artifacthub/library/pod-security-policy/volumes/1.1.0/samples/psp-volume-types/example_allowed_no_volume.yaml new file mode 100644 index 000000000..8db11bfa3 --- /dev/null +++ b/artifacthub/library/pod-security-policy/volumes/1.1.0/samples/psp-volume-types/example_allowed_no_volume.yaml @@ -0,0 +1,12 @@ +apiVersion: v1 +kind: Pod +metadata: + name: nginx-without-volume-allowed + labels: + app: nginx-without-volume-types +spec: + containers: + - name: nginx + image: nginx + - name: nginx2 + image: nginx \ No newline at end of file diff --git a/artifacthub/library/pod-security-policy/volumes/1.1.0/suite.yaml b/artifacthub/library/pod-security-policy/volumes/1.1.0/suite.yaml index 083aad6eb..27a7a0b80 100644 --- a/artifacthub/library/pod-security-policy/volumes/1.1.0/suite.yaml +++ b/artifacthub/library/pod-security-policy/volumes/1.1.0/suite.yaml @@ -15,6 +15,10 @@ tests: object: samples/psp-volume-types/example_allowed.yaml assertions: - violations: no + - name: example-allowed-without-volume + object: samples/psp-volume-types/example_allowed_no_volume.yaml + assertions: + - violations: no - name: update object: samples/psp-volume-types/update.yaml assertions: diff --git a/library/pod-security-policy/selinux/samples/psp-selinux-v2/example_allowed_without_selinux_opts.yaml b/library/pod-security-policy/selinux/samples/psp-selinux-v2/example_allowed_without_selinux_opts.yaml new file mode 100644 index 000000000..f47cb90b2 --- /dev/null +++ b/library/pod-security-policy/selinux/samples/psp-selinux-v2/example_allowed_without_selinux_opts.yaml @@ -0,0 +1,10 @@ +apiVersion: v1 +kind: Pod +metadata: + name: nginx-selinux-allowed-without-selinux-opts + labels: + app: nginx-selinux +spec: + containers: + - name: nginx + image: nginx diff --git a/library/pod-security-policy/selinux/suite.yaml b/library/pod-security-policy/selinux/suite.yaml index 1bbaf360e..11ef74285 100644 --- a/library/pod-security-policy/selinux/suite.yaml +++ b/library/pod-security-policy/selinux/suite.yaml @@ -15,6 +15,10 @@ tests: object: samples/psp-selinux-v2/example_allowed.yaml assertions: - violations: no + - name: example-allowed-wihtout-selinux-opts + object: samples/psp-selinux-v2/example_allowed_without_selinux_opts.yaml + assertions: + - violations: no - name: disallowed-ephemeral object: samples/psp-selinux-v2/disallowed_ephemeral.yaml assertions: diff --git a/library/pod-security-policy/volumes/samples/psp-volume-types/example_allowed_no_volume.yaml b/library/pod-security-policy/volumes/samples/psp-volume-types/example_allowed_no_volume.yaml new file mode 100644 index 000000000..8db11bfa3 --- /dev/null +++ b/library/pod-security-policy/volumes/samples/psp-volume-types/example_allowed_no_volume.yaml @@ -0,0 +1,12 @@ +apiVersion: v1 +kind: Pod +metadata: + name: nginx-without-volume-allowed + labels: + app: nginx-without-volume-types +spec: + containers: + - name: nginx + image: nginx + - name: nginx2 + image: nginx \ No newline at end of file diff --git a/library/pod-security-policy/volumes/suite.yaml b/library/pod-security-policy/volumes/suite.yaml index 083aad6eb..27a7a0b80 100644 --- a/library/pod-security-policy/volumes/suite.yaml +++ b/library/pod-security-policy/volumes/suite.yaml @@ -15,6 +15,10 @@ tests: object: samples/psp-volume-types/example_allowed.yaml assertions: - violations: no + - name: example-allowed-without-volume + object: samples/psp-volume-types/example_allowed_no_volume.yaml + assertions: + - violations: no - name: update object: samples/psp-volume-types/update.yaml assertions: diff --git a/website/docs/validation/selinux.md b/website/docs/validation/selinux.md index f116145a0..efbb99f95 100644 --- a/website/docs/validation/selinux.md +++ b/website/docs/validation/selinux.md @@ -312,6 +312,30 @@ Usage kubectl apply -f https://raw.githubusercontent.com/open-policy-agent/gatekeeper-library/master/library/pod-security-policy/selinux/samples/psp-selinux-v2/example_allowed.yaml ``` + +
+example-allowed-wihtout-selinux-opts + +```yaml +apiVersion: v1 +kind: Pod +metadata: + name: nginx-selinux-allowed-without-selinux-opts + labels: + app: nginx-selinux +spec: + containers: + - name: nginx + image: nginx + +``` + +Usage + +```shell +kubectl apply -f https://raw.githubusercontent.com/open-policy-agent/gatekeeper-library/master/library/pod-security-policy/selinux/samples/psp-selinux-v2/example_allowed_without_selinux_opts.yaml +``` +
disallowed-ephemeral diff --git a/website/docs/validation/volumes.md b/website/docs/validation/volumes.md index 070f152ee..32c18dcf5 100644 --- a/website/docs/validation/volumes.md +++ b/website/docs/validation/volumes.md @@ -208,6 +208,31 @@ Usage kubectl apply -f https://raw.githubusercontent.com/open-policy-agent/gatekeeper-library/master/library/pod-security-policy/volumes/samples/psp-volume-types/example_allowed.yaml ``` +
+
+example-allowed-without-volume + +```yaml +apiVersion: v1 +kind: Pod +metadata: + name: nginx-without-volume-allowed + labels: + app: nginx-without-volume-types +spec: + containers: + - name: nginx + image: nginx + - name: nginx2 + image: nginx +``` + +Usage + +```shell +kubectl apply -f https://raw.githubusercontent.com/open-policy-agent/gatekeeper-library/master/library/pod-security-policy/volumes/samples/psp-volume-types/example_allowed_no_volume.yaml +``` +
From 1a9349a4a833dd5d0525e2a3b87464544b6148db Mon Sep 17 00:00:00 2001 From: Jaydip Gabani Date: Thu, 23 Jan 2025 02:11:30 +0000 Subject: [PATCH 7/7] fixing cel to match with rego Signed-off-by: Jaydip Gabani --- .../selinux/1.1.0/artifacthub-pkg.yml | 2 +- .../samples/psp-selinux-v2/constraint2.yaml | 11 ++ .../selinux/1.1.0/suite.yaml | 24 +++ .../selinux/1.1.0/template.yaml | 4 +- .../samples/psp-selinux-v2/constraint2.yaml | 11 ++ .../pod-security-policy/selinux/suite.yaml | 24 +++ .../pod-security-policy/selinux/template.yaml | 4 +- src/pod-security-policy/selinux/src.cel | 4 +- website/docs/validation/selinux.md | 148 +++++++++++++++++- 9 files changed, 223 insertions(+), 9 deletions(-) create mode 100644 artifacthub/library/pod-security-policy/selinux/1.1.0/samples/psp-selinux-v2/constraint2.yaml create mode 100644 library/pod-security-policy/selinux/samples/psp-selinux-v2/constraint2.yaml diff --git a/artifacthub/library/pod-security-policy/selinux/1.1.0/artifacthub-pkg.yml b/artifacthub/library/pod-security-policy/selinux/1.1.0/artifacthub-pkg.yml index a1692a116..417b81ed8 100644 --- a/artifacthub/library/pod-security-policy/selinux/1.1.0/artifacthub-pkg.yml +++ b/artifacthub/library/pod-security-policy/selinux/1.1.0/artifacthub-pkg.yml @@ -3,7 +3,7 @@ name: k8spspselinuxv2 displayName: SELinux V2 createdAt: "2024-05-20T18:10:16Z" description: Defines an allow-list of seLinuxOptions configurations for pod containers. Corresponds to a PodSecurityPolicy requiring SELinux configs. For more information, see https://kubernetes.io/docs/concepts/policy/pod-security-policy/#selinux -digest: 15d870eec167f92a25cc85e9751bc2980d11457b3caab60d3ff2794a277c63c5 +digest: d493a5cbaf488e226d1c1133c917d1e2b0eac47b60618a3714ab8c69b07ae3cb license: Apache-2.0 homeURL: https://open-policy-agent.github.io/gatekeeper-library/website/selinux keywords: diff --git a/artifacthub/library/pod-security-policy/selinux/1.1.0/samples/psp-selinux-v2/constraint2.yaml b/artifacthub/library/pod-security-policy/selinux/1.1.0/samples/psp-selinux-v2/constraint2.yaml new file mode 100644 index 000000000..ba26434b3 --- /dev/null +++ b/artifacthub/library/pod-security-policy/selinux/1.1.0/samples/psp-selinux-v2/constraint2.yaml @@ -0,0 +1,11 @@ +apiVersion: constraints.gatekeeper.sh/v1beta1 +kind: K8sPSPSELinuxV2 +metadata: + name: psp-selinux-v2 +spec: + match: + kinds: + - apiGroups: [""] + kinds: ["Pod"] + parameters: + allowedSELinuxOptions: [] \ No newline at end of file diff --git a/artifacthub/library/pod-security-policy/selinux/1.1.0/suite.yaml b/artifacthub/library/pod-security-policy/selinux/1.1.0/suite.yaml index 11ef74285..48ec3ea49 100644 --- a/artifacthub/library/pod-security-policy/selinux/1.1.0/suite.yaml +++ b/artifacthub/library/pod-security-policy/selinux/1.1.0/suite.yaml @@ -27,3 +27,27 @@ tests: object: samples/psp-selinux-v2/update.yaml assertions: - violations: no +- name: deny-all-selinux-options + template: template.yaml + constraint: samples/psp-selinux-v2/constraint2.yaml + cases: + - name: example-disallowed + object: samples/psp-selinux-v2/example_disallowed.yaml + assertions: + - violations: yes + - name: example-allowed + object: samples/psp-selinux-v2/example_allowed.yaml + assertions: + - violations: yes + - name: example-allowed-wihtout-selinux-opts + object: samples/psp-selinux-v2/example_allowed_without_selinux_opts.yaml + assertions: + - violations: no + - name: disallowed-ephemeral + object: samples/psp-selinux-v2/disallowed_ephemeral.yaml + assertions: + - violations: yes + - name: update + object: samples/psp-selinux-v2/update.yaml + assertions: + - violations: no diff --git a/artifacthub/library/pod-security-policy/selinux/1.1.0/template.yaml b/artifacthub/library/pod-security-policy/selinux/1.1.0/template.yaml index 853b8777a..ca0db732d 100644 --- a/artifacthub/library/pod-security-policy/selinux/1.1.0/template.yaml +++ b/artifacthub/library/pod-security-policy/selinux/1.1.0/template.yaml @@ -65,7 +65,7 @@ spec: has(variables.anyObject.spec.securityContext) && has(variables.anyObject.spec.securityContext.seLinuxOptions) ? (has(variables.params.allowedSELinuxOptions) ? ( - variables.params.allowedSELinuxOptions.all(opts, + size(variables.params.allowedSELinuxOptions) > 0 && variables.params.allowedSELinuxOptions.all(opts, (has(opts.level) ? has(variables.anyObject.spec.securityContext.seLinuxOptions.level) && (variables.anyObject.spec.securityContext.seLinuxOptions.level == opts.level) : !has(variables.anyObject.spec.securityContext.seLinuxOptions.level)) && (has(opts.role) ? has(variables.anyObject.spec.securityContext.seLinuxOptions.role) && (variables.anyObject.spec.securityContext.seLinuxOptions.role == opts.role) : !has(variables.anyObject.spec.securityContext.seLinuxOptions.role)) && (has(opts.type) ? has(variables.anyObject.spec.securityContext.seLinuxOptions.type) && (variables.anyObject.spec.securityContext.seLinuxOptions.type == opts.type) : !has(variables.anyObject.spec.securityContext.seLinuxOptions.type)) && @@ -98,7 +98,7 @@ spec: (variables.containers + variables.initContainers + variables.ephemeralContainers).filter(c, !(c.image in variables.exemptImages) && (has(c.securityContext.seLinuxOptions) ? ( has(variables.params.allowedSELinuxOptions) ? ( - !variables.params.allowedSELinuxOptions.all(opts, + size(variables.params.allowedSELinuxOptions) == 0 || !variables.params.allowedSELinuxOptions.all(opts, (has(opts.level) ? has(c.securityContext.seLinuxOptions.level) && (c.securityContext.seLinuxOptions.level == opts.level) : !has(c.securityContext.seLinuxOptions.level)) && (has(opts.role) ? has(c.securityContext.seLinuxOptions.role) && (c.securityContext.seLinuxOptions.role == opts.role) : !has(c.securityContext.seLinuxOptions.role)) && (has(opts.type) ? has(c.securityContext.seLinuxOptions.type) && (c.securityContext.seLinuxOptions.type == opts.type) : !has(c.securityContext.seLinuxOptions.type)) && diff --git a/library/pod-security-policy/selinux/samples/psp-selinux-v2/constraint2.yaml b/library/pod-security-policy/selinux/samples/psp-selinux-v2/constraint2.yaml new file mode 100644 index 000000000..ba26434b3 --- /dev/null +++ b/library/pod-security-policy/selinux/samples/psp-selinux-v2/constraint2.yaml @@ -0,0 +1,11 @@ +apiVersion: constraints.gatekeeper.sh/v1beta1 +kind: K8sPSPSELinuxV2 +metadata: + name: psp-selinux-v2 +spec: + match: + kinds: + - apiGroups: [""] + kinds: ["Pod"] + parameters: + allowedSELinuxOptions: [] \ No newline at end of file diff --git a/library/pod-security-policy/selinux/suite.yaml b/library/pod-security-policy/selinux/suite.yaml index 11ef74285..48ec3ea49 100644 --- a/library/pod-security-policy/selinux/suite.yaml +++ b/library/pod-security-policy/selinux/suite.yaml @@ -27,3 +27,27 @@ tests: object: samples/psp-selinux-v2/update.yaml assertions: - violations: no +- name: deny-all-selinux-options + template: template.yaml + constraint: samples/psp-selinux-v2/constraint2.yaml + cases: + - name: example-disallowed + object: samples/psp-selinux-v2/example_disallowed.yaml + assertions: + - violations: yes + - name: example-allowed + object: samples/psp-selinux-v2/example_allowed.yaml + assertions: + - violations: yes + - name: example-allowed-wihtout-selinux-opts + object: samples/psp-selinux-v2/example_allowed_without_selinux_opts.yaml + assertions: + - violations: no + - name: disallowed-ephemeral + object: samples/psp-selinux-v2/disallowed_ephemeral.yaml + assertions: + - violations: yes + - name: update + object: samples/psp-selinux-v2/update.yaml + assertions: + - violations: no diff --git a/library/pod-security-policy/selinux/template.yaml b/library/pod-security-policy/selinux/template.yaml index 853b8777a..ca0db732d 100644 --- a/library/pod-security-policy/selinux/template.yaml +++ b/library/pod-security-policy/selinux/template.yaml @@ -65,7 +65,7 @@ spec: has(variables.anyObject.spec.securityContext) && has(variables.anyObject.spec.securityContext.seLinuxOptions) ? (has(variables.params.allowedSELinuxOptions) ? ( - variables.params.allowedSELinuxOptions.all(opts, + size(variables.params.allowedSELinuxOptions) > 0 && variables.params.allowedSELinuxOptions.all(opts, (has(opts.level) ? has(variables.anyObject.spec.securityContext.seLinuxOptions.level) && (variables.anyObject.spec.securityContext.seLinuxOptions.level == opts.level) : !has(variables.anyObject.spec.securityContext.seLinuxOptions.level)) && (has(opts.role) ? has(variables.anyObject.spec.securityContext.seLinuxOptions.role) && (variables.anyObject.spec.securityContext.seLinuxOptions.role == opts.role) : !has(variables.anyObject.spec.securityContext.seLinuxOptions.role)) && (has(opts.type) ? has(variables.anyObject.spec.securityContext.seLinuxOptions.type) && (variables.anyObject.spec.securityContext.seLinuxOptions.type == opts.type) : !has(variables.anyObject.spec.securityContext.seLinuxOptions.type)) && @@ -98,7 +98,7 @@ spec: (variables.containers + variables.initContainers + variables.ephemeralContainers).filter(c, !(c.image in variables.exemptImages) && (has(c.securityContext.seLinuxOptions) ? ( has(variables.params.allowedSELinuxOptions) ? ( - !variables.params.allowedSELinuxOptions.all(opts, + size(variables.params.allowedSELinuxOptions) == 0 || !variables.params.allowedSELinuxOptions.all(opts, (has(opts.level) ? has(c.securityContext.seLinuxOptions.level) && (c.securityContext.seLinuxOptions.level == opts.level) : !has(c.securityContext.seLinuxOptions.level)) && (has(opts.role) ? has(c.securityContext.seLinuxOptions.role) && (c.securityContext.seLinuxOptions.role == opts.role) : !has(c.securityContext.seLinuxOptions.role)) && (has(opts.type) ? has(c.securityContext.seLinuxOptions.type) && (c.securityContext.seLinuxOptions.type == opts.type) : !has(c.securityContext.seLinuxOptions.type)) && diff --git a/src/pod-security-policy/selinux/src.cel b/src/pod-security-policy/selinux/src.cel index c8f1e86fb..b012718af 100644 --- a/src/pod-security-policy/selinux/src.cel +++ b/src/pod-security-policy/selinux/src.cel @@ -4,7 +4,7 @@ variables: has(variables.anyObject.spec.securityContext) && has(variables.anyObject.spec.securityContext.seLinuxOptions) ? (has(variables.params.allowedSELinuxOptions) ? ( - variables.params.allowedSELinuxOptions.all(opts, + size(variables.params.allowedSELinuxOptions) > 0 && variables.params.allowedSELinuxOptions.all(opts, (has(opts.level) ? has(variables.anyObject.spec.securityContext.seLinuxOptions.level) && (variables.anyObject.spec.securityContext.seLinuxOptions.level == opts.level) : !has(variables.anyObject.spec.securityContext.seLinuxOptions.level)) && (has(opts.role) ? has(variables.anyObject.spec.securityContext.seLinuxOptions.role) && (variables.anyObject.spec.securityContext.seLinuxOptions.role == opts.role) : !has(variables.anyObject.spec.securityContext.seLinuxOptions.role)) && (has(opts.type) ? has(variables.anyObject.spec.securityContext.seLinuxOptions.type) && (variables.anyObject.spec.securityContext.seLinuxOptions.type == opts.type) : !has(variables.anyObject.spec.securityContext.seLinuxOptions.type)) && @@ -37,7 +37,7 @@ variables: (variables.containers + variables.initContainers + variables.ephemeralContainers).filter(c, !(c.image in variables.exemptImages) && (has(c.securityContext.seLinuxOptions) ? ( has(variables.params.allowedSELinuxOptions) ? ( - !variables.params.allowedSELinuxOptions.all(opts, + size(variables.params.allowedSELinuxOptions) == 0 || !variables.params.allowedSELinuxOptions.all(opts, (has(opts.level) ? has(c.securityContext.seLinuxOptions.level) && (c.securityContext.seLinuxOptions.level == opts.level) : !has(c.securityContext.seLinuxOptions.level)) && (has(opts.role) ? has(c.securityContext.seLinuxOptions.role) && (c.securityContext.seLinuxOptions.role == opts.role) : !has(c.securityContext.seLinuxOptions.role)) && (has(opts.type) ? has(c.securityContext.seLinuxOptions.type) && (c.securityContext.seLinuxOptions.type == opts.type) : !has(c.securityContext.seLinuxOptions.type)) && diff --git a/website/docs/validation/selinux.md b/website/docs/validation/selinux.md index efbb99f95..3afac5846 100644 --- a/website/docs/validation/selinux.md +++ b/website/docs/validation/selinux.md @@ -77,7 +77,7 @@ spec: has(variables.anyObject.spec.securityContext) && has(variables.anyObject.spec.securityContext.seLinuxOptions) ? (has(variables.params.allowedSELinuxOptions) ? ( - variables.params.allowedSELinuxOptions.all(opts, + size(variables.params.allowedSELinuxOptions) > 0 && variables.params.allowedSELinuxOptions.all(opts, (has(opts.level) ? has(variables.anyObject.spec.securityContext.seLinuxOptions.level) && (variables.anyObject.spec.securityContext.seLinuxOptions.level == opts.level) : !has(variables.anyObject.spec.securityContext.seLinuxOptions.level)) && (has(opts.role) ? has(variables.anyObject.spec.securityContext.seLinuxOptions.role) && (variables.anyObject.spec.securityContext.seLinuxOptions.role == opts.role) : !has(variables.anyObject.spec.securityContext.seLinuxOptions.role)) && (has(opts.type) ? has(variables.anyObject.spec.securityContext.seLinuxOptions.type) && (variables.anyObject.spec.securityContext.seLinuxOptions.type == opts.type) : !has(variables.anyObject.spec.securityContext.seLinuxOptions.type)) && @@ -110,7 +110,7 @@ spec: (variables.containers + variables.initContainers + variables.ephemeralContainers).filter(c, !(c.image in variables.exemptImages) && (has(c.securityContext.seLinuxOptions) ? ( has(variables.params.allowedSELinuxOptions) ? ( - !variables.params.allowedSELinuxOptions.all(opts, + size(variables.params.allowedSELinuxOptions) == 0 || !variables.params.allowedSELinuxOptions.all(opts, (has(opts.level) ? has(c.securityContext.seLinuxOptions.level) && (c.securityContext.seLinuxOptions.level == opts.level) : !has(c.securityContext.seLinuxOptions.level)) && (has(opts.role) ? has(c.securityContext.seLinuxOptions.role) && (c.securityContext.seLinuxOptions.role == opts.role) : !has(c.securityContext.seLinuxOptions.role)) && (has(opts.type) ? has(c.securityContext.seLinuxOptions.type) && (c.securityContext.seLinuxOptions.type == opts.type) : !has(c.securityContext.seLinuxOptions.type)) && @@ -369,4 +369,148 @@ kubectl apply -f https://raw.githubusercontent.com/open-policy-agent/gatekeeper- +
+deny-all-selinux-options + +
+constraint + +```yaml +apiVersion: constraints.gatekeeper.sh/v1beta1 +kind: K8sPSPSELinuxV2 +metadata: + name: psp-selinux-v2 +spec: + match: + kinds: + - apiGroups: [""] + kinds: ["Pod"] + parameters: + allowedSELinuxOptions: [] +``` + +Usage + +```shell +kubectl apply -f https://raw.githubusercontent.com/open-policy-agent/gatekeeper-library/master/library/pod-security-policy/selinux/samples/psp-selinux-v2/constraint2.yaml +``` + +
+ +
+example-disallowed + +```yaml +apiVersion: v1 +kind: Pod +metadata: + name: nginx-selinux-disallowed + labels: + app: nginx-selinux +spec: + containers: + - name: nginx + image: nginx + securityContext: + seLinuxOptions: + level: s1:c234,c567 + user: sysadm_u + role: sysadm_r + type: svirt_lxc_net_t + +``` + +Usage + +```shell +kubectl apply -f https://raw.githubusercontent.com/open-policy-agent/gatekeeper-library/master/library/pod-security-policy/selinux/samples/psp-selinux-v2/example_disallowed.yaml +``` + +
+
+example-allowed + +```yaml +apiVersion: v1 +kind: Pod +metadata: + name: nginx-selinux-allowed + labels: + app: nginx-selinux +spec: + containers: + - name: nginx + image: nginx + securityContext: + seLinuxOptions: + level: s0:c123,c456 + role: object_r + type: svirt_sandbox_file_t + user: system_u + +``` + +Usage + +```shell +kubectl apply -f https://raw.githubusercontent.com/open-policy-agent/gatekeeper-library/master/library/pod-security-policy/selinux/samples/psp-selinux-v2/example_allowed.yaml +``` + +
+
+example-allowed-wihtout-selinux-opts + +```yaml +apiVersion: v1 +kind: Pod +metadata: + name: nginx-selinux-allowed-without-selinux-opts + labels: + app: nginx-selinux +spec: + containers: + - name: nginx + image: nginx + +``` + +Usage + +```shell +kubectl apply -f https://raw.githubusercontent.com/open-policy-agent/gatekeeper-library/master/library/pod-security-policy/selinux/samples/psp-selinux-v2/example_allowed_without_selinux_opts.yaml +``` + +
+
+disallowed-ephemeral + +```yaml +apiVersion: v1 +kind: Pod +metadata: + name: nginx-selinux-disallowed + labels: + app: nginx-selinux +spec: + ephemeralContainers: + - name: nginx + image: nginx + securityContext: + seLinuxOptions: + level: s1:c234,c567 + user: sysadm_u + role: sysadm_r + type: svirt_lxc_net_t + +``` + +Usage + +```shell +kubectl apply -f https://raw.githubusercontent.com/open-policy-agent/gatekeeper-library/master/library/pod-security-policy/selinux/samples/psp-selinux-v2/disallowed_ephemeral.yaml +``` + +
+ +
\ No newline at end of file