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..417b81ed8
--- /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: d493a5cbaf488e226d1c1133c917d1e2b0eac47b60618a3714ab8c69b07ae3cb
+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/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/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_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/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..48ec3ea49
--- /dev/null
+++ b/artifacthub/library/pod-security-policy/selinux/1.1.0/suite.yaml
@@ -0,0 +1,53 @@
+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: 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
+- 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
new file mode 100644
index 000000000..ca0db732d
--- /dev/null
+++ b/artifacthub/library/pod-security-policy/selinux/1.1.0/template.yaml
@@ -0,0 +1,202 @@
+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: usingAllowedSELinuxOptions
+ expression: |
+ has(variables.anyObject.spec.securityContext) && has(variables.anyObject.spec.securityContext.seLinuxOptions) ?
+ (has(variables.params.allowedSELinuxOptions) ?
+ (
+ 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)) &&
+ (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))
+ )
+ ) :
+ true)
+ : true
+ - name: containers
+ expression: 'has(variables.anyObject.spec.containers) ? variables.anyObject.spec.containers.filter(c, has(c.securityContext) && has(c.securityContext.seLinuxOptions)) : []'
+ - name: initContainers
+ expression: 'has(variables.anyObject.spec.initContainers) ? variables.anyObject.spec.initContainers.filter(c, has(c.securityContext) && has(c.securityContext.seLinuxOptions)) : []'
+ - name: ephemeralContainers
+ 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) ? [] :
+ 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) ?
+ (
+ 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)) &&
+ (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.usingAllowedSELinuxOptions'
+ 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(", ") + ". Allowed options: [" + variables.params.allowedSELinuxOptions.map(opts, "{ level: " + opts.level + ", role: " + opts.role + ", type: " + opts.type + ", user: " + opts.user + "}").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..ca79b7c88
--- /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: cf81297bf562f15dc11e9c56a6e78c7e0345934cea0ae6285735d9bc66a366f1
+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_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/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..27a7a0b80
--- /dev/null
+++ b/artifacthub/library/pod-security-policy/volumes/1.1.0/suite.yaml
@@ -0,0 +1,25 @@
+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: 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:
+ - 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..28a7db6f4
--- /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(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: " + variables.anyObject.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/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/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..48ec3ea49 100644
--- a/library/pod-security-policy/selinux/suite.yaml
+++ b/library/pod-security-policy/selinux/suite.yaml
@@ -15,6 +15,34 @@ 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:
+ - violations: yes
+ - name: update
+ 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:
diff --git a/library/pod-security-policy/selinux/template.yaml b/library/pod-security-policy/selinux/template.yaml
index 6ecc70675..ca0db732d 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,147 @@ spec:
description: "An SELinux user."
targets:
- target: admission.k8s.gatekeeper.sh
- rego: |
- package k8spspselinux
+ code:
+ - engine: K8sNativeValidation
+ source:
+ variables:
+ - name: usingAllowedSELinuxOptions
+ expression: |
+ has(variables.anyObject.spec.securityContext) && has(variables.anyObject.spec.securityContext.seLinuxOptions) ?
+ (has(variables.params.allowedSELinuxOptions) ?
+ (
+ 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)) &&
+ (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))
+ )
+ ) :
+ true)
+ : true
+ - name: containers
+ expression: 'has(variables.anyObject.spec.containers) ? variables.anyObject.spec.containers.filter(c, has(c.securityContext) && has(c.securityContext.seLinuxOptions)) : []'
+ - name: initContainers
+ expression: 'has(variables.anyObject.spec.initContainers) ? variables.anyObject.spec.initContainers.filter(c, has(c.securityContext) && has(c.securityContext.seLinuxOptions)) : []'
+ - name: ephemeralContainers
+ 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) ? [] :
+ 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) ?
+ (
+ 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)) &&
+ (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.usingAllowedSELinuxOptions'
+ 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(", ") + ". Allowed options: [" + variables.params.allowedSELinuxOptions.map(opts, "{ level: " + opts.level + ", role: " + opts.role + ", type: " + opts.type + ", user: " + opts.user + "}").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/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/library/pod-security-policy/volumes/template.yaml b/library/pod-security-policy/volumes/template.yaml
index 74165c8f4..28a7db6f4 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(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: " + variables.anyObject.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..b012718af
--- /dev/null
+++ b/src/pod-security-policy/selinux/src.cel
@@ -0,0 +1,53 @@
+variables:
+- name: usingAllowedSELinuxOptions
+ expression: |
+ has(variables.anyObject.spec.securityContext) && has(variables.anyObject.spec.securityContext.seLinuxOptions) ?
+ (has(variables.params.allowedSELinuxOptions) ?
+ (
+ 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)) &&
+ (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))
+ )
+ ) :
+ true)
+ : true
+- name: containers
+ expression: 'has(variables.anyObject.spec.containers) ? variables.anyObject.spec.containers.filter(c, has(c.securityContext) && has(c.securityContext.seLinuxOptions)) : []'
+- name: initContainers
+ expression: 'has(variables.anyObject.spec.initContainers) ? variables.anyObject.spec.initContainers.filter(c, has(c.securityContext) && has(c.securityContext.seLinuxOptions)) : []'
+- name: ephemeralContainers
+ 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) ? [] :
+ 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) ?
+ (
+ 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)) &&
+ (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.usingAllowedSELinuxOptions'
+ 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(", ") + ". Allowed options: [" + variables.params.allowedSELinuxOptions.map(opts, "{ level: " + opts.level + ", role: " + opts.role + ", type: " + opts.type + ", user: " + opts.user + "}").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..fbadb8135
--- /dev/null
+++ b/src/pod-security-policy/volumes/src.cel
@@ -0,0 +1,9 @@
+variables:
+- name: 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: " + 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 ddf97c740..3afac5846 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,150 @@ 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: usingAllowedSELinuxOptions
+ expression: |
+ has(variables.anyObject.spec.securityContext) && has(variables.anyObject.spec.securityContext.seLinuxOptions) ?
+ (has(variables.params.allowedSELinuxOptions) ?
+ (
+ 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)) &&
+ (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))
+ )
+ ) :
+ true)
+ : true
+ - name: containers
+ expression: 'has(variables.anyObject.spec.containers) ? variables.anyObject.spec.containers.filter(c, has(c.securityContext) && has(c.securityContext.seLinuxOptions)) : []'
+ - name: initContainers
+ expression: 'has(variables.anyObject.spec.initContainers) ? variables.anyObject.spec.initContainers.filter(c, has(c.securityContext) && has(c.securityContext.seLinuxOptions)) : []'
+ - name: ephemeralContainers
+ 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) ? [] :
+ 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) ?
+ (
+ 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)) &&
+ (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.usingAllowedSELinuxOptions'
+ 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(", ") + ". Allowed options: [" + variables.params.allowedSELinuxOptions.map(opts, "{ level: " + opts.level + ", role: " + opts.role + ", type: " + opts.type + ", user: " + opts.user + "}").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)
+ }
```
@@ -254,6 +312,174 @@ 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
+
+```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
+```
+
+
+
+
+
+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
diff --git a/website/docs/validation/volumes.md b/website/docs/validation/volumes.md
index d829de620..32c18dcf5 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(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: " + variables.anyObject.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"
+ }
```
@@ -194,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
+```
+