diff --git a/.github/workflows/workflow.yaml b/.github/workflows/workflow.yaml index 761158645..5e9c20c0d 100644 --- a/.github/workflows/workflow.yaml +++ b/.github/workflows/workflow.yaml @@ -45,7 +45,7 @@ jobs: strategy: matrix: os: [ "ubuntu-latest", "macos-latest" ] - opa: [ "v0.42.2" ] + opa: [ "v0.44.0", "v0.57.1" ] name: Unit test on ${{ matrix.os }} opa ${{ matrix.opa }} steps: - name: Harden Runner diff --git a/artifacthub/library/general/allowedrepos/1.0.1/artifacthub-pkg.yml b/artifacthub/library/general/allowedrepos/1.0.1/artifacthub-pkg.yml new file mode 100644 index 000000000..a0c03d51f --- /dev/null +++ b/artifacthub/library/general/allowedrepos/1.0.1/artifacthub-pkg.yml @@ -0,0 +1,22 @@ +version: 1.0.1 +name: k8sallowedrepos +displayName: Allowed Repositories +createdAt: "2023-10-30T20:59:57Z" +description: Requires container images to begin with a string from the specified list. +digest: eaff16a982c2d3029b280b3d4061d82b55215ac648efaafa341e25c7c77b635f +license: Apache-2.0 +homeURL: https://open-policy-agent.github.io/gatekeeper-library/website/allowedrepos +keywords: + - gatekeeper + - open-policy-agent + - policies +readme: |- + # Allowed Repositories + Requires container images to begin with a string from the specified list. +install: |- + ### Usage + ```shell + kubectl apply -f https://raw.githubusercontent.com/open-policy-agent/gatekeeper-library/master/artifacthub/library/general/allowedrepos/1.0.1/template.yaml + ``` +provider: + name: Gatekeeper Library diff --git a/artifacthub/library/general/allowedrepos/1.0.1/kustomization.yaml b/artifacthub/library/general/allowedrepos/1.0.1/kustomization.yaml new file mode 100644 index 000000000..7d70d11b7 --- /dev/null +++ b/artifacthub/library/general/allowedrepos/1.0.1/kustomization.yaml @@ -0,0 +1,2 @@ +resources: + - template.yaml diff --git a/artifacthub/library/general/allowedrepos/1.0.1/samples/repo-must-be-openpolicyagent/constraint.yaml b/artifacthub/library/general/allowedrepos/1.0.1/samples/repo-must-be-openpolicyagent/constraint.yaml new file mode 100644 index 000000000..be500b5ae --- /dev/null +++ b/artifacthub/library/general/allowedrepos/1.0.1/samples/repo-must-be-openpolicyagent/constraint.yaml @@ -0,0 +1,14 @@ +apiVersion: constraints.gatekeeper.sh/v1beta1 +kind: K8sAllowedRepos +metadata: + name: repo-is-openpolicyagent +spec: + match: + kinds: + - apiGroups: [""] + kinds: ["Pod"] + namespaces: + - "default" + parameters: + repos: + - "openpolicyagent/" diff --git a/artifacthub/library/general/allowedrepos/1.0.1/samples/repo-must-be-openpolicyagent/disallowed_all.yaml b/artifacthub/library/general/allowedrepos/1.0.1/samples/repo-must-be-openpolicyagent/disallowed_all.yaml new file mode 100644 index 000000000..bec477884 --- /dev/null +++ b/artifacthub/library/general/allowedrepos/1.0.1/samples/repo-must-be-openpolicyagent/disallowed_all.yaml @@ -0,0 +1,26 @@ +apiVersion: v1 +kind: Pod +metadata: + name: nginx-disallowed +spec: + initContainers: + - name: nginx + image: nginx + resources: + limits: + cpu: "100m" + memory: "30Mi" + containers: + - name: nginx + image: nginx + resources: + limits: + cpu: "100m" + memory: "30Mi" + ephemeralContainers: + - name: nginx + image: nginx + resources: + limits: + cpu: "100m" + memory: "30Mi" diff --git a/artifacthub/library/general/allowedrepos/1.0.1/samples/repo-must-be-openpolicyagent/example_allowed.yaml b/artifacthub/library/general/allowedrepos/1.0.1/samples/repo-must-be-openpolicyagent/example_allowed.yaml new file mode 100644 index 000000000..2dc3cd246 --- /dev/null +++ b/artifacthub/library/general/allowedrepos/1.0.1/samples/repo-must-be-openpolicyagent/example_allowed.yaml @@ -0,0 +1,16 @@ +apiVersion: v1 +kind: Pod +metadata: + name: opa-allowed +spec: + containers: + - name: opa + image: openpolicyagent/opa:0.9.2 + args: + - "run" + - "--server" + - "--addr=localhost:8080" + resources: + limits: + cpu: "100m" + memory: "30Mi" diff --git a/artifacthub/library/general/allowedrepos/1.0.1/samples/repo-must-be-openpolicyagent/example_disallowed_both.yaml b/artifacthub/library/general/allowedrepos/1.0.1/samples/repo-must-be-openpolicyagent/example_disallowed_both.yaml new file mode 100644 index 000000000..4d5f3ba64 --- /dev/null +++ b/artifacthub/library/general/allowedrepos/1.0.1/samples/repo-must-be-openpolicyagent/example_disallowed_both.yaml @@ -0,0 +1,19 @@ +apiVersion: v1 +kind: Pod +metadata: + name: nginx-disallowed +spec: + initContainers: + - name: nginxinit + image: nginx + resources: + limits: + cpu: "100m" + memory: "30Mi" + containers: + - name: nginx + image: nginx + resources: + limits: + cpu: "100m" + memory: "30Mi" diff --git a/artifacthub/library/general/allowedrepos/1.0.1/samples/repo-must-be-openpolicyagent/example_disallowed_container.yaml b/artifacthub/library/general/allowedrepos/1.0.1/samples/repo-must-be-openpolicyagent/example_disallowed_container.yaml new file mode 100644 index 000000000..face5057e --- /dev/null +++ b/artifacthub/library/general/allowedrepos/1.0.1/samples/repo-must-be-openpolicyagent/example_disallowed_container.yaml @@ -0,0 +1,12 @@ +apiVersion: v1 +kind: Pod +metadata: + name: nginx-disallowed +spec: + containers: + - name: nginx + image: nginx + resources: + limits: + cpu: "100m" + memory: "30Mi" diff --git a/artifacthub/library/general/allowedrepos/1.0.1/samples/repo-must-be-openpolicyagent/example_disallowed_initcontainer.yaml b/artifacthub/library/general/allowedrepos/1.0.1/samples/repo-must-be-openpolicyagent/example_disallowed_initcontainer.yaml new file mode 100644 index 000000000..6f7a886c6 --- /dev/null +++ b/artifacthub/library/general/allowedrepos/1.0.1/samples/repo-must-be-openpolicyagent/example_disallowed_initcontainer.yaml @@ -0,0 +1,23 @@ +apiVersion: v1 +kind: Pod +metadata: + name: nginx-disallowed +spec: + initContainers: + - name: nginxinit + image: nginx + resources: + limits: + cpu: "100m" + memory: "30Mi" + containers: + - name: opa + image: openpolicyagent/opa:0.9.2 + args: + - "run" + - "--server" + - "--addr=localhost:8080" + resources: + limits: + cpu: "100m" + memory: "30Mi" diff --git a/artifacthub/library/general/allowedrepos/1.0.1/suite.yaml b/artifacthub/library/general/allowedrepos/1.0.1/suite.yaml new file mode 100644 index 000000000..819b8457c --- /dev/null +++ b/artifacthub/library/general/allowedrepos/1.0.1/suite.yaml @@ -0,0 +1,43 @@ +kind: Suite +apiVersion: test.gatekeeper.sh/v1alpha1 +metadata: + name: allowedrepos +tests: +- name: allowed-repos + template: template.yaml + constraint: samples/repo-must-be-openpolicyagent/constraint.yaml + cases: + - name: example-allowed + object: samples/repo-must-be-openpolicyagent/example_allowed.yaml + assertions: + - violations: no + - name: container-disallowed + object: samples/repo-must-be-openpolicyagent/example_disallowed_container.yaml + assertions: + - violations: yes + message: container + - name: initcontainer-disallowed + object: samples/repo-must-be-openpolicyagent/example_disallowed_initcontainer.yaml + assertions: + - violations: 1 + message: initContainer + - violations: 0 + message: container + - name: both-disallowed + object: samples/repo-must-be-openpolicyagent/example_disallowed_both.yaml + assertions: + - violations: 2 + - message: initContainer + violations: 1 + - message: container + violations: 1 + - name: all-disallowed + object: samples/repo-must-be-openpolicyagent/disallowed_all.yaml + assertions: + - violations: 3 + - message: initContainer + violations: 1 + - message: container + violations: 1 + - message: ephemeralContainer + violations: 1 diff --git a/artifacthub/library/general/allowedrepos/1.0.1/template.yaml b/artifacthub/library/general/allowedrepos/1.0.1/template.yaml new file mode 100644 index 000000000..3c554d8e7 --- /dev/null +++ b/artifacthub/library/general/allowedrepos/1.0.1/template.yaml @@ -0,0 +1,46 @@ +apiVersion: templates.gatekeeper.sh/v1 +kind: ConstraintTemplate +metadata: + name: k8sallowedrepos + annotations: + metadata.gatekeeper.sh/title: "Allowed Repositories" + metadata.gatekeeper.sh/version: 1.0.1 + description: >- + Requires container images to begin with a string from the specified list. +spec: + crd: + spec: + names: + kind: K8sAllowedRepos + validation: + # Schema for the `parameters` field + openAPIV3Schema: + type: object + properties: + repos: + description: The list of prefixes a container image is allowed to have. + type: array + items: + type: string + targets: + - target: admission.k8s.gatekeeper.sh + rego: | + package k8sallowedrepos + + violation[{"msg": msg}] { + container := input.review.object.spec.containers[_] + not strings.any_prefix_match(container.image, input.parameters.repos) + msg := sprintf("container <%v> has an invalid image repo <%v>, allowed repos are %v", [container.name, container.image, input.parameters.repos]) + } + + violation[{"msg": msg}] { + container := input.review.object.spec.initContainers[_] + not strings.any_prefix_match(container.image, input.parameters.repos) + msg := sprintf("initContainer <%v> has an invalid image repo <%v>, allowed repos are %v", [container.name, container.image, input.parameters.repos]) + } + + violation[{"msg": msg}] { + container := input.review.object.spec.ephemeralContainers[_] + not strings.any_prefix_match(container.image, input.parameters.repos) + msg := sprintf("ephemeralContainer <%v> has an invalid image repo <%v>, allowed repos are %v", [container.name, container.image, input.parameters.repos]) + } diff --git a/artifacthub/library/general/containerlimits/1.0.1/artifacthub-pkg.yml b/artifacthub/library/general/containerlimits/1.0.1/artifacthub-pkg.yml new file mode 100644 index 000000000..d006729a3 --- /dev/null +++ b/artifacthub/library/general/containerlimits/1.0.1/artifacthub-pkg.yml @@ -0,0 +1,25 @@ +version: 1.0.1 +name: k8scontainerlimits +displayName: Container Limits +createdAt: "2023-10-30T20:59:58Z" +description: |- + Requires containers to have memory and CPU limits set and constrains limits to be within the specified maximum values. + https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/ +digest: fa0ce11ca6bacb6320053424c65d0626ee7ef96b4d359862eea031b13c8239ce +license: Apache-2.0 +homeURL: https://open-policy-agent.github.io/gatekeeper-library/website/containerlimits +keywords: + - gatekeeper + - open-policy-agent + - policies +readme: |- + # Container Limits + Requires containers to have memory and CPU limits set and constrains limits to be within the specified maximum values. + https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/ +install: |- + ### Usage + ```shell + kubectl apply -f https://raw.githubusercontent.com/open-policy-agent/gatekeeper-library/master/artifacthub/library/general/containerlimits/1.0.1/template.yaml + ``` +provider: + name: Gatekeeper Library diff --git a/artifacthub/library/general/containerlimits/1.0.1/kustomization.yaml b/artifacthub/library/general/containerlimits/1.0.1/kustomization.yaml new file mode 100644 index 000000000..7d70d11b7 --- /dev/null +++ b/artifacthub/library/general/containerlimits/1.0.1/kustomization.yaml @@ -0,0 +1,2 @@ +resources: + - template.yaml diff --git a/artifacthub/library/general/containerlimits/1.0.1/samples/container-must-have-limits/constraint.yaml b/artifacthub/library/general/containerlimits/1.0.1/samples/container-must-have-limits/constraint.yaml new file mode 100644 index 000000000..2b06fd8d1 --- /dev/null +++ b/artifacthub/library/general/containerlimits/1.0.1/samples/container-must-have-limits/constraint.yaml @@ -0,0 +1,12 @@ +apiVersion: constraints.gatekeeper.sh/v1beta1 +kind: K8sContainerLimits +metadata: + name: container-must-have-limits +spec: + match: + kinds: + - apiGroups: [""] + kinds: ["Pod"] + parameters: + cpu: "200m" + memory: "1Gi" diff --git a/artifacthub/library/general/containerlimits/1.0.1/samples/container-must-have-limits/example_allowed.yaml b/artifacthub/library/general/containerlimits/1.0.1/samples/container-must-have-limits/example_allowed.yaml new file mode 100644 index 000000000..c77c3668f --- /dev/null +++ b/artifacthub/library/general/containerlimits/1.0.1/samples/container-must-have-limits/example_allowed.yaml @@ -0,0 +1,18 @@ +apiVersion: v1 +kind: Pod +metadata: + name: opa-allowed + labels: + owner: me.agilebank.demo +spec: + containers: + - name: opa + image: openpolicyagent/opa:0.9.2 + args: + - "run" + - "--server" + - "--addr=localhost:8080" + resources: + limits: + cpu: "100m" + memory: "1Gi" diff --git a/artifacthub/library/general/containerlimits/1.0.1/samples/container-must-have-limits/example_disallowed.yaml b/artifacthub/library/general/containerlimits/1.0.1/samples/container-must-have-limits/example_disallowed.yaml new file mode 100644 index 000000000..a5bd508a7 --- /dev/null +++ b/artifacthub/library/general/containerlimits/1.0.1/samples/container-must-have-limits/example_disallowed.yaml @@ -0,0 +1,18 @@ +apiVersion: v1 +kind: Pod +metadata: + name: opa-disallowed + labels: + owner: me.agilebank.demo +spec: + containers: + - name: opa + image: openpolicyagent/opa:0.9.2 + args: + - "run" + - "--server" + - "--addr=localhost:8080" + resources: + limits: + cpu: "100m" + memory: "2Gi" \ No newline at end of file diff --git a/artifacthub/library/general/containerlimits/1.0.1/suite.yaml b/artifacthub/library/general/containerlimits/1.0.1/suite.yaml new file mode 100644 index 000000000..c22bd5b77 --- /dev/null +++ b/artifacthub/library/general/containerlimits/1.0.1/suite.yaml @@ -0,0 +1,17 @@ +kind: Suite +apiVersion: test.gatekeeper.sh/v1alpha1 +metadata: + name: containerlimits +tests: +- name: container-limits + template: template.yaml + constraint: samples/container-must-have-limits/constraint.yaml + cases: + - name: example-allowed + object: samples/container-must-have-limits/example_allowed.yaml + assertions: + - violations: no + - name: example-disallowed + object: samples/container-must-have-limits/example_disallowed.yaml + assertions: + - violations: yes diff --git a/artifacthub/library/general/containerlimits/1.0.1/template.yaml b/artifacthub/library/general/containerlimits/1.0.1/template.yaml new file mode 100644 index 000000000..4b254c663 --- /dev/null +++ b/artifacthub/library/general/containerlimits/1.0.1/template.yaml @@ -0,0 +1,264 @@ +apiVersion: templates.gatekeeper.sh/v1 +kind: ConstraintTemplate +metadata: + name: k8scontainerlimits + annotations: + metadata.gatekeeper.sh/title: "Container Limits" + metadata.gatekeeper.sh/version: 1.0.1 + description: >- + Requires containers to have memory and CPU limits set and constrains + limits to be within the specified maximum values. + + https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/ +spec: + crd: + spec: + names: + kind: K8sContainerLimits + validation: + # Schema for the `parameters` field + openAPIV3Schema: + type: object + 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 + cpu: + description: "The maximum allowed cpu limit on a Pod, exclusive." + type: string + memory: + description: "The maximum allowed memory limit on a Pod, exclusive." + type: string + targets: + - target: admission.k8s.gatekeeper.sh + rego: | + package k8scontainerlimits + + import data.lib.exempt_container.is_exempt + + missing(obj, field) = true { + not obj[field] + } + + missing(obj, field) = true { + obj[field] == "" + } + + canonify_cpu(orig) = new { + is_number(orig) + new := orig * 1000 + } + + canonify_cpu(orig) = new { + not is_number(orig) + endswith(orig, "m") + new := to_number(replace(orig, "m", "")) + } + + canonify_cpu(orig) = new { + not is_number(orig) + not endswith(orig, "m") + regex.match("^[0-9]+(\\.[0-9]+)?$", orig) + new := to_number(orig) * 1000 + } + + # 10 ** 21 + mem_multiple("E") = 1000000000000000000000 { true } + + # 10 ** 18 + mem_multiple("P") = 1000000000000000000 { true } + + # 10 ** 15 + mem_multiple("T") = 1000000000000000 { true } + + # 10 ** 12 + mem_multiple("G") = 1000000000000 { true } + + # 10 ** 9 + mem_multiple("M") = 1000000000 { true } + + # 10 ** 6 + mem_multiple("k") = 1000000 { true } + + # 10 ** 3 + mem_multiple("") = 1000 { true } + + # Kubernetes accepts millibyte precision when it probably shouldn't. + # https://github.com/kubernetes/kubernetes/issues/28741 + # 10 ** 0 + mem_multiple("m") = 1 { true } + + # 1000 * 2 ** 10 + mem_multiple("Ki") = 1024000 { true } + + # 1000 * 2 ** 20 + mem_multiple("Mi") = 1048576000 { true } + + # 1000 * 2 ** 30 + mem_multiple("Gi") = 1073741824000 { true } + + # 1000 * 2 ** 40 + mem_multiple("Ti") = 1099511627776000 { true } + + # 1000 * 2 ** 50 + mem_multiple("Pi") = 1125899906842624000 { true } + + # 1000 * 2 ** 60 + mem_multiple("Ei") = 1152921504606846976000 { true } + + get_suffix(mem) = suffix { + not is_string(mem) + suffix := "" + } + + get_suffix(mem) = suffix { + is_string(mem) + count(mem) > 0 + suffix := substring(mem, count(mem) - 1, -1) + mem_multiple(suffix) + } + + get_suffix(mem) = suffix { + is_string(mem) + count(mem) > 1 + suffix := substring(mem, count(mem) - 2, -1) + mem_multiple(suffix) + } + + get_suffix(mem) = suffix { + is_string(mem) + count(mem) > 1 + not mem_multiple(substring(mem, count(mem) - 1, -1)) + not mem_multiple(substring(mem, count(mem) - 2, -1)) + suffix := "" + } + + get_suffix(mem) = suffix { + is_string(mem) + count(mem) == 1 + not mem_multiple(substring(mem, count(mem) - 1, -1)) + suffix := "" + } + + get_suffix(mem) = suffix { + is_string(mem) + count(mem) == 0 + suffix := "" + } + + canonify_mem(orig) = new { + is_number(orig) + new := orig * 1000 + } + + canonify_mem(orig) = new { + not is_number(orig) + suffix := get_suffix(orig) + raw := replace(orig, suffix, "") + regex.match("^[0-9]+(\\.[0-9]+)?$", raw) + new := to_number(raw) * mem_multiple(suffix) + } + + violation[{"msg": msg}] { + general_violation[{"msg": msg, "field": "containers"}] + } + + violation[{"msg": msg}] { + general_violation[{"msg": msg, "field": "initContainers"}] + } + + # Ephemeral containers not checked as it is not possible to set field. + + general_violation[{"msg": msg, "field": field}] { + container := input.review.object.spec[field][_] + not is_exempt(container) + cpu_orig := container.resources.limits.cpu + not canonify_cpu(cpu_orig) + msg := sprintf("container <%v> cpu limit <%v> could not be parsed", [container.name, cpu_orig]) + } + + general_violation[{"msg": msg, "field": field}] { + container := input.review.object.spec[field][_] + not is_exempt(container) + mem_orig := container.resources.limits.memory + not canonify_mem(mem_orig) + msg := sprintf("container <%v> memory limit <%v> could not be parsed", [container.name, mem_orig]) + } + + general_violation[{"msg": msg, "field": field}] { + container := input.review.object.spec[field][_] + not is_exempt(container) + not container.resources + msg := sprintf("container <%v> has no resource limits", [container.name]) + } + + general_violation[{"msg": msg, "field": field}] { + container := input.review.object.spec[field][_] + not is_exempt(container) + not container.resources.limits + msg := sprintf("container <%v> has no resource limits", [container.name]) + } + + general_violation[{"msg": msg, "field": field}] { + container := input.review.object.spec[field][_] + not is_exempt(container) + missing(container.resources.limits, "cpu") + msg := sprintf("container <%v> has no cpu limit", [container.name]) + } + + general_violation[{"msg": msg, "field": field}] { + container := input.review.object.spec[field][_] + not is_exempt(container) + missing(container.resources.limits, "memory") + msg := sprintf("container <%v> has no memory limit", [container.name]) + } + + general_violation[{"msg": msg, "field": field}] { + container := input.review.object.spec[field][_] + not is_exempt(container) + cpu_orig := container.resources.limits.cpu + cpu := canonify_cpu(cpu_orig) + max_cpu_orig := input.parameters.cpu + max_cpu := canonify_cpu(max_cpu_orig) + cpu > max_cpu + msg := sprintf("container <%v> cpu limit <%v> is higher than the maximum allowed of <%v>", [container.name, cpu_orig, max_cpu_orig]) + } + + general_violation[{"msg": msg, "field": field}] { + container := input.review.object.spec[field][_] + not is_exempt(container) + mem_orig := container.resources.limits.memory + mem := canonify_mem(mem_orig) + max_mem_orig := input.parameters.memory + max_mem := canonify_mem(max_mem_orig) + mem > max_mem + msg := sprintf("container <%v> memory limit <%v> is higher than the maximum allowed of <%v>", [container.name, mem_orig, max_mem_orig]) + } + libs: + - | + 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/general/containerrequests/1.0.1/artifacthub-pkg.yml b/artifacthub/library/general/containerrequests/1.0.1/artifacthub-pkg.yml new file mode 100644 index 000000000..f6318008a --- /dev/null +++ b/artifacthub/library/general/containerrequests/1.0.1/artifacthub-pkg.yml @@ -0,0 +1,25 @@ +version: 1.0.1 +name: k8scontainerrequests +displayName: Container Requests +createdAt: "2023-10-30T20:59:58Z" +description: |- + Requires containers to have memory and CPU requests set and constrains requests to be within the specified maximum values. + https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/ +digest: f8cb14a41eb63e15bd55178cdd4b3c7c4f7e9ec1aebd296ff36f51b201113254 +license: Apache-2.0 +homeURL: https://open-policy-agent.github.io/gatekeeper-library/website/containerrequests +keywords: + - gatekeeper + - open-policy-agent + - policies +readme: |- + # Container Requests + Requires containers to have memory and CPU requests set and constrains requests to be within the specified maximum values. + https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/ +install: |- + ### Usage + ```shell + kubectl apply -f https://raw.githubusercontent.com/open-policy-agent/gatekeeper-library/master/artifacthub/library/general/containerrequests/1.0.1/template.yaml + ``` +provider: + name: Gatekeeper Library diff --git a/artifacthub/library/general/containerrequests/1.0.1/kustomization.yaml b/artifacthub/library/general/containerrequests/1.0.1/kustomization.yaml new file mode 100644 index 000000000..7d70d11b7 --- /dev/null +++ b/artifacthub/library/general/containerrequests/1.0.1/kustomization.yaml @@ -0,0 +1,2 @@ +resources: + - template.yaml diff --git a/artifacthub/library/general/containerrequests/1.0.1/samples/container-must-have-requests/constraint.yaml b/artifacthub/library/general/containerrequests/1.0.1/samples/container-must-have-requests/constraint.yaml new file mode 100644 index 000000000..1bcc3572f --- /dev/null +++ b/artifacthub/library/general/containerrequests/1.0.1/samples/container-must-have-requests/constraint.yaml @@ -0,0 +1,12 @@ +apiVersion: constraints.gatekeeper.sh/v1beta1 +kind: K8sContainerRequests +metadata: + name: container-must-have-requests +spec: + match: + kinds: + - apiGroups: [""] + kinds: ["Pod"] + parameters: + cpu: "200m" + memory: "1Gi" diff --git a/artifacthub/library/general/containerrequests/1.0.1/samples/container-must-have-requests/example_allowed.yaml b/artifacthub/library/general/containerrequests/1.0.1/samples/container-must-have-requests/example_allowed.yaml new file mode 100644 index 000000000..48af2a4b3 --- /dev/null +++ b/artifacthub/library/general/containerrequests/1.0.1/samples/container-must-have-requests/example_allowed.yaml @@ -0,0 +1,18 @@ +apiVersion: v1 +kind: Pod +metadata: + name: opa-allowed + labels: + owner: me.agilebank.demo +spec: + containers: + - name: opa + image: openpolicyagent/opa:0.9.2 + args: + - "run" + - "--server" + - "--addr=localhost:8080" + resources: + requests: + cpu: "100m" + memory: "1Gi" diff --git a/artifacthub/library/general/containerrequests/1.0.1/samples/container-must-have-requests/example_disallowed.yaml b/artifacthub/library/general/containerrequests/1.0.1/samples/container-must-have-requests/example_disallowed.yaml new file mode 100644 index 000000000..126b8631b --- /dev/null +++ b/artifacthub/library/general/containerrequests/1.0.1/samples/container-must-have-requests/example_disallowed.yaml @@ -0,0 +1,18 @@ +apiVersion: v1 +kind: Pod +metadata: + name: opa-disallowed + labels: + owner: me.agilebank.demo +spec: + containers: + - name: opa + image: openpolicyagent/opa:0.9.2 + args: + - "run" + - "--server" + - "--addr=localhost:8080" + resources: + requests: + cpu: "100m" + memory: "2Gi" diff --git a/artifacthub/library/general/containerrequests/1.0.1/suite.yaml b/artifacthub/library/general/containerrequests/1.0.1/suite.yaml new file mode 100644 index 000000000..1c4b224eb --- /dev/null +++ b/artifacthub/library/general/containerrequests/1.0.1/suite.yaml @@ -0,0 +1,17 @@ +kind: Suite +apiVersion: test.gatekeeper.sh/v1alpha1 +metadata: + name: containerrequests +tests: +- name: container-requests + template: template.yaml + constraint: samples/container-must-have-requests/constraint.yaml + cases: + - name: example-allowed + object: samples/container-must-have-requests/example_allowed.yaml + assertions: + - violations: no + - name: example-disallowed + object: samples/container-must-have-requests/example_disallowed.yaml + assertions: + - violations: yes diff --git a/artifacthub/library/general/containerrequests/1.0.1/template.yaml b/artifacthub/library/general/containerrequests/1.0.1/template.yaml new file mode 100644 index 000000000..a67e8b786 --- /dev/null +++ b/artifacthub/library/general/containerrequests/1.0.1/template.yaml @@ -0,0 +1,264 @@ +apiVersion: templates.gatekeeper.sh/v1 +kind: ConstraintTemplate +metadata: + name: k8scontainerrequests + annotations: + metadata.gatekeeper.sh/title: "Container Requests" + metadata.gatekeeper.sh/version: 1.0.1 + description: >- + Requires containers to have memory and CPU requests set and constrains + requests to be within the specified maximum values. + + https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/ +spec: + crd: + spec: + names: + kind: K8sContainerRequests + validation: + # Schema for the `parameters` field + openAPIV3Schema: + type: object + 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 + cpu: + description: "The maximum allowed cpu request on a Pod, exclusive." + type: string + memory: + description: "The maximum allowed memory request on a Pod, exclusive." + type: string + targets: + - target: admission.k8s.gatekeeper.sh + rego: | + package k8scontainerrequests + + import data.lib.exempt_container.is_exempt + + missing(obj, field) = true { + not obj[field] + } + + missing(obj, field) = true { + obj[field] == "" + } + + canonify_cpu(orig) = new { + is_number(orig) + new := orig * 1000 + } + + canonify_cpu(orig) = new { + not is_number(orig) + endswith(orig, "m") + new := to_number(replace(orig, "m", "")) + } + + canonify_cpu(orig) = new { + not is_number(orig) + not endswith(orig, "m") + regex.match("^[0-9]+(\\.[0-9]+)?$", orig) + new := to_number(orig) * 1000 + } + + # 10 ** 21 + mem_multiple("E") = 1000000000000000000000 { true } + + # 10 ** 18 + mem_multiple("P") = 1000000000000000000 { true } + + # 10 ** 15 + mem_multiple("T") = 1000000000000000 { true } + + # 10 ** 12 + mem_multiple("G") = 1000000000000 { true } + + # 10 ** 9 + mem_multiple("M") = 1000000000 { true } + + # 10 ** 6 + mem_multiple("k") = 1000000 { true } + + # 10 ** 3 + mem_multiple("") = 1000 { true } + + # Kubernetes accepts millibyte precision when it probably shouldn't. + # https://github.com/kubernetes/kubernetes/issues/28741 + # 10 ** 0 + mem_multiple("m") = 1 { true } + + # 1000 * 2 ** 10 + mem_multiple("Ki") = 1024000 { true } + + # 1000 * 2 ** 20 + mem_multiple("Mi") = 1048576000 { true } + + # 1000 * 2 ** 30 + mem_multiple("Gi") = 1073741824000 { true } + + # 1000 * 2 ** 40 + mem_multiple("Ti") = 1099511627776000 { true } + + # 1000 * 2 ** 50 + mem_multiple("Pi") = 1125899906842624000 { true } + + # 1000 * 2 ** 60 + mem_multiple("Ei") = 1152921504606846976000 { true } + + get_suffix(mem) = suffix { + not is_string(mem) + suffix := "" + } + + get_suffix(mem) = suffix { + is_string(mem) + count(mem) > 0 + suffix := substring(mem, count(mem) - 1, -1) + mem_multiple(suffix) + } + + get_suffix(mem) = suffix { + is_string(mem) + count(mem) > 1 + suffix := substring(mem, count(mem) - 2, -1) + mem_multiple(suffix) + } + + get_suffix(mem) = suffix { + is_string(mem) + count(mem) > 1 + not mem_multiple(substring(mem, count(mem) - 1, -1)) + not mem_multiple(substring(mem, count(mem) - 2, -1)) + suffix := "" + } + + get_suffix(mem) = suffix { + is_string(mem) + count(mem) == 1 + not mem_multiple(substring(mem, count(mem) - 1, -1)) + suffix := "" + } + + get_suffix(mem) = suffix { + is_string(mem) + count(mem) == 0 + suffix := "" + } + + canonify_mem(orig) = new { + is_number(orig) + new := orig * 1000 + } + + canonify_mem(orig) = new { + not is_number(orig) + suffix := get_suffix(orig) + raw := replace(orig, suffix, "") + regex.match("^[0-9]+(\\.[0-9]+)?$", raw) + new := to_number(raw) * mem_multiple(suffix) + } + + violation[{"msg": msg}] { + general_violation[{"msg": msg, "field": "containers"}] + } + + violation[{"msg": msg}] { + general_violation[{"msg": msg, "field": "initContainers"}] + } + + # Ephemeral containers not checked as it is not possible to set field. + + general_violation[{"msg": msg, "field": field}] { + container := input.review.object.spec[field][_] + not is_exempt(container) + cpu_orig := container.resources.requests.cpu + not canonify_cpu(cpu_orig) + msg := sprintf("container <%v> cpu request <%v> could not be parsed", [container.name, cpu_orig]) + } + + general_violation[{"msg": msg, "field": field}] { + container := input.review.object.spec[field][_] + not is_exempt(container) + mem_orig := container.resources.requests.memory + not canonify_mem(mem_orig) + msg := sprintf("container <%v> memory request <%v> could not be parsed", [container.name, mem_orig]) + } + + general_violation[{"msg": msg, "field": field}] { + container := input.review.object.spec[field][_] + not is_exempt(container) + not container.resources + msg := sprintf("container <%v> has no resource requests", [container.name]) + } + + general_violation[{"msg": msg, "field": field}] { + container := input.review.object.spec[field][_] + not is_exempt(container) + not container.resources.requests + msg := sprintf("container <%v> has no resource requests", [container.name]) + } + + general_violation[{"msg": msg, "field": field}] { + container := input.review.object.spec[field][_] + not is_exempt(container) + missing(container.resources.requests, "cpu") + msg := sprintf("container <%v> has no cpu request", [container.name]) + } + + general_violation[{"msg": msg, "field": field}] { + container := input.review.object.spec[field][_] + not is_exempt(container) + missing(container.resources.requests, "memory") + msg := sprintf("container <%v> has no memory request", [container.name]) + } + + general_violation[{"msg": msg, "field": field}] { + container := input.review.object.spec[field][_] + not is_exempt(container) + cpu_orig := container.resources.requests.cpu + cpu := canonify_cpu(cpu_orig) + max_cpu_orig := input.parameters.cpu + max_cpu := canonify_cpu(max_cpu_orig) + cpu > max_cpu + msg := sprintf("container <%v> cpu request <%v> is higher than the maximum allowed of <%v>", [container.name, cpu_orig, max_cpu_orig]) + } + + general_violation[{"msg": msg, "field": field}] { + container := input.review.object.spec[field][_] + not is_exempt(container) + mem_orig := container.resources.requests.memory + mem := canonify_mem(mem_orig) + max_mem_orig := input.parameters.memory + max_mem := canonify_mem(max_mem_orig) + mem > max_mem + msg := sprintf("container <%v> memory request <%v> is higher than the maximum allowed of <%v>", [container.name, mem_orig, max_mem_orig]) + } + libs: + - | + 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/general/containerresourceratios/1.0.1/artifacthub-pkg.yml b/artifacthub/library/general/containerresourceratios/1.0.1/artifacthub-pkg.yml new file mode 100644 index 000000000..1b62d50cb --- /dev/null +++ b/artifacthub/library/general/containerresourceratios/1.0.1/artifacthub-pkg.yml @@ -0,0 +1,25 @@ +version: 1.0.1 +name: k8scontainerratios +displayName: Container Ratios +createdAt: "2023-10-30T20:59:58Z" +description: |- + Sets a maximum ratio for container resource limits to requests. + https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/ +digest: 1a85e6bfea3820f092cdea95dfdb9d8b14fb48d90e565b0e432d5faca597b4d1 +license: Apache-2.0 +homeURL: https://open-policy-agent.github.io/gatekeeper-library/website/containerresourceratios +keywords: + - gatekeeper + - open-policy-agent + - policies +readme: |- + # Container Ratios + Sets a maximum ratio for container resource limits to requests. + https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/ +install: |- + ### Usage + ```shell + kubectl apply -f https://raw.githubusercontent.com/open-policy-agent/gatekeeper-library/master/artifacthub/library/general/containerresourceratios/1.0.1/template.yaml + ``` +provider: + name: Gatekeeper Library diff --git a/artifacthub/library/general/containerresourceratios/1.0.1/kustomization.yaml b/artifacthub/library/general/containerresourceratios/1.0.1/kustomization.yaml new file mode 100644 index 000000000..7d70d11b7 --- /dev/null +++ b/artifacthub/library/general/containerresourceratios/1.0.1/kustomization.yaml @@ -0,0 +1,2 @@ +resources: + - template.yaml diff --git a/artifacthub/library/general/containerresourceratios/1.0.1/samples/container-must-meet-memory-and-cpu-ratio/constraint.yaml b/artifacthub/library/general/containerresourceratios/1.0.1/samples/container-must-meet-memory-and-cpu-ratio/constraint.yaml new file mode 100644 index 000000000..c49c5bd2c --- /dev/null +++ b/artifacthub/library/general/containerresourceratios/1.0.1/samples/container-must-meet-memory-and-cpu-ratio/constraint.yaml @@ -0,0 +1,12 @@ +apiVersion: constraints.gatekeeper.sh/v1beta1 +kind: K8sContainerRatios +metadata: + name: container-must-meet-memory-and-cpu-ratio +spec: + match: + kinds: + - apiGroups: [""] + kinds: ["Pod"] + parameters: + ratio: "1" + cpuRatio: "10" diff --git a/artifacthub/library/general/containerresourceratios/1.0.1/samples/container-must-meet-memory-and-cpu-ratio/example_allowed.yaml b/artifacthub/library/general/containerresourceratios/1.0.1/samples/container-must-meet-memory-and-cpu-ratio/example_allowed.yaml new file mode 100644 index 000000000..700786f9e --- /dev/null +++ b/artifacthub/library/general/containerresourceratios/1.0.1/samples/container-must-meet-memory-and-cpu-ratio/example_allowed.yaml @@ -0,0 +1,21 @@ +apiVersion: v1 +kind: Pod +metadata: + name: opa-allowed + labels: + owner: me.agilebank.demo +spec: + containers: + - name: opa + image: openpolicyagent/opa:0.9.2 + args: + - "run" + - "--server" + - "--addr=localhost:8080" + resources: + limits: + cpu: "4" + memory: "2Gi" + requests: + cpu: "1" + memory: "2Gi" diff --git a/artifacthub/library/general/containerresourceratios/1.0.1/samples/container-must-meet-memory-and-cpu-ratio/example_disallowed.yaml b/artifacthub/library/general/containerresourceratios/1.0.1/samples/container-must-meet-memory-and-cpu-ratio/example_disallowed.yaml new file mode 100644 index 000000000..bf8b3e87c --- /dev/null +++ b/artifacthub/library/general/containerresourceratios/1.0.1/samples/container-must-meet-memory-and-cpu-ratio/example_disallowed.yaml @@ -0,0 +1,21 @@ +apiVersion: v1 +kind: Pod +metadata: + name: opa-disallowed + labels: + owner: me.agilebank.demo +spec: + containers: + - name: opa + image: openpolicyagent/opa:0.9.2 + args: + - "run" + - "--server" + - "--addr=localhost:8080" + resources: + limits: + cpu: "4" + memory: "2Gi" + requests: + cpu: "100m" + memory: "2Gi" diff --git a/artifacthub/library/general/containerresourceratios/1.0.1/samples/container-must-meet-ratio/constraint.yaml b/artifacthub/library/general/containerresourceratios/1.0.1/samples/container-must-meet-ratio/constraint.yaml new file mode 100644 index 000000000..db7ac53e6 --- /dev/null +++ b/artifacthub/library/general/containerresourceratios/1.0.1/samples/container-must-meet-ratio/constraint.yaml @@ -0,0 +1,11 @@ +apiVersion: constraints.gatekeeper.sh/v1beta1 +kind: K8sContainerRatios +metadata: + name: container-must-meet-ratio +spec: + match: + kinds: + - apiGroups: [""] + kinds: ["Pod"] + parameters: + ratio: "2" diff --git a/artifacthub/library/general/containerresourceratios/1.0.1/samples/container-must-meet-ratio/example_allowed.yaml b/artifacthub/library/general/containerresourceratios/1.0.1/samples/container-must-meet-ratio/example_allowed.yaml new file mode 100644 index 000000000..eb8ba6860 --- /dev/null +++ b/artifacthub/library/general/containerresourceratios/1.0.1/samples/container-must-meet-ratio/example_allowed.yaml @@ -0,0 +1,21 @@ +apiVersion: v1 +kind: Pod +metadata: + name: opa-disallowed + labels: + owner: me.agilebank.demo +spec: + containers: + - name: opa + image: openpolicyagent/opa:0.9.2 + args: + - "run" + - "--server" + - "--addr=localhost:8080" + resources: + limits: + cpu: "200m" + memory: "200Mi" + requests: + cpu: "100m" + memory: "100Mi" diff --git a/artifacthub/library/general/containerresourceratios/1.0.1/samples/container-must-meet-ratio/example_disallowed.yaml b/artifacthub/library/general/containerresourceratios/1.0.1/samples/container-must-meet-ratio/example_disallowed.yaml new file mode 100644 index 000000000..4b3b12715 --- /dev/null +++ b/artifacthub/library/general/containerresourceratios/1.0.1/samples/container-must-meet-ratio/example_disallowed.yaml @@ -0,0 +1,21 @@ +apiVersion: v1 +kind: Pod +metadata: + name: opa-disallowed + labels: + owner: me.agilebank.demo +spec: + containers: + - name: opa + image: openpolicyagent/opa:0.9.2 + args: + - "run" + - "--server" + - "--addr=localhost:8080" + resources: + limits: + cpu: "800m" + memory: "2Gi" + requests: + cpu: "100m" + memory: "100Mi" diff --git a/artifacthub/library/general/containerresourceratios/1.0.1/suite.yaml b/artifacthub/library/general/containerresourceratios/1.0.1/suite.yaml new file mode 100644 index 000000000..8df0686b7 --- /dev/null +++ b/artifacthub/library/general/containerresourceratios/1.0.1/suite.yaml @@ -0,0 +1,29 @@ +kind: Suite +apiVersion: test.gatekeeper.sh/v1alpha1 +metadata: + name: containerresourceratios +tests: + - name: memory-ratio-only + template: template.yaml + constraint: samples/container-must-meet-ratio/constraint.yaml + cases: + - name: example-allowed + object: samples/container-must-meet-ratio/example_allowed.yaml + assertions: + - violations: no + - name: example-disallowed + object: samples/container-must-meet-ratio/example_disallowed.yaml + assertions: + - violations: yes + - name: memory-and-cpu-ratios + template: template.yaml + constraint: samples/container-must-meet-memory-and-cpu-ratio/constraint.yaml + cases: + - name: example-allowed + object: samples/container-must-meet-memory-and-cpu-ratio/example_allowed.yaml + assertions: + - violations: no + - name: example-disallowed + object: samples/container-must-meet-memory-and-cpu-ratio/example_disallowed.yaml + assertions: + - violations: yes diff --git a/artifacthub/library/general/containerresourceratios/1.0.1/template.yaml b/artifacthub/library/general/containerresourceratios/1.0.1/template.yaml new file mode 100644 index 000000000..94a9753aa --- /dev/null +++ b/artifacthub/library/general/containerresourceratios/1.0.1/template.yaml @@ -0,0 +1,313 @@ +apiVersion: templates.gatekeeper.sh/v1 +kind: ConstraintTemplate +metadata: + name: k8scontainerratios + annotations: + metadata.gatekeeper.sh/title: "Container Ratios" + metadata.gatekeeper.sh/version: 1.0.1 + description: >- + Sets a maximum ratio for container resource limits to requests. + + https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/ +spec: + crd: + spec: + names: + kind: K8sContainerRatios + validation: + openAPIV3Schema: + type: object + 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 + ratio: + type: string + description: >- + The maximum allowed ratio of `resources.limits` to + `resources.requests` on a container. + cpuRatio: + type: string + description: >- + The maximum allowed ratio of `resources.limits.cpu` to + `resources.requests.cpu` on a container. If not specified, + equal to `ratio`. + targets: + - target: admission.k8s.gatekeeper.sh + rego: | + package k8scontainerratios + + import data.lib.exempt_container.is_exempt + + missing(obj, field) = true { + not obj[field] + } + + missing(obj, field) = true { + obj[field] == "" + } + + canonify_cpu(orig) = new { + is_number(orig) + new := orig * 1000 + } + + canonify_cpu(orig) = new { + not is_number(orig) + endswith(orig, "m") + new := to_number(replace(orig, "m", "")) + } + + canonify_cpu(orig) = new { + not is_number(orig) + not endswith(orig, "m") + regex.match("^[0-9]+$", orig) + new := to_number(orig) * 1000 + } + + canonify_cpu(orig) = new { + not is_number(orig) + not endswith(orig, "m") + regex.match("^[0-9]+[.][0-9]+$", orig) + new := to_number(orig) * 1000 + } + + # 10 ** 21 + mem_multiple("E") = 1000000000000000000000 { true } + + # 10 ** 18 + mem_multiple("P") = 1000000000000000000 { true } + + # 10 ** 15 + mem_multiple("T") = 1000000000000000 { true } + + # 10 ** 12 + mem_multiple("G") = 1000000000000 { true } + + # 10 ** 9 + mem_multiple("M") = 1000000000 { true } + + # 10 ** 6 + mem_multiple("k") = 1000000 { true } + + # 10 ** 3 + mem_multiple("") = 1000 { true } + + # Kubernetes accepts millibyte precision when it probably shouldn't. + # https://github.com/kubernetes/kubernetes/issues/28741 + # 10 ** 0 + mem_multiple("m") = 1 { true } + + # 1000 * 2 ** 10 + mem_multiple("Ki") = 1024000 { true } + + # 1000 * 2 ** 20 + mem_multiple("Mi") = 1048576000 { true } + + # 1000 * 2 ** 30 + mem_multiple("Gi") = 1073741824000 { true } + + # 1000 * 2 ** 40 + mem_multiple("Ti") = 1099511627776000 { true } + + # 1000 * 2 ** 50 + mem_multiple("Pi") = 1125899906842624000 { true } + + # 1000 * 2 ** 60 + mem_multiple("Ei") = 1152921504606846976000 { true } + + get_suffix(mem) = suffix { + not is_string(mem) + suffix := "" + } + + get_suffix(mem) = suffix { + is_string(mem) + count(mem) > 0 + suffix := substring(mem, count(mem) - 1, -1) + mem_multiple(suffix) + } + + get_suffix(mem) = suffix { + is_string(mem) + count(mem) > 1 + suffix := substring(mem, count(mem) - 2, -1) + mem_multiple(suffix) + } + + get_suffix(mem) = suffix { + is_string(mem) + count(mem) > 1 + not mem_multiple(substring(mem, count(mem) - 1, -1)) + not mem_multiple(substring(mem, count(mem) - 2, -1)) + suffix := "" + } + + get_suffix(mem) = suffix { + is_string(mem) + count(mem) == 1 + not mem_multiple(substring(mem, count(mem) - 1, -1)) + suffix := "" + } + + get_suffix(mem) = suffix { + is_string(mem) + count(mem) == 0 + suffix := "" + } + + canonify_mem(orig) = new { + is_number(orig) + new := orig * 1000 + } + + canonify_mem(orig) = new { + not is_number(orig) + suffix := get_suffix(orig) + raw := replace(orig, suffix, "") + regex.match("^[0-9]+(\\.[0-9]+)?$", raw) + new := to_number(raw) * mem_multiple(suffix) + } + + violation[{"msg": msg}] { + general_violation[{"msg": msg, "field": "containers"}] + } + + violation[{"msg": msg}] { + general_violation[{"msg": msg, "field": "initContainers"}] + } + + # Ephemeral containers not checked as it is not possible to set field. + + general_violation[{"msg": msg, "field": field}] { + container := input.review.object.spec[field][_] + not is_exempt(container) + cpu_orig := container.resources.limits.cpu + not canonify_cpu(cpu_orig) + msg := sprintf("container <%v> cpu limit <%v> could not be parsed", [container.name, cpu_orig]) + } + + general_violation[{"msg": msg, "field": field}] { + container := input.review.object.spec[field][_] + not is_exempt(container) + mem_orig := container.resources.limits.memory + not canonify_mem(mem_orig) + msg := sprintf("container <%v> memory limit <%v> could not be parsed", [container.name, mem_orig]) + } + + general_violation[{"msg": msg, "field": field}] { + container := input.review.object.spec[field][_] + not is_exempt(container) + cpu_orig := container.resources.requests.cpu + not canonify_cpu(cpu_orig) + msg := sprintf("container <%v> cpu request <%v> could not be parsed", [container.name, cpu_orig]) + } + + general_violation[{"msg": msg, "field": field}] { + container := input.review.object.spec[field][_] + not is_exempt(container) + mem_orig := container.resources.requests.memory + not canonify_mem(mem_orig) + msg := sprintf("container <%v> memory request <%v> could not be parsed", [container.name, mem_orig]) + } + + general_violation[{"msg": msg, "field": field}] { + container := input.review.object.spec[field][_] + not is_exempt(container) + not container.resources + msg := sprintf("container <%v> has no resource limits", [container.name]) + } + + general_violation[{"msg": msg, "field": field}] { + container := input.review.object.spec[field][_] + not is_exempt(container) + not container.resources.limits + msg := sprintf("container <%v> has no resource limits", [container.name]) + } + + general_violation[{"msg": msg, "field": field}] { + container := input.review.object.spec[field][_] + not is_exempt(container) + missing(container.resources.limits, "cpu") + msg := sprintf("container <%v> has no cpu limit", [container.name]) + } + + general_violation[{"msg": msg, "field": field}] { + container := input.review.object.spec[field][_] + not is_exempt(container) + missing(container.resources.limits, "memory") + msg := sprintf("container <%v> has no memory limit", [container.name]) + } + + general_violation[{"msg": msg, "field": field}] { + container := input.review.object.spec[field][_] + not is_exempt(container) + not container.resources.requests + msg := sprintf("container <%v> has no resource requests", [container.name]) + } + + general_violation[{"msg": msg, "field": field}] { + container := input.review.object.spec[field][_] + not is_exempt(container) + missing(container.resources.requests, "cpu") + msg := sprintf("container <%v> has no cpu request", [container.name]) + } + + general_violation[{"msg": msg, "field": field}] { + container := input.review.object.spec[field][_] + not is_exempt(container) + missing(container.resources.requests, "memory") + msg := sprintf("container <%v> has no memory request", [container.name]) + } + + general_violation[{"msg": msg, "field": field}] { + container := input.review.object.spec[field][_] + not is_exempt(container) + cpu_limits_orig := container.resources.limits.cpu + cpu_limits := canonify_cpu(cpu_limits_orig) + cpu_requests_orig := container.resources.requests.cpu + cpu_requests := canonify_cpu(cpu_requests_orig) + cpu_ratio := object.get(input.parameters, "cpuRatio", input.parameters.ratio) + to_number(cpu_limits) > to_number(cpu_ratio) * to_number(cpu_requests) + msg := sprintf("container <%v> cpu limit <%v> is higher than the maximum allowed ratio of <%v>", [container.name, cpu_limits_orig, cpu_ratio]) + } + + general_violation[{"msg": msg, "field": field}] { + container := input.review.object.spec[field][_] + not is_exempt(container) + mem_limits_orig := container.resources.limits.memory + mem_requests_orig := container.resources.requests.memory + mem_limits := canonify_mem(mem_limits_orig) + mem_requests := canonify_mem(mem_requests_orig) + mem_ratio := input.parameters.ratio + to_number(mem_limits) > to_number(mem_ratio) * to_number(mem_requests) + msg := sprintf("container <%v> memory limit <%v> is higher than the maximum allowed ratio of <%v>", [container.name, mem_limits_orig, mem_ratio]) + } + libs: + - | + 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/general/disallowedtags/1.0.1/artifacthub-pkg.yml b/artifacthub/library/general/disallowedtags/1.0.1/artifacthub-pkg.yml new file mode 100644 index 000000000..191ca7b00 --- /dev/null +++ b/artifacthub/library/general/disallowedtags/1.0.1/artifacthub-pkg.yml @@ -0,0 +1,25 @@ +version: 1.0.1 +name: k8sdisallowedtags +displayName: Disallow tags +createdAt: "2023-10-30T20:59:59Z" +description: |- + Requires container images to have an image tag different from the ones in the specified list. + https://kubernetes.io/docs/concepts/containers/images/#image-names +digest: c678f10ef73f11162ccc8ba6a5891cd033168273e386db9d5634179dc4cafa3c +license: Apache-2.0 +homeURL: https://open-policy-agent.github.io/gatekeeper-library/website/disallowedtags +keywords: + - gatekeeper + - open-policy-agent + - policies +readme: |- + # Disallow tags + Requires container images to have an image tag different from the ones in the specified list. + https://kubernetes.io/docs/concepts/containers/images/#image-names +install: |- + ### Usage + ```shell + kubectl apply -f https://raw.githubusercontent.com/open-policy-agent/gatekeeper-library/master/artifacthub/library/general/disallowedtags/1.0.1/template.yaml + ``` +provider: + name: Gatekeeper Library diff --git a/artifacthub/library/general/disallowedtags/1.0.1/kustomization.yaml b/artifacthub/library/general/disallowedtags/1.0.1/kustomization.yaml new file mode 100644 index 000000000..a2469fa0a --- /dev/null +++ b/artifacthub/library/general/disallowedtags/1.0.1/kustomization.yaml @@ -0,0 +1,4 @@ +apiVersion: kustomize.config.k8s.io/v1beta1 +kind: Kustomization +resources: + - template.yaml diff --git a/artifacthub/library/general/disallowedtags/1.0.1/samples/container-image-must-not-have-latest-tag/constraint.yaml b/artifacthub/library/general/disallowedtags/1.0.1/samples/container-image-must-not-have-latest-tag/constraint.yaml new file mode 100644 index 000000000..cceb50565 --- /dev/null +++ b/artifacthub/library/general/disallowedtags/1.0.1/samples/container-image-must-not-have-latest-tag/constraint.yaml @@ -0,0 +1,14 @@ +apiVersion: constraints.gatekeeper.sh/v1beta1 +kind: K8sDisallowedTags +metadata: + name: container-image-must-not-have-latest-tag +spec: + match: + kinds: + - apiGroups: [""] + kinds: ["Pod"] + namespaces: + - "default" + parameters: + tags: ["latest"] + exemptImages: ["openpolicyagent/opa-exp:latest", "openpolicyagent/opa-exp2:latest"] diff --git a/artifacthub/library/general/disallowedtags/1.0.1/samples/container-image-must-not-have-latest-tag/disallowed_tag_ephemeral.yaml b/artifacthub/library/general/disallowedtags/1.0.1/samples/container-image-must-not-have-latest-tag/disallowed_tag_ephemeral.yaml new file mode 100644 index 000000000..66db83c15 --- /dev/null +++ b/artifacthub/library/general/disallowedtags/1.0.1/samples/container-image-must-not-have-latest-tag/disallowed_tag_ephemeral.yaml @@ -0,0 +1,19 @@ +apiVersion: v1 +kind: Pod +metadata: + name: opa-disallowed-ephemeral +spec: + containers: + - name: opa + image: openpolicyagent/opa:0.9.2 + args: + - "run" + - "--server" + - "--addr=localhost:8080" + ephemeralContainers: + - name: opa + image: openpolicyagent/opa:latest + args: + - "run" + - "--server" + - "--addr=localhost:8080" diff --git a/artifacthub/library/general/disallowedtags/1.0.1/samples/container-image-must-not-have-latest-tag/example_allowed.yaml b/artifacthub/library/general/disallowedtags/1.0.1/samples/container-image-must-not-have-latest-tag/example_allowed.yaml new file mode 100644 index 000000000..cc6407401 --- /dev/null +++ b/artifacthub/library/general/disallowedtags/1.0.1/samples/container-image-must-not-have-latest-tag/example_allowed.yaml @@ -0,0 +1,12 @@ +apiVersion: v1 +kind: Pod +metadata: + name: opa-allowed +spec: + containers: + - name: opa + image: openpolicyagent/opa:0.9.2 + args: + - "run" + - "--server" + - "--addr=localhost:8080" diff --git a/artifacthub/library/general/disallowedtags/1.0.1/samples/container-image-must-not-have-latest-tag/example_disallowed_tag.yaml b/artifacthub/library/general/disallowedtags/1.0.1/samples/container-image-must-not-have-latest-tag/example_disallowed_tag.yaml new file mode 100644 index 000000000..1c689315f --- /dev/null +++ b/artifacthub/library/general/disallowedtags/1.0.1/samples/container-image-must-not-have-latest-tag/example_disallowed_tag.yaml @@ -0,0 +1,12 @@ +apiVersion: v1 +kind: Pod +metadata: + name: opa-disallowed-2 +spec: + containers: + - name: opa + image: openpolicyagent/opa:latest + args: + - "run" + - "--server" + - "--addr=localhost:8080" diff --git a/artifacthub/library/general/disallowedtags/1.0.1/samples/container-image-must-not-have-latest-tag/example_exempt_image_w_disallowed_tag.yaml b/artifacthub/library/general/disallowedtags/1.0.1/samples/container-image-must-not-have-latest-tag/example_exempt_image_w_disallowed_tag.yaml new file mode 100644 index 000000000..2bd249fec --- /dev/null +++ b/artifacthub/library/general/disallowedtags/1.0.1/samples/container-image-must-not-have-latest-tag/example_exempt_image_w_disallowed_tag.yaml @@ -0,0 +1,24 @@ +apiVersion: v1 +kind: Pod +metadata: + name: opa-exempt-allowed +spec: + containers: + - name: opa-exp + image: openpolicyagent/opa-exp:latest + args: + - "run" + - "--server" + - "--addr=localhost:8080" + - name: opa-init + image: openpolicyagent/init:v1 + args: + - "run" + - "--server" + - "--addr=localhost:8080" + - name: opa-exp2 + image: openpolicyagent/opa-exp2:latest + args: + - "run" + - "--server" + - "--addr=localhost:8080" diff --git a/artifacthub/library/general/disallowedtags/1.0.1/samples/container-image-must-not-have-latest-tag/example_no_tag.yaml b/artifacthub/library/general/disallowedtags/1.0.1/samples/container-image-must-not-have-latest-tag/example_no_tag.yaml new file mode 100644 index 000000000..3da276bf8 --- /dev/null +++ b/artifacthub/library/general/disallowedtags/1.0.1/samples/container-image-must-not-have-latest-tag/example_no_tag.yaml @@ -0,0 +1,12 @@ +apiVersion: v1 +kind: Pod +metadata: + name: opa-disallowed +spec: + containers: + - name: opa + image: openpolicyagent/opa + args: + - "run" + - "--server" + - "--addr=localhost:8080" diff --git a/artifacthub/library/general/disallowedtags/1.0.1/samples/container-image-must-not-have-latest-tag/example_some_disallowed_tags.yaml b/artifacthub/library/general/disallowedtags/1.0.1/samples/container-image-must-not-have-latest-tag/example_some_disallowed_tags.yaml new file mode 100644 index 000000000..3596fc0c4 --- /dev/null +++ b/artifacthub/library/general/disallowedtags/1.0.1/samples/container-image-must-not-have-latest-tag/example_some_disallowed_tags.yaml @@ -0,0 +1,30 @@ +apiVersion: v1 +kind: Pod +metadata: + name: opa-disallowed-3 +spec: + containers: + - name: opa + image: openpolicyagent/opa-exp:latest + args: + - "run" + - "--server" + - "--addr=localhost:8080" + - name: opa-init + image: openpolicyagent/init:latest + args: + - "run" + - "--server" + - "--addr=localhost:8080" + - name: opa-exp2 + image: openpolicyagent/opa-exp2:latest + args: + - "run" + - "--server" + - "--addr=localhost:8080" + - name: opa-monitor + image: openpolicyagent/monitor:latest + args: + - "run" + - "--server" + - "--addr=localhost:8080" diff --git a/artifacthub/library/general/disallowedtags/1.0.1/suite.yaml b/artifacthub/library/general/disallowedtags/1.0.1/suite.yaml new file mode 100644 index 000000000..3f67b403c --- /dev/null +++ b/artifacthub/library/general/disallowedtags/1.0.1/suite.yaml @@ -0,0 +1,33 @@ +kind: Suite +apiVersion: test.gatekeeper.sh/v1alpha1 +metadata: + name: disallowedtags +tests: +- name: disallowed-tags + template: template.yaml + constraint: samples/container-image-must-not-have-latest-tag/constraint.yaml + cases: + - name: allowed + object: samples/container-image-must-not-have-latest-tag/example_allowed.yaml + assertions: + - violations: no + - name: exempt-images-with-disallowed-tags + object: samples/container-image-must-not-have-latest-tag/example_exempt_image_w_disallowed_tag.yaml + assertions: + - violations: no + - name: no-tag + object: samples/container-image-must-not-have-latest-tag/example_no_tag.yaml + assertions: + - violations: yes + - name: single-disallowed-tag + object: samples/container-image-must-not-have-latest-tag/example_disallowed_tag.yaml + assertions: + - violations: yes + - name: single-disallowed-tag-ephemeral + object: samples/container-image-must-not-have-latest-tag/disallowed_tag_ephemeral.yaml + assertions: + - violations: yes + - name: some-disallow-tags + object: samples/container-image-must-not-have-latest-tag/example_some_disallowed_tags.yaml + assertions: + - violations: yes diff --git a/artifacthub/library/general/disallowedtags/1.0.1/template.yaml b/artifacthub/library/general/disallowedtags/1.0.1/template.yaml new file mode 100644 index 000000000..43651dd0c --- /dev/null +++ b/artifacthub/library/general/disallowedtags/1.0.1/template.yaml @@ -0,0 +1,89 @@ +apiVersion: templates.gatekeeper.sh/v1 +kind: ConstraintTemplate +metadata: + name: k8sdisallowedtags + annotations: + metadata.gatekeeper.sh/title: "Disallow tags" + metadata.gatekeeper.sh/version: 1.0.1 + description: >- + Requires container images to have an image tag different from the ones in + the specified list. + + https://kubernetes.io/docs/concepts/containers/images/#image-names +spec: + crd: + spec: + names: + kind: K8sDisallowedTags + validation: + # Schema for the `parameters` field + openAPIV3Schema: + type: object + 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 + tags: + type: array + description: Disallowed container image tags. + items: + type: string + targets: + - target: admission.k8s.gatekeeper.sh + rego: | + package k8sdisallowedtags + + import data.lib.exempt_container.is_exempt + + violation[{"msg": msg}] { + container := input_containers[_] + not is_exempt(container) + tags := [tag_with_prefix | tag := input.parameters.tags[_]; tag_with_prefix := concat(":", ["", tag])] + strings.any_suffix_match(container.image, tags) + msg := sprintf("container <%v> uses a disallowed tag <%v>; disallowed tags are %v", [container.name, container.image, input.parameters.tags]) + } + + violation[{"msg": msg}] { + container := input_containers[_] + not is_exempt(container) + not contains(container.image, ":") + msg := sprintf("container <%v> didn't specify an image tag <%v>", [container.name, container.image]) + } + + input_containers[c] { + c := input.review.object.spec.containers[_] + } + input_containers[c] { + c := input.review.object.spec.initContainers[_] + } + input_containers[c] { + c := input.review.object.spec.ephemeralContainers[_] + } + libs: + - | + 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/general/ephemeralstoragelimit/1.0.2/artifacthub-pkg.yml b/artifacthub/library/general/ephemeralstoragelimit/1.0.2/artifacthub-pkg.yml new file mode 100644 index 000000000..53ba3245a --- /dev/null +++ b/artifacthub/library/general/ephemeralstoragelimit/1.0.2/artifacthub-pkg.yml @@ -0,0 +1,25 @@ +version: 1.0.2 +name: k8scontainerephemeralstoragelimit +displayName: Container ephemeral storage limit +createdAt: "2023-10-30T20:59:59Z" +description: |- + Requires containers to have an ephemeral storage limit set and constrains the limit to be within the specified maximum values. + https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/ +digest: d176d78005ddec48c2b46cf33e246eba8089425e95058c29828843983de37f4d +license: Apache-2.0 +homeURL: https://open-policy-agent.github.io/gatekeeper-library/website/ephemeralstoragelimit +keywords: + - gatekeeper + - open-policy-agent + - policies +readme: |- + # Container ephemeral storage limit + Requires containers to have an ephemeral storage limit set and constrains the limit to be within the specified maximum values. + https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/ +install: |- + ### Usage + ```shell + kubectl apply -f https://raw.githubusercontent.com/open-policy-agent/gatekeeper-library/master/artifacthub/library/general/ephemeralstoragelimit/1.0.2/template.yaml + ``` +provider: + name: Gatekeeper Library diff --git a/artifacthub/library/general/ephemeralstoragelimit/1.0.2/kustomization.yaml b/artifacthub/library/general/ephemeralstoragelimit/1.0.2/kustomization.yaml new file mode 100644 index 000000000..7d70d11b7 --- /dev/null +++ b/artifacthub/library/general/ephemeralstoragelimit/1.0.2/kustomization.yaml @@ -0,0 +1,2 @@ +resources: + - template.yaml diff --git a/artifacthub/library/general/ephemeralstoragelimit/1.0.2/samples/container-must-have-ephemeral-storage-limit/constraint.yaml b/artifacthub/library/general/ephemeralstoragelimit/1.0.2/samples/container-must-have-ephemeral-storage-limit/constraint.yaml new file mode 100644 index 000000000..4575bdf60 --- /dev/null +++ b/artifacthub/library/general/ephemeralstoragelimit/1.0.2/samples/container-must-have-ephemeral-storage-limit/constraint.yaml @@ -0,0 +1,11 @@ +apiVersion: constraints.gatekeeper.sh/v1beta1 +kind: K8sContainerEphemeralStorageLimit +metadata: + name: container-ephemeral-storage-limit +spec: + match: + kinds: + - apiGroups: [""] + kinds: ["Pod"] + parameters: + ephemeral-storage: "500Mi" diff --git a/artifacthub/library/general/ephemeralstoragelimit/1.0.2/samples/container-must-have-ephemeral-storage-limit/example_allowed_ephemeral-storage-initContainer.yaml b/artifacthub/library/general/ephemeralstoragelimit/1.0.2/samples/container-must-have-ephemeral-storage-limit/example_allowed_ephemeral-storage-initContainer.yaml new file mode 100644 index 000000000..fe1b7bac0 --- /dev/null +++ b/artifacthub/library/general/ephemeralstoragelimit/1.0.2/samples/container-must-have-ephemeral-storage-limit/example_allowed_ephemeral-storage-initContainer.yaml @@ -0,0 +1,33 @@ +apiVersion: v1 +kind: Pod +metadata: + name: opa-allowed + labels: + owner: me.agilebank.demo +spec: + initContainers: + - name: init-opa + image: openpolicyagent/opa:0.9.2 + args: + - "run" + - "--server" + - "--addr=localhost:8080" + resources: + limits: + cpu: "100m" + memory: "1Gi" + ephemeral-storage: "100Mi" + + + containers: + - name: opa + image: openpolicyagent/opa:0.9.2 + args: + - "run" + - "--server" + - "--addr=localhost:8080" + resources: + limits: + cpu: "100m" + memory: "1Gi" + ephemeral-storage: "100Mi" diff --git a/artifacthub/library/general/ephemeralstoragelimit/1.0.2/samples/container-must-have-ephemeral-storage-limit/example_allowed_ephemeral-storage.yaml b/artifacthub/library/general/ephemeralstoragelimit/1.0.2/samples/container-must-have-ephemeral-storage-limit/example_allowed_ephemeral-storage.yaml new file mode 100644 index 000000000..3c1f5ce9e --- /dev/null +++ b/artifacthub/library/general/ephemeralstoragelimit/1.0.2/samples/container-must-have-ephemeral-storage-limit/example_allowed_ephemeral-storage.yaml @@ -0,0 +1,20 @@ +apiVersion: v1 +kind: Pod +metadata: + name: opa-allowed + labels: + owner: me.agilebank.demo +spec: + containers: + - name: opa + image: openpolicyagent/opa:0.9.2 + args: + - "run" + - "--server" + - "--addr=localhost:8080" + resources: + limits: + cpu: "100m" + memory: "1Gi" + + ephemeral-storage: "100Mi" diff --git a/artifacthub/library/general/ephemeralstoragelimit/1.0.2/samples/container-must-have-ephemeral-storage-limit/example_disallowed_ephemeral_storage_limit_1Pi-initContainer.yaml b/artifacthub/library/general/ephemeralstoragelimit/1.0.2/samples/container-must-have-ephemeral-storage-limit/example_disallowed_ephemeral_storage_limit_1Pi-initContainer.yaml new file mode 100644 index 000000000..05d512d3c --- /dev/null +++ b/artifacthub/library/general/ephemeralstoragelimit/1.0.2/samples/container-must-have-ephemeral-storage-limit/example_disallowed_ephemeral_storage_limit_1Pi-initContainer.yaml @@ -0,0 +1,31 @@ +apiVersion: v1 +kind: Pod +metadata: + name: opa-disallowed + labels: + owner: me.agilebank.demo +spec: + initContainers: + - name: init-opa + image: openpolicyagent/opa:0.9.2 + args: + - "run" + - "--server" + - "--addr=localhost:8080" + resources: + limits: + cpu: "100m" + memory: "1Gi" + ephemeral-storage: "1Pi" + containers: + - name: opa + image: openpolicyagent/opa:0.9.2 + args: + - "run" + - "--server" + - "--addr=localhost:8080" + resources: + limits: + cpu: "100m" + memory: "1Gi" + ephemeral-storage: "100Mi" diff --git a/artifacthub/library/general/ephemeralstoragelimit/1.0.2/samples/container-must-have-ephemeral-storage-limit/example_disallowed_ephemeral_storage_limit_1Pi.yaml b/artifacthub/library/general/ephemeralstoragelimit/1.0.2/samples/container-must-have-ephemeral-storage-limit/example_disallowed_ephemeral_storage_limit_1Pi.yaml new file mode 100644 index 000000000..7dae0395b --- /dev/null +++ b/artifacthub/library/general/ephemeralstoragelimit/1.0.2/samples/container-must-have-ephemeral-storage-limit/example_disallowed_ephemeral_storage_limit_1Pi.yaml @@ -0,0 +1,20 @@ +apiVersion: v1 +kind: Pod +metadata: + name: opa-disallowed + labels: + owner: me.agilebank.demo +spec: + containers: + - name: opa + image: openpolicyagent/opa:0.9.2 + args: + - "run" + - "--server" + - "--addr=localhost:8080" + resources: + limits: + cpu: "100m" + memory: "1Gi" + + ephemeral-storage: "1Pi" diff --git a/artifacthub/library/general/ephemeralstoragelimit/1.0.2/samples/container-must-have-ephemeral-storage-limit/example_disallowed_ephemeral_storage_limit_unspecified.yaml b/artifacthub/library/general/ephemeralstoragelimit/1.0.2/samples/container-must-have-ephemeral-storage-limit/example_disallowed_ephemeral_storage_limit_unspecified.yaml new file mode 100644 index 000000000..6e81b1118 --- /dev/null +++ b/artifacthub/library/general/ephemeralstoragelimit/1.0.2/samples/container-must-have-ephemeral-storage-limit/example_disallowed_ephemeral_storage_limit_unspecified.yaml @@ -0,0 +1,18 @@ +apiVersion: v1 +kind: Pod +metadata: + name: opa-disallowed + labels: + owner: me.agilebank.demo +spec: + containers: + - name: opa + image: openpolicyagent/opa:0.9.2 + args: + - "run" + - "--server" + - "--addr=localhost:8080" + resources: + limits: + cpu: "100m" + memory: "2Gi" diff --git a/artifacthub/library/general/ephemeralstoragelimit/1.0.2/samples/container-must-have-ephemeral-storage-limit/update.yaml b/artifacthub/library/general/ephemeralstoragelimit/1.0.2/samples/container-must-have-ephemeral-storage-limit/update.yaml new file mode 100644 index 000000000..c0ff27893 --- /dev/null +++ b/artifacthub/library/general/ephemeralstoragelimit/1.0.2/samples/container-must-have-ephemeral-storage-limit/update.yaml @@ -0,0 +1,24 @@ +kind: AdmissionReview +apiVersion: admission.k8s.io/v1beta1 +request: + operation: "UPDATE" + object: + apiVersion: v1 + kind: Pod + metadata: + name: opa-allowed + labels: + owner: me.agilebank.demo + spec: + containers: + - name: opa + image: openpolicyagent/opa:0.9.2 + args: + - "run" + - "--server" + - "--addr=localhost:8080" + resources: + limits: + cpu: "100m" + memory: "1Gi" + ephemeral-storage: "1Pi" diff --git a/artifacthub/library/general/ephemeralstoragelimit/1.0.2/suite.yaml b/artifacthub/library/general/ephemeralstoragelimit/1.0.2/suite.yaml new file mode 100644 index 000000000..a6b99410d --- /dev/null +++ b/artifacthub/library/general/ephemeralstoragelimit/1.0.2/suite.yaml @@ -0,0 +1,33 @@ +kind: Suite +apiVersion: test.gatekeeper.sh/v1alpha1 +metadata: + name: ephemeral-storage-limit +tests: +- name: ephemeral-storage-limit + template: template.yaml + constraint: samples/container-must-have-ephemeral-storage-limit/constraint.yaml + cases: + - name: ephemeral-storage-limit-100Mi + object: samples/container-must-have-ephemeral-storage-limit/example_allowed_ephemeral-storage.yaml + assertions: + - violations: no + - name: ephemeral-storage-limit-initContainer-100Mi + object: samples/container-must-have-ephemeral-storage-limit/example_allowed_ephemeral-storage-initContainer.yaml + assertions: + - violations: no + - name: ephemeral-storage-limit-unspecified + object: samples/container-must-have-ephemeral-storage-limit/example_disallowed_ephemeral_storage_limit_unspecified.yaml + assertions: + - violations: yes + - name: ephemeral-storage-limit-1Pi + object: samples/container-must-have-ephemeral-storage-limit/example_disallowed_ephemeral_storage_limit_1Pi.yaml + assertions: + - violations: yes + - name: ephemeral-storage-limit-initContainer-1Pi + object: samples/container-must-have-ephemeral-storage-limit/example_disallowed_ephemeral_storage_limit_1Pi-initContainer.yaml + assertions: + - violations: yes + - name: ephemeral-storage-limit-update + object: samples/container-must-have-ephemeral-storage-limit/update.yaml + assertions: + - violations: no diff --git a/artifacthub/library/general/ephemeralstoragelimit/1.0.2/template.yaml b/artifacthub/library/general/ephemeralstoragelimit/1.0.2/template.yaml new file mode 100644 index 000000000..a9dca71d2 --- /dev/null +++ b/artifacthub/library/general/ephemeralstoragelimit/1.0.2/template.yaml @@ -0,0 +1,232 @@ +apiVersion: templates.gatekeeper.sh/v1 +kind: ConstraintTemplate +metadata: + name: k8scontainerephemeralstoragelimit + annotations: + metadata.gatekeeper.sh/title: "Container ephemeral storage limit" + metadata.gatekeeper.sh/version: 1.0.2 + description: >- + Requires containers to have an ephemeral storage limit set and constrains + the limit to be within the specified maximum values. + + https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/ +spec: + crd: + spec: + names: + kind: K8sContainerEphemeralStorageLimit + validation: + # Schema for the `parameters` field + openAPIV3Schema: + type: object + 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 + ephemeral-storage: + description: "The maximum allowed ephemeral storage limit on a Pod, exclusive." + type: string + targets: + - target: admission.k8s.gatekeeper.sh + rego: | + package k8scontainerephemeralstoragelimit + + import data.lib.exclude_update.is_update + import data.lib.exempt_container.is_exempt + + missing(obj, field) = true { + not obj[field] + } + + missing(obj, field) = true { + obj[field] == "" + } + + has_field(object, field) = true { + object[field] + } + + # 10 ** 21 + storage_multiple("E") = 1000000000000000000000 { true } + + # 10 ** 18 + storage_multiple("P") = 1000000000000000000 { true } + + # 10 ** 15 + storage_multiple("T") = 1000000000000000 { true } + + # 10 ** 12 + storage_multiple("G") = 1000000000000 { true } + + # 10 ** 9 + storage_multiple("M") = 1000000000 { true } + + # 10 ** 6 + storage_multiple("k") = 1000000 { true } + + # 10 ** 3 + storage_multiple("") = 1000 { true } + + # Kubernetes accepts millibyte precision when it probably shouldn't. + # https://github.com/kubernetes/kubernetes/issues/28741 + # 10 ** 0 + storage_multiple("m") = 1 { true } + + # 1000 * 2 ** 10 + storage_multiple("Ki") = 1024000 { true } + + # 1000 * 2 ** 20 + storage_multiple("Mi") = 1048576000 { true } + + # 1000 * 2 ** 30 + storage_multiple("Gi") = 1073741824000 { true } + + # 1000 * 2 ** 40 + storage_multiple("Ti") = 1099511627776000 { true } + + # 1000 * 2 ** 50 + storage_multiple("Pi") = 1125899906842624000 { true } + + # 1000 * 2 ** 60 + storage_multiple("Ei") = 1152921504606846976000 { true } + + get_suffix(storage) = suffix { + not is_string(storage) + suffix := "" + } + + get_suffix(storage) = suffix { + is_string(storage) + count(storage) > 0 + suffix := substring(storage, count(storage) - 1, -1) + storage_multiple(suffix) + } + + get_suffix(storage) = suffix { + is_string(storage) + count(storage) > 1 + suffix := substring(storage, count(storage) - 2, -1) + storage_multiple(suffix) + } + + get_suffix(storage) = suffix { + is_string(storage) + count(storage) > 1 + not storage_multiple(substring(storage, count(storage) - 1, -1)) + not storage_multiple(substring(storage, count(storage) - 2, -1)) + suffix := "" + } + + get_suffix(storage) = suffix { + is_string(storage) + count(storage) == 1 + not storage_multiple(substring(storage, count(storage) - 1, -1)) + suffix := "" + } + + get_suffix(storage) = suffix { + is_string(storage) + count(storage) == 0 + suffix := "" + } + + canonify_storage(orig) = new { + is_number(orig) + new := orig * 1000 + } + + canonify_storage(orig) = new { + not is_number(orig) + suffix := get_suffix(orig) + raw := replace(orig, suffix, "") + regex.match("^[0-9]+(\\.[0-9]+)?$", raw) + new := to_number(raw) * storage_multiple(suffix) + } + + violation[{"msg": msg}] { + # spec.containers.resources.limits["ephemeral-storage"] field is immutable. + not is_update(input.review) + + general_violation[{"msg": msg, "field": "containers"}] + } + + violation[{"msg": msg}] { + not is_update(input.review) + general_violation[{"msg": msg, "field": "initContainers"}] + } + + # Ephemeral containers not checked as it is not possible to set field. + + general_violation[{"msg": msg, "field": field}] { + container := input.review.object.spec[field][_] + not is_exempt(container) + storage_orig := container.resources.limits["ephemeral-storage"] + not canonify_storage(storage_orig) + msg := sprintf("container <%v> ephemeral-storage limit <%v> could not be parsed", [container.name, storage_orig]) + } + + general_violation[{"msg": msg, "field": field}] { + container := input.review.object.spec[field][_] + not is_exempt(container) + not container.resources + msg := sprintf("container <%v> has no resource limits", [container.name]) + } + + general_violation[{"msg": msg, "field": field}] { + container := input.review.object.spec[field][_] + not is_exempt(container) + not container.resources.limits + msg := sprintf("container <%v> has no resource limits", [container.name]) + } + + general_violation[{"msg": msg, "field": field}] { + container := input.review.object.spec[field][_] + not is_exempt(container) + missing(container.resources.limits, "ephemeral-storage") + msg := sprintf("container <%v> has no ephemeral-storage limit", [container.name]) + } + + general_violation[{"msg": msg, "field": field}] { + container := input.review.object.spec[field][_] + not is_exempt(container) + storage_orig := container.resources.limits["ephemeral-storage"] + storage := canonify_storage(storage_orig) + max_storage_orig := input.parameters["ephemeral-storage"] + max_storage := canonify_storage(max_storage_orig) + storage > max_storage + msg := sprintf("container <%v> ephemeral-storage limit <%v> is higher than the maximum allowed of <%v>", [container.name, storage_orig, max_storage_orig]) + } + 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/general/httpsonly/1.0.2/artifacthub-pkg.yml b/artifacthub/library/general/httpsonly/1.0.2/artifacthub-pkg.yml new file mode 100644 index 000000000..7174a9b3c --- /dev/null +++ b/artifacthub/library/general/httpsonly/1.0.2/artifacthub-pkg.yml @@ -0,0 +1,25 @@ +version: 1.0.2 +name: k8shttpsonly +displayName: HTTPS Only +createdAt: "2023-10-30T21:00:00Z" +description: |- + Requires Ingress resources to be HTTPS only. Ingress resources must include the `kubernetes.io/ingress.allow-http` annotation, set to `false`. By default a valid TLS {} configuration is required, this can be made optional by setting the `tlsOptional` parameter to `true`. + https://kubernetes.io/docs/concepts/services-networking/ingress/#tls +digest: 1cacfb5327a12bdd71767fe5e82007e73f233b0edd7f9555722d865c8b9a9c10 +license: Apache-2.0 +homeURL: https://open-policy-agent.github.io/gatekeeper-library/website/httpsonly +keywords: + - gatekeeper + - open-policy-agent + - policies +readme: |- + # HTTPS Only + Requires Ingress resources to be HTTPS only. Ingress resources must include the `kubernetes.io/ingress.allow-http` annotation, set to `false`. By default a valid TLS {} configuration is required, this can be made optional by setting the `tlsOptional` parameter to `true`. + https://kubernetes.io/docs/concepts/services-networking/ingress/#tls +install: |- + ### Usage + ```shell + kubectl apply -f https://raw.githubusercontent.com/open-policy-agent/gatekeeper-library/master/artifacthub/library/general/httpsonly/1.0.2/template.yaml + ``` +provider: + name: Gatekeeper Library diff --git a/artifacthub/library/general/httpsonly/1.0.2/kustomization.yaml b/artifacthub/library/general/httpsonly/1.0.2/kustomization.yaml new file mode 100644 index 000000000..7d70d11b7 --- /dev/null +++ b/artifacthub/library/general/httpsonly/1.0.2/kustomization.yaml @@ -0,0 +1,2 @@ +resources: + - template.yaml diff --git a/artifacthub/library/general/httpsonly/1.0.2/samples/ingress-https-only-tls-optional/constraint.yaml b/artifacthub/library/general/httpsonly/1.0.2/samples/ingress-https-only-tls-optional/constraint.yaml new file mode 100644 index 000000000..a92540d91 --- /dev/null +++ b/artifacthub/library/general/httpsonly/1.0.2/samples/ingress-https-only-tls-optional/constraint.yaml @@ -0,0 +1,11 @@ +apiVersion: constraints.gatekeeper.sh/v1beta1 +kind: K8sHttpsOnly +metadata: + name: ingress-https-only-tls-optional +spec: + match: + kinds: + - apiGroups: ["extensions", "networking.k8s.io"] + kinds: ["Ingress"] + parameters: + tlsOptional: true diff --git a/artifacthub/library/general/httpsonly/1.0.2/samples/ingress-https-only-tls-optional/example_allowed.yaml b/artifacthub/library/general/httpsonly/1.0.2/samples/ingress-https-only-tls-optional/example_allowed.yaml new file mode 100644 index 000000000..27a94ee8b --- /dev/null +++ b/artifacthub/library/general/httpsonly/1.0.2/samples/ingress-https-only-tls-optional/example_allowed.yaml @@ -0,0 +1,18 @@ +apiVersion: networking.k8s.io/v1 +kind: Ingress +metadata: + name: ingress-demo-allowed-tls-optional + annotations: + kubernetes.io/ingress.allow-http: "false" +spec: + rules: + - host: example-host.example.com + http: + paths: + - pathType: Prefix + path: "/" + backend: + service: + name: nginx + port: + number: 80 diff --git a/artifacthub/library/general/httpsonly/1.0.2/samples/ingress-https-only-tls-optional/example_disallowed.yaml b/artifacthub/library/general/httpsonly/1.0.2/samples/ingress-https-only-tls-optional/example_disallowed.yaml new file mode 100644 index 000000000..c6097a9f7 --- /dev/null +++ b/artifacthub/library/general/httpsonly/1.0.2/samples/ingress-https-only-tls-optional/example_disallowed.yaml @@ -0,0 +1,16 @@ +apiVersion: networking.k8s.io/v1 +kind: Ingress +metadata: + name: ingress-demo-disallowed-tls-optional +spec: + rules: + - host: example-host.example.com + http: + paths: + - pathType: Prefix + path: "/" + backend: + service: + name: nginx + port: + number: 80 diff --git a/artifacthub/library/general/httpsonly/1.0.2/samples/ingress-https-only/constraint.yaml b/artifacthub/library/general/httpsonly/1.0.2/samples/ingress-https-only/constraint.yaml new file mode 100644 index 000000000..e3bd9ca97 --- /dev/null +++ b/artifacthub/library/general/httpsonly/1.0.2/samples/ingress-https-only/constraint.yaml @@ -0,0 +1,9 @@ +apiVersion: constraints.gatekeeper.sh/v1beta1 +kind: K8sHttpsOnly +metadata: + name: ingress-https-only +spec: + match: + kinds: + - apiGroups: ["extensions", "networking.k8s.io"] + kinds: ["Ingress"] diff --git a/artifacthub/library/general/httpsonly/1.0.2/samples/ingress-https-only/example_allowed.yaml b/artifacthub/library/general/httpsonly/1.0.2/samples/ingress-https-only/example_allowed.yaml new file mode 100644 index 000000000..4d48fdc3a --- /dev/null +++ b/artifacthub/library/general/httpsonly/1.0.2/samples/ingress-https-only/example_allowed.yaml @@ -0,0 +1,19 @@ +apiVersion: networking.k8s.io/v1 +kind: Ingress +metadata: + name: ingress-demo-allowed + annotations: + kubernetes.io/ingress.allow-http: "false" +spec: + tls: [{}] + rules: + - host: example-host.example.com + http: + paths: + - pathType: Prefix + path: "/" + backend: + service: + name: nginx + port: + number: 80 diff --git a/artifacthub/library/general/httpsonly/1.0.2/samples/ingress-https-only/example_disallowed.yaml b/artifacthub/library/general/httpsonly/1.0.2/samples/ingress-https-only/example_disallowed.yaml new file mode 100644 index 000000000..730ec1dc4 --- /dev/null +++ b/artifacthub/library/general/httpsonly/1.0.2/samples/ingress-https-only/example_disallowed.yaml @@ -0,0 +1,16 @@ +apiVersion: networking.k8s.io/v1 +kind: Ingress +metadata: + name: ingress-demo-disallowed +spec: + rules: + - host: example-host.example.com + http: + paths: + - pathType: Prefix + path: "/" + backend: + service: + name: nginx + port: + number: 80 diff --git a/artifacthub/library/general/httpsonly/1.0.2/suite.yaml b/artifacthub/library/general/httpsonly/1.0.2/suite.yaml new file mode 100644 index 000000000..a40395524 --- /dev/null +++ b/artifacthub/library/general/httpsonly/1.0.2/suite.yaml @@ -0,0 +1,29 @@ +kind: Suite +apiVersion: test.gatekeeper.sh/v1alpha1 +metadata: + name: httpsonly +tests: +- name: tls-required + template: template.yaml + constraint: samples/ingress-https-only/constraint.yaml + cases: + - name: example-allowed + object: samples/ingress-https-only/example_allowed.yaml + assertions: + - violations: no + - name: example-disallowed + object: samples/ingress-https-only/example_disallowed.yaml + assertions: + - violations: yes +- name: tls-optional + template: template.yaml + constraint: samples/ingress-https-only-tls-optional/constraint.yaml + cases: + - name: example-allowed-tls-optional + object: samples/ingress-https-only-tls-optional/example_allowed.yaml + assertions: + - violations: no + - name: example-disallowed-tls-optional + object: samples/ingress-https-only-tls-optional/example_disallowed.yaml + assertions: + - violations: yes diff --git a/artifacthub/library/general/httpsonly/1.0.2/sync.yaml b/artifacthub/library/general/httpsonly/1.0.2/sync.yaml new file mode 100644 index 000000000..b5f00c4dd --- /dev/null +++ b/artifacthub/library/general/httpsonly/1.0.2/sync.yaml @@ -0,0 +1,14 @@ +apiVersion: config.gatekeeper.sh/v1alpha1 +kind: Config +metadata: + name: config + namespace: "gatekeeper-system" +spec: + sync: + syncOnly: + - group: "extensions" + version: "v1beta1" + kind: "Ingress" + - group: "networking.k8s.io" + version: "v1beta1" + kind: "Ingress" diff --git a/artifacthub/library/general/httpsonly/1.0.2/template.yaml b/artifacthub/library/general/httpsonly/1.0.2/template.yaml new file mode 100644 index 000000000..5293fe72c --- /dev/null +++ b/artifacthub/library/general/httpsonly/1.0.2/template.yaml @@ -0,0 +1,71 @@ +apiVersion: templates.gatekeeper.sh/v1 +kind: ConstraintTemplate +metadata: + name: k8shttpsonly + annotations: + metadata.gatekeeper.sh/title: "HTTPS Only" + metadata.gatekeeper.sh/version: 1.0.2 + description: >- + Requires Ingress resources to be HTTPS only. Ingress resources must + include the `kubernetes.io/ingress.allow-http` annotation, set to `false`. + By default a valid TLS {} configuration is required, this can be made + optional by setting the `tlsOptional` parameter to `true`. + + https://kubernetes.io/docs/concepts/services-networking/ingress/#tls +spec: + crd: + spec: + names: + kind: K8sHttpsOnly + validation: + # Schema for the `parameters` field + openAPIV3Schema: + type: object + description: >- + Requires Ingress resources to be HTTPS only. Ingress resources must + include the `kubernetes.io/ingress.allow-http` annotation, set to + `false`. By default a valid TLS {} configuration is required, this + can be made optional by setting the `tlsOptional` parameter to + `true`. + properties: + tlsOptional: + type: boolean + description: "When set to `true` the TLS {} is optional, defaults + to false." + targets: + - target: admission.k8s.gatekeeper.sh + rego: | + package k8shttpsonly + + violation[{"msg": msg}] { + input.review.object.kind == "Ingress" + regex.match("^(extensions|networking.k8s.io)/", input.review.object.apiVersion) + ingress := input.review.object + not https_complete(ingress) + not tls_is_optional + msg := sprintf("Ingress should be https. tls configuration and allow-http=false annotation are required for %v", [ingress.metadata.name]) + } + + violation[{"msg": msg}] { + input.review.object.kind == "Ingress" + regex.match("^(extensions|networking.k8s.io)/", input.review.object.apiVersion) + ingress := input.review.object + not annotation_complete(ingress) + tls_is_optional + msg := sprintf("Ingress should be https. The allow-http=false annotation is required for %v", [ingress.metadata.name]) + } + + https_complete(ingress) = true { + ingress.spec["tls"] + count(ingress.spec.tls) > 0 + ingress.metadata.annotations["kubernetes.io/ingress.allow-http"] == "false" + } + + annotation_complete(ingress) = true { + ingress.metadata.annotations["kubernetes.io/ingress.allow-http"] == "false" + } + + tls_is_optional { + parameters := object.get(input, "parameters", {}) + object.get(parameters, "tlsOptional", false) == true + } diff --git a/artifacthub/library/general/imagedigests/1.0.1/artifacthub-pkg.yml b/artifacthub/library/general/imagedigests/1.0.1/artifacthub-pkg.yml new file mode 100644 index 000000000..b7d77075b --- /dev/null +++ b/artifacthub/library/general/imagedigests/1.0.1/artifacthub-pkg.yml @@ -0,0 +1,25 @@ +version: 1.0.1 +name: k8simagedigests +displayName: Image Digests +createdAt: "2023-10-30T21:00:00Z" +description: |- + Requires container images to contain a digest. + https://kubernetes.io/docs/concepts/containers/images/ +digest: ef359e8377bf69afbe0e7e7cbc48549baa6974f22aa98d88de4417c5b455ef18 +license: Apache-2.0 +homeURL: https://open-policy-agent.github.io/gatekeeper-library/website/imagedigests +keywords: + - gatekeeper + - open-policy-agent + - policies +readme: |- + # Image Digests + Requires container images to contain a digest. + https://kubernetes.io/docs/concepts/containers/images/ +install: |- + ### Usage + ```shell + kubectl apply -f https://raw.githubusercontent.com/open-policy-agent/gatekeeper-library/master/artifacthub/library/general/imagedigests/1.0.1/template.yaml + ``` +provider: + name: Gatekeeper Library diff --git a/artifacthub/library/general/imagedigests/1.0.1/kustomization.yaml b/artifacthub/library/general/imagedigests/1.0.1/kustomization.yaml new file mode 100644 index 000000000..7d70d11b7 --- /dev/null +++ b/artifacthub/library/general/imagedigests/1.0.1/kustomization.yaml @@ -0,0 +1,2 @@ +resources: + - template.yaml diff --git a/artifacthub/library/general/imagedigests/1.0.1/samples/container-image-must-have-digest/constraint.yaml b/artifacthub/library/general/imagedigests/1.0.1/samples/container-image-must-have-digest/constraint.yaml new file mode 100644 index 000000000..e1cae7cdf --- /dev/null +++ b/artifacthub/library/general/imagedigests/1.0.1/samples/container-image-must-have-digest/constraint.yaml @@ -0,0 +1,11 @@ +apiVersion: constraints.gatekeeper.sh/v1beta1 +kind: K8sImageDigests +metadata: + name: container-image-must-have-digest +spec: + match: + kinds: + - apiGroups: [""] + kinds: ["Pod"] + namespaces: + - "default" diff --git a/artifacthub/library/general/imagedigests/1.0.1/samples/container-image-must-have-digest/disallowed_all.yaml b/artifacthub/library/general/imagedigests/1.0.1/samples/container-image-must-have-digest/disallowed_all.yaml new file mode 100644 index 000000000..b576d4301 --- /dev/null +++ b/artifacthub/library/general/imagedigests/1.0.1/samples/container-image-must-have-digest/disallowed_all.yaml @@ -0,0 +1,26 @@ +apiVersion: v1 +kind: Pod +metadata: + name: opa-disallowed +spec: + initContainers: + - name: opainit + image: openpolicyagent/opa:0.9.2 + args: + - "run" + - "--server" + - "--addr=localhost:8080" + containers: + - name: opa + image: openpolicyagent/opa:0.9.2 + args: + - "run" + - "--server" + - "--addr=localhost:8080" + ephemeralContainers: + - name: opa + image: openpolicyagent/opa:0.9.2 + args: + - "run" + - "--server" + - "--addr=localhost:8080" diff --git a/artifacthub/library/general/imagedigests/1.0.1/samples/container-image-must-have-digest/example_allowed.yaml b/artifacthub/library/general/imagedigests/1.0.1/samples/container-image-must-have-digest/example_allowed.yaml new file mode 100644 index 000000000..81b3fea48 --- /dev/null +++ b/artifacthub/library/general/imagedigests/1.0.1/samples/container-image-must-have-digest/example_allowed.yaml @@ -0,0 +1,12 @@ +apiVersion: v1 +kind: Pod +metadata: + name: opa-allowed +spec: + containers: + - name: opa + image: openpolicyagent/opa:0.9.2@sha256:04ff8fce2afd1a3bc26260348e5b290e8d945b1fad4b4c16d22834c2f3a1814a + args: + - "run" + - "--server" + - "--addr=localhost:8080" diff --git a/artifacthub/library/general/imagedigests/1.0.1/samples/container-image-must-have-digest/example_disallowed.yaml b/artifacthub/library/general/imagedigests/1.0.1/samples/container-image-must-have-digest/example_disallowed.yaml new file mode 100644 index 000000000..a19eef5c6 --- /dev/null +++ b/artifacthub/library/general/imagedigests/1.0.1/samples/container-image-must-have-digest/example_disallowed.yaml @@ -0,0 +1,19 @@ +apiVersion: v1 +kind: Pod +metadata: + name: opa-disallowed +spec: + initContainers: + - name: opainit + image: openpolicyagent/opa:0.9.2 + args: + - "run" + - "--server" + - "--addr=localhost:8080" + containers: + - name: opa + image: openpolicyagent/opa:0.9.2 + args: + - "run" + - "--server" + - "--addr=localhost:8080" diff --git a/artifacthub/library/general/imagedigests/1.0.1/suite.yaml b/artifacthub/library/general/imagedigests/1.0.1/suite.yaml new file mode 100644 index 000000000..3e853c8f6 --- /dev/null +++ b/artifacthub/library/general/imagedigests/1.0.1/suite.yaml @@ -0,0 +1,31 @@ +kind: Suite +apiVersion: test.gatekeeper.sh/v1alpha1 +metadata: + name: imagedigests +tests: +- name: container-image-must-have-digest + template: template.yaml + constraint: samples/container-image-must-have-digest/constraint.yaml + cases: + - name: example-allowed + object: samples/container-image-must-have-digest/example_allowed.yaml + assertions: + - violations: no + - name: example-disallowed + object: samples/container-image-must-have-digest/example_disallowed.yaml + assertions: + - violations: 2 + - message: initContainer + violations: 1 + - message: container + violations: 1 + - name: disallowed-all + object: samples/container-image-must-have-digest/disallowed_all.yaml + assertions: + - violations: 3 + - message: initContainer + violations: 1 + - message: container + violations: 1 + - message: ephemeralContainer + violations: 1 diff --git a/artifacthub/library/general/imagedigests/1.0.1/template.yaml b/artifacthub/library/general/imagedigests/1.0.1/template.yaml new file mode 100644 index 000000000..e00a4b608 --- /dev/null +++ b/artifacthub/library/general/imagedigests/1.0.1/template.yaml @@ -0,0 +1,82 @@ +apiVersion: templates.gatekeeper.sh/v1 +kind: ConstraintTemplate +metadata: + name: k8simagedigests + annotations: + metadata.gatekeeper.sh/title: "Image Digests" + metadata.gatekeeper.sh/version: 1.0.1 + description: >- + Requires container images to contain a digest. + + https://kubernetes.io/docs/concepts/containers/images/ +spec: + crd: + spec: + names: + kind: K8sImageDigests + validation: + openAPIV3Schema: + type: object + description: >- + Requires container images to contain a digest. + + https://kubernetes.io/docs/concepts/containers/images/ + 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 + targets: + - target: admission.k8s.gatekeeper.sh + rego: | + package k8simagedigests + + import data.lib.exempt_container.is_exempt + + violation[{"msg": msg}] { + container := input.review.object.spec.containers[_] + not is_exempt(container) + not regex.match("@[a-z0-9]+([+._-][a-z0-9]+)*:[a-zA-Z0-9=_-]+", container.image) + msg := sprintf("container <%v> uses an image without a digest <%v>", [container.name, container.image]) + } + + violation[{"msg": msg}] { + container := input.review.object.spec.initContainers[_] + not is_exempt(container) + not regex.match("@[a-z0-9]+([+._-][a-z0-9]+)*:[a-zA-Z0-9=_-]+", container.image) + msg := sprintf("initContainer <%v> uses an image without a digest <%v>", [container.name, container.image]) + } + + violation[{"msg": msg}] { + container := input.review.object.spec.ephemeralContainers[_] + not is_exempt(container) + not regex.match("@[a-z0-9]+([+._-][a-z0-9]+)*:[a-zA-Z0-9=_-]+", container.image) + msg := sprintf("ephemeralContainer <%v> uses an image without a digest <%v>", [container.name, container.image]) + } + libs: + - | + 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/general/noupdateserviceaccount/1.0.1/README.md b/artifacthub/library/general/noupdateserviceaccount/1.0.1/README.md new file mode 100644 index 000000000..4843dc5dc --- /dev/null +++ b/artifacthub/library/general/noupdateserviceaccount/1.0.1/README.md @@ -0,0 +1,13 @@ +# NoUpdateServiceAccount + +**NOTE:** This policy is ignored in `audit` mode, because it only blocks +updates to existing resources, not specific configurations. + +The `NoUpdateServiceAccount` constraint blocks updating the service account on +resources that abstract over Pods. + +This policy helps prevent workloads with "update-self" permissions from +escalating further in the cluster by selecting a new service account to +run as. It is especially useful for workloads running in sensitive +namespaces like `kube-system`, where nearby service accounts are likely to +have cluster admin rights. diff --git a/artifacthub/library/general/noupdateserviceaccount/1.0.1/artifacthub-pkg.yml b/artifacthub/library/general/noupdateserviceaccount/1.0.1/artifacthub-pkg.yml new file mode 100644 index 000000000..25f517ecc --- /dev/null +++ b/artifacthub/library/general/noupdateserviceaccount/1.0.1/artifacthub-pkg.yml @@ -0,0 +1,22 @@ +version: 1.0.1 +name: noupdateserviceaccount +displayName: Block updating Service Account +createdAt: "2023-10-30T21:00:00Z" +description: Blocks updating the service account on resources that abstract over Pods. This policy is ignored in audit mode. +digest: ebe8c51d51643cc8d55a2f315f19326db6c81c1fba9c0e0bfb9914b657a67203 +license: Apache-2.0 +homeURL: https://open-policy-agent.github.io/gatekeeper-library/website/noupdateserviceaccount +keywords: + - gatekeeper + - open-policy-agent + - policies +readme: |- + # Block updating Service Account + Blocks updating the service account on resources that abstract over Pods. This policy is ignored in audit mode. +install: |- + ### Usage + ```shell + kubectl apply -f https://raw.githubusercontent.com/open-policy-agent/gatekeeper-library/master/artifacthub/library/general/noupdateserviceaccount/1.0.1/template.yaml + ``` +provider: + name: Gatekeeper Library diff --git a/artifacthub/library/general/noupdateserviceaccount/1.0.1/kustomization.yaml b/artifacthub/library/general/noupdateserviceaccount/1.0.1/kustomization.yaml new file mode 100644 index 000000000..7d70d11b7 --- /dev/null +++ b/artifacthub/library/general/noupdateserviceaccount/1.0.1/kustomization.yaml @@ -0,0 +1,2 @@ +resources: + - template.yaml diff --git a/artifacthub/library/general/noupdateserviceaccount/1.0.1/samples/noupdateserviceaccount/constraint.yaml b/artifacthub/library/general/noupdateserviceaccount/1.0.1/samples/noupdateserviceaccount/constraint.yaml new file mode 100644 index 000000000..d8920759e --- /dev/null +++ b/artifacthub/library/general/noupdateserviceaccount/1.0.1/samples/noupdateserviceaccount/constraint.yaml @@ -0,0 +1,33 @@ +# IMPORTANT: Before deploying this policy, make sure you allow-list any groups +# or users that need to deploy workloads to kube-system, such as cluster- +# lifecycle controllers, addon managers, etc. Such controllers may need to +# update service account names during automated rollouts (e.g. of refactored +# configurations). You can allow-list them with the allowedGroups and +# allowedUsers properties of the NoUpdateServiceAccount Constraint. +apiVersion: constraints.gatekeeper.sh/v1beta1 +kind: NoUpdateServiceAccount +metadata: + name: no-update-kube-system-service-account +spec: + match: + namespaces: ["kube-system"] + kinds: + - apiGroups: [""] + kinds: + # You can optionally add "Pod" here, but it is unnecessary because + # Pod service account immutability is enforced by the Kubernetes API. + - "ReplicationController" + - apiGroups: ["apps"] + kinds: + - "ReplicaSet" + - "Deployment" + - "StatefulSet" + - "DaemonSet" + - apiGroups: ["batch"] + kinds: + # You can optionally add "Job" here, but it is unnecessary because + # Job service account immutability is enforced by the Kubernetes API. + - "CronJob" + parameters: + allowedGroups: [] + allowedUsers: [] diff --git a/artifacthub/library/general/noupdateserviceaccount/1.0.1/samples/noupdateserviceaccount/example_allowed.yaml b/artifacthub/library/general/noupdateserviceaccount/1.0.1/samples/noupdateserviceaccount/example_allowed.yaml new file mode 100644 index 000000000..c6bbde27b --- /dev/null +++ b/artifacthub/library/general/noupdateserviceaccount/1.0.1/samples/noupdateserviceaccount/example_allowed.yaml @@ -0,0 +1,31 @@ +# Note: The gator tests currently require exactly one object per example file. +# Since this is an update-triggered policy, at least two objects are technically +# required to demonstrate it. Due to the gator requirement, we only have one +# object below. The policy should allow changing everything but the +# serviceAccountName field. +kind: Deployment +apiVersion: apps/v1 +metadata: + name: policy-test + namespace: kube-system + labels: + app: policy-test +spec: + replicas: 1 + selector: + matchLabels: + app: policy-test-deploy + template: + metadata: + labels: + app: policy-test-deploy + spec: + # Changing anything except this field should be allowed by the policy. + serviceAccountName: policy-test-sa-1 + containers: + - name: policy-test + image: ubuntu + command: + - /bin/bash + - -c + - sleep 99999 diff --git a/artifacthub/library/general/noupdateserviceaccount/1.0.1/suite.yaml b/artifacthub/library/general/noupdateserviceaccount/1.0.1/suite.yaml new file mode 100644 index 000000000..8d4a0ec03 --- /dev/null +++ b/artifacthub/library/general/noupdateserviceaccount/1.0.1/suite.yaml @@ -0,0 +1,20 @@ +kind: Suite +apiVersion: test.gatekeeper.sh/v1alpha1 +metadata: + name: noupdateserviceaccount +tests: + - name: noupdateserviceaccount + template: template.yaml + constraint: samples/noupdateserviceaccount/constraint.yaml + cases: + - name: example-allowed + object: samples/noupdateserviceaccount/example_allowed.yaml + assertions: + - violations: no + # Since the tests are currently stateless, they can't exercise level-triggered + # events like changing a field. For now, manually test example_disallowed.yaml + # instead. + # - name: example-disallowed + # object: samples/noupdateserviceaccount/example_disallowed.yaml + # assertions: + # - violations: yes diff --git a/artifacthub/library/general/noupdateserviceaccount/1.0.1/template.yaml b/artifacthub/library/general/noupdateserviceaccount/1.0.1/template.yaml new file mode 100644 index 000000000..782a0d313 --- /dev/null +++ b/artifacthub/library/general/noupdateserviceaccount/1.0.1/template.yaml @@ -0,0 +1,106 @@ +apiVersion: templates.gatekeeper.sh/v1 +kind: ConstraintTemplate +metadata: + name: noupdateserviceaccount + annotations: + metadata.gatekeeper.sh/title: "Block updating Service Account" + metadata.gatekeeper.sh/version: 1.0.1 + description: "Blocks updating the service account on resources that abstract over Pods. This policy is ignored in audit mode." +spec: + crd: + spec: + names: + kind: NoUpdateServiceAccount + validation: + openAPIV3Schema: + type: object + properties: + allowedGroups: + description: Groups that should be allowed to bypass the policy. + type: array + items: + type: string + allowedUsers: + description: Users that should be allowed to bypass the policy. + type: array + items: + type: string + targets: + - target: admission.k8s.gatekeeper.sh + rego: | + package noupdateserviceaccount + + privileged(userInfo, allowedUsers, _) { + # Allow if the user is in allowedUsers. + # Use object.get so omitted parameters can't cause policy bypass by + # evaluating to undefined. + username := object.get(userInfo, "username", "") + allowedUsers[_] == username + } + + privileged(userInfo, _, allowedGroups) { + # Allow if the user's groups intersect allowedGroups. + # Use object.get so omitted parameters can't cause policy bypass by + # evaluating to undefined. + userGroups := object.get(userInfo, "groups", []) + groups := {g | g := userGroups[_]} + allowed := {g | g := allowedGroups[_]} + intersection := groups & allowed + count(intersection) > 0 + } + + get_service_account(obj) = spec { + obj.kind == "Pod" + spec := obj.spec.serviceAccountName + } { + obj.kind == "ReplicationController" + spec := obj.spec.template.spec.serviceAccountName + } { + obj.kind == "ReplicaSet" + spec := obj.spec.template.spec.serviceAccountName + } { + obj.kind == "Deployment" + spec := obj.spec.template.spec.serviceAccountName + } { + obj.kind == "StatefulSet" + spec := obj.spec.template.spec.serviceAccountName + } { + obj.kind == "DaemonSet" + spec := obj.spec.template.spec.serviceAccountName + } { + obj.kind == "Job" + spec := obj.spec.template.spec.serviceAccountName + } { + obj.kind == "CronJob" + spec := obj.spec.jobTemplate.spec.template.spec.serviceAccountName + } + + violation[{"msg": msg}] { + # This policy only applies to updates of existing resources. + input.review.operation == "UPDATE" + + # Use object.get so omitted parameters can't cause policy bypass by + # evaluating to undefined. + params := object.get(input, "parameters", {}) + allowedUsers := object.get(params, "allowedUsers", []) + allowedGroups := object.get(params, "allowedGroups", []) + + # Extract the service account. + oldKSA := get_service_account(input.review.oldObject) + newKSA := get_service_account(input.review.object) + + # Deny unprivileged users and groups from changing serviceAccountName. + not privileged(input.review.userInfo, allowedUsers, allowedGroups) + oldKSA != newKSA + msg := "user does not have permission to modify serviceAccountName" + } { + # Defensively require object to have a serviceAccountName. + input.review.operation == "UPDATE" + not get_service_account(input.review.object) + msg := "missing serviceAccountName field in object under review" + } { + # Defensively require oldObject to have a serviceAccountName. + input.review.operation == "UPDATE" + not get_service_account(input.review.oldObject) + msg := "missing serviceAccountName field in oldObject under review" + } diff --git a/artifacthub/library/general/replicalimits/1.0.2/artifacthub-pkg.yml b/artifacthub/library/general/replicalimits/1.0.2/artifacthub-pkg.yml new file mode 100644 index 000000000..3b46cf798 --- /dev/null +++ b/artifacthub/library/general/replicalimits/1.0.2/artifacthub-pkg.yml @@ -0,0 +1,22 @@ +version: 1.0.2 +name: k8sreplicalimits +displayName: Replica Limits +createdAt: "2023-10-30T21:00:00Z" +description: Requires that objects with the field `spec.replicas` (Deployments, ReplicaSets, etc.) specify a number of replicas within defined ranges. +digest: 858bf59f6c7408f2fb390a181b2f6db5e4d8fbe5eb580aa45b5601d6ae2d4064 +license: Apache-2.0 +homeURL: https://open-policy-agent.github.io/gatekeeper-library/website/replicalimits +keywords: + - gatekeeper + - open-policy-agent + - policies +readme: |- + # Replica Limits + Requires that objects with the field `spec.replicas` (Deployments, ReplicaSets, etc.) specify a number of replicas within defined ranges. +install: |- + ### Usage + ```shell + kubectl apply -f https://raw.githubusercontent.com/open-policy-agent/gatekeeper-library/master/artifacthub/library/general/replicalimits/1.0.2/template.yaml + ``` +provider: + name: Gatekeeper Library diff --git a/artifacthub/library/general/replicalimits/1.0.2/kustomization.yaml b/artifacthub/library/general/replicalimits/1.0.2/kustomization.yaml new file mode 100644 index 000000000..7d70d11b7 --- /dev/null +++ b/artifacthub/library/general/replicalimits/1.0.2/kustomization.yaml @@ -0,0 +1,2 @@ +resources: + - template.yaml diff --git a/artifacthub/library/general/replicalimits/1.0.2/samples/replicalimits/constraint.yaml b/artifacthub/library/general/replicalimits/1.0.2/samples/replicalimits/constraint.yaml new file mode 100644 index 000000000..b496235f3 --- /dev/null +++ b/artifacthub/library/general/replicalimits/1.0.2/samples/replicalimits/constraint.yaml @@ -0,0 +1,13 @@ +apiVersion: constraints.gatekeeper.sh/v1beta1 +kind: K8sReplicaLimits +metadata: + name: replica-limits +spec: + match: + kinds: + - apiGroups: ["apps"] + kinds: ["Deployment"] + parameters: + ranges: + - min_replicas: 3 + max_replicas: 50 diff --git a/artifacthub/library/general/replicalimits/1.0.2/samples/replicalimits/example_allowed.yaml b/artifacthub/library/general/replicalimits/1.0.2/samples/replicalimits/example_allowed.yaml new file mode 100644 index 000000000..f5a2b1d8c --- /dev/null +++ b/artifacthub/library/general/replicalimits/1.0.2/samples/replicalimits/example_allowed.yaml @@ -0,0 +1,19 @@ +apiVersion: apps/v1 +kind: Deployment +metadata: + name: allowed-deployment +spec: + selector: + matchLabels: + app: nginx + replicas: 3 + template: + metadata: + labels: + app: nginx + spec: + containers: + - name: nginx + image: nginx:1.14.2 + ports: + - containerPort: 80 diff --git a/artifacthub/library/general/replicalimits/1.0.2/samples/replicalimits/example_disallowed.yaml b/artifacthub/library/general/replicalimits/1.0.2/samples/replicalimits/example_disallowed.yaml new file mode 100644 index 000000000..1c4899d20 --- /dev/null +++ b/artifacthub/library/general/replicalimits/1.0.2/samples/replicalimits/example_disallowed.yaml @@ -0,0 +1,19 @@ +apiVersion: apps/v1 +kind: Deployment +metadata: + name: disallowed-deployment +spec: + selector: + matchLabels: + app: nginx + replicas: 100 + template: + metadata: + labels: + app: nginx + spec: + containers: + - name: nginx + image: nginx:1.14.2 + ports: + - containerPort: 80 diff --git a/artifacthub/library/general/replicalimits/1.0.2/suite.yaml b/artifacthub/library/general/replicalimits/1.0.2/suite.yaml new file mode 100644 index 000000000..598efb814 --- /dev/null +++ b/artifacthub/library/general/replicalimits/1.0.2/suite.yaml @@ -0,0 +1,17 @@ +kind: Suite +apiVersion: test.gatekeeper.sh/v1alpha1 +metadata: + name: replicalimits +tests: +- name: replica-limit + template: template.yaml + constraint: samples/replicalimits/constraint.yaml + cases: + - name: example-allowed + object: samples/replicalimits/example_allowed.yaml + assertions: + - violations: no + - name: example-disallowed + object: samples/replicalimits/example_disallowed.yaml + assertions: + - violations: yes diff --git a/artifacthub/library/general/replicalimits/1.0.2/template.yaml b/artifacthub/library/general/replicalimits/1.0.2/template.yaml new file mode 100644 index 000000000..2e44fb2c1 --- /dev/null +++ b/artifacthub/library/general/replicalimits/1.0.2/template.yaml @@ -0,0 +1,58 @@ +apiVersion: templates.gatekeeper.sh/v1 +kind: ConstraintTemplate +metadata: + name: k8sreplicalimits + annotations: + metadata.gatekeeper.sh/title: "Replica Limits" + metadata.gatekeeper.sh/version: 1.0.2 + description: >- + Requires that objects with the field `spec.replicas` (Deployments, + ReplicaSets, etc.) specify a number of replicas within defined ranges. +spec: + crd: + spec: + names: + kind: K8sReplicaLimits + validation: + # Schema for the `parameters` field + openAPIV3Schema: + type: object + properties: + ranges: + type: array + description: Allowed ranges for numbers of replicas. Values are inclusive. + items: + type: object + description: A range of allowed replicas. Values are inclusive. + properties: + min_replicas: + description: The minimum number of replicas allowed, inclusive. + type: integer + max_replicas: + description: The maximum number of replicas allowed, inclusive. + type: integer + targets: + - target: admission.k8s.gatekeeper.sh + rego: | + package k8sreplicalimits + + object_name = input.review.object.metadata.name + object_kind = input.review.kind.kind + + violation[{"msg": msg}] { + spec := input.review.object.spec + not input_replica_limit(spec) + msg := sprintf("The provided number of replicas is not allowed for %v: %v. Allowed ranges: %v", [object_kind, object_name, input.parameters]) + } + + input_replica_limit(spec) { + provided := spec.replicas + count(input.parameters.ranges) > 0 + range := input.parameters.ranges[_] + value_within_range(range, provided) + } + + value_within_range(range, value) { + range.min_replicas <= value + range.max_replicas >= value + } diff --git a/artifacthub/library/general/requiredannotations/1.0.1/artifacthub-pkg.yml b/artifacthub/library/general/requiredannotations/1.0.1/artifacthub-pkg.yml new file mode 100644 index 000000000..424fe5cc1 --- /dev/null +++ b/artifacthub/library/general/requiredannotations/1.0.1/artifacthub-pkg.yml @@ -0,0 +1,22 @@ +version: 1.0.1 +name: k8srequiredannotations +displayName: Required Annotations +createdAt: "2023-10-30T21:00:00Z" +description: Requires resources to contain specified annotations, with values matching provided regular expressions. +digest: 332839ec5e037ea20aa5b9a204ad2490ad76d05f5d2b961ace5e90c7b8c864be +license: Apache-2.0 +homeURL: https://open-policy-agent.github.io/gatekeeper-library/website/requiredannotations +keywords: + - gatekeeper + - open-policy-agent + - policies +readme: |- + # Required Annotations + Requires resources to contain specified annotations, with values matching provided regular expressions. +install: |- + ### Usage + ```shell + kubectl apply -f https://raw.githubusercontent.com/open-policy-agent/gatekeeper-library/master/artifacthub/library/general/requiredannotations/1.0.1/template.yaml + ``` +provider: + name: Gatekeeper Library diff --git a/artifacthub/library/general/requiredannotations/1.0.1/kustomization.yaml b/artifacthub/library/general/requiredannotations/1.0.1/kustomization.yaml new file mode 100644 index 000000000..7d70d11b7 --- /dev/null +++ b/artifacthub/library/general/requiredannotations/1.0.1/kustomization.yaml @@ -0,0 +1,2 @@ +resources: + - template.yaml diff --git a/artifacthub/library/general/requiredannotations/1.0.1/samples/all-must-have-certain-set-of-annotations/constraint.yaml b/artifacthub/library/general/requiredannotations/1.0.1/samples/all-must-have-certain-set-of-annotations/constraint.yaml new file mode 100644 index 000000000..033700136 --- /dev/null +++ b/artifacthub/library/general/requiredannotations/1.0.1/samples/all-must-have-certain-set-of-annotations/constraint.yaml @@ -0,0 +1,18 @@ +apiVersion: constraints.gatekeeper.sh/v1beta1 +kind: K8sRequiredAnnotations +metadata: + name: all-must-have-certain-set-of-annotations +spec: + match: + kinds: + - apiGroups: [""] + kinds: ["Service"] + parameters: + message: "All services must have a `a8r.io/owner` and `a8r.io/runbook` annotations." + annotations: + - key: a8r.io/owner + # Matches email address or github user + allowedRegex: ^([A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\.[A-Za-z]{2,6}|[a-z]{1,39})$ + - key: a8r.io/runbook + # Matches urls including or not http/https + allowedRegex: ^(http:\/\/www\.|https:\/\/www\.|http:\/\/|https:\/\/)?[a-z0-9]+([\-\.]{1}[a-z0-9]+)*\.[a-z]{2,5}(:[0-9]{1,5})?(\/.*)?$ diff --git a/artifacthub/library/general/requiredannotations/1.0.1/samples/all-must-have-certain-set-of-annotations/example_allowed.yaml b/artifacthub/library/general/requiredannotations/1.0.1/samples/all-must-have-certain-set-of-annotations/example_allowed.yaml new file mode 100644 index 000000000..b3b9f95ad --- /dev/null +++ b/artifacthub/library/general/requiredannotations/1.0.1/samples/all-must-have-certain-set-of-annotations/example_allowed.yaml @@ -0,0 +1,14 @@ +apiVersion: v1 +kind: Service +metadata: + name: allowed-service + annotations: + a8r.io/owner: "dev-team-alfa@contoso.com" + a8r.io/runbook: "https://confluence.contoso.com/dev-team-alfa/runbooks" +spec: + ports: + - name: http + port: 80 + targetPort: 8080 + selector: + app: foo diff --git a/artifacthub/library/general/requiredannotations/1.0.1/samples/all-must-have-certain-set-of-annotations/example_disallowed.yaml b/artifacthub/library/general/requiredannotations/1.0.1/samples/all-must-have-certain-set-of-annotations/example_disallowed.yaml new file mode 100644 index 000000000..62c01b877 --- /dev/null +++ b/artifacthub/library/general/requiredannotations/1.0.1/samples/all-must-have-certain-set-of-annotations/example_disallowed.yaml @@ -0,0 +1,11 @@ +apiVersion: v1 +kind: Service +metadata: + name: disallowed-service +spec: + ports: + - name: http + port: 80 + targetPort: 8080 + selector: + app: foo diff --git a/artifacthub/library/general/requiredannotations/1.0.1/suite.yaml b/artifacthub/library/general/requiredannotations/1.0.1/suite.yaml new file mode 100644 index 000000000..48bf7303a --- /dev/null +++ b/artifacthub/library/general/requiredannotations/1.0.1/suite.yaml @@ -0,0 +1,17 @@ +kind: Suite +apiVersion: test.gatekeeper.sh/v1alpha1 +metadata: + name: requiredannotations +tests: +- name: must-have-set-of-annotations + template: template.yaml + constraint: samples/all-must-have-certain-set-of-annotations/constraint.yaml + cases: + - name: example-allowed + object: samples/all-must-have-certain-set-of-annotations/example_allowed.yaml + assertions: + - violations: no + - name: example-disallowed + object: samples/all-must-have-certain-set-of-annotations/example_disallowed.yaml + assertions: + - violations: yes diff --git a/artifacthub/library/general/requiredannotations/1.0.1/template.yaml b/artifacthub/library/general/requiredannotations/1.0.1/template.yaml new file mode 100644 index 000000000..634acb181 --- /dev/null +++ b/artifacthub/library/general/requiredannotations/1.0.1/template.yaml @@ -0,0 +1,59 @@ +apiVersion: templates.gatekeeper.sh/v1 +kind: ConstraintTemplate +metadata: + name: k8srequiredannotations + annotations: + metadata.gatekeeper.sh/title: "Required Annotations" + metadata.gatekeeper.sh/version: 1.0.1 + description: >- + Requires resources to contain specified annotations, with values matching + provided regular expressions. +spec: + crd: + spec: + names: + kind: K8sRequiredAnnotations + validation: + openAPIV3Schema: + type: object + properties: + message: + type: string + annotations: + type: array + description: >- + A list of annotations and values the object must specify. + items: + type: object + properties: + key: + type: string + description: >- + The required annotation. + allowedRegex: + type: string + description: >- + If specified, a regular expression the annotation's value + must match. The value must contain at least one match for + the regular expression. + targets: + - target: admission.k8s.gatekeeper.sh + rego: | + package k8srequiredannotations + + violation[{"msg": msg, "details": {"missing_annotations": missing}}] { + provided := {annotation | input.review.object.metadata.annotations[annotation]} + required := {annotation | annotation := input.parameters.annotations[_].key} + missing := required - provided + count(missing) > 0 + msg := sprintf("you must provide annotation(s): %v", [missing]) + } + + violation[{"msg": msg}] { + value := input.review.object.metadata.annotations[key] + expected := input.parameters.annotations[_] + expected.key == key + expected.allowedRegex != "" + not regex.match(expected.allowedRegex, value) + msg := sprintf("Annotation <%v: %v> does not satisfy allowed regex: %v", [key, value, expected.allowedRegex]) + } diff --git a/artifacthub/library/general/requiredlabels/1.0.1/artifacthub-pkg.yml b/artifacthub/library/general/requiredlabels/1.0.1/artifacthub-pkg.yml new file mode 100644 index 000000000..c8a953a27 --- /dev/null +++ b/artifacthub/library/general/requiredlabels/1.0.1/artifacthub-pkg.yml @@ -0,0 +1,22 @@ +version: 1.0.1 +name: k8srequiredlabels +displayName: Required Labels +createdAt: "2023-10-30T21:00:00Z" +description: Requires resources to contain specified labels, with values matching provided regular expressions. +digest: aa4cbb2bbaba13b310108f7944ba8200c0adbaf865f8f3dfd7cbdc3c760b5eea +license: Apache-2.0 +homeURL: https://open-policy-agent.github.io/gatekeeper-library/website/requiredlabels +keywords: + - gatekeeper + - open-policy-agent + - policies +readme: |- + # Required Labels + Requires resources to contain specified labels, with values matching provided regular expressions. +install: |- + ### Usage + ```shell + kubectl apply -f https://raw.githubusercontent.com/open-policy-agent/gatekeeper-library/master/artifacthub/library/general/requiredlabels/1.0.1/template.yaml + ``` +provider: + name: Gatekeeper Library diff --git a/artifacthub/library/general/requiredlabels/1.0.1/kustomization.yaml b/artifacthub/library/general/requiredlabels/1.0.1/kustomization.yaml new file mode 100644 index 000000000..7d70d11b7 --- /dev/null +++ b/artifacthub/library/general/requiredlabels/1.0.1/kustomization.yaml @@ -0,0 +1,2 @@ +resources: + - template.yaml diff --git a/artifacthub/library/general/requiredlabels/1.0.1/samples/all-must-have-owner/constraint.yaml b/artifacthub/library/general/requiredlabels/1.0.1/samples/all-must-have-owner/constraint.yaml new file mode 100644 index 000000000..806e9862f --- /dev/null +++ b/artifacthub/library/general/requiredlabels/1.0.1/samples/all-must-have-owner/constraint.yaml @@ -0,0 +1,14 @@ +apiVersion: constraints.gatekeeper.sh/v1beta1 +kind: K8sRequiredLabels +metadata: + name: all-must-have-owner +spec: + match: + kinds: + - apiGroups: [""] + kinds: ["Namespace"] + parameters: + message: "All namespaces must have an `owner` label that points to your company username" + labels: + - key: owner + allowedRegex: "^[a-zA-Z]+.agilebank.demo$" diff --git a/artifacthub/library/general/requiredlabels/1.0.1/samples/all-must-have-owner/example_allowed.yaml b/artifacthub/library/general/requiredlabels/1.0.1/samples/all-must-have-owner/example_allowed.yaml new file mode 100644 index 000000000..e2d3b9c03 --- /dev/null +++ b/artifacthub/library/general/requiredlabels/1.0.1/samples/all-must-have-owner/example_allowed.yaml @@ -0,0 +1,6 @@ +apiVersion: v1 +kind: Namespace +metadata: + name: allowed-namespace + labels: + owner: user.agilebank.demo diff --git a/artifacthub/library/general/requiredlabels/1.0.1/samples/all-must-have-owner/example_disallowed.yaml b/artifacthub/library/general/requiredlabels/1.0.1/samples/all-must-have-owner/example_disallowed.yaml new file mode 100644 index 000000000..a7a53610a --- /dev/null +++ b/artifacthub/library/general/requiredlabels/1.0.1/samples/all-must-have-owner/example_disallowed.yaml @@ -0,0 +1,4 @@ +apiVersion: v1 +kind: Namespace +metadata: + name: disallowed-namespace diff --git a/artifacthub/library/general/requiredlabels/1.0.1/suite.yaml b/artifacthub/library/general/requiredlabels/1.0.1/suite.yaml new file mode 100644 index 000000000..64c5b4130 --- /dev/null +++ b/artifacthub/library/general/requiredlabels/1.0.1/suite.yaml @@ -0,0 +1,17 @@ +kind: Suite +apiVersion: test.gatekeeper.sh/v1alpha1 +metadata: + name: requiredlabels +tests: +- name: must-have-owner + template: template.yaml + constraint: samples/all-must-have-owner/constraint.yaml + cases: + - name: example-allowed + object: samples/all-must-have-owner/example_allowed.yaml + assertions: + - violations: no + - name: example-disallowed + object: samples/all-must-have-owner/example_disallowed.yaml + assertions: + - violations: yes diff --git a/artifacthub/library/general/requiredlabels/1.0.1/template.yaml b/artifacthub/library/general/requiredlabels/1.0.1/template.yaml new file mode 100644 index 000000000..aa865394c --- /dev/null +++ b/artifacthub/library/general/requiredlabels/1.0.1/template.yaml @@ -0,0 +1,68 @@ +apiVersion: templates.gatekeeper.sh/v1 +kind: ConstraintTemplate +metadata: + name: k8srequiredlabels + annotations: + metadata.gatekeeper.sh/title: "Required Labels" + metadata.gatekeeper.sh/version: 1.0.1 + description: >- + Requires resources to contain specified labels, with values matching + provided regular expressions. +spec: + crd: + spec: + names: + kind: K8sRequiredLabels + validation: + openAPIV3Schema: + type: object + properties: + message: + type: string + labels: + type: array + description: >- + A list of labels and values the object must specify. + items: + type: object + properties: + key: + type: string + description: >- + The required label. + allowedRegex: + type: string + description: >- + If specified, a regular expression the annotation's value + must match. The value must contain at least one match for + the regular expression. + targets: + - target: admission.k8s.gatekeeper.sh + rego: | + package k8srequiredlabels + + get_message(parameters, _default) := _default { + not parameters.message + } + + get_message(parameters, _) := parameters.message + + violation[{"msg": msg, "details": {"missing_labels": missing}}] { + provided := {label | input.review.object.metadata.labels[label]} + required := {label | label := input.parameters.labels[_].key} + missing := required - provided + count(missing) > 0 + def_msg := sprintf("you must provide labels: %v", [missing]) + msg := get_message(input.parameters, def_msg) + } + + violation[{"msg": msg}] { + value := input.review.object.metadata.labels[key] + expected := input.parameters.labels[_] + expected.key == key + # do not match if allowedRegex is not defined, or is an empty string + expected.allowedRegex != "" + not regex.match(expected.allowedRegex, value) + def_msg := sprintf("Label <%v: %v> does not satisfy allowed regex: %v", [key, value, expected.allowedRegex]) + msg := get_message(input.parameters, def_msg) + } diff --git a/artifacthub/library/general/uniqueingresshost/1.0.4/artifacthub-pkg.yml b/artifacthub/library/general/uniqueingresshost/1.0.4/artifacthub-pkg.yml new file mode 100644 index 000000000..595927481 --- /dev/null +++ b/artifacthub/library/general/uniqueingresshost/1.0.4/artifacthub-pkg.yml @@ -0,0 +1,25 @@ +version: 1.0.4 +name: k8suniqueingresshost +displayName: Unique Ingress Host +createdAt: "2023-10-30T21:00:00Z" +description: |- + Requires all Ingress rule hosts to be unique. + Does not handle hostname wildcards: https://kubernetes.io/docs/concepts/services-networking/ingress/ +digest: 8c335b1ae3f5d162beea4b6f747c632a871c98ea62b762ac4ae4d90259cdfb5d +license: Apache-2.0 +homeURL: https://open-policy-agent.github.io/gatekeeper-library/website/uniqueingresshost +keywords: + - gatekeeper + - open-policy-agent + - policies +readme: |- + # Unique Ingress Host + Requires all Ingress rule hosts to be unique. + Does not handle hostname wildcards: https://kubernetes.io/docs/concepts/services-networking/ingress/ +install: |- + ### Usage + ```shell + kubectl apply -f https://raw.githubusercontent.com/open-policy-agent/gatekeeper-library/master/artifacthub/library/general/uniqueingresshost/1.0.4/template.yaml + ``` +provider: + name: Gatekeeper Library diff --git a/artifacthub/library/general/uniqueingresshost/1.0.4/kustomization.yaml b/artifacthub/library/general/uniqueingresshost/1.0.4/kustomization.yaml new file mode 100644 index 000000000..7d70d11b7 --- /dev/null +++ b/artifacthub/library/general/uniqueingresshost/1.0.4/kustomization.yaml @@ -0,0 +1,2 @@ +resources: + - template.yaml diff --git a/artifacthub/library/general/uniqueingresshost/1.0.4/samples/unique-ingress-host/constraint.yaml b/artifacthub/library/general/uniqueingresshost/1.0.4/samples/unique-ingress-host/constraint.yaml new file mode 100644 index 000000000..b4d7f852f --- /dev/null +++ b/artifacthub/library/general/uniqueingresshost/1.0.4/samples/unique-ingress-host/constraint.yaml @@ -0,0 +1,9 @@ +apiVersion: constraints.gatekeeper.sh/v1beta1 +kind: K8sUniqueIngressHost +metadata: + name: unique-ingress-host +spec: + match: + kinds: + - apiGroups: ["extensions", "networking.k8s.io"] + kinds: ["Ingress"] diff --git a/artifacthub/library/general/uniqueingresshost/1.0.4/samples/unique-ingress-host/example_allowed.yaml b/artifacthub/library/general/uniqueingresshost/1.0.4/samples/unique-ingress-host/example_allowed.yaml new file mode 100644 index 000000000..1e819e200 --- /dev/null +++ b/artifacthub/library/general/uniqueingresshost/1.0.4/samples/unique-ingress-host/example_allowed.yaml @@ -0,0 +1,27 @@ +apiVersion: networking.k8s.io/v1 +kind: Ingress +metadata: + name: ingress-host-allowed + namespace: default +spec: + rules: + - host: example-allowed-host.example.com + http: + paths: + - pathType: Prefix + path: "/" + backend: + service: + name: nginx + port: + number: 80 + - host: example-allowed-host1.example.com + http: + paths: + - pathType: Prefix + path: "/" + backend: + service: + name: nginx2 + port: + number: 80 diff --git a/artifacthub/library/general/uniqueingresshost/1.0.4/samples/unique-ingress-host/example_disallowed.yaml b/artifacthub/library/general/uniqueingresshost/1.0.4/samples/unique-ingress-host/example_disallowed.yaml new file mode 100644 index 000000000..c61893ed6 --- /dev/null +++ b/artifacthub/library/general/uniqueingresshost/1.0.4/samples/unique-ingress-host/example_disallowed.yaml @@ -0,0 +1,17 @@ +apiVersion: networking.k8s.io/v1 +kind: Ingress +metadata: + name: ingress-host-disallowed + namespace: default +spec: + rules: + - host: example-host.example.com + http: + paths: + - pathType: Prefix + path: "/" + backend: + service: + name: nginx + port: + number: 80 diff --git a/artifacthub/library/general/uniqueingresshost/1.0.4/samples/unique-ingress-host/example_disallowed2.yaml b/artifacthub/library/general/uniqueingresshost/1.0.4/samples/unique-ingress-host/example_disallowed2.yaml new file mode 100644 index 000000000..1ca131f13 --- /dev/null +++ b/artifacthub/library/general/uniqueingresshost/1.0.4/samples/unique-ingress-host/example_disallowed2.yaml @@ -0,0 +1,27 @@ +apiVersion: networking.k8s.io/v1 +kind: Ingress +metadata: + name: ingress-host-disallowed2 + namespace: default +spec: + rules: + - host: example-host2.example.com + http: + paths: + - pathType: Prefix + path: "/" + backend: + service: + name: nginx + port: + number: 80 + - host: example-host3.example.com + http: + paths: + - pathType: Prefix + path: "/" + backend: + service: + name: nginx2 + port: + number: 80 diff --git a/artifacthub/library/general/uniqueingresshost/1.0.4/samples/unique-ingress-host/example_inventory_disallowed.yaml b/artifacthub/library/general/uniqueingresshost/1.0.4/samples/unique-ingress-host/example_inventory_disallowed.yaml new file mode 100644 index 000000000..06bc70922 --- /dev/null +++ b/artifacthub/library/general/uniqueingresshost/1.0.4/samples/unique-ingress-host/example_inventory_disallowed.yaml @@ -0,0 +1,17 @@ +apiVersion: networking.k8s.io/v1 +kind: Ingress +metadata: + name: ingress-host-example + namespace: default +spec: + rules: + - host: example-host.example.com + http: + paths: + - pathType: Prefix + path: "/" + backend: + service: + name: nginx + port: + number: 80 diff --git a/artifacthub/library/general/uniqueingresshost/1.0.4/samples/unique-ingress-host/example_inventory_disallowed2.yaml b/artifacthub/library/general/uniqueingresshost/1.0.4/samples/unique-ingress-host/example_inventory_disallowed2.yaml new file mode 100644 index 000000000..3f826aeeb --- /dev/null +++ b/artifacthub/library/general/uniqueingresshost/1.0.4/samples/unique-ingress-host/example_inventory_disallowed2.yaml @@ -0,0 +1,17 @@ +apiVersion: networking.k8s.io/v1 +kind: Ingress +metadata: + name: ingress-host-example2 + namespace: default +spec: + rules: + - host: example-host2.example.com + http: + paths: + - pathType: Prefix + path: "/" + backend: + service: + name: nginx + port: + number: 80 diff --git a/artifacthub/library/general/uniqueingresshost/1.0.4/suite.yaml b/artifacthub/library/general/uniqueingresshost/1.0.4/suite.yaml new file mode 100644 index 000000000..630838d1d --- /dev/null +++ b/artifacthub/library/general/uniqueingresshost/1.0.4/suite.yaml @@ -0,0 +1,25 @@ +kind: Suite +apiVersion: test.gatekeeper.sh/v1alpha1 +metadata: + name: uniqueingresshost +tests: +- name: unique-ingress-host + template: template.yaml + constraint: samples/unique-ingress-host/constraint.yaml + cases: + - name: example-allowed + object: samples/unique-ingress-host/example_allowed.yaml + assertions: + - violations: no + - name: example-disallowed + object: samples/unique-ingress-host/example_disallowed.yaml + inventory: + - samples/unique-ingress-host/example_inventory_disallowed.yaml + assertions: + - violations: yes + - name: example-disallowed2 + object: samples/unique-ingress-host/example_disallowed2.yaml + inventory: + - samples/unique-ingress-host/example_inventory_disallowed2.yaml + assertions: + - violations: yes diff --git a/artifacthub/library/general/uniqueingresshost/1.0.4/sync.yaml b/artifacthub/library/general/uniqueingresshost/1.0.4/sync.yaml new file mode 100644 index 000000000..ce25235ac --- /dev/null +++ b/artifacthub/library/general/uniqueingresshost/1.0.4/sync.yaml @@ -0,0 +1,17 @@ +apiVersion: config.gatekeeper.sh/v1alpha1 +kind: Config +metadata: + name: config + namespace: "gatekeeper-system" +spec: + sync: + syncOnly: + - group: "extensions" + version: "v1beta1" + kind: "Ingress" + - group: "networking.k8s.io" + version: "v1beta1" + kind: "Ingress" + - group: "networking.k8s.io" + version: "v1" + kind: "Ingress" diff --git a/artifacthub/library/general/uniqueingresshost/1.0.4/template.yaml b/artifacthub/library/general/uniqueingresshost/1.0.4/template.yaml new file mode 100644 index 000000000..c534b2a20 --- /dev/null +++ b/artifacthub/library/general/uniqueingresshost/1.0.4/template.yaml @@ -0,0 +1,52 @@ +apiVersion: templates.gatekeeper.sh/v1 +kind: ConstraintTemplate +metadata: + name: k8suniqueingresshost + annotations: + metadata.gatekeeper.sh/title: "Unique Ingress Host" + metadata.gatekeeper.sh/version: 1.0.4 + metadata.gatekeeper.sh/requires-sync-data: | + "[ + [ + { + "groups": ["extensions"], + "versions": ["v1beta1"], + "kinds": ["Ingress"] + }, + { + "groups": ["networking.k8s.io"], + "versions": ["v1beta1", "v1"], + "kinds": ["Ingress"] + } + ] + ]" + description: >- + Requires all Ingress rule hosts to be unique. + + Does not handle hostname wildcards: + https://kubernetes.io/docs/concepts/services-networking/ingress/ +spec: + crd: + spec: + names: + kind: K8sUniqueIngressHost + targets: + - target: admission.k8s.gatekeeper.sh + rego: | + package k8suniqueingresshost + + identical(obj, review) { + obj.metadata.namespace == review.object.metadata.namespace + obj.metadata.name == review.object.metadata.name + } + + violation[{"msg": msg}] { + input.review.kind.kind == "Ingress" + regex.match("^(extensions|networking.k8s.io)$", input.review.kind.group) + host := input.review.object.spec.rules[_].host + other := data.inventory.namespace[_][otherapiversion]["Ingress"][name] + regex.match("^(extensions|networking.k8s.io)/.+$", otherapiversion) + other.spec.rules[_].host == host + not identical(other, input.review) + msg := sprintf("ingress host conflicts with an existing ingress <%v>", [host]) + } diff --git a/artifacthub/library/pod-security-policy/capabilities/1.0.2/artifacthub-pkg.yml b/artifacthub/library/pod-security-policy/capabilities/1.0.2/artifacthub-pkg.yml new file mode 100644 index 000000000..681ac0400 --- /dev/null +++ b/artifacthub/library/pod-security-policy/capabilities/1.0.2/artifacthub-pkg.yml @@ -0,0 +1,22 @@ +version: 1.0.2 +name: k8spspcapabilities +displayName: Capabilities +createdAt: "2023-10-30T21:00:01Z" +description: Controls Linux capabilities on containers. Corresponds to the `allowedCapabilities` and `requiredDropCapabilities` fields in a PodSecurityPolicy. For more information, see https://kubernetes.io/docs/concepts/policy/pod-security-policy/#capabilities +digest: 6a8f1f152f379ac8ca91ad35c9d0da66bdabd1d9f61c62cf15310b7f1a37de1d +license: Apache-2.0 +homeURL: https://open-policy-agent.github.io/gatekeeper-library/website/capabilities +keywords: + - gatekeeper + - open-policy-agent + - policies +readme: |- + # Capabilities + Controls Linux capabilities on containers. Corresponds to the `allowedCapabilities` and `requiredDropCapabilities` fields in a PodSecurityPolicy. For more information, see https://kubernetes.io/docs/concepts/policy/pod-security-policy/#capabilities +install: |- + ### Usage + ```shell + kubectl apply -f https://raw.githubusercontent.com/open-policy-agent/gatekeeper-library/master/artifacthub/library/pod-security-policy/capabilities/1.0.2/template.yaml + ``` +provider: + name: Gatekeeper Library diff --git a/artifacthub/library/pod-security-policy/capabilities/1.0.2/kustomization.yaml b/artifacthub/library/pod-security-policy/capabilities/1.0.2/kustomization.yaml new file mode 100644 index 000000000..7d70d11b7 --- /dev/null +++ b/artifacthub/library/pod-security-policy/capabilities/1.0.2/kustomization.yaml @@ -0,0 +1,2 @@ +resources: + - template.yaml diff --git a/artifacthub/library/pod-security-policy/capabilities/1.0.2/samples/capabilities-demo/constraint.yaml b/artifacthub/library/pod-security-policy/capabilities/1.0.2/samples/capabilities-demo/constraint.yaml new file mode 100644 index 000000000..3f856082f --- /dev/null +++ b/artifacthub/library/pod-security-policy/capabilities/1.0.2/samples/capabilities-demo/constraint.yaml @@ -0,0 +1,14 @@ +apiVersion: constraints.gatekeeper.sh/v1beta1 +kind: K8sPSPCapabilities +metadata: + name: capabilities-demo +spec: + match: + kinds: + - apiGroups: [""] + kinds: ["Pod"] + namespaces: + - "default" + parameters: + allowedCapabilities: ["something"] + requiredDropCapabilities: ["must_drop"] diff --git a/artifacthub/library/pod-security-policy/capabilities/1.0.2/samples/capabilities-demo/disallowed_ephemeral.yaml b/artifacthub/library/pod-security-policy/capabilities/1.0.2/samples/capabilities-demo/disallowed_ephemeral.yaml new file mode 100644 index 000000000..5467c826e --- /dev/null +++ b/artifacthub/library/pod-security-policy/capabilities/1.0.2/samples/capabilities-demo/disallowed_ephemeral.yaml @@ -0,0 +1,21 @@ +apiVersion: v1 +kind: Pod +metadata: + name: opa-disallowed + labels: + owner: me.agilebank.demo +spec: + ephemeralContainers: + - name: opa + image: openpolicyagent/opa:0.9.2 + args: + - "run" + - "--server" + - "--addr=localhost:8080" + securityContext: + capabilities: + add: ["disallowedcapability"] + resources: + limits: + cpu: "100m" + memory: "30Mi" diff --git a/artifacthub/library/pod-security-policy/capabilities/1.0.2/samples/capabilities-demo/example_allowed.yaml b/artifacthub/library/pod-security-policy/capabilities/1.0.2/samples/capabilities-demo/example_allowed.yaml new file mode 100644 index 000000000..41bf6a0ed --- /dev/null +++ b/artifacthub/library/pod-security-policy/capabilities/1.0.2/samples/capabilities-demo/example_allowed.yaml @@ -0,0 +1,22 @@ +apiVersion: v1 +kind: Pod +metadata: + name: opa-allowed + labels: + owner: me.agilebank.demo +spec: + containers: + - name: opa + image: openpolicyagent/opa:0.9.2 + args: + - "run" + - "--server" + - "--addr=localhost:8080" + securityContext: + capabilities: + add: ["something"] + drop: ["must_drop", "another_one"] + resources: + limits: + cpu: "100m" + memory: "30Mi" diff --git a/artifacthub/library/pod-security-policy/capabilities/1.0.2/samples/capabilities-demo/example_disallowed.yaml b/artifacthub/library/pod-security-policy/capabilities/1.0.2/samples/capabilities-demo/example_disallowed.yaml new file mode 100644 index 000000000..fdd886189 --- /dev/null +++ b/artifacthub/library/pod-security-policy/capabilities/1.0.2/samples/capabilities-demo/example_disallowed.yaml @@ -0,0 +1,21 @@ +apiVersion: v1 +kind: Pod +metadata: + name: opa-disallowed + labels: + owner: me.agilebank.demo +spec: + containers: + - name: opa + image: openpolicyagent/opa:0.9.2 + args: + - "run" + - "--server" + - "--addr=localhost:8080" + securityContext: + capabilities: + add: ["disallowedcapability"] + resources: + limits: + cpu: "100m" + memory: "30Mi" \ No newline at end of file diff --git a/artifacthub/library/pod-security-policy/capabilities/1.0.2/samples/capabilities-demo/update.yaml b/artifacthub/library/pod-security-policy/capabilities/1.0.2/samples/capabilities-demo/update.yaml new file mode 100644 index 000000000..df8ea0070 --- /dev/null +++ b/artifacthub/library/pod-security-policy/capabilities/1.0.2/samples/capabilities-demo/update.yaml @@ -0,0 +1,26 @@ +kind: AdmissionReview +apiVersion: admission.k8s.io/v1beta1 +request: + operation: "UPDATE" + object: + apiVersion: v1 + kind: Pod + metadata: + name: opa-disallowed + labels: + owner: me.agilebank.demo + spec: + containers: + - name: opa + image: openpolicyagent/opa:0.9.2 + args: + - "run" + - "--server" + - "--addr=localhost:8080" + securityContext: + capabilities: + add: ["disallowedcapability"] + resources: + limits: + cpu: "100m" + memory: "30Mi" diff --git a/artifacthub/library/pod-security-policy/capabilities/1.0.2/suite.yaml b/artifacthub/library/pod-security-policy/capabilities/1.0.2/suite.yaml new file mode 100644 index 000000000..48c2fcb46 --- /dev/null +++ b/artifacthub/library/pod-security-policy/capabilities/1.0.2/suite.yaml @@ -0,0 +1,25 @@ +kind: Suite +apiVersion: test.gatekeeper.sh/v1alpha1 +metadata: + name: capabilities +tests: + - name: capabilities + template: template.yaml + constraint: samples/capabilities-demo/constraint.yaml + cases: + - name: example-disallowed + object: samples/capabilities-demo/example_disallowed.yaml + assertions: + - violations: yes + - name: example-allowed + object: samples/capabilities-demo/example_allowed.yaml + assertions: + - violations: no + - name: disallowed-ephemeral + object: samples/capabilities-demo/disallowed_ephemeral.yaml + assertions: + - violations: yes + - name: update + object: samples/capabilities-demo/update.yaml + assertions: + - violations: no diff --git a/artifacthub/library/pod-security-policy/capabilities/1.0.2/template.yaml b/artifacthub/library/pod-security-policy/capabilities/1.0.2/template.yaml new file mode 100644 index 000000000..2501a1538 --- /dev/null +++ b/artifacthub/library/pod-security-policy/capabilities/1.0.2/template.yaml @@ -0,0 +1,160 @@ +apiVersion: templates.gatekeeper.sh/v1 +kind: ConstraintTemplate +metadata: + name: k8spspcapabilities + annotations: + metadata.gatekeeper.sh/title: "Capabilities" + metadata.gatekeeper.sh/version: 1.0.2 + description: >- + Controls Linux capabilities on containers. Corresponds to the + `allowedCapabilities` and `requiredDropCapabilities` fields in a + PodSecurityPolicy. For more information, see + https://kubernetes.io/docs/concepts/policy/pod-security-policy/#capabilities +spec: + crd: + spec: + names: + kind: K8sPSPCapabilities + validation: + # Schema for the `parameters` field + openAPIV3Schema: + type: object + description: >- + Controls Linux capabilities on containers. Corresponds to the + `allowedCapabilities` and `requiredDropCapabilities` fields in a + PodSecurityPolicy. For more information, see + https://kubernetes.io/docs/concepts/policy/pod-security-policy/#capabilities + 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 + allowedCapabilities: + type: array + description: "A list of Linux capabilities that can be added to a container." + items: + type: string + requiredDropCapabilities: + type: array + description: "A list of Linux capabilities that are required to be dropped from a container." + items: + type: string + targets: + - target: admission.k8s.gatekeeper.sh + rego: | + package capabilities + + import data.lib.exclude_update.is_update + import data.lib.exempt_container.is_exempt + + violation[{"msg": msg}] { + # spec.containers.securityContext.capabilities field is immutable. + not is_update(input.review) + + container := input.review.object.spec.containers[_] + not is_exempt(container) + has_disallowed_capabilities(container) + msg := sprintf("container <%v> has a disallowed capability. Allowed capabilities are %v", [container.name, get_default(input.parameters, "allowedCapabilities", "NONE")]) + } + + violation[{"msg": msg}] { + not is_update(input.review) + container := input.review.object.spec.containers[_] + not is_exempt(container) + missing_drop_capabilities(container) + msg := sprintf("container <%v> is not dropping all required capabilities. Container must drop all of %v or \"ALL\"", [container.name, input.parameters.requiredDropCapabilities]) + } + + + + violation[{"msg": msg}] { + not is_update(input.review) + container := input.review.object.spec.initContainers[_] + not is_exempt(container) + has_disallowed_capabilities(container) + msg := sprintf("init container <%v> has a disallowed capability. Allowed capabilities are %v", [container.name, get_default(input.parameters, "allowedCapabilities", "NONE")]) + } + + violation[{"msg": msg}] { + not is_update(input.review) + container := input.review.object.spec.initContainers[_] + not is_exempt(container) + missing_drop_capabilities(container) + msg := sprintf("init container <%v> is not dropping all required capabilities. Container must drop all of %v or \"ALL\"", [container.name, input.parameters.requiredDropCapabilities]) + } + + + + violation[{"msg": msg}] { + not is_update(input.review) + container := input.review.object.spec.ephemeralContainers[_] + not is_exempt(container) + has_disallowed_capabilities(container) + msg := sprintf("ephemeral container <%v> has a disallowed capability. Allowed capabilities are %v", [container.name, get_default(input.parameters, "allowedCapabilities", "NONE")]) + } + + violation[{"msg": msg}] { + not is_update(input.review) + container := input.review.object.spec.ephemeralContainers[_] + not is_exempt(container) + missing_drop_capabilities(container) + msg := sprintf("ephemeral container <%v> is not dropping all required capabilities. Container must drop all of %v or \"ALL\"", [container.name, input.parameters.requiredDropCapabilities]) + } + + + has_disallowed_capabilities(container) { + allowed := {c | c := lower(input.parameters.allowedCapabilities[_])} + not allowed["*"] + capabilities := {c | c := lower(container.securityContext.capabilities.add[_])} + + count(capabilities - allowed) > 0 + } + + missing_drop_capabilities(container) { + must_drop := {c | c := lower(input.parameters.requiredDropCapabilities[_])} + all := {"all"} + dropped := {c | c := lower(container.securityContext.capabilities.drop[_])} + + count(must_drop - dropped) > 0 + count(all - dropped) > 0 + } + + get_default(obj, param, _) := obj[param] + + get_default(obj, param, _default) := _default { + not obj[param] + not obj[param] == false + } + 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/forbidden-sysctls/1.1.3/README.md b/artifacthub/library/pod-security-policy/forbidden-sysctls/1.1.3/README.md new file mode 100644 index 000000000..d8a40937d --- /dev/null +++ b/artifacthub/library/pod-security-policy/forbidden-sysctls/1.1.3/README.md @@ -0,0 +1,36 @@ +# Forbidden Sysctls security context policy + +The forbidden sysctls constraint allows one to limit the set of kernel parameters that can be modified by pods. This is accomplished by specifying a combination of allowed and forbidden sysctls using either of two parameters: `allowedSysctls` and `forbiddenSysctls`. + +## Parameters + +`allowedSysctls`: A list of explicitly allowed sysctls. Any sysctl not in this list will be considered forbidden. '*' and trailing wildcards are supported. If unspecified, no limitations are made by this parameter. + +`forbiddenSysctls`: A list of explicitly denied sysctls. Any sysctl in this list will be considered forbidden. '*' and trailing wildcards are supported. If unspecified, no limitations are made by this parameter. + +## Examples + +```yaml +parameters: + allowedSysctls: ['*'] + forbiddenSysctls: + - kernel.msg* + - net.core.somaxconn +``` + +```yaml +parameters: + allowedSysctls: + - kernel.shm_rmid_forced + - net.ipv4.ip_local_port_range + - net.ipv4.tcp_syncookies + - net.ipv4.ping_group_range + forbiddenSysctls: [] +``` + +*Note*: `forbiddenSysctls` takes precedence, such that an explicitly forbidden sysctl is still forbidden even if it appears in `allowedSysctls` as well. However in practice, such overlap between the rules should be avoided. + +## References + +* [Using sysctls in a Kubernetes Cluster](https://kubernetes.io/docs/tasks/administer-cluster/sysctl-cluster/) +* [Kubernetes API Reference - Sysctl](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.19/#sysctl-v1-core) \ No newline at end of file diff --git a/artifacthub/library/pod-security-policy/forbidden-sysctls/1.1.3/artifacthub-pkg.yml b/artifacthub/library/pod-security-policy/forbidden-sysctls/1.1.3/artifacthub-pkg.yml new file mode 100644 index 000000000..21402ceae --- /dev/null +++ b/artifacthub/library/pod-security-policy/forbidden-sysctls/1.1.3/artifacthub-pkg.yml @@ -0,0 +1,22 @@ +version: 1.1.3 +name: k8spspforbiddensysctls +displayName: Forbidden Sysctls +createdAt: "2023-10-30T21:00:01Z" +description: Controls the `sysctl` profile used by containers. Corresponds to the `allowedUnsafeSysctls` and `forbiddenSysctls` fields in a PodSecurityPolicy. When specified, any sysctl not in the `allowedSysctls` parameter is considered to be forbidden. The `forbiddenSysctls` parameter takes precedence over the `allowedSysctls` parameter. For more information, see https://kubernetes.io/docs/tasks/administer-cluster/sysctl-cluster/ +digest: 97bcd0da74c88e9c8c8e55738081253a0fb45e0289b76f17cbe5d5632d751d6f +license: Apache-2.0 +homeURL: https://open-policy-agent.github.io/gatekeeper-library/website/forbidden-sysctls +keywords: + - gatekeeper + - open-policy-agent + - policies +readme: |- + # Forbidden Sysctls + Controls the `sysctl` profile used by containers. Corresponds to the `allowedUnsafeSysctls` and `forbiddenSysctls` fields in a PodSecurityPolicy. When specified, any sysctl not in the `allowedSysctls` parameter is considered to be forbidden. The `forbiddenSysctls` parameter takes precedence over the `allowedSysctls` parameter. For more information, see https://kubernetes.io/docs/tasks/administer-cluster/sysctl-cluster/ +install: |- + ### Usage + ```shell + kubectl apply -f https://raw.githubusercontent.com/open-policy-agent/gatekeeper-library/master/artifacthub/library/pod-security-policy/forbidden-sysctls/1.1.3/template.yaml + ``` +provider: + name: Gatekeeper Library diff --git a/artifacthub/library/pod-security-policy/forbidden-sysctls/1.1.3/kustomization.yaml b/artifacthub/library/pod-security-policy/forbidden-sysctls/1.1.3/kustomization.yaml new file mode 100644 index 000000000..7d70d11b7 --- /dev/null +++ b/artifacthub/library/pod-security-policy/forbidden-sysctls/1.1.3/kustomization.yaml @@ -0,0 +1,2 @@ +resources: + - template.yaml diff --git a/artifacthub/library/pod-security-policy/forbidden-sysctls/1.1.3/samples/psp-forbidden-sysctls/constraint.yaml b/artifacthub/library/pod-security-policy/forbidden-sysctls/1.1.3/samples/psp-forbidden-sysctls/constraint.yaml new file mode 100644 index 000000000..39abf4b23 --- /dev/null +++ b/artifacthub/library/pod-security-policy/forbidden-sysctls/1.1.3/samples/psp-forbidden-sysctls/constraint.yaml @@ -0,0 +1,15 @@ +apiVersion: constraints.gatekeeper.sh/v1beta1 +kind: K8sPSPForbiddenSysctls +metadata: + name: psp-forbidden-sysctls +spec: + match: + kinds: + - apiGroups: [""] + kinds: ["Pod"] + parameters: + forbiddenSysctls: + # - "*" # * may be used to forbid all sysctls + - kernel.* + allowedSysctls: + - "*" # allows all sysctls. allowedSysctls is optional. diff --git a/artifacthub/library/pod-security-policy/forbidden-sysctls/1.1.3/samples/psp-forbidden-sysctls/example_allowed.yaml b/artifacthub/library/pod-security-policy/forbidden-sysctls/1.1.3/samples/psp-forbidden-sysctls/example_allowed.yaml new file mode 100644 index 000000000..4b6cc4b66 --- /dev/null +++ b/artifacthub/library/pod-security-policy/forbidden-sysctls/1.1.3/samples/psp-forbidden-sysctls/example_allowed.yaml @@ -0,0 +1,14 @@ +apiVersion: v1 +kind: Pod +metadata: + name: nginx-forbidden-sysctls-disallowed + labels: + app: nginx-forbidden-sysctls +spec: + containers: + - name: nginx + image: nginx + securityContext: + sysctls: + - name: net.core.somaxconn + value: "1024" diff --git a/artifacthub/library/pod-security-policy/forbidden-sysctls/1.1.3/samples/psp-forbidden-sysctls/example_disallowed.yaml b/artifacthub/library/pod-security-policy/forbidden-sysctls/1.1.3/samples/psp-forbidden-sysctls/example_disallowed.yaml new file mode 100644 index 000000000..34ab8f344 --- /dev/null +++ b/artifacthub/library/pod-security-policy/forbidden-sysctls/1.1.3/samples/psp-forbidden-sysctls/example_disallowed.yaml @@ -0,0 +1,16 @@ +apiVersion: v1 +kind: Pod +metadata: + name: nginx-forbidden-sysctls-disallowed + labels: + app: nginx-forbidden-sysctls +spec: + containers: + - name: nginx + image: nginx + securityContext: + sysctls: + - name: kernel.msgmax + value: "65536" + - name: net.core.somaxconn + value: "1024" diff --git a/artifacthub/library/pod-security-policy/forbidden-sysctls/1.1.3/samples/psp-forbidden-sysctls/update.yaml b/artifacthub/library/pod-security-policy/forbidden-sysctls/1.1.3/samples/psp-forbidden-sysctls/update.yaml new file mode 100644 index 000000000..e4e732be9 --- /dev/null +++ b/artifacthub/library/pod-security-policy/forbidden-sysctls/1.1.3/samples/psp-forbidden-sysctls/update.yaml @@ -0,0 +1,21 @@ +kind: AdmissionReview +apiVersion: admission.k8s.io/v1beta1 +request: + operation: "UPDATE" + object: + apiVersion: v1 + kind: Pod + metadata: + name: nginx-forbidden-sysctls-disallowed + labels: + app: nginx-forbidden-sysctls + spec: + containers: + - name: nginx + image: nginx + securityContext: + sysctls: + - name: kernel.msgmax + value: "65536" + - name: net.core.somaxconn + value: "1024" diff --git a/artifacthub/library/pod-security-policy/forbidden-sysctls/1.1.3/suite.yaml b/artifacthub/library/pod-security-policy/forbidden-sysctls/1.1.3/suite.yaml new file mode 100644 index 000000000..d00f85b8b --- /dev/null +++ b/artifacthub/library/pod-security-policy/forbidden-sysctls/1.1.3/suite.yaml @@ -0,0 +1,21 @@ +kind: Suite +apiVersion: test.gatekeeper.sh/v1alpha1 +metadata: + name: forbidden-sysctls +tests: + - name: forbidden-sysctls + template: template.yaml + constraint: samples/psp-forbidden-sysctls/constraint.yaml + cases: + - name: example-disallowed + object: samples/psp-forbidden-sysctls/example_disallowed.yaml + assertions: + - violations: yes + - name: example-allowed + object: samples/psp-forbidden-sysctls/example_allowed.yaml + assertions: + - violations: no + - name: update + object: samples/psp-forbidden-sysctls/update.yaml + assertions: + - violations: no diff --git a/artifacthub/library/pod-security-policy/forbidden-sysctls/1.1.3/template.yaml b/artifacthub/library/pod-security-policy/forbidden-sysctls/1.1.3/template.yaml new file mode 100644 index 000000000..053c0eae5 --- /dev/null +++ b/artifacthub/library/pod-security-policy/forbidden-sysctls/1.1.3/template.yaml @@ -0,0 +1,100 @@ +apiVersion: templates.gatekeeper.sh/v1 +kind: ConstraintTemplate +metadata: + name: k8spspforbiddensysctls + annotations: + metadata.gatekeeper.sh/title: "Forbidden Sysctls" + metadata.gatekeeper.sh/version: 1.1.3 + description: >- + Controls the `sysctl` profile used by containers. Corresponds to the + `allowedUnsafeSysctls` and `forbiddenSysctls` fields in a PodSecurityPolicy. + When specified, any sysctl not in the `allowedSysctls` parameter is considered to be forbidden. + The `forbiddenSysctls` parameter takes precedence over the `allowedSysctls` parameter. + For more information, see https://kubernetes.io/docs/tasks/administer-cluster/sysctl-cluster/ +spec: + crd: + spec: + names: + kind: K8sPSPForbiddenSysctls + validation: + # Schema for the `parameters` field + openAPIV3Schema: + type: object + description: >- + Controls the `sysctl` profile used by containers. Corresponds to the + `allowedUnsafeSysctls` and `forbiddenSysctls` fields in a PodSecurityPolicy. + When specified, any sysctl not in the `allowedSysctls` parameter is considered to be forbidden. + The `forbiddenSysctls` parameter takes precedence over the `allowedSysctls` parameter. + For more information, see https://kubernetes.io/docs/tasks/administer-cluster/sysctl-cluster/ + properties: + allowedSysctls: + type: array + description: "An allow-list of sysctls. `*` allows all sysctls not listed in the `forbiddenSysctls` parameter." + items: + type: string + forbiddenSysctls: + type: array + description: "A disallow-list of sysctls. `*` forbids all sysctls." + items: + type: string + targets: + - target: admission.k8s.gatekeeper.sh + rego: | + package k8spspforbiddensysctls + + import data.lib.exclude_update.is_update + + # Block if forbidden + violation[{"msg": msg, "details": {}}] { + # spec.securityContext.sysctls field is immutable. + not is_update(input.review) + + sysctl := input.review.object.spec.securityContext.sysctls[_].name + forbidden_sysctl(sysctl) + msg := sprintf("The sysctl %v is not allowed, pod: %v. Forbidden sysctls: %v", [sysctl, input.review.object.metadata.name, input.parameters.forbiddenSysctls]) + } + + # Block if not explicitly allowed + violation[{"msg": msg, "details": {}}] { + not is_update(input.review) + sysctl := input.review.object.spec.securityContext.sysctls[_].name + not allowed_sysctl(sysctl) + msg := sprintf("The sysctl %v is not explicitly allowed, pod: %v. Allowed sysctls: %v", [sysctl, input.review.object.metadata.name, input.parameters.allowedSysctls]) + } + + # * may be used to forbid all sysctls + forbidden_sysctl(_) { + input.parameters.forbiddenSysctls[_] == "*" + } + + forbidden_sysctl(sysctl) { + input.parameters.forbiddenSysctls[_] == sysctl + } + + forbidden_sysctl(sysctl) { + forbidden := input.parameters.forbiddenSysctls[_] + endswith(forbidden, "*") + startswith(sysctl, trim_suffix(forbidden, "*")) + } + + # * may be used to allow all sysctls + allowed_sysctl(_) { + input.parameters.allowedSysctls[_] == "*" + } + + allowed_sysctl(sysctl) { + input.parameters.allowedSysctls[_] == sysctl + } + + allowed_sysctl(sysctl) { + allowed := input.parameters.allowedSysctls[_] + endswith(allowed, "*") + startswith(sysctl, trim_suffix(allowed, "*")) + } + libs: + - | + package lib.exclude_update + + is_update(review) { + review.operation == "UPDATE" + } diff --git a/artifacthub/library/pod-security-policy/fsgroup/1.0.2/README.md b/artifacthub/library/pod-security-policy/fsgroup/1.0.2/README.md new file mode 100644 index 000000000..b70d94d45 --- /dev/null +++ b/artifacthub/library/pod-security-policy/fsgroup/1.0.2/README.md @@ -0,0 +1,7 @@ +# Deprecated + +**This Policy is deprecated** + +Please use the FSGroup settings on the users policy to enforce FSGroup Settings. + +[Users Policy](../users) diff --git a/artifacthub/library/pod-security-policy/fsgroup/1.0.2/artifacthub-pkg.yml b/artifacthub/library/pod-security-policy/fsgroup/1.0.2/artifacthub-pkg.yml new file mode 100644 index 000000000..de11f20c9 --- /dev/null +++ b/artifacthub/library/pod-security-policy/fsgroup/1.0.2/artifacthub-pkg.yml @@ -0,0 +1,22 @@ +version: 1.0.2 +name: k8spspfsgroup +displayName: FS Group +createdAt: "2023-10-30T21:00:01Z" +description: Controls allocating an FSGroup that owns the Pod's volumes. Corresponds to the `fsGroup` field in a PodSecurityPolicy. For more information, see https://kubernetes.io/docs/concepts/policy/pod-security-policy/#volumes-and-file-systems +digest: fbccd31e516f56b1a82fdd979614e110862a2434c89171398eb95db0d468f50b +license: Apache-2.0 +homeURL: https://open-policy-agent.github.io/gatekeeper-library/website/fsgroup +keywords: + - gatekeeper + - open-policy-agent + - policies +readme: |- + # FS Group + Controls allocating an FSGroup that owns the Pod's volumes. Corresponds to the `fsGroup` 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/fsgroup/1.0.2/template.yaml + ``` +provider: + name: Gatekeeper Library diff --git a/artifacthub/library/pod-security-policy/fsgroup/1.0.2/kustomization.yaml b/artifacthub/library/pod-security-policy/fsgroup/1.0.2/kustomization.yaml new file mode 100644 index 000000000..7d70d11b7 --- /dev/null +++ b/artifacthub/library/pod-security-policy/fsgroup/1.0.2/kustomization.yaml @@ -0,0 +1,2 @@ +resources: + - template.yaml diff --git a/artifacthub/library/pod-security-policy/fsgroup/1.0.2/samples/psp-fsgroup/constraint.yaml b/artifacthub/library/pod-security-policy/fsgroup/1.0.2/samples/psp-fsgroup/constraint.yaml new file mode 100644 index 000000000..4eb14fe3c --- /dev/null +++ b/artifacthub/library/pod-security-policy/fsgroup/1.0.2/samples/psp-fsgroup/constraint.yaml @@ -0,0 +1,14 @@ +apiVersion: constraints.gatekeeper.sh/v1beta1 +kind: K8sPSPFSGroup +metadata: + name: psp-fsgroup +spec: + match: + kinds: + - apiGroups: [""] + kinds: ["Pod"] + parameters: + rule: "MayRunAs" #"MustRunAs" #"MayRunAs", "RunAsAny" + ranges: + - min: 1 + max: 1000 diff --git a/artifacthub/library/pod-security-policy/fsgroup/1.0.2/samples/psp-fsgroup/example_allowed.yaml b/artifacthub/library/pod-security-policy/fsgroup/1.0.2/samples/psp-fsgroup/example_allowed.yaml new file mode 100644 index 000000000..17d3274c3 --- /dev/null +++ b/artifacthub/library/pod-security-policy/fsgroup/1.0.2/samples/psp-fsgroup/example_allowed.yaml @@ -0,0 +1,17 @@ +apiVersion: v1 +kind: Pod +metadata: + name: fsgroup-disallowed +spec: + securityContext: + fsGroup: 500 # directory will have group ID 500 + volumes: + - name: fsgroup-demo-vol + emptyDir: {} + containers: + - name: fsgroup-demo + image: busybox + command: ["sh", "-c", "sleep 1h"] + volumeMounts: + - name: fsgroup-demo-vol + mountPath: /data/demo diff --git a/artifacthub/library/pod-security-policy/fsgroup/1.0.2/samples/psp-fsgroup/example_disallowed.yaml b/artifacthub/library/pod-security-policy/fsgroup/1.0.2/samples/psp-fsgroup/example_disallowed.yaml new file mode 100644 index 000000000..9caf7c0a3 --- /dev/null +++ b/artifacthub/library/pod-security-policy/fsgroup/1.0.2/samples/psp-fsgroup/example_disallowed.yaml @@ -0,0 +1,17 @@ +apiVersion: v1 +kind: Pod +metadata: + name: fsgroup-disallowed +spec: + securityContext: + fsGroup: 2000 # directory will have group ID 2000 + volumes: + - name: fsgroup-demo-vol + emptyDir: {} + containers: + - name: fsgroup-demo + image: busybox + command: [ "sh", "-c", "sleep 1h" ] + volumeMounts: + - name: fsgroup-demo-vol + mountPath: /data/demo diff --git a/artifacthub/library/pod-security-policy/fsgroup/1.0.2/samples/psp-fsgroup/update.yaml b/artifacthub/library/pod-security-policy/fsgroup/1.0.2/samples/psp-fsgroup/update.yaml new file mode 100644 index 000000000..c0de7258a --- /dev/null +++ b/artifacthub/library/pod-security-policy/fsgroup/1.0.2/samples/psp-fsgroup/update.yaml @@ -0,0 +1,22 @@ +kind: AdmissionReview +apiVersion: admission.k8s.io/v1beta1 +request: + operation: "UPDATE" + object: + apiVersion: v1 + kind: Pod + metadata: + name: fsgroup-disallowed + spec: + securityContext: + fsGroup: 2000 # directory will have group ID 2000 + volumes: + - name: fsgroup-demo-vol + emptyDir: {} + containers: + - name: fsgroup-demo + image: busybox + command: [ "sh", "-c", "sleep 1h" ] + volumeMounts: + - name: fsgroup-demo-vol + mountPath: /data/demo diff --git a/artifacthub/library/pod-security-policy/fsgroup/1.0.2/suite.yaml b/artifacthub/library/pod-security-policy/fsgroup/1.0.2/suite.yaml new file mode 100644 index 000000000..cb102e785 --- /dev/null +++ b/artifacthub/library/pod-security-policy/fsgroup/1.0.2/suite.yaml @@ -0,0 +1,21 @@ +kind: Suite +apiVersion: test.gatekeeper.sh/v1alpha1 +metadata: + name: fsgroup +tests: + - name: fsgroup + template: template.yaml + constraint: samples/psp-fsgroup/constraint.yaml + cases: + - name: example-disallowed + object: samples/psp-fsgroup/example_disallowed.yaml + assertions: + - violations: yes + - name: example-allowed + object: samples/psp-fsgroup/example_allowed.yaml + assertions: + - violations: no + - name: update + object: samples/psp-fsgroup/update.yaml + assertions: + - violations: no diff --git a/artifacthub/library/pod-security-policy/fsgroup/1.0.2/template.yaml b/artifacthub/library/pod-security-policy/fsgroup/1.0.2/template.yaml new file mode 100644 index 000000000..4e1b9449a --- /dev/null +++ b/artifacthub/library/pod-security-policy/fsgroup/1.0.2/template.yaml @@ -0,0 +1,105 @@ +apiVersion: templates.gatekeeper.sh/v1 +kind: ConstraintTemplate +metadata: + name: k8spspfsgroup + annotations: + metadata.gatekeeper.sh/title: "FS Group" + metadata.gatekeeper.sh/version: 1.0.2 + description: >- + Controls allocating an FSGroup that owns the Pod's volumes. Corresponds + to the `fsGroup` 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: K8sPSPFSGroup + validation: + # Schema for the `parameters` field + openAPIV3Schema: + type: object + description: >- + Controls allocating an FSGroup that owns the Pod's volumes. Corresponds + to the `fsGroup` field in a PodSecurityPolicy. For more information, see + https://kubernetes.io/docs/concepts/policy/pod-security-policy/#volumes-and-file-systems + properties: + rule: + description: "An FSGroup rule name." + enum: + - MayRunAs + - MustRunAs + - RunAsAny + type: string + ranges: + type: array + description: "GID ranges affected by the rule." + items: + type: object + properties: + min: + description: "The minimum GID in the range, inclusive." + type: integer + max: + description: "The maximum GID in the range, inclusive." + type: integer + targets: + - target: admission.k8s.gatekeeper.sh + rego: | + package k8spspfsgroup + + import data.lib.exclude_update.is_update + + violation[{"msg": msg, "details": {}}] { + # spec.securityContext.fsGroup field is immutable. + not is_update(input.review) + + spec := input.review.object.spec + not input_fsGroup_allowed(spec) + msg := sprintf("The provided pod spec fsGroup is not allowed, pod: %v. Allowed fsGroup: %v", [input.review.object.metadata.name, input.parameters]) + } + + input_fsGroup_allowed(_) { + # RunAsAny - No range is required. Allows any fsGroup ID to be specified. + input.parameters.rule == "RunAsAny" + } + input_fsGroup_allowed(spec) { + # MustRunAs - Validates pod spec fsgroup against all ranges + input.parameters.rule == "MustRunAs" + fg := spec.securityContext.fsGroup + count(input.parameters.ranges) > 0 + range := input.parameters.ranges[_] + value_within_range(range, fg) + } + input_fsGroup_allowed(spec) { + # MayRunAs - Validates pod spec fsgroup against all ranges or allow pod spec fsgroup to be left unset + input.parameters.rule == "MayRunAs" + not has_field(spec, "securityContext") + } + input_fsGroup_allowed(spec) { + # MayRunAs - Validates pod spec fsgroup against all ranges or allow pod spec fsgroup to be left unset + input.parameters.rule == "MayRunAs" + not spec.securityContext.fsGroup + } + input_fsGroup_allowed(spec) { + # MayRunAs - Validates pod spec fsgroup against all ranges or allow pod spec fsgroup to be left unset + input.parameters.rule == "MayRunAs" + fg := spec.securityContext.fsGroup + count(input.parameters.ranges) > 0 + range := input.parameters.ranges[_] + value_within_range(range, fg) + } + value_within_range(range, value) { + range.min <= value + range.max >= value + } + # 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" + } diff --git a/artifacthub/library/pod-security-policy/host-filesystem/1.0.2/artifacthub-pkg.yml b/artifacthub/library/pod-security-policy/host-filesystem/1.0.2/artifacthub-pkg.yml new file mode 100644 index 000000000..714090b4f --- /dev/null +++ b/artifacthub/library/pod-security-policy/host-filesystem/1.0.2/artifacthub-pkg.yml @@ -0,0 +1,22 @@ +version: 1.0.2 +name: k8spsphostfilesystem +displayName: Host Filesystem +createdAt: "2023-10-30T21:00:01Z" +description: Controls usage of the host filesystem. Corresponds to the `allowedHostPaths` field in a PodSecurityPolicy. For more information, see https://kubernetes.io/docs/concepts/policy/pod-security-policy/#volumes-and-file-systems +digest: 48def0bbdca86b91c2d545e4b155793a69dc202192d8547f69d6d2b84e41a319 +license: Apache-2.0 +homeURL: https://open-policy-agent.github.io/gatekeeper-library/website/host-filesystem +keywords: + - gatekeeper + - open-policy-agent + - policies +readme: |- + # Host Filesystem + Controls usage of the host filesystem. Corresponds to the `allowedHostPaths` 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/host-filesystem/1.0.2/template.yaml + ``` +provider: + name: Gatekeeper Library diff --git a/artifacthub/library/pod-security-policy/host-filesystem/1.0.2/kustomization.yaml b/artifacthub/library/pod-security-policy/host-filesystem/1.0.2/kustomization.yaml new file mode 100644 index 000000000..7d70d11b7 --- /dev/null +++ b/artifacthub/library/pod-security-policy/host-filesystem/1.0.2/kustomization.yaml @@ -0,0 +1,2 @@ +resources: + - template.yaml diff --git a/artifacthub/library/pod-security-policy/host-filesystem/1.0.2/samples/psp-host-filesystem/constraint.yaml b/artifacthub/library/pod-security-policy/host-filesystem/1.0.2/samples/psp-host-filesystem/constraint.yaml new file mode 100644 index 000000000..7cbd7b824 --- /dev/null +++ b/artifacthub/library/pod-security-policy/host-filesystem/1.0.2/samples/psp-host-filesystem/constraint.yaml @@ -0,0 +1,13 @@ +apiVersion: constraints.gatekeeper.sh/v1beta1 +kind: K8sPSPHostFilesystem +metadata: + name: psp-host-filesystem +spec: + match: + kinds: + - apiGroups: [""] + kinds: ["Pod"] + parameters: + allowedHostPaths: + - readOnly: true + pathPrefix: "/foo" diff --git a/artifacthub/library/pod-security-policy/host-filesystem/1.0.2/samples/psp-host-filesystem/disallowed_ephemeral.yaml b/artifacthub/library/pod-security-policy/host-filesystem/1.0.2/samples/psp-host-filesystem/disallowed_ephemeral.yaml new file mode 100644 index 000000000..beece55c0 --- /dev/null +++ b/artifacthub/library/pod-security-policy/host-filesystem/1.0.2/samples/psp-host-filesystem/disallowed_ephemeral.yaml @@ -0,0 +1,18 @@ +apiVersion: v1 +kind: Pod +metadata: + name: nginx-host-filesystem + labels: + app: nginx-host-filesystem-disallowed +spec: + ephemeralContainers: + - name: nginx + image: nginx + volumeMounts: + - mountPath: /cache + name: cache-volume + readOnly: true + volumes: + - name: cache-volume + hostPath: + path: /tmp # directory location on host diff --git a/artifacthub/library/pod-security-policy/host-filesystem/1.0.2/samples/psp-host-filesystem/example_allowed.yaml b/artifacthub/library/pod-security-policy/host-filesystem/1.0.2/samples/psp-host-filesystem/example_allowed.yaml new file mode 100644 index 000000000..abc60d882 --- /dev/null +++ b/artifacthub/library/pod-security-policy/host-filesystem/1.0.2/samples/psp-host-filesystem/example_allowed.yaml @@ -0,0 +1,18 @@ +apiVersion: v1 +kind: Pod +metadata: + name: nginx-host-filesystem + labels: + app: nginx-host-filesystem-disallowed +spec: + containers: + - name: nginx + image: nginx + volumeMounts: + - mountPath: /cache + name: cache-volume + readOnly: true + volumes: + - name: cache-volume + hostPath: + path: /foo/bar diff --git a/artifacthub/library/pod-security-policy/host-filesystem/1.0.2/samples/psp-host-filesystem/example_disallowed.yaml b/artifacthub/library/pod-security-policy/host-filesystem/1.0.2/samples/psp-host-filesystem/example_disallowed.yaml new file mode 100644 index 000000000..53107694f --- /dev/null +++ b/artifacthub/library/pod-security-policy/host-filesystem/1.0.2/samples/psp-host-filesystem/example_disallowed.yaml @@ -0,0 +1,18 @@ +apiVersion: v1 +kind: Pod +metadata: + name: nginx-host-filesystem + labels: + app: nginx-host-filesystem-disallowed +spec: + containers: + - name: nginx + image: nginx + volumeMounts: + - mountPath: /cache + name: cache-volume + readOnly: true + volumes: + - name: cache-volume + hostPath: + path: /tmp # directory location on host diff --git a/artifacthub/library/pod-security-policy/host-filesystem/1.0.2/samples/psp-host-filesystem/update.yaml b/artifacthub/library/pod-security-policy/host-filesystem/1.0.2/samples/psp-host-filesystem/update.yaml new file mode 100644 index 000000000..68b28a536 --- /dev/null +++ b/artifacthub/library/pod-security-policy/host-filesystem/1.0.2/samples/psp-host-filesystem/update.yaml @@ -0,0 +1,23 @@ +kind: AdmissionReview +apiVersion: admission.k8s.io/v1beta1 +request: + operation: "UPDATE" + object: + apiVersion: v1 + kind: Pod + metadata: + name: nginx-host-filesystem + labels: + app: nginx-host-filesystem-disallowed + spec: + containers: + - name: nginx + image: nginx + volumeMounts: + - mountPath: /cache + name: cache-volume + readOnly: true + volumes: + - name: cache-volume + hostPath: + path: /tmp # directory location on host diff --git a/artifacthub/library/pod-security-policy/host-filesystem/1.0.2/suite.yaml b/artifacthub/library/pod-security-policy/host-filesystem/1.0.2/suite.yaml new file mode 100644 index 000000000..5441df8cc --- /dev/null +++ b/artifacthub/library/pod-security-policy/host-filesystem/1.0.2/suite.yaml @@ -0,0 +1,25 @@ +kind: Suite +apiVersion: test.gatekeeper.sh/v1alpha1 +metadata: + name: host-filesystem +tests: + - name: host-filesystem + template: template.yaml + constraint: samples/psp-host-filesystem/constraint.yaml + cases: + - name: example-disallowed + object: samples/psp-host-filesystem/example_disallowed.yaml + assertions: + - violations: yes + - name: example-allowed + object: samples/psp-host-filesystem/example_allowed.yaml + assertions: + - violations: no + - name: disallowed-ephemeral + object: samples/psp-host-filesystem/disallowed_ephemeral.yaml + assertions: + - violations: yes + - name: update + object: samples/psp-host-filesystem/update.yaml + assertions: + - violations: no diff --git a/artifacthub/library/pod-security-policy/host-filesystem/1.0.2/template.yaml b/artifacthub/library/pod-security-policy/host-filesystem/1.0.2/template.yaml new file mode 100644 index 000000000..5f506c351 --- /dev/null +++ b/artifacthub/library/pod-security-policy/host-filesystem/1.0.2/template.yaml @@ -0,0 +1,148 @@ +apiVersion: templates.gatekeeper.sh/v1 +kind: ConstraintTemplate +metadata: + name: k8spsphostfilesystem + annotations: + metadata.gatekeeper.sh/title: "Host Filesystem" + metadata.gatekeeper.sh/version: 1.0.2 + description: >- + Controls usage of the host filesystem. Corresponds to the + `allowedHostPaths` 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: K8sPSPHostFilesystem + validation: + # Schema for the `parameters` field + openAPIV3Schema: + type: object + description: >- + Controls usage of the host filesystem. Corresponds to the + `allowedHostPaths` field in a PodSecurityPolicy. For more information, + see + https://kubernetes.io/docs/concepts/policy/pod-security-policy/#volumes-and-file-systems + properties: + allowedHostPaths: + type: array + description: "An array of hostpath objects, representing paths and read/write configuration." + items: + type: object + properties: + pathPrefix: + type: string + description: "The path prefix that the host volume must match." + readOnly: + type: boolean + description: "when set to true, any container volumeMounts matching the pathPrefix must include `readOnly: true`." + targets: + - target: admission.k8s.gatekeeper.sh + rego: | + package k8spsphostfilesystem + + import data.lib.exclude_update.is_update + + violation[{"msg": msg, "details": {}}] { + # spec.volumes field is immutable. + not is_update(input.review) + + volume := input_hostpath_volumes[_] + allowedPaths := get_allowed_paths(input) + input_hostpath_violation(allowedPaths, volume) + msg := sprintf("HostPath volume %v is not allowed, pod: %v. Allowed path: %v", [volume, input.review.object.metadata.name, allowedPaths]) + } + + input_hostpath_violation(allowedPaths, _) { + # An empty list means all host paths are blocked + allowedPaths == [] + } + input_hostpath_violation(allowedPaths, volume) { + not input_hostpath_allowed(allowedPaths, volume) + } + + get_allowed_paths(arg) = out { + not arg.parameters + out = [] + } + get_allowed_paths(arg) = out { + not arg.parameters.allowedHostPaths + out = [] + } + get_allowed_paths(arg) = out { + out = arg.parameters.allowedHostPaths + } + + input_hostpath_allowed(allowedPaths, volume) { + allowedHostPath := allowedPaths[_] + path_matches(allowedHostPath.pathPrefix, volume.hostPath.path) + not allowedHostPath.readOnly == true + } + + input_hostpath_allowed(allowedPaths, volume) { + allowedHostPath := allowedPaths[_] + path_matches(allowedHostPath.pathPrefix, volume.hostPath.path) + allowedHostPath.readOnly + not writeable_input_volume_mounts(volume.name) + } + + writeable_input_volume_mounts(volume_name) { + container := input_containers[_] + mount := container.volumeMounts[_] + mount.name == volume_name + not mount.readOnly + } + + # This allows "/foo", "/foo/", "/foo/bar" etc., but + # disallows "/fool", "/etc/foo" etc. + path_matches(prefix, path) { + a := path_array(prefix) + b := path_array(path) + prefix_matches(a, b) + } + path_array(p) = out { + p != "/" + out := split(trim(p, "/"), "/") + } + # This handles the special case for "/", since + # split(trim("/", "/"), "/") == [""] + path_array("/") = [] + + prefix_matches(a, b) { + count(a) <= count(b) + not any_not_equal_upto(a, b, count(a)) + } + + any_not_equal_upto(a, b, n) { + a[i] != b[i] + i < n + } + + input_hostpath_volumes[v] { + v := input.review.object.spec.volumes[_] + has_field(v, "hostPath") + } + + # has_field returns whether an object has a field + has_field(object, field) = true { + object[field] + } + input_containers[c] { + c := input.review.object.spec.containers[_] + } + + input_containers[c] { + c := input.review.object.spec.initContainers[_] + } + + input_containers[c] { + c := input.review.object.spec.ephemeralContainers[_] + } + libs: + - | + package lib.exclude_update + + is_update(review) { + review.operation == "UPDATE" + } diff --git a/artifacthub/library/pod-security-policy/host-network-ports/1.0.2/artifacthub-pkg.yml b/artifacthub/library/pod-security-policy/host-network-ports/1.0.2/artifacthub-pkg.yml new file mode 100644 index 000000000..54ebdc968 --- /dev/null +++ b/artifacthub/library/pod-security-policy/host-network-ports/1.0.2/artifacthub-pkg.yml @@ -0,0 +1,22 @@ +version: 1.0.2 +name: k8spsphostnetworkingports +displayName: Host Networking Ports +createdAt: "2023-10-30T21:00:01Z" +description: Controls usage of host network namespace by pod containers. Specific ports must be specified. Corresponds to the `hostNetwork` and `hostPorts` fields in a PodSecurityPolicy. For more information, see https://kubernetes.io/docs/concepts/policy/pod-security-policy/#host-namespaces +digest: ae7dce558b0f89d28d03646ba8b2f5fdbfe179bc2d4f082d544042d798fcff4b +license: Apache-2.0 +homeURL: https://open-policy-agent.github.io/gatekeeper-library/website/host-network-ports +keywords: + - gatekeeper + - open-policy-agent + - policies +readme: |- + # Host Networking Ports + Controls usage of host network namespace by pod containers. Specific ports must be specified. Corresponds to the `hostNetwork` and `hostPorts` fields in a PodSecurityPolicy. For more information, see https://kubernetes.io/docs/concepts/policy/pod-security-policy/#host-namespaces +install: |- + ### Usage + ```shell + kubectl apply -f https://raw.githubusercontent.com/open-policy-agent/gatekeeper-library/master/artifacthub/library/pod-security-policy/host-network-ports/1.0.2/template.yaml + ``` +provider: + name: Gatekeeper Library diff --git a/artifacthub/library/pod-security-policy/host-network-ports/1.0.2/kustomization.yaml b/artifacthub/library/pod-security-policy/host-network-ports/1.0.2/kustomization.yaml new file mode 100644 index 000000000..7d70d11b7 --- /dev/null +++ b/artifacthub/library/pod-security-policy/host-network-ports/1.0.2/kustomization.yaml @@ -0,0 +1,2 @@ +resources: + - template.yaml diff --git a/artifacthub/library/pod-security-policy/host-network-ports/1.0.2/samples/psp-host-network-ports/constraint.yaml b/artifacthub/library/pod-security-policy/host-network-ports/1.0.2/samples/psp-host-network-ports/constraint.yaml new file mode 100644 index 000000000..fcbc5d805 --- /dev/null +++ b/artifacthub/library/pod-security-policy/host-network-ports/1.0.2/samples/psp-host-network-ports/constraint.yaml @@ -0,0 +1,13 @@ +apiVersion: constraints.gatekeeper.sh/v1beta1 +kind: K8sPSPHostNetworkingPorts +metadata: + name: psp-host-network-ports +spec: + match: + kinds: + - apiGroups: [""] + kinds: ["Pod"] + parameters: + hostNetwork: true + min: 80 + max: 9000 diff --git a/artifacthub/library/pod-security-policy/host-network-ports/1.0.2/samples/psp-host-network-ports/disallowed_ephemeral.yaml b/artifacthub/library/pod-security-policy/host-network-ports/1.0.2/samples/psp-host-network-ports/disallowed_ephemeral.yaml new file mode 100644 index 000000000..7a4fa3114 --- /dev/null +++ b/artifacthub/library/pod-security-policy/host-network-ports/1.0.2/samples/psp-host-network-ports/disallowed_ephemeral.yaml @@ -0,0 +1,14 @@ +apiVersion: v1 +kind: Pod +metadata: + name: nginx-host-networking-ports-disallowed + labels: + app: nginx-host-networking-ports +spec: + hostNetwork: true + ephemeralContainers: + - name: nginx + image: nginx + ports: + - containerPort: 9001 + hostPort: 9001 diff --git a/artifacthub/library/pod-security-policy/host-network-ports/1.0.2/samples/psp-host-network-ports/example_allowed.yaml b/artifacthub/library/pod-security-policy/host-network-ports/1.0.2/samples/psp-host-network-ports/example_allowed.yaml new file mode 100644 index 000000000..08b321fe5 --- /dev/null +++ b/artifacthub/library/pod-security-policy/host-network-ports/1.0.2/samples/psp-host-network-ports/example_allowed.yaml @@ -0,0 +1,14 @@ +apiVersion: v1 +kind: Pod +metadata: + name: nginx-host-networking-ports-allowed + labels: + app: nginx-host-networking-ports +spec: + hostNetwork: false + containers: + - name: nginx + image: nginx + ports: + - containerPort: 9000 + hostPort: 80 diff --git a/artifacthub/library/pod-security-policy/host-network-ports/1.0.2/samples/psp-host-network-ports/example_disallowed.yaml b/artifacthub/library/pod-security-policy/host-network-ports/1.0.2/samples/psp-host-network-ports/example_disallowed.yaml new file mode 100644 index 000000000..9a496cd60 --- /dev/null +++ b/artifacthub/library/pod-security-policy/host-network-ports/1.0.2/samples/psp-host-network-ports/example_disallowed.yaml @@ -0,0 +1,14 @@ +apiVersion: v1 +kind: Pod +metadata: + name: nginx-host-networking-ports-disallowed + labels: + app: nginx-host-networking-ports +spec: + hostNetwork: true + containers: + - name: nginx + image: nginx + ports: + - containerPort: 9001 + hostPort: 9001 diff --git a/artifacthub/library/pod-security-policy/host-network-ports/1.0.2/samples/psp-host-network-ports/update.yaml b/artifacthub/library/pod-security-policy/host-network-ports/1.0.2/samples/psp-host-network-ports/update.yaml new file mode 100644 index 000000000..231096430 --- /dev/null +++ b/artifacthub/library/pod-security-policy/host-network-ports/1.0.2/samples/psp-host-network-ports/update.yaml @@ -0,0 +1,19 @@ +kind: AdmissionReview +apiVersion: admission.k8s.io/v1beta1 +request: + operation: "UPDATE" + object: + apiVersion: v1 + kind: Pod + metadata: + name: nginx-host-networking-ports-disallowed + labels: + app: nginx-host-networking-ports + spec: + hostNetwork: true + containers: + - name: nginx + image: nginx + ports: + - containerPort: 9001 + hostPort: 9001 diff --git a/artifacthub/library/pod-security-policy/host-network-ports/1.0.2/suite.yaml b/artifacthub/library/pod-security-policy/host-network-ports/1.0.2/suite.yaml new file mode 100644 index 000000000..710df69eb --- /dev/null +++ b/artifacthub/library/pod-security-policy/host-network-ports/1.0.2/suite.yaml @@ -0,0 +1,25 @@ +kind: Suite +apiVersion: test.gatekeeper.sh/v1alpha1 +metadata: + name: host-network-ports +tests: +- name: use-of-host-networking-ports-blocked + template: template.yaml + constraint: samples/psp-host-network-ports/constraint.yaml + cases: + - name: example-disallowed + object: samples/psp-host-network-ports/example_disallowed.yaml + assertions: + - violations: yes + - name: example-allowed + object: samples/psp-host-network-ports/example_allowed.yaml + assertions: + - violations: no + - name: disallowed-ephemeral + object: samples/psp-host-network-ports/disallowed_ephemeral.yaml + assertions: + - violations: yes + - name: update + object: samples/psp-host-network-ports/update.yaml + assertions: + - violations: no diff --git a/artifacthub/library/pod-security-policy/host-network-ports/1.0.2/template.yaml b/artifacthub/library/pod-security-policy/host-network-ports/1.0.2/template.yaml new file mode 100644 index 000000000..0f04aae03 --- /dev/null +++ b/artifacthub/library/pod-security-policy/host-network-ports/1.0.2/template.yaml @@ -0,0 +1,118 @@ +apiVersion: templates.gatekeeper.sh/v1 +kind: ConstraintTemplate +metadata: + name: k8spsphostnetworkingports + annotations: + metadata.gatekeeper.sh/title: "Host Networking Ports" + metadata.gatekeeper.sh/version: 1.0.2 + description: >- + Controls usage of host network namespace by pod containers. Specific + ports must be specified. Corresponds to the `hostNetwork` and + `hostPorts` fields in a PodSecurityPolicy. For more information, see + https://kubernetes.io/docs/concepts/policy/pod-security-policy/#host-namespaces +spec: + crd: + spec: + names: + kind: K8sPSPHostNetworkingPorts + validation: + # Schema for the `parameters` field + openAPIV3Schema: + type: object + description: >- + Controls usage of host network namespace by pod containers. Specific + ports must be specified. Corresponds to the `hostNetwork` and + `hostPorts` fields in a PodSecurityPolicy. For more information, see + https://kubernetes.io/docs/concepts/policy/pod-security-policy/#host-namespaces + 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 + hostNetwork: + description: "Determines if the policy allows the use of HostNetwork in the pod spec." + type: boolean + min: + description: "The start of the allowed port range, inclusive." + type: integer + max: + description: "The end of the allowed port range, inclusive." + type: integer + targets: + - target: admission.k8s.gatekeeper.sh + rego: | + package k8spsphostnetworkingports + + import data.lib.exclude_update.is_update + import data.lib.exempt_container.is_exempt + + violation[{"msg": msg, "details": {}}] { + # spec.hostNetwork field is immutable. + not is_update(input.review) + + input_share_hostnetwork(input.review.object) + msg := sprintf("The specified hostNetwork and hostPort are not allowed, pod: %v. Allowed values: %v", [input.review.object.metadata.name, input.parameters]) + } + + input_share_hostnetwork(o) { + not input.parameters.hostNetwork + o.spec.hostNetwork + } + + input_share_hostnetwork(_) { + hostPort := input_containers[_].ports[_].hostPort + hostPort < input.parameters.min + } + + input_share_hostnetwork(_) { + hostPort := input_containers[_].ports[_].hostPort + hostPort > input.parameters.max + } + + input_containers[c] { + c := input.review.object.spec.containers[_] + not is_exempt(c) + } + + input_containers[c] { + c := input.review.object.spec.initContainers[_] + not is_exempt(c) + } + + input_containers[c] { + c := input.review.object.spec.ephemeralContainers[_] + not is_exempt(c) + } + 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/proc-mount/1.0.3/README.md b/artifacthub/library/pod-security-policy/proc-mount/1.0.3/README.md new file mode 100644 index 000000000..9e45b7207 --- /dev/null +++ b/artifacthub/library/pod-security-policy/proc-mount/1.0.3/README.md @@ -0,0 +1,12 @@ +# ProcMount security context policy + +`procMount` denotes the type of proc mount to use for the containers. The default is `DefaultProcMount` which uses the container runtime defaults for readonly paths and masked paths. + +Types of proc mount are: + +- `DefaultProcMount` uses the container runtime default ProcType. Most container runtimes mask certain paths in /proc to avoid accidental security exposure of special devices or information. + +- `UnmaskedProcMount` bypasses the default masking behavior of the container runtime and ensures the newly created /proc the container stays in tact with no modifications. + +This requires the `ProcMountType` feature flag to be enabled. Set `--feature-gates=ProcMountType=true` in Kubernetes API Server to be able to use `Unmasked` procMount type (requires v1.12 and above). For more information, see +https://kubernetes.io/docs/reference/command-line-tools-reference/kube-apiserver/#options and https://kubernetes.io/docs/reference/command-line-tools-reference/feature-gates/. diff --git a/artifacthub/library/pod-security-policy/proc-mount/1.0.3/artifacthub-pkg.yml b/artifacthub/library/pod-security-policy/proc-mount/1.0.3/artifacthub-pkg.yml new file mode 100644 index 000000000..cd2ef8855 --- /dev/null +++ b/artifacthub/library/pod-security-policy/proc-mount/1.0.3/artifacthub-pkg.yml @@ -0,0 +1,22 @@ +version: 1.0.3 +name: k8spspprocmount +displayName: Proc Mount +createdAt: "2023-10-30T21:00:01Z" +description: Controls the allowed `procMount` types for the container. Corresponds to the `allowedProcMountTypes` field in a PodSecurityPolicy. For more information, see https://kubernetes.io/docs/concepts/policy/pod-security-policy/#allowedprocmounttypes +digest: f143a4f9759f7ee3e2b987948a74df1b534b55e5b30c6304aef417647cb04aef +license: Apache-2.0 +homeURL: https://open-policy-agent.github.io/gatekeeper-library/website/proc-mount +keywords: + - gatekeeper + - open-policy-agent + - policies +readme: |- + # Proc Mount + Controls the allowed `procMount` types for the container. Corresponds to the `allowedProcMountTypes` field in a PodSecurityPolicy. For more information, see https://kubernetes.io/docs/concepts/policy/pod-security-policy/#allowedprocmounttypes +install: |- + ### Usage + ```shell + kubectl apply -f https://raw.githubusercontent.com/open-policy-agent/gatekeeper-library/master/artifacthub/library/pod-security-policy/proc-mount/1.0.3/template.yaml + ``` +provider: + name: Gatekeeper Library diff --git a/artifacthub/library/pod-security-policy/proc-mount/1.0.3/kustomization.yaml b/artifacthub/library/pod-security-policy/proc-mount/1.0.3/kustomization.yaml new file mode 100644 index 000000000..7d70d11b7 --- /dev/null +++ b/artifacthub/library/pod-security-policy/proc-mount/1.0.3/kustomization.yaml @@ -0,0 +1,2 @@ +resources: + - template.yaml diff --git a/artifacthub/library/pod-security-policy/proc-mount/1.0.3/samples/psp-proc-mount/constraint.yaml b/artifacthub/library/pod-security-policy/proc-mount/1.0.3/samples/psp-proc-mount/constraint.yaml new file mode 100644 index 000000000..1d7434ac0 --- /dev/null +++ b/artifacthub/library/pod-security-policy/proc-mount/1.0.3/samples/psp-proc-mount/constraint.yaml @@ -0,0 +1,11 @@ +apiVersion: constraints.gatekeeper.sh/v1beta1 +kind: K8sPSPProcMount +metadata: + name: psp-proc-mount +spec: + match: + kinds: + - apiGroups: [""] + kinds: ["Pod"] + parameters: + procMount: Default diff --git a/artifacthub/library/pod-security-policy/proc-mount/1.0.3/samples/psp-proc-mount/disallowed_ephemeral.yaml b/artifacthub/library/pod-security-policy/proc-mount/1.0.3/samples/psp-proc-mount/disallowed_ephemeral.yaml new file mode 100644 index 000000000..4be38f45d --- /dev/null +++ b/artifacthub/library/pod-security-policy/proc-mount/1.0.3/samples/psp-proc-mount/disallowed_ephemeral.yaml @@ -0,0 +1,12 @@ +apiVersion: v1 +kind: Pod +metadata: + name: nginx-proc-mount-disallowed + labels: + app: nginx-proc-mount +spec: + ephemeralContainers: + - name: nginx + image: nginx + securityContext: + procMount: Unmasked #Default diff --git a/artifacthub/library/pod-security-policy/proc-mount/1.0.3/samples/psp-proc-mount/example_allowed.yaml b/artifacthub/library/pod-security-policy/proc-mount/1.0.3/samples/psp-proc-mount/example_allowed.yaml new file mode 100644 index 000000000..c9b13ac71 --- /dev/null +++ b/artifacthub/library/pod-security-policy/proc-mount/1.0.3/samples/psp-proc-mount/example_allowed.yaml @@ -0,0 +1,12 @@ +apiVersion: v1 +kind: Pod +metadata: + name: nginx-proc-mount-disallowed + labels: + app: nginx-proc-mount +spec: + containers: + - name: nginx + image: nginx + securityContext: + procMount: Default diff --git a/artifacthub/library/pod-security-policy/proc-mount/1.0.3/samples/psp-proc-mount/example_disallowed.yaml b/artifacthub/library/pod-security-policy/proc-mount/1.0.3/samples/psp-proc-mount/example_disallowed.yaml new file mode 100644 index 000000000..403c7cb2a --- /dev/null +++ b/artifacthub/library/pod-security-policy/proc-mount/1.0.3/samples/psp-proc-mount/example_disallowed.yaml @@ -0,0 +1,12 @@ +apiVersion: v1 +kind: Pod +metadata: + name: nginx-proc-mount-disallowed + labels: + app: nginx-proc-mount +spec: + containers: + - name: nginx + image: nginx + securityContext: + procMount: Unmasked #Default diff --git a/artifacthub/library/pod-security-policy/proc-mount/1.0.3/samples/psp-proc-mount/update.yaml b/artifacthub/library/pod-security-policy/proc-mount/1.0.3/samples/psp-proc-mount/update.yaml new file mode 100644 index 000000000..dc21b1142 --- /dev/null +++ b/artifacthub/library/pod-security-policy/proc-mount/1.0.3/samples/psp-proc-mount/update.yaml @@ -0,0 +1,17 @@ +kind: AdmissionReview +apiVersion: admission.k8s.io/v1beta1 +request: + operation: "UPDATE" + object: + apiVersion: v1 + kind: Pod + metadata: + name: nginx-proc-mount-disallowed + labels: + app: nginx-proc-mount + spec: + containers: + - name: nginx + image: nginx + securityContext: + procMount: Unmasked #Default diff --git a/artifacthub/library/pod-security-policy/proc-mount/1.0.3/suite.yaml b/artifacthub/library/pod-security-policy/proc-mount/1.0.3/suite.yaml new file mode 100644 index 000000000..501493e14 --- /dev/null +++ b/artifacthub/library/pod-security-policy/proc-mount/1.0.3/suite.yaml @@ -0,0 +1,25 @@ +kind: Suite +apiVersion: test.gatekeeper.sh/v1alpha1 +metadata: + name: proc-mount +tests: +- name: default-proc-mount-required + template: template.yaml + constraint: samples/psp-proc-mount/constraint.yaml + cases: + - name: example-disallowed + object: samples/psp-proc-mount/example_disallowed.yaml + assertions: + - violations: yes + - name: example-allowed + object: samples/psp-proc-mount/example_allowed.yaml + assertions: + - violations: no + - name: disallowed-ephemeral + object: samples/psp-proc-mount/disallowed_ephemeral.yaml + assertions: + - violations: yes + - name: update + object: samples/psp-proc-mount/update.yaml + assertions: + - violations: no diff --git a/artifacthub/library/pod-security-policy/proc-mount/1.0.3/template.yaml b/artifacthub/library/pod-security-policy/proc-mount/1.0.3/template.yaml new file mode 100644 index 000000000..5fb816793 --- /dev/null +++ b/artifacthub/library/pod-security-policy/proc-mount/1.0.3/template.yaml @@ -0,0 +1,138 @@ +apiVersion: templates.gatekeeper.sh/v1 +kind: ConstraintTemplate +metadata: + name: k8spspprocmount + annotations: + metadata.gatekeeper.sh/title: "Proc Mount" + metadata.gatekeeper.sh/version: 1.0.3 + description: >- + Controls the allowed `procMount` types for the container. Corresponds to + the `allowedProcMountTypes` field in a PodSecurityPolicy. For more + information, see + https://kubernetes.io/docs/concepts/policy/pod-security-policy/#allowedprocmounttypes +spec: + crd: + spec: + names: + kind: K8sPSPProcMount + validation: + # Schema for the `parameters` field + openAPIV3Schema: + type: object + description: >- + Controls the allowed `procMount` types for the container. Corresponds to + the `allowedProcMountTypes` field in a PodSecurityPolicy. For more + information, see + https://kubernetes.io/docs/concepts/policy/pod-security-policy/#allowedprocmounttypes + 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 + procMount: + type: string + description: >- + Defines the strategy for the security exposure of certain paths + in `/proc` by the container runtime. Setting to `Default` uses + the runtime defaults, where `Unmasked` bypasses the default + behavior. + enum: + - Default + - Unmasked + targets: + - target: admission.k8s.gatekeeper.sh + rego: | + package k8spspprocmount + + import data.lib.exclude_update.is_update + import data.lib.exempt_container.is_exempt + + violation[{"msg": msg, "details": {}}] { + # spec.containers.securityContext.procMount field is immutable. + not is_update(input.review) + + c := input_containers[_] + not is_exempt(c) + allowedProcMount := get_allowed_proc_mount(input) + not input_proc_mount_type_allowed(allowedProcMount, c) + msg := sprintf("ProcMount type is not allowed, container: %v. Allowed procMount types: %v", [c.name, allowedProcMount]) + } + + input_proc_mount_type_allowed(allowedProcMount, c) { + allowedProcMount == "default" + lower(c.securityContext.procMount) == "default" + } + input_proc_mount_type_allowed(allowedProcMount, _) { + allowedProcMount == "unmasked" + } + + input_containers[c] { + c := input.review.object.spec.containers[_] + c.securityContext.procMount + } + input_containers[c] { + c := input.review.object.spec.initContainers[_] + c.securityContext.procMount + } + input_containers[c] { + c := input.review.object.spec.ephemeralContainers[_] + c.securityContext.procMount + } + + get_allowed_proc_mount(arg) = out { + not arg.parameters + out = "default" + } + get_allowed_proc_mount(arg) = out { + not arg.parameters.procMount + out = "default" + } + get_allowed_proc_mount(arg) = out { + arg.parameters.procMount + not valid_proc_mount(arg.parameters.procMount) + out = "default" + } + get_allowed_proc_mount(arg) = out { + valid_proc_mount(arg.parameters.procMount) + out = lower(arg.parameters.procMount) + } + + valid_proc_mount(str) { + lower(str) == "default" + } + valid_proc_mount(str) { + lower(str) == "unmasked" + } + 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/seccomp/1.0.1/artifacthub-pkg.yml b/artifacthub/library/pod-security-policy/seccomp/1.0.1/artifacthub-pkg.yml new file mode 100644 index 000000000..8b14fcfcb --- /dev/null +++ b/artifacthub/library/pod-security-policy/seccomp/1.0.1/artifacthub-pkg.yml @@ -0,0 +1,22 @@ +version: 1.0.1 +name: k8spspseccomp +displayName: Seccomp +createdAt: "2023-10-30T21:00:02Z" +description: Controls the seccomp profile used by containers. Corresponds to the `seccomp.security.alpha.kubernetes.io/allowedProfileNames` annotation on a PodSecurityPolicy. For more information, see https://kubernetes.io/docs/concepts/policy/pod-security-policy/#seccomp +digest: cfa37037755930c6c076fd04a0124baa5b0918548ecccd51b1fa3a3365d5c8a1 +license: Apache-2.0 +homeURL: https://open-policy-agent.github.io/gatekeeper-library/website/seccomp +keywords: + - gatekeeper + - open-policy-agent + - policies +readme: |- + # Seccomp + Controls the seccomp profile used by containers. Corresponds to the `seccomp.security.alpha.kubernetes.io/allowedProfileNames` annotation on a PodSecurityPolicy. For more information, see https://kubernetes.io/docs/concepts/policy/pod-security-policy/#seccomp +install: |- + ### Usage + ```shell + kubectl apply -f https://raw.githubusercontent.com/open-policy-agent/gatekeeper-library/master/artifacthub/library/pod-security-policy/seccomp/1.0.1/template.yaml + ``` +provider: + name: Gatekeeper Library diff --git a/artifacthub/library/pod-security-policy/seccomp/1.0.1/kustomization.yaml b/artifacthub/library/pod-security-policy/seccomp/1.0.1/kustomization.yaml new file mode 100644 index 000000000..7d70d11b7 --- /dev/null +++ b/artifacthub/library/pod-security-policy/seccomp/1.0.1/kustomization.yaml @@ -0,0 +1,2 @@ +resources: + - template.yaml diff --git a/artifacthub/library/pod-security-policy/seccomp/1.0.1/samples/psp-seccomp/constraint.yaml b/artifacthub/library/pod-security-policy/seccomp/1.0.1/samples/psp-seccomp/constraint.yaml new file mode 100644 index 000000000..d26af154e --- /dev/null +++ b/artifacthub/library/pod-security-policy/seccomp/1.0.1/samples/psp-seccomp/constraint.yaml @@ -0,0 +1,13 @@ +apiVersion: constraints.gatekeeper.sh/v1beta1 +kind: K8sPSPSeccomp +metadata: + name: psp-seccomp +spec: + match: + kinds: + - apiGroups: [""] + kinds: ["Pod"] + parameters: + allowedProfiles: + - runtime/default + - docker/default diff --git a/artifacthub/library/pod-security-policy/seccomp/1.0.1/samples/psp-seccomp/disallowed_ephemeral.yaml b/artifacthub/library/pod-security-policy/seccomp/1.0.1/samples/psp-seccomp/disallowed_ephemeral.yaml new file mode 100644 index 000000000..1555d700e --- /dev/null +++ b/artifacthub/library/pod-security-policy/seccomp/1.0.1/samples/psp-seccomp/disallowed_ephemeral.yaml @@ -0,0 +1,12 @@ +apiVersion: v1 +kind: Pod +metadata: + name: nginx-seccomp-disallowed + annotations: + container.seccomp.security.alpha.kubernetes.io/nginx: unconfined + labels: + app: nginx-seccomp +spec: + ephemeralContainers: + - name: nginx + image: nginx diff --git a/artifacthub/library/pod-security-policy/seccomp/1.0.1/samples/psp-seccomp/example_allowed.yaml b/artifacthub/library/pod-security-policy/seccomp/1.0.1/samples/psp-seccomp/example_allowed.yaml new file mode 100644 index 000000000..2ff43d307 --- /dev/null +++ b/artifacthub/library/pod-security-policy/seccomp/1.0.1/samples/psp-seccomp/example_allowed.yaml @@ -0,0 +1,12 @@ +apiVersion: v1 +kind: Pod +metadata: + name: nginx-seccomp-allowed + annotations: + container.seccomp.security.alpha.kubernetes.io/nginx: runtime/default + labels: + app: nginx-seccomp +spec: + containers: + - name: nginx + image: nginx diff --git a/artifacthub/library/pod-security-policy/seccomp/1.0.1/samples/psp-seccomp/example_allowed2.yaml b/artifacthub/library/pod-security-policy/seccomp/1.0.1/samples/psp-seccomp/example_allowed2.yaml new file mode 100644 index 000000000..f8766e774 --- /dev/null +++ b/artifacthub/library/pod-security-policy/seccomp/1.0.1/samples/psp-seccomp/example_allowed2.yaml @@ -0,0 +1,12 @@ +apiVersion: v1 +kind: Pod +metadata: + name: nginx-seccomp-allowed2 + annotations: + seccomp.security.alpha.kubernetes.io/pod: runtime/default + labels: + app: nginx-seccomp +spec: + containers: + - name: nginx + image: nginx diff --git a/artifacthub/library/pod-security-policy/seccomp/1.0.1/samples/psp-seccomp/example_disallowed.yaml b/artifacthub/library/pod-security-policy/seccomp/1.0.1/samples/psp-seccomp/example_disallowed.yaml new file mode 100644 index 000000000..8e94ca7e6 --- /dev/null +++ b/artifacthub/library/pod-security-policy/seccomp/1.0.1/samples/psp-seccomp/example_disallowed.yaml @@ -0,0 +1,12 @@ +apiVersion: v1 +kind: Pod +metadata: + name: nginx-seccomp-disallowed + annotations: + container.seccomp.security.alpha.kubernetes.io/nginx: unconfined + labels: + app: nginx-seccomp +spec: + containers: + - name: nginx + image: nginx diff --git a/artifacthub/library/pod-security-policy/seccomp/1.0.1/samples/psp-seccomp/example_disallowed2.yaml b/artifacthub/library/pod-security-policy/seccomp/1.0.1/samples/psp-seccomp/example_disallowed2.yaml new file mode 100644 index 000000000..6008d8f72 --- /dev/null +++ b/artifacthub/library/pod-security-policy/seccomp/1.0.1/samples/psp-seccomp/example_disallowed2.yaml @@ -0,0 +1,12 @@ +apiVersion: v1 +kind: Pod +metadata: + name: nginx-seccomp-disallowed2 + annotations: + seccomp.security.alpha.kubernetes.io/pod: unconfined + labels: + app: nginx-seccomp +spec: + containers: + - name: nginx + image: nginx diff --git a/artifacthub/library/pod-security-policy/seccomp/1.0.1/suite.yaml b/artifacthub/library/pod-security-policy/seccomp/1.0.1/suite.yaml new file mode 100644 index 000000000..62336b26e --- /dev/null +++ b/artifacthub/library/pod-security-policy/seccomp/1.0.1/suite.yaml @@ -0,0 +1,32 @@ +kind: Suite +apiVersion: test.gatekeeper.sh/v1alpha1 +metadata: + name: seccomp +tests: +- name: default-seccomp-required + template: template.yaml + constraint: samples/psp-seccomp/constraint.yaml + cases: + - name: example-disallowed-global + object: samples/psp-seccomp/example_disallowed2.yaml + assertions: + - violations: 1 + message: "Seccomp profile 'unconfined' is not allowed for container 'nginx'. Found at: annotation seccomp.security.alpha.kubernetes.io/pod" + - name: example-disallowed-container + object: samples/psp-seccomp/example_disallowed.yaml + assertions: + - violations: 1 + message: "Seccomp profile 'unconfined' is not allowed for container 'nginx'. Found at: annotation container.seccomp.security.alpha.kubernetes.io/nginx" + - name: example-allowed-container + object: samples/psp-seccomp/example_allowed.yaml + assertions: + - violations: no + - name: example-allowed-global + object: samples/psp-seccomp/example_allowed2.yaml + assertions: + - violations: no + - name: disallowed-ephemeral + object: samples/psp-seccomp/disallowed_ephemeral.yaml + assertions: + - violations: 1 + message: "Seccomp profile 'unconfined' is not allowed for container 'nginx'. Found at: annotation container.seccomp.security.alpha.kubernetes.io/nginx" diff --git a/artifacthub/library/pod-security-policy/seccomp/1.0.1/template.yaml b/artifacthub/library/pod-security-policy/seccomp/1.0.1/template.yaml new file mode 100644 index 000000000..d252a1ace --- /dev/null +++ b/artifacthub/library/pod-security-policy/seccomp/1.0.1/template.yaml @@ -0,0 +1,281 @@ +apiVersion: templates.gatekeeper.sh/v1 +kind: ConstraintTemplate +metadata: + name: k8spspseccomp + annotations: + metadata.gatekeeper.sh/title: "Seccomp" + metadata.gatekeeper.sh/version: 1.0.1 + description: >- + Controls the seccomp profile used by containers. Corresponds to the + `seccomp.security.alpha.kubernetes.io/allowedProfileNames` annotation on + a PodSecurityPolicy. For more information, see + https://kubernetes.io/docs/concepts/policy/pod-security-policy/#seccomp +spec: + crd: + spec: + names: + kind: K8sPSPSeccomp + validation: + # Schema for the `parameters` field + openAPIV3Schema: + type: object + description: >- + Controls the seccomp profile used by containers. Corresponds to the + `seccomp.security.alpha.kubernetes.io/allowedProfileNames` annotation on + a PodSecurityPolicy. For more information, see + https://kubernetes.io/docs/concepts/policy/pod-security-policy/#seccomp + 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 + allowedProfiles: + type: array + description: >- + An array of allowed profile values for seccomp on Pods/Containers. + + Can use the annotation naming scheme: `runtime/default`, `docker/default`, `unconfined` and/or + `localhost/some-profile.json`. The item `localhost/*` will allow any localhost based profile. + + Can also use the securityContext naming scheme: `RuntimeDefault`, `Unconfined` + and/or `Localhost`. For securityContext `Localhost`, use the parameter `allowedLocalhostProfiles` + to list the allowed profile JSON files. + + The policy code will translate between the two schemes so it is not necessary to use both. + + Putting a `*` in this array allows all Profiles to be used. + + This field is required since with an empty list this policy will block all workloads. + items: + type: string + allowedLocalhostFiles: + type: array + description: >- + When using securityContext naming scheme for seccomp and including `Localhost` this array holds + the allowed profile JSON files. + + Putting a `*` in this array will allows all JSON files to be used. + + This field is required to allow `Localhost` in securityContext as with an empty list it will block. + items: + type: string + targets: + - target: admission.k8s.gatekeeper.sh + rego: | + package k8spspseccomp + + import data.lib.exempt_container.is_exempt + + container_annotation_key_prefix = "container.seccomp.security.alpha.kubernetes.io/" + + pod_annotation_key = "seccomp.security.alpha.kubernetes.io/pod" + + naming_translation = { + # securityContext -> annotation + "RuntimeDefault": ["runtime/default", "docker/default"], + "Unconfined": ["unconfined"], + "Localhost": ["localhost"], + # annotation -> securityContext + "runtime/default": ["RuntimeDefault"], + "docker/default": ["RuntimeDefault"], + "unconfined": ["Unconfined"], + "localhost": ["Localhost"], + } + + violation[{"msg": msg}] { + not input_wildcard_allowed_profiles + allowed_profiles := get_allowed_profiles + container := input_containers[name] + not is_exempt(container) + result := get_profile(container) + not allowed_profile(result.profile, result.file, allowed_profiles) + msg := get_message(result.profile, result.file, name, result.location, allowed_profiles) + } + + get_message(profile, _, name, location, allowed_profiles) = message { + not profile == "Localhost" + message := sprintf("Seccomp profile '%v' is not allowed for container '%v'. Found at: %v. Allowed profiles: %v", [profile, name, location, allowed_profiles]) + } + + get_message(profile, file, name, location, allowed_profiles) = message { + profile == "Localhost" + message := sprintf("Seccomp profile '%v' with file '%v' is not allowed for container '%v'. Found at: %v. Allowed profiles: %v", [profile, file, name, location, allowed_profiles]) + } + + input_wildcard_allowed_profiles { + input.parameters.allowedProfiles[_] == "*" + } + + input_wildcard_allowed_files { + input.parameters.allowedLocalhostFiles[_] == "*" + } + + input_wildcard_allowed_files { + "localhost/*" == input.parameters.allowedProfiles[_] + } + + # Simple allowed Profiles + allowed_profile(profile, _, allowed) { + not startswith(lower(profile), "localhost") + profile == allowed[_] + } + + # seccomp Localhost without wildcard + allowed_profile(profile, file, allowed) { + profile == "Localhost" + not input_wildcard_allowed_files + profile == allowed[_] + allowed_files := {x | x := object.get(input.parameters, "allowedLocalhostFiles", [])[_]} | get_annotation_localhost_files + file == allowed_files[_] + } + + # seccomp Localhost with wildcard + allowed_profile(profile, _, allowed) { + profile == "Localhost" + input_wildcard_allowed_files + profile == allowed[_] + } + + # annotation localhost with wildcard + allowed_profile(profile, _, allowed) { + "localhost/*" == allowed[_] + startswith(profile, "localhost/") + } + + # annotation localhost without wildcard + allowed_profile(profile, _, allowed) { + startswith(profile, "localhost/") + profile == allowed[_] + } + + # Localhost files from annotation scheme + get_annotation_localhost_files[file] { + profile := input.parameters.allowedProfiles[_] + startswith(profile, "localhost/") + file := replace(profile, "localhost/", "") + } + + # The profiles explicitly in the list + get_allowed_profiles[allowed] { + allowed := input.parameters.allowedProfiles[_] + } + + # The simply translated profiles + get_allowed_profiles[allowed] { + profile := input.parameters.allowedProfiles[_] + not startswith(lower(profile), "localhost") + allowed := naming_translation[profile][_] + } + + # Seccomp Localhost to annotation translation + get_allowed_profiles[allowed] { + profile := input.parameters.allowedProfiles[_] + profile == "Localhost" + file := object.get(input.parameters, "allowedLocalhostFiles", [])[_] + allowed := sprintf("%v/%v", [naming_translation[profile][_], file]) + } + + # Annotation localhost to Seccomp translation + get_allowed_profiles[allowed] { + profile := input.parameters.allowedProfiles[_] + startswith(profile, "localhost") + allowed := naming_translation.localhost[_] + } + + # Container profile as defined in pod annotation + get_profile(container) = {"profile": profile, "file": "", "location": location} { + not has_securitycontext_container(container) + not has_annotation(get_container_annotation_key(container.name)) + not has_securitycontext_pod + profile := input.review.object.metadata.annotations[pod_annotation_key] + location := sprintf("annotation %v", [pod_annotation_key]) + } + + # Container profile as defined in container annotation + get_profile(container) = {"profile": profile, "file": "", "location": location} { + not has_securitycontext_container(container) + not has_securitycontext_pod + container_annotation := get_container_annotation_key(container.name) + has_annotation(container_annotation) + profile := input.review.object.metadata.annotations[container_annotation] + location := sprintf("annotation %v", [container_annotation]) + } + + # Container profile as defined in pods securityContext + get_profile(container) = {"profile": profile, "file": file, "location": location} { + not has_securitycontext_container(container) + profile := input.review.object.spec.securityContext.seccompProfile.type + file := object.get(input.review.object.spec.securityContext.seccompProfile, "localhostProfile", "") + location := "pod securityContext" + } + + # Container profile as defined in containers securityContext + get_profile(container) = {"profile": profile, "file": file, "location": location} { + has_securitycontext_container(container) + profile := container.securityContext.seccompProfile.type + file := object.get(container.securityContext.seccompProfile, "localhostProfile", "") + location := "container securityContext" + } + + # Container profile missing + get_profile(container) = {"profile": "not configured", "file": "", "location": "no explicit profile found"} { + not has_annotation(get_container_annotation_key(container.name)) + not has_annotation(pod_annotation_key) + not has_securitycontext_pod + not has_securitycontext_container(container) + } + + has_annotation(annotation) { + input.review.object.metadata.annotations[annotation] + } + + has_securitycontext_pod { + input.review.object.spec.securityContext.seccompProfile + } + + has_securitycontext_container(container) { + container.securityContext.seccompProfile + } + + get_container_annotation_key(name) = annotation { + annotation := concat("", [container_annotation_key_prefix, name]) + } + + input_containers[container.name] = container { + container := input.review.object.spec.containers[_] + } + + input_containers[container.name] = container { + container := input.review.object.spec.initContainers[_] + } + + input_containers[container.name] = container { + container := input.review.object.spec.ephemeralContainers[_] + } + libs: + - | + 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/selinux/1.0.2/artifacthub-pkg.yml b/artifacthub/library/pod-security-policy/selinux/1.0.2/artifacthub-pkg.yml new file mode 100644 index 000000000..4b7ae97a0 --- /dev/null +++ b/artifacthub/library/pod-security-policy/selinux/1.0.2/artifacthub-pkg.yml @@ -0,0 +1,22 @@ +version: 1.0.2 +name: k8spspselinuxv2 +displayName: SELinux V2 +createdAt: "2023-10-30T21:00:02Z" +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: a472297f77af518459c368a2bf1c38c0fe6023f492fc6796fde75ad7a4ea131f +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.0.2/template.yaml + ``` +provider: + name: Gatekeeper Library diff --git a/artifacthub/library/pod-security-policy/selinux/1.0.2/kustomization.yaml b/artifacthub/library/pod-security-policy/selinux/1.0.2/kustomization.yaml new file mode 100644 index 000000000..7d70d11b7 --- /dev/null +++ b/artifacthub/library/pod-security-policy/selinux/1.0.2/kustomization.yaml @@ -0,0 +1,2 @@ +resources: + - template.yaml diff --git a/artifacthub/library/pod-security-policy/selinux/1.0.2/samples/psp-selinux-v2/constraint.yaml b/artifacthub/library/pod-security-policy/selinux/1.0.2/samples/psp-selinux-v2/constraint.yaml new file mode 100644 index 000000000..f88bbcd69 --- /dev/null +++ b/artifacthub/library/pod-security-policy/selinux/1.0.2/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.0.2/samples/psp-selinux-v2/disallowed_ephemeral.yaml b/artifacthub/library/pod-security-policy/selinux/1.0.2/samples/psp-selinux-v2/disallowed_ephemeral.yaml new file mode 100644 index 000000000..3a35fc737 --- /dev/null +++ b/artifacthub/library/pod-security-policy/selinux/1.0.2/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.0.2/samples/psp-selinux-v2/example_allowed.yaml b/artifacthub/library/pod-security-policy/selinux/1.0.2/samples/psp-selinux-v2/example_allowed.yaml new file mode 100644 index 000000000..4eaf2dc92 --- /dev/null +++ b/artifacthub/library/pod-security-policy/selinux/1.0.2/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.0.2/samples/psp-selinux-v2/example_disallowed.yaml b/artifacthub/library/pod-security-policy/selinux/1.0.2/samples/psp-selinux-v2/example_disallowed.yaml new file mode 100644 index 000000000..7eb7fee11 --- /dev/null +++ b/artifacthub/library/pod-security-policy/selinux/1.0.2/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.0.2/samples/psp-selinux-v2/update.yaml b/artifacthub/library/pod-security-policy/selinux/1.0.2/samples/psp-selinux-v2/update.yaml new file mode 100644 index 000000000..581419e9d --- /dev/null +++ b/artifacthub/library/pod-security-policy/selinux/1.0.2/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.0.2/suite.yaml b/artifacthub/library/pod-security-policy/selinux/1.0.2/suite.yaml new file mode 100644 index 000000000..1bbaf360e --- /dev/null +++ b/artifacthub/library/pod-security-policy/selinux/1.0.2/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.0.2/template.yaml b/artifacthub/library/pod-security-policy/selinux/1.0.2/template.yaml new file mode 100644 index 000000000..a2a502b16 --- /dev/null +++ b/artifacthub/library/pod-security-policy/selinux/1.0.2/template.yaml @@ -0,0 +1,144 @@ +apiVersion: templates.gatekeeper.sh/v1 +kind: ConstraintTemplate +metadata: + name: k8spspselinuxv2 + annotations: + metadata.gatekeeper.sh/title: "SELinux V2" + metadata.gatekeeper.sh/version: 1.0.2 + 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 + 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/users/1.0.2/artifacthub-pkg.yml b/artifacthub/library/pod-security-policy/users/1.0.2/artifacthub-pkg.yml new file mode 100644 index 000000000..5cfa65e70 --- /dev/null +++ b/artifacthub/library/pod-security-policy/users/1.0.2/artifacthub-pkg.yml @@ -0,0 +1,22 @@ +version: 1.0.2 +name: k8spspallowedusers +displayName: Allowed Users +createdAt: "2023-10-30T21:00:02Z" +description: Controls the user and group IDs of the container and some volumes. Corresponds to the `runAsUser`, `runAsGroup`, `supplementalGroups`, and `fsGroup` fields in a PodSecurityPolicy. For more information, see https://kubernetes.io/docs/concepts/policy/pod-security-policy/#users-and-groups +digest: 485bfc85639175c748da7632863dd3c91ad7f4dbd2544d2579cb82732ee795ea +license: Apache-2.0 +homeURL: https://open-policy-agent.github.io/gatekeeper-library/website/users +keywords: + - gatekeeper + - open-policy-agent + - policies +readme: |- + # Allowed Users + Controls the user and group IDs of the container and some volumes. Corresponds to the `runAsUser`, `runAsGroup`, `supplementalGroups`, and `fsGroup` fields in a PodSecurityPolicy. For more information, see https://kubernetes.io/docs/concepts/policy/pod-security-policy/#users-and-groups +install: |- + ### Usage + ```shell + kubectl apply -f https://raw.githubusercontent.com/open-policy-agent/gatekeeper-library/master/artifacthub/library/pod-security-policy/users/1.0.2/template.yaml + ``` +provider: + name: Gatekeeper Library diff --git a/artifacthub/library/pod-security-policy/users/1.0.2/kustomization.yaml b/artifacthub/library/pod-security-policy/users/1.0.2/kustomization.yaml new file mode 100644 index 000000000..7d70d11b7 --- /dev/null +++ b/artifacthub/library/pod-security-policy/users/1.0.2/kustomization.yaml @@ -0,0 +1,2 @@ +resources: + - template.yaml diff --git a/artifacthub/library/pod-security-policy/users/1.0.2/samples/psp-pods-allowed-user-ranges/constraint.yaml b/artifacthub/library/pod-security-policy/users/1.0.2/samples/psp-pods-allowed-user-ranges/constraint.yaml new file mode 100644 index 000000000..e69974578 --- /dev/null +++ b/artifacthub/library/pod-security-policy/users/1.0.2/samples/psp-pods-allowed-user-ranges/constraint.yaml @@ -0,0 +1,30 @@ +apiVersion: constraints.gatekeeper.sh/v1beta1 +kind: K8sPSPAllowedUsers +metadata: + name: psp-pods-allowed-user-ranges +spec: + match: + kinds: + - apiGroups: [""] + kinds: ["Pod"] + parameters: + runAsUser: + rule: MustRunAs # MustRunAsNonRoot # RunAsAny + ranges: + - min: 100 + max: 200 + runAsGroup: + rule: MustRunAs # MayRunAs # RunAsAny + ranges: + - min: 100 + max: 200 + supplementalGroups: + rule: MustRunAs # MayRunAs # RunAsAny + ranges: + - min: 100 + max: 200 + fsGroup: + rule: MustRunAs # MayRunAs # RunAsAny + ranges: + - min: 100 + max: 200 diff --git a/artifacthub/library/pod-security-policy/users/1.0.2/samples/psp-pods-allowed-user-ranges/disallowed_ephemeral.yaml b/artifacthub/library/pod-security-policy/users/1.0.2/samples/psp-pods-allowed-user-ranges/disallowed_ephemeral.yaml new file mode 100644 index 000000000..6297f0dfd --- /dev/null +++ b/artifacthub/library/pod-security-policy/users/1.0.2/samples/psp-pods-allowed-user-ranges/disallowed_ephemeral.yaml @@ -0,0 +1,17 @@ +apiVersion: v1 +kind: Pod +metadata: + name: nginx-users-disallowed + labels: + app: nginx-users +spec: + securityContext: + supplementalGroups: + - 250 + fsGroup: 250 + ephemeralContainers: + - name: nginx + image: nginx + securityContext: + runAsUser: 250 + runAsGroup: 250 diff --git a/artifacthub/library/pod-security-policy/users/1.0.2/samples/psp-pods-allowed-user-ranges/example_allowed.yaml b/artifacthub/library/pod-security-policy/users/1.0.2/samples/psp-pods-allowed-user-ranges/example_allowed.yaml new file mode 100644 index 000000000..79899ed98 --- /dev/null +++ b/artifacthub/library/pod-security-policy/users/1.0.2/samples/psp-pods-allowed-user-ranges/example_allowed.yaml @@ -0,0 +1,17 @@ +apiVersion: v1 +kind: Pod +metadata: + name: nginx-users-allowed + labels: + app: nginx-users +spec: + securityContext: + supplementalGroups: + - 199 + fsGroup: 199 + containers: + - name: nginx + image: nginx + securityContext: + runAsUser: 199 + runAsGroup: 199 diff --git a/artifacthub/library/pod-security-policy/users/1.0.2/samples/psp-pods-allowed-user-ranges/example_disallowed.yaml b/artifacthub/library/pod-security-policy/users/1.0.2/samples/psp-pods-allowed-user-ranges/example_disallowed.yaml new file mode 100644 index 000000000..516cce14b --- /dev/null +++ b/artifacthub/library/pod-security-policy/users/1.0.2/samples/psp-pods-allowed-user-ranges/example_disallowed.yaml @@ -0,0 +1,17 @@ +apiVersion: v1 +kind: Pod +metadata: + name: nginx-users-disallowed + labels: + app: nginx-users +spec: + securityContext: + supplementalGroups: + - 250 + fsGroup: 250 + containers: + - name: nginx + image: nginx + securityContext: + runAsUser: 250 + runAsGroup: 250 diff --git a/artifacthub/library/pod-security-policy/users/1.0.2/samples/psp-pods-allowed-user-ranges/update.yaml b/artifacthub/library/pod-security-policy/users/1.0.2/samples/psp-pods-allowed-user-ranges/update.yaml new file mode 100644 index 000000000..6f4d3ed72 --- /dev/null +++ b/artifacthub/library/pod-security-policy/users/1.0.2/samples/psp-pods-allowed-user-ranges/update.yaml @@ -0,0 +1,22 @@ +kind: AdmissionReview +apiVersion: admission.k8s.io/v1beta1 +request: + operation: "UPDATE" + object: + apiVersion: v1 + kind: Pod + metadata: + name: nginx-users-disallowed + labels: + app: nginx-users + spec: + securityContext: + supplementalGroups: + - 250 + fsGroup: 250 + containers: + - name: nginx + image: nginx + securityContext: + runAsUser: 250 + runAsGroup: 250 diff --git a/artifacthub/library/pod-security-policy/users/1.0.2/suite.yaml b/artifacthub/library/pod-security-policy/users/1.0.2/suite.yaml new file mode 100644 index 000000000..5c6e49640 --- /dev/null +++ b/artifacthub/library/pod-security-policy/users/1.0.2/suite.yaml @@ -0,0 +1,25 @@ +kind: Suite +apiVersion: test.gatekeeper.sh/v1alpha1 +metadata: + name: users +tests: +- name: users-and-groups-together + template: template.yaml + constraint: samples/psp-pods-allowed-user-ranges/constraint.yaml + cases: + - name: example-disallowed + object: samples/psp-pods-allowed-user-ranges/example_disallowed.yaml + assertions: + - violations: yes + - name: example-allowed + object: samples/psp-pods-allowed-user-ranges/example_allowed.yaml + assertions: + - violations: no + - name: disallowed-ephemeral + object: samples/psp-pods-allowed-user-ranges/disallowed_ephemeral.yaml + assertions: + - violations: yes + - name: update + object: samples/psp-pods-allowed-user-ranges/update.yaml + assertions: + - violations: no diff --git a/artifacthub/library/pod-security-policy/users/1.0.2/template.yaml b/artifacthub/library/pod-security-policy/users/1.0.2/template.yaml new file mode 100644 index 000000000..613fc9307 --- /dev/null +++ b/artifacthub/library/pod-security-policy/users/1.0.2/template.yaml @@ -0,0 +1,289 @@ +apiVersion: templates.gatekeeper.sh/v1 +kind: ConstraintTemplate +metadata: + name: k8spspallowedusers + annotations: + metadata.gatekeeper.sh/title: "Allowed Users" + metadata.gatekeeper.sh/version: 1.0.2 + description: >- + Controls the user and group IDs of the container and some volumes. + Corresponds to the `runAsUser`, `runAsGroup`, `supplementalGroups`, and + `fsGroup` fields in a PodSecurityPolicy. For more information, see + https://kubernetes.io/docs/concepts/policy/pod-security-policy/#users-and-groups +spec: + crd: + spec: + names: + kind: K8sPSPAllowedUsers + validation: + openAPIV3Schema: + type: object + description: >- + Controls the user and group IDs of the container and some volumes. + Corresponds to the `runAsUser`, `runAsGroup`, `supplementalGroups`, and + `fsGroup` fields in a PodSecurityPolicy. For more information, see + https://kubernetes.io/docs/concepts/policy/pod-security-policy/#users-and-groups + 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 + runAsUser: + type: object + description: "Controls which user ID values are allowed in a Pod or container-level SecurityContext." + properties: + rule: + type: string + description: "A strategy for applying the runAsUser restriction." + enum: + - MustRunAs + - MustRunAsNonRoot + - RunAsAny + ranges: + type: array + description: "A list of user ID ranges affected by the rule." + items: + type: object + description: "The range of user IDs affected by the rule." + properties: + min: + type: integer + description: "The minimum user ID in the range, inclusive." + max: + type: integer + description: "The maximum user ID in the range, inclusive." + runAsGroup: + type: object + description: "Controls which group ID values are allowed in a Pod or container-level SecurityContext." + properties: + rule: + type: string + description: "A strategy for applying the runAsGroup restriction." + enum: + - MustRunAs + - MayRunAs + - RunAsAny + ranges: + type: array + description: "A list of group ID ranges affected by the rule." + items: + type: object + description: "The range of group IDs affected by the rule." + properties: + min: + type: integer + description: "The minimum group ID in the range, inclusive." + max: + type: integer + description: "The maximum group ID in the range, inclusive." + supplementalGroups: + type: object + description: "Controls the supplementalGroups values that are allowed in a Pod or container-level SecurityContext." + properties: + rule: + type: string + description: "A strategy for applying the supplementalGroups restriction." + enum: + - MustRunAs + - MayRunAs + - RunAsAny + ranges: + type: array + description: "A list of group ID ranges affected by the rule." + items: + type: object + description: "The range of group IDs affected by the rule." + properties: + min: + type: integer + description: "The minimum group ID in the range, inclusive." + max: + type: integer + description: "The maximum group ID in the range, inclusive." + fsGroup: + type: object + description: "Controls the fsGroup values that are allowed in a Pod or container-level SecurityContext." + properties: + rule: + type: string + description: "A strategy for applying the fsGroup restriction." + enum: + - MustRunAs + - MayRunAs + - RunAsAny + ranges: + type: array + description: "A list of group ID ranges affected by the rule." + items: + type: object + description: "The range of group IDs affected by the rule." + properties: + min: + type: integer + description: "The minimum group ID in the range, inclusive." + max: + type: integer + description: "The maximum group ID in the range, inclusive." + targets: + - target: admission.k8s.gatekeeper.sh + rego: | + package k8spspallowedusers + + import data.lib.exclude_update.is_update + import data.lib.exempt_container.is_exempt + + violation[{"msg": msg}] { + # runAsUser, runAsGroup, supplementalGroups, fsGroup fields are immutable. + not is_update(input.review) + + fields := ["runAsUser", "runAsGroup", "supplementalGroups", "fsGroup"] + field := fields[_] + container := input_containers[_] + not is_exempt(container) + msg := get_type_violation(field, container) + } + + get_type_violation(field, container) = msg { + field == "runAsUser" + params := input.parameters[field] + msg := get_user_violation(params, container) + } + + get_type_violation(field, container) = msg { + field != "runAsUser" + params := input.parameters[field] + msg := get_violation(field, params, container) + } + + # RunAsUser (separate due to "MustRunAsNonRoot") + get_user_violation(params, container) = msg { + rule := params.rule + provided_user := get_field_value("runAsUser", container, input.review) + not accept_users(rule, provided_user) + msg := sprintf("Container %v is attempting to run as disallowed user %v. Allowed runAsUser: %v", [container.name, provided_user, params]) + } + + get_user_violation(params, container) = msg { + not get_field_value("runAsUser", container, input.review) + params.rule = "MustRunAs" + msg := sprintf("Container %v is attempting to run without a required securityContext/runAsUser", [container.name]) + } + + get_user_violation(params, container) = msg { + params.rule = "MustRunAsNonRoot" + not get_field_value("runAsUser", container, input.review) + not get_field_value("runAsNonRoot", container, input.review) + msg := sprintf("Container %v is attempting to run without a required securityContext/runAsNonRoot or securityContext/runAsUser != 0", [container.name]) + } + + accept_users("RunAsAny", _) + + accept_users("MustRunAsNonRoot", provided_user) := provided_user != 0 + + accept_users("MustRunAs", provided_user) := res { + ranges := input.parameters.runAsUser.ranges + res := is_in_range(provided_user, ranges) + } + + # Group Options + get_violation(field, params, container) = msg { + rule := params.rule + provided_value := get_field_value(field, container, input.review) + not is_array(provided_value) + not accept_value(rule, provided_value, params.ranges) + msg := sprintf("Container %v is attempting to run as disallowed group %v. Allowed %v: %v", [container.name, provided_value, field, params]) + } + # SupplementalGroups is array value + get_violation(field, params, container) = msg { + rule := params.rule + array_value := get_field_value(field, container, input.review) + is_array(array_value) + provided_value := array_value[_] + not accept_value(rule, provided_value, params.ranges) + msg := sprintf("Container %v is attempting to run with disallowed supplementalGroups %v. Allowed %v: %v", [container.name, array_value, field, params]) + } + + get_violation(field, params, container) = msg { + not get_field_value(field, container, input.review) + params.rule == "MustRunAs" + msg := sprintf("Container %v is attempting to run without a required securityContext/%v. Allowed %v: %v", [container.name, field, field, params]) + } + + accept_value("RunAsAny", _, _) + + accept_value("MayRunAs", provided_value, ranges) := is_in_range(provided_value, ranges) + + accept_value("MustRunAs", provided_value, ranges) := is_in_range(provided_value, ranges) + + + # If container level is provided, that takes precedence + get_field_value(field, container, _) := get_seccontext_field(field, container) + + # If no container level exists, use pod level + get_field_value(field, container, review) = out { + not has_seccontext_field(field, container) + review.kind.kind == "Pod" + pod_value := get_seccontext_field(field, review.object.spec) + out := pod_value + } + + # Helper Functions + is_in_range(val, ranges) = res { + matching := {1 | val >= ranges[j].min; val <= ranges[j].max} + res := count(matching) > 0 + } + + has_seccontext_field(field, obj) { + get_seccontext_field(field, obj) + } + + has_seccontext_field(field, obj) { + get_seccontext_field(field, obj) == false + } + + get_seccontext_field(field, obj) = out { + out = obj.securityContext[field] + } + + input_containers[c] { + c := input.review.object.spec.containers[_] + } + input_containers[c] { + c := input.review.object.spec.initContainers[_] + } + input_containers[c] { + c := input.review.object.spec.ephemeralContainers[_] + } + 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.0.2/artifacthub-pkg.yml b/artifacthub/library/pod-security-policy/volumes/1.0.2/artifacthub-pkg.yml new file mode 100644 index 000000000..39688ea1a --- /dev/null +++ b/artifacthub/library/pod-security-policy/volumes/1.0.2/artifacthub-pkg.yml @@ -0,0 +1,22 @@ +version: 1.0.2 +name: k8spspvolumetypes +displayName: Volume Types +createdAt: "2023-10-30T21:00:02Z" +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: e94d48090afb1d63dc8fdf84ffaa64e650a14d02244bbc9099eeab73d89ec5c6 +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.0.2/template.yaml + ``` +provider: + name: Gatekeeper Library diff --git a/artifacthub/library/pod-security-policy/volumes/1.0.2/kustomization.yaml b/artifacthub/library/pod-security-policy/volumes/1.0.2/kustomization.yaml new file mode 100644 index 000000000..7d70d11b7 --- /dev/null +++ b/artifacthub/library/pod-security-policy/volumes/1.0.2/kustomization.yaml @@ -0,0 +1,2 @@ +resources: + - template.yaml diff --git a/artifacthub/library/pod-security-policy/volumes/1.0.2/samples/psp-volume-types/constraint.yaml b/artifacthub/library/pod-security-policy/volumes/1.0.2/samples/psp-volume-types/constraint.yaml new file mode 100644 index 000000000..0638df7cb --- /dev/null +++ b/artifacthub/library/pod-security-policy/volumes/1.0.2/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.0.2/samples/psp-volume-types/example_allowed.yaml b/artifacthub/library/pod-security-policy/volumes/1.0.2/samples/psp-volume-types/example_allowed.yaml new file mode 100644 index 000000000..df6251e7d --- /dev/null +++ b/artifacthub/library/pod-security-policy/volumes/1.0.2/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.0.2/samples/psp-volume-types/example_disallowed.yaml b/artifacthub/library/pod-security-policy/volumes/1.0.2/samples/psp-volume-types/example_disallowed.yaml new file mode 100644 index 000000000..562cf59d8 --- /dev/null +++ b/artifacthub/library/pod-security-policy/volumes/1.0.2/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.0.2/samples/psp-volume-types/update.yaml b/artifacthub/library/pod-security-policy/volumes/1.0.2/samples/psp-volume-types/update.yaml new file mode 100644 index 000000000..f25f07267 --- /dev/null +++ b/artifacthub/library/pod-security-policy/volumes/1.0.2/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.0.2/suite.yaml b/artifacthub/library/pod-security-policy/volumes/1.0.2/suite.yaml new file mode 100644 index 000000000..083aad6eb --- /dev/null +++ b/artifacthub/library/pod-security-policy/volumes/1.0.2/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.0.2/template.yaml b/artifacthub/library/pod-security-policy/volumes/1.0.2/template.yaml new file mode 100644 index 000000000..74165c8f4 --- /dev/null +++ b/artifacthub/library/pod-security-policy/volumes/1.0.2/template.yaml @@ -0,0 +1,64 @@ +apiVersion: templates.gatekeeper.sh/v1 +kind: ConstraintTemplate +metadata: + name: k8spspvolumetypes + annotations: + metadata.gatekeeper.sh/title: "Volume Types" + metadata.gatekeeper.sh/version: 1.0.2 + 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 + 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/general/allowedrepos/template.yaml b/library/general/allowedrepos/template.yaml index 23ad89603..3c554d8e7 100644 --- a/library/general/allowedrepos/template.yaml +++ b/library/general/allowedrepos/template.yaml @@ -4,7 +4,7 @@ metadata: name: k8sallowedrepos annotations: metadata.gatekeeper.sh/title: "Allowed Repositories" - metadata.gatekeeper.sh/version: 1.0.0 + metadata.gatekeeper.sh/version: 1.0.1 description: >- Requires container images to begin with a string from the specified list. spec: @@ -29,21 +29,18 @@ spec: violation[{"msg": msg}] { container := input.review.object.spec.containers[_] - satisfied := [good | repo = input.parameters.repos[_] ; good = startswith(container.image, repo)] - not any(satisfied) + not strings.any_prefix_match(container.image, input.parameters.repos) msg := sprintf("container <%v> has an invalid image repo <%v>, allowed repos are %v", [container.name, container.image, input.parameters.repos]) } violation[{"msg": msg}] { container := input.review.object.spec.initContainers[_] - satisfied := [good | repo = input.parameters.repos[_] ; good = startswith(container.image, repo)] - not any(satisfied) + not strings.any_prefix_match(container.image, input.parameters.repos) msg := sprintf("initContainer <%v> has an invalid image repo <%v>, allowed repos are %v", [container.name, container.image, input.parameters.repos]) } violation[{"msg": msg}] { container := input.review.object.spec.ephemeralContainers[_] - satisfied := [good | repo = input.parameters.repos[_] ; good = startswith(container.image, repo)] - not any(satisfied) + not strings.any_prefix_match(container.image, input.parameters.repos) msg := sprintf("ephemeralContainer <%v> has an invalid image repo <%v>, allowed repos are %v", [container.name, container.image, input.parameters.repos]) } diff --git a/library/general/containerlimits/template.yaml b/library/general/containerlimits/template.yaml index 8e6867240..4b254c663 100644 --- a/library/general/containerlimits/template.yaml +++ b/library/general/containerlimits/template.yaml @@ -4,7 +4,7 @@ metadata: name: k8scontainerlimits annotations: metadata.gatekeeper.sh/title: "Container Limits" - metadata.gatekeeper.sh/version: 1.0.0 + metadata.gatekeeper.sh/version: 1.0.1 description: >- Requires containers to have memory and CPU limits set and constrains limits to be within the specified maximum values. @@ -65,7 +65,7 @@ spec: canonify_cpu(orig) = new { not is_number(orig) not endswith(orig, "m") - re_match("^[0-9]+(\\.[0-9]+)?$", orig) + regex.match("^[0-9]+(\\.[0-9]+)?$", orig) new := to_number(orig) * 1000 } @@ -162,7 +162,7 @@ spec: not is_number(orig) suffix := get_suffix(orig) raw := replace(orig, suffix, "") - re_match("^[0-9]+(\\.[0-9]+)?$", raw) + regex.match("^[0-9]+(\\.[0-9]+)?$", raw) new := to_number(raw) * mem_multiple(suffix) } diff --git a/library/general/containerrequests/template.yaml b/library/general/containerrequests/template.yaml index 5a78959bb..a67e8b786 100644 --- a/library/general/containerrequests/template.yaml +++ b/library/general/containerrequests/template.yaml @@ -4,7 +4,7 @@ metadata: name: k8scontainerrequests annotations: metadata.gatekeeper.sh/title: "Container Requests" - metadata.gatekeeper.sh/version: 1.0.0 + metadata.gatekeeper.sh/version: 1.0.1 description: >- Requires containers to have memory and CPU requests set and constrains requests to be within the specified maximum values. @@ -65,7 +65,7 @@ spec: canonify_cpu(orig) = new { not is_number(orig) not endswith(orig, "m") - re_match("^[0-9]+(\\.[0-9]+)?$", orig) + regex.match("^[0-9]+(\\.[0-9]+)?$", orig) new := to_number(orig) * 1000 } @@ -162,7 +162,7 @@ spec: not is_number(orig) suffix := get_suffix(orig) raw := replace(orig, suffix, "") - re_match("^[0-9]+(\\.[0-9]+)?$", raw) + regex.match("^[0-9]+(\\.[0-9]+)?$", raw) new := to_number(raw) * mem_multiple(suffix) } diff --git a/library/general/containerresourceratios/template.yaml b/library/general/containerresourceratios/template.yaml index 5b79df483..94a9753aa 100644 --- a/library/general/containerresourceratios/template.yaml +++ b/library/general/containerresourceratios/template.yaml @@ -4,7 +4,7 @@ metadata: name: k8scontainerratios annotations: metadata.gatekeeper.sh/title: "Container Ratios" - metadata.gatekeeper.sh/version: 1.0.0 + metadata.gatekeeper.sh/version: 1.0.1 description: >- Sets a maximum ratio for container resource limits to requests. @@ -68,14 +68,14 @@ spec: canonify_cpu(orig) = new { not is_number(orig) not endswith(orig, "m") - re_match("^[0-9]+$", orig) + regex.match("^[0-9]+$", orig) new := to_number(orig) * 1000 } canonify_cpu(orig) = new { not is_number(orig) not endswith(orig, "m") - re_match("^[0-9]+[.][0-9]+$", orig) + regex.match("^[0-9]+[.][0-9]+$", orig) new := to_number(orig) * 1000 } @@ -172,7 +172,7 @@ spec: not is_number(orig) suffix := get_suffix(orig) raw := replace(orig, suffix, "") - re_match("^[0-9]+(\\.[0-9]+)?$", raw) + regex.match("^[0-9]+(\\.[0-9]+)?$", raw) new := to_number(raw) * mem_multiple(suffix) } diff --git a/library/general/disallowedtags/template.yaml b/library/general/disallowedtags/template.yaml index 79100e1ca..43651dd0c 100644 --- a/library/general/disallowedtags/template.yaml +++ b/library/general/disallowedtags/template.yaml @@ -4,7 +4,7 @@ metadata: name: k8sdisallowedtags annotations: metadata.gatekeeper.sh/title: "Disallow tags" - metadata.gatekeeper.sh/version: 1.0.0 + metadata.gatekeeper.sh/version: 1.0.1 description: >- Requires container images to have an image tag different from the ones in the specified list. @@ -44,16 +44,15 @@ spec: violation[{"msg": msg}] { container := input_containers[_] not is_exempt(container) - tags := [forbid | tag = input.parameters.tags[_] ; forbid = endswith(container.image, concat(":", ["", tag]))] - any(tags) + tags := [tag_with_prefix | tag := input.parameters.tags[_]; tag_with_prefix := concat(":", ["", tag])] + strings.any_suffix_match(container.image, tags) msg := sprintf("container <%v> uses a disallowed tag <%v>; disallowed tags are %v", [container.name, container.image, input.parameters.tags]) } violation[{"msg": msg}] { container := input_containers[_] not is_exempt(container) - tag := [contains(container.image, ":")] - not all(tag) + not contains(container.image, ":") msg := sprintf("container <%v> didn't specify an image tag <%v>", [container.name, container.image]) } diff --git a/library/general/ephemeralstoragelimit/template.yaml b/library/general/ephemeralstoragelimit/template.yaml index 2f7bf1b2b..a9dca71d2 100644 --- a/library/general/ephemeralstoragelimit/template.yaml +++ b/library/general/ephemeralstoragelimit/template.yaml @@ -4,7 +4,7 @@ metadata: name: k8scontainerephemeralstoragelimit annotations: metadata.gatekeeper.sh/title: "Container ephemeral storage limit" - metadata.gatekeeper.sh/version: 1.0.1 + metadata.gatekeeper.sh/version: 1.0.2 description: >- Requires containers to have an ephemeral storage limit set and constrains the limit to be within the specified maximum values. @@ -146,7 +146,7 @@ spec: not is_number(orig) suffix := get_suffix(orig) raw := replace(orig, suffix, "") - re_match("^[0-9]+(\\.[0-9]+)?$", raw) + regex.match("^[0-9]+(\\.[0-9]+)?$", raw) new := to_number(raw) * storage_multiple(suffix) } diff --git a/library/general/httpsonly/template.yaml b/library/general/httpsonly/template.yaml index c7698c150..5293fe72c 100644 --- a/library/general/httpsonly/template.yaml +++ b/library/general/httpsonly/template.yaml @@ -4,7 +4,7 @@ metadata: name: k8shttpsonly annotations: metadata.gatekeeper.sh/title: "HTTPS Only" - metadata.gatekeeper.sh/version: 1.0.1 + metadata.gatekeeper.sh/version: 1.0.2 description: >- Requires Ingress resources to be HTTPS only. Ingress resources must include the `kubernetes.io/ingress.allow-http` annotation, set to `false`. @@ -39,19 +39,19 @@ spec: violation[{"msg": msg}] { input.review.object.kind == "Ingress" - re_match("^(extensions|networking.k8s.io)/", input.review.object.apiVersion) + regex.match("^(extensions|networking.k8s.io)/", input.review.object.apiVersion) ingress := input.review.object not https_complete(ingress) - not tls_is_optional(ingress) + not tls_is_optional msg := sprintf("Ingress should be https. tls configuration and allow-http=false annotation are required for %v", [ingress.metadata.name]) } violation[{"msg": msg}] { input.review.object.kind == "Ingress" - re_match("^(extensions|networking.k8s.io)/", input.review.object.apiVersion) + regex.match("^(extensions|networking.k8s.io)/", input.review.object.apiVersion) ingress := input.review.object not annotation_complete(ingress) - not tls_not_optional(ingress) + tls_is_optional msg := sprintf("Ingress should be https. The allow-http=false annotation is required for %v", [ingress.metadata.name]) } @@ -65,15 +65,7 @@ spec: ingress.metadata.annotations["kubernetes.io/ingress.allow-http"] == "false" } - tls_is_optional(ingress) = true { + tls_is_optional { parameters := object.get(input, "parameters", {}) - tlsOptional := object.get(parameters, "tlsOptional", false) - is_boolean(tlsOptional) - true == tlsOptional - } - - tls_not_optional(ingress) = true { - parameters := object.get(input, "parameters", {}) - tlsOptional := object.get(parameters, "tlsOptional", false) - true != tlsOptional + object.get(parameters, "tlsOptional", false) == true } diff --git a/library/general/imagedigests/template.yaml b/library/general/imagedigests/template.yaml index 49ac46bad..e00a4b608 100644 --- a/library/general/imagedigests/template.yaml +++ b/library/general/imagedigests/template.yaml @@ -4,7 +4,7 @@ metadata: name: k8simagedigests annotations: metadata.gatekeeper.sh/title: "Image Digests" - metadata.gatekeeper.sh/version: 1.0.0 + metadata.gatekeeper.sh/version: 1.0.1 description: >- Requires container images to contain a digest. @@ -42,24 +42,21 @@ spec: violation[{"msg": msg}] { container := input.review.object.spec.containers[_] not is_exempt(container) - satisfied := [re_match("@[a-z0-9]+([+._-][a-z0-9]+)*:[a-zA-Z0-9=_-]+", container.image)] - not all(satisfied) + not regex.match("@[a-z0-9]+([+._-][a-z0-9]+)*:[a-zA-Z0-9=_-]+", container.image) msg := sprintf("container <%v> uses an image without a digest <%v>", [container.name, container.image]) } violation[{"msg": msg}] { container := input.review.object.spec.initContainers[_] not is_exempt(container) - satisfied := [re_match("@[a-z0-9]+([+._-][a-z0-9]+)*:[a-zA-Z0-9=_-]+", container.image)] - not all(satisfied) + not regex.match("@[a-z0-9]+([+._-][a-z0-9]+)*:[a-zA-Z0-9=_-]+", container.image) msg := sprintf("initContainer <%v> uses an image without a digest <%v>", [container.name, container.image]) } violation[{"msg": msg}] { container := input.review.object.spec.ephemeralContainers[_] not is_exempt(container) - satisfied := [re_match("@[a-z0-9]+([+._-][a-z0-9]+)*:[a-zA-Z0-9=_-]+", container.image)] - not all(satisfied) + not regex.match("@[a-z0-9]+([+._-][a-z0-9]+)*:[a-zA-Z0-9=_-]+", container.image) msg := sprintf("ephemeralContainer <%v> uses an image without a digest <%v>", [container.name, container.image]) } libs: diff --git a/library/general/noupdateserviceaccount/template.yaml b/library/general/noupdateserviceaccount/template.yaml index 1855c205d..782a0d313 100644 --- a/library/general/noupdateserviceaccount/template.yaml +++ b/library/general/noupdateserviceaccount/template.yaml @@ -4,7 +4,7 @@ metadata: name: noupdateserviceaccount annotations: metadata.gatekeeper.sh/title: "Block updating Service Account" - metadata.gatekeeper.sh/version: 1.0.0 + metadata.gatekeeper.sh/version: 1.0.1 description: "Blocks updating the service account on resources that abstract over Pods. This policy is ignored in audit mode." spec: crd: @@ -30,13 +30,15 @@ spec: rego: | package noupdateserviceaccount - privileged(userInfo, allowedUsers, allowedGroups) { + privileged(userInfo, allowedUsers, _) { # Allow if the user is in allowedUsers. # Use object.get so omitted parameters can't cause policy bypass by # evaluating to undefined. username := object.get(userInfo, "username", "") allowedUsers[_] == username - } { + } + + privileged(userInfo, _, allowedGroups) { # Allow if the user's groups intersect allowedGroups. # Use object.get so omitted parameters can't cause policy bypass by # evaluating to undefined. diff --git a/library/general/replicalimits/template.yaml b/library/general/replicalimits/template.yaml index 540abc67f..2e44fb2c1 100644 --- a/library/general/replicalimits/template.yaml +++ b/library/general/replicalimits/template.yaml @@ -4,7 +4,7 @@ metadata: name: k8sreplicalimits annotations: metadata.gatekeeper.sh/title: "Replica Limits" - metadata.gatekeeper.sh/version: 1.0.1 + metadata.gatekeeper.sh/version: 1.0.2 description: >- Requires that objects with the field `spec.replicas` (Deployments, ReplicaSets, etc.) specify a number of replicas within defined ranges. @@ -46,7 +46,7 @@ spec: } input_replica_limit(spec) { - provided := input.review.object.spec.replicas + provided := spec.replicas count(input.parameters.ranges) > 0 range := input.parameters.ranges[_] value_within_range(range, provided) diff --git a/library/general/requiredannotations/template.yaml b/library/general/requiredannotations/template.yaml index f4a15e930..634acb181 100644 --- a/library/general/requiredannotations/template.yaml +++ b/library/general/requiredannotations/template.yaml @@ -4,7 +4,7 @@ metadata: name: k8srequiredannotations annotations: metadata.gatekeeper.sh/title: "Required Annotations" - metadata.gatekeeper.sh/version: 1.0.0 + metadata.gatekeeper.sh/version: 1.0.1 description: >- Requires resources to contain specified annotations, with values matching provided regular expressions. @@ -54,6 +54,6 @@ spec: expected := input.parameters.annotations[_] expected.key == key expected.allowedRegex != "" - not re_match(expected.allowedRegex, value) + not regex.match(expected.allowedRegex, value) msg := sprintf("Annotation <%v: %v> does not satisfy allowed regex: %v", [key, value, expected.allowedRegex]) } diff --git a/library/general/requiredlabels/template.yaml b/library/general/requiredlabels/template.yaml index 77323da67..aa865394c 100644 --- a/library/general/requiredlabels/template.yaml +++ b/library/general/requiredlabels/template.yaml @@ -4,7 +4,7 @@ metadata: name: k8srequiredlabels annotations: metadata.gatekeeper.sh/title: "Required Labels" - metadata.gatekeeper.sh/version: 1.0.0 + metadata.gatekeeper.sh/version: 1.0.1 description: >- Requires resources to contain specified labels, with values matching provided regular expressions. @@ -41,14 +41,11 @@ spec: rego: | package k8srequiredlabels - get_message(parameters, _default) = msg { + get_message(parameters, _default) := _default { not parameters.message - msg := _default } - get_message(parameters, _default) = msg { - msg := parameters.message - } + get_message(parameters, _) := parameters.message violation[{"msg": msg, "details": {"missing_labels": missing}}] { provided := {label | input.review.object.metadata.labels[label]} @@ -65,7 +62,7 @@ spec: expected.key == key # do not match if allowedRegex is not defined, or is an empty string expected.allowedRegex != "" - not re_match(expected.allowedRegex, value) + not regex.match(expected.allowedRegex, value) def_msg := sprintf("Label <%v: %v> does not satisfy allowed regex: %v", [key, value, expected.allowedRegex]) msg := get_message(input.parameters, def_msg) } diff --git a/library/general/uniqueingresshost/template.yaml b/library/general/uniqueingresshost/template.yaml index 2f6c2efa6..c534b2a20 100644 --- a/library/general/uniqueingresshost/template.yaml +++ b/library/general/uniqueingresshost/template.yaml @@ -4,7 +4,7 @@ metadata: name: k8suniqueingresshost annotations: metadata.gatekeeper.sh/title: "Unique Ingress Host" - metadata.gatekeeper.sh/version: 1.0.3 + metadata.gatekeeper.sh/version: 1.0.4 metadata.gatekeeper.sh/requires-sync-data: | "[ [ @@ -42,10 +42,10 @@ spec: violation[{"msg": msg}] { input.review.kind.kind == "Ingress" - re_match("^(extensions|networking.k8s.io)$", input.review.kind.group) + regex.match("^(extensions|networking.k8s.io)$", input.review.kind.group) host := input.review.object.spec.rules[_].host other := data.inventory.namespace[_][otherapiversion]["Ingress"][name] - re_match("^(extensions|networking.k8s.io)/.+$", otherapiversion) + regex.match("^(extensions|networking.k8s.io)/.+$", otherapiversion) other.spec.rules[_].host == host not identical(other, input.review) msg := sprintf("ingress host conflicts with an existing ingress <%v>", [host]) diff --git a/library/pod-security-policy/capabilities/template.yaml b/library/pod-security-policy/capabilities/template.yaml index 0df32e927..2501a1538 100644 --- a/library/pod-security-policy/capabilities/template.yaml +++ b/library/pod-security-policy/capabilities/template.yaml @@ -4,7 +4,7 @@ metadata: name: k8spspcapabilities annotations: metadata.gatekeeper.sh/title: "Capabilities" - metadata.gatekeeper.sh/version: 1.0.1 + metadata.gatekeeper.sh/version: 1.0.2 description: >- Controls Linux capabilities on containers. Corresponds to the `allowedCapabilities` and `requiredDropCapabilities` fields in a @@ -125,14 +125,11 @@ spec: count(all - dropped) > 0 } - get_default(obj, param, _default) = out { - out = obj[param] - } + get_default(obj, param, _) := obj[param] - get_default(obj, param, _default) = out { + get_default(obj, param, _default) := _default { not obj[param] not obj[param] == false - out = _default } libs: - | diff --git a/library/pod-security-policy/forbidden-sysctls/template.yaml b/library/pod-security-policy/forbidden-sysctls/template.yaml index 3d3c1d9a0..053c0eae5 100644 --- a/library/pod-security-policy/forbidden-sysctls/template.yaml +++ b/library/pod-security-policy/forbidden-sysctls/template.yaml @@ -4,7 +4,7 @@ metadata: name: k8spspforbiddensysctls annotations: metadata.gatekeeper.sh/title: "Forbidden Sysctls" - metadata.gatekeeper.sh/version: 1.1.2 + metadata.gatekeeper.sh/version: 1.1.3 description: >- Controls the `sysctl` profile used by containers. Corresponds to the `allowedUnsafeSysctls` and `forbiddenSysctls` fields in a PodSecurityPolicy. @@ -63,7 +63,7 @@ spec: } # * may be used to forbid all sysctls - forbidden_sysctl(sysctl) { + forbidden_sysctl(_) { input.parameters.forbiddenSysctls[_] == "*" } @@ -78,7 +78,7 @@ spec: } # * may be used to allow all sysctls - allowed_sysctl(sysctl) { + allowed_sysctl(_) { input.parameters.allowedSysctls[_] == "*" } diff --git a/library/pod-security-policy/fsgroup/template.yaml b/library/pod-security-policy/fsgroup/template.yaml index d3f56af81..4e1b9449a 100644 --- a/library/pod-security-policy/fsgroup/template.yaml +++ b/library/pod-security-policy/fsgroup/template.yaml @@ -4,7 +4,7 @@ metadata: name: k8spspfsgroup annotations: metadata.gatekeeper.sh/title: "FS Group" - metadata.gatekeeper.sh/version: 1.0.1 + metadata.gatekeeper.sh/version: 1.0.2 description: >- Controls allocating an FSGroup that owns the Pod's volumes. Corresponds to the `fsGroup` field in a PodSecurityPolicy. For more information, see @@ -58,7 +58,7 @@ spec: msg := sprintf("The provided pod spec fsGroup is not allowed, pod: %v. Allowed fsGroup: %v", [input.review.object.metadata.name, input.parameters]) } - input_fsGroup_allowed(spec) { + input_fsGroup_allowed(_) { # RunAsAny - No range is required. Allows any fsGroup ID to be specified. input.parameters.rule == "RunAsAny" } diff --git a/library/pod-security-policy/host-filesystem/template.yaml b/library/pod-security-policy/host-filesystem/template.yaml index 2ef796fd4..5f506c351 100644 --- a/library/pod-security-policy/host-filesystem/template.yaml +++ b/library/pod-security-policy/host-filesystem/template.yaml @@ -4,7 +4,7 @@ metadata: name: k8spsphostfilesystem annotations: metadata.gatekeeper.sh/title: "Host Filesystem" - metadata.gatekeeper.sh/version: 1.0.1 + metadata.gatekeeper.sh/version: 1.0.2 description: >- Controls usage of the host filesystem. Corresponds to the `allowedHostPaths` field in a PodSecurityPolicy. For more information, @@ -54,7 +54,7 @@ spec: msg := sprintf("HostPath volume %v is not allowed, pod: %v. Allowed path: %v", [volume, input.review.object.metadata.name, allowedPaths]) } - input_hostpath_violation(allowedPaths, volume) { + input_hostpath_violation(allowedPaths, _) { # An empty list means all host paths are blocked allowedPaths == [] } diff --git a/library/pod-security-policy/host-network-ports/template.yaml b/library/pod-security-policy/host-network-ports/template.yaml index 31a9d9e56..0f04aae03 100644 --- a/library/pod-security-policy/host-network-ports/template.yaml +++ b/library/pod-security-policy/host-network-ports/template.yaml @@ -4,7 +4,7 @@ metadata: name: k8spsphostnetworkingports annotations: metadata.gatekeeper.sh/title: "Host Networking Ports" - metadata.gatekeeper.sh/version: 1.0.1 + metadata.gatekeeper.sh/version: 1.0.2 description: >- Controls usage of host network namespace by pod containers. Specific ports must be specified. Corresponds to the `hostNetwork` and @@ -65,12 +65,12 @@ spec: o.spec.hostNetwork } - input_share_hostnetwork(o) { + input_share_hostnetwork(_) { hostPort := input_containers[_].ports[_].hostPort hostPort < input.parameters.min } - input_share_hostnetwork(o) { + input_share_hostnetwork(_) { hostPort := input_containers[_].ports[_].hostPort hostPort > input.parameters.max } diff --git a/library/pod-security-policy/proc-mount/template.yaml b/library/pod-security-policy/proc-mount/template.yaml index bbf2244da..5fb816793 100644 --- a/library/pod-security-policy/proc-mount/template.yaml +++ b/library/pod-security-policy/proc-mount/template.yaml @@ -4,7 +4,7 @@ metadata: name: k8spspprocmount annotations: metadata.gatekeeper.sh/title: "Proc Mount" - metadata.gatekeeper.sh/version: 1.0.2 + metadata.gatekeeper.sh/version: 1.0.3 description: >- Controls the allowed `procMount` types for the container. Corresponds to the `allowedProcMountTypes` field in a PodSecurityPolicy. For more @@ -68,7 +68,7 @@ spec: allowedProcMount == "default" lower(c.securityContext.procMount) == "default" } - input_proc_mount_type_allowed(allowedProcMount, c) { + input_proc_mount_type_allowed(allowedProcMount, _) { allowedProcMount == "unmasked" } diff --git a/library/pod-security-policy/seccomp/template.yaml b/library/pod-security-policy/seccomp/template.yaml index 3ed313929..d252a1ace 100644 --- a/library/pod-security-policy/seccomp/template.yaml +++ b/library/pod-security-policy/seccomp/template.yaml @@ -4,7 +4,7 @@ metadata: name: k8spspseccomp annotations: metadata.gatekeeper.sh/title: "Seccomp" - metadata.gatekeeper.sh/version: 1.0.0 + metadata.gatekeeper.sh/version: 1.0.1 description: >- Controls the seccomp profile used by containers. Corresponds to the `seccomp.security.alpha.kubernetes.io/allowedProfileNames` annotation on @@ -98,7 +98,7 @@ spec: msg := get_message(result.profile, result.file, name, result.location, allowed_profiles) } - get_message(profile, file, name, location, allowed_profiles) = message { + get_message(profile, _, name, location, allowed_profiles) = message { not profile == "Localhost" message := sprintf("Seccomp profile '%v' is not allowed for container '%v'. Found at: %v. Allowed profiles: %v", [profile, name, location, allowed_profiles]) } @@ -121,7 +121,7 @@ spec: } # Simple allowed Profiles - allowed_profile(profile, file, allowed) { + allowed_profile(profile, _, allowed) { not startswith(lower(profile), "localhost") profile == allowed[_] } @@ -136,20 +136,20 @@ spec: } # seccomp Localhost with wildcard - allowed_profile(profile, file, allowed) { + allowed_profile(profile, _, allowed) { profile == "Localhost" input_wildcard_allowed_files profile == allowed[_] } # annotation localhost with wildcard - allowed_profile(profile, file, allowed) { + allowed_profile(profile, _, allowed) { "localhost/*" == allowed[_] startswith(profile, "localhost/") } # annotation localhost without wildcard - allowed_profile(profile, file, allowed) { + allowed_profile(profile, _, allowed) { startswith(profile, "localhost/") profile == allowed[_] } diff --git a/library/pod-security-policy/selinux/template.yaml b/library/pod-security-policy/selinux/template.yaml index 61729eceb..a2a502b16 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.1 + metadata.gatekeeper.sh/version: 1.0.2 description: >- Defines an allow-list of seLinuxOptions configurations for pod containers. Corresponds to a PodSecurityPolicy requiring SELinux configs. @@ -94,7 +94,7 @@ spec: field_allowed(field, options, params) { params[field] == options[field] } - field_allowed(field, options, params) { + field_allowed(field, options, _) { not has_field(options, field) } diff --git a/library/pod-security-policy/users/template.yaml b/library/pod-security-policy/users/template.yaml index 1e572443e..613fc9307 100644 --- a/library/pod-security-policy/users/template.yaml +++ b/library/pod-security-policy/users/template.yaml @@ -4,7 +4,7 @@ metadata: name: k8spspallowedusers annotations: metadata.gatekeeper.sh/title: "Allowed Users" - metadata.gatekeeper.sh/version: 1.0.1 + metadata.gatekeeper.sh/version: 1.0.2 description: >- Controls the user and group IDs of the container and some volumes. Corresponds to the `runAsUser`, `runAsGroup`, `supplementalGroups`, and @@ -182,11 +182,11 @@ spec: msg := sprintf("Container %v is attempting to run without a required securityContext/runAsNonRoot or securityContext/runAsUser != 0", [container.name]) } - accept_users("RunAsAny", provided_user) {true} + accept_users("RunAsAny", _) - accept_users("MustRunAsNonRoot", provided_user) = res {res := provided_user != 0} + accept_users("MustRunAsNonRoot", provided_user) := provided_user != 0 - accept_users("MustRunAs", provided_user) = res { + accept_users("MustRunAs", provided_user) := res { ranges := input.parameters.runAsUser.ranges res := is_in_range(provided_user, ranges) } @@ -215,18 +215,15 @@ spec: msg := sprintf("Container %v is attempting to run without a required securityContext/%v. Allowed %v: %v", [container.name, field, field, params]) } - accept_value("RunAsAny", provided_value, ranges) {true} + accept_value("RunAsAny", _, _) - accept_value("MayRunAs", provided_value, ranges) = res { res := is_in_range(provided_value, ranges)} + accept_value("MayRunAs", provided_value, ranges) := is_in_range(provided_value, ranges) - accept_value("MustRunAs", provided_value, ranges) = res { res := is_in_range(provided_value, ranges)} + accept_value("MustRunAs", provided_value, ranges) := is_in_range(provided_value, ranges) # If container level is provided, that takes precedence - get_field_value(field, container, review) = out { - container_value := get_seccontext_field(field, container) - out := container_value - } + get_field_value(field, container, _) := get_seccontext_field(field, container) # If no container level exists, use pod level get_field_value(field, container, review) = out { diff --git a/library/pod-security-policy/volumes/template.yaml b/library/pod-security-policy/volumes/template.yaml index 458cb3178..74165c8f4 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.1 + metadata.gatekeeper.sh/version: 1.0.2 description: >- Restricts mountable volume types to those specified by the user. Corresponds to the `volumes` field in a PodSecurityPolicy. For more @@ -48,7 +48,7 @@ spec: } # * may be used to allow all volume types - input_volume_type_allowed(field) { + input_volume_type_allowed(_) { input.parameters.volumes[_] == "*" } diff --git a/src/general/allowedrepos/constraint.tmpl b/src/general/allowedrepos/constraint.tmpl index 52dac8a0d..8f0b53fd3 100644 --- a/src/general/allowedrepos/constraint.tmpl +++ b/src/general/allowedrepos/constraint.tmpl @@ -4,7 +4,7 @@ metadata: name: k8sallowedrepos annotations: metadata.gatekeeper.sh/title: "Allowed Repositories" - metadata.gatekeeper.sh/version: 1.0.0 + metadata.gatekeeper.sh/version: 1.0.1 description: >- Requires container images to begin with a string from the specified list. spec: diff --git a/src/general/allowedrepos/src.rego b/src/general/allowedrepos/src.rego index 649dafb77..37ae159de 100644 --- a/src/general/allowedrepos/src.rego +++ b/src/general/allowedrepos/src.rego @@ -2,21 +2,18 @@ package k8sallowedrepos violation[{"msg": msg}] { container := input.review.object.spec.containers[_] - satisfied := [good | repo = input.parameters.repos[_] ; good = startswith(container.image, repo)] - not any(satisfied) + not strings.any_prefix_match(container.image, input.parameters.repos) msg := sprintf("container <%v> has an invalid image repo <%v>, allowed repos are %v", [container.name, container.image, input.parameters.repos]) } violation[{"msg": msg}] { container := input.review.object.spec.initContainers[_] - satisfied := [good | repo = input.parameters.repos[_] ; good = startswith(container.image, repo)] - not any(satisfied) + not strings.any_prefix_match(container.image, input.parameters.repos) msg := sprintf("initContainer <%v> has an invalid image repo <%v>, allowed repos are %v", [container.name, container.image, input.parameters.repos]) } violation[{"msg": msg}] { container := input.review.object.spec.ephemeralContainers[_] - satisfied := [good | repo = input.parameters.repos[_] ; good = startswith(container.image, repo)] - not any(satisfied) + not strings.any_prefix_match(container.image, input.parameters.repos) msg := sprintf("ephemeralContainer <%v> has an invalid image repo <%v>, allowed repos are %v", [container.name, container.image, input.parameters.repos]) } diff --git a/src/general/allowedrepos/src_test.rego b/src/general/allowedrepos/src_test.rego index 7eede7c23..932bc4dc0 100644 --- a/src/general/allowedrepos/src_test.rego +++ b/src/general/allowedrepos/src_test.rego @@ -1,75 +1,75 @@ package k8sallowedrepos test_input_allowed_container { - input := { "review": input_review(input_container_allowed), "parameters": {"repos": ["allowed"]}} - results := violation with input as input + inp := { "review": input_review(input_container_allowed), "parameters": {"repos": ["allowed"]}} + results := violation with input as inp count(results) == 0 } test_input_allowed_container_x2 { - input := { "review": input_review(input_container_allowed), "parameters": {"repos": ["other", "allowed"]}} - results := violation with input as input + inp := { "review": input_review(input_container_allowed), "parameters": {"repos": ["other", "allowed"]}} + results := violation with input as inp count(results) == 0 } test_input_allowed_dual_container { - input := { "review": input_review(input_container_dual_allowed), "parameters": {"repos": ["allowed"]}} - results := violation with input as input + inp := { "review": input_review(input_container_dual_allowed), "parameters": {"repos": ["allowed"]}} + results := violation with input as inp count(results) == 0 } test_input_denied_container { - input := { "review": input_review(input_container_denied), "parameters": {"repos": ["allowed"]}} - results := violation with input as input + inp := { "review": input_review(input_container_denied), "parameters": {"repos": ["allowed"]}} + results := violation with input as inp count(results) == 1 } test_input_denied_container_x2 { - input := { "review": input_review(input_container_denied), "parameters": {"repos": ["other", "allowed"]}} - results := violation with input as input + inp := { "review": input_review(input_container_denied), "parameters": {"repos": ["other", "allowed"]}} + results := violation with input as inp count(results) == 1 } test_input_denied_dual_container { - input := { "review": input_review(input_container_dual_denied), "parameters": {"repos": ["allowed"]}} - results := violation with input as input + inp := { "review": input_review(input_container_dual_denied), "parameters": {"repos": ["allowed"]}} + results := violation with input as inp count(results) == 2 } test_input_denied_mixed_container { - input := { "review": input_review(array.concat(input_container_allowed, input_container_denied)), "parameters": {"repos": ["allowed"]}} - results := violation with input as input + inp := { "review": input_review(array.concat(input_container_allowed, input_container_denied)), "parameters": {"repos": ["allowed"]}} + results := violation with input as inp count(results) == 1 } # init containers test_input_allowed_container { - input := { "review": input_init_review(input_container_allowed), "parameters": {"repos": ["allowed"]}} - results := violation with input as input + inp := { "review": input_init_review(input_container_allowed), "parameters": {"repos": ["allowed"]}} + results := violation with input as inp count(results) == 0 } test_input_allowed_container_x2 { - input := { "review": input_init_review(input_container_allowed), "parameters": {"repos": ["other", "allowed"]}} - results := violation with input as input + inp := { "review": input_init_review(input_container_allowed), "parameters": {"repos": ["other", "allowed"]}} + results := violation with input as inp count(results) == 0 } test_input_allowed_dual_container { - input := { "review": input_init_review(input_container_dual_allowed), "parameters": {"repos": ["allowed"]}} - results := violation with input as input + inp := { "review": input_init_review(input_container_dual_allowed), "parameters": {"repos": ["allowed"]}} + results := violation with input as inp count(results) == 0 } test_input_denied_container { - input := { "review": input_init_review(input_container_denied), "parameters": {"repos": ["allowed"]}} - results := violation with input as input + inp := { "review": input_init_review(input_container_denied), "parameters": {"repos": ["allowed"]}} + results := violation with input as inp count(results) == 1 } test_input_denied_container_x2 { - input := { "review": input_init_review(input_container_denied), "parameters": {"repos": ["other", "allowed"]}} - results := violation with input as input + inp := { "review": input_init_review(input_container_denied), "parameters": {"repos": ["other", "allowed"]}} + results := violation with input as inp count(results) == 1 } test_input_denied_dual_container { - input := { "review": input_init_review(input_container_dual_denied), "parameters": {"repos": ["allowed"]}} - results := violation with input as input + inp := { "review": input_init_review(input_container_dual_denied), "parameters": {"repos": ["allowed"]}} + results := violation with input as inp count(results) == 2 } test_input_denied_mixed_container { - input := { "review": input_init_review(array.concat(input_container_allowed, input_container_denied)), "parameters": {"repos": ["allowed"]}} - results := violation with input as input + inp := { "review": input_init_review(array.concat(input_container_allowed, input_container_denied)), "parameters": {"repos": ["allowed"]}} + results := violation with input as inp count(results) == 1 } diff --git a/src/general/automount-serviceaccount-token/src_test.rego b/src/general/automount-serviceaccount-token/src_test.rego index ec2c75ea2..ef78ba609 100644 --- a/src/general/automount-serviceaccount-token/src_test.rego +++ b/src/general/automount-serviceaccount-token/src_test.rego @@ -1,26 +1,26 @@ package k8sautomountserviceaccounttoken test_input_pod_not_automountserviceaccounttoken_allowed { - input := {"review": input_review_disabled_automountserviceaccounttoken} - results := violation with input as input + inp := {"review": input_review_disabled_automountserviceaccounttoken} + results := violation with input as inp count(results) == 0 } test_input_pod_automountserviceaccounttoken_not_allowed { - input := {"review": input_review_enabled_automountserviceaccounttoken} - results := violation with input as input + inp := {"review": input_review_enabled_automountserviceaccounttoken} + results := violation with input as inp count(results) > 0 } test_input_pod_automountserviceaccounttoken_not_defined { - input := {"review": input_review_no_automountserviceaccounttoken_defined_and_enabled_volumemount} - results := violation with input as input + inp := {"review": input_review_no_automountserviceaccounttoken_defined_and_enabled_volumemount} + results := violation with input as inp count(results) > 0 } test_update { - input := {"review": object.union(input_review_enabled_automountserviceaccounttoken, {"operation": "UPDATE"})} - results := violation with input as input + inp := {"review": object.union(input_review_enabled_automountserviceaccounttoken, {"operation": "UPDATE"})} + results := violation with input as inp count(results) == 0 } diff --git a/src/general/block-endpoint-edit-default-role/src_test.rego b/src/general/block-endpoint-edit-default-role/src_test.rego index 8cbe0118b..5eda05194 100644 --- a/src/general/block-endpoint-edit-default-role/src_test.rego +++ b/src/general/block-endpoint-edit-default-role/src_test.rego @@ -1,32 +1,32 @@ package k8sblockendpointeditdefaultrole test_input_no_endpoints_edit_role_allow { - input := { "review": input_review_withoutendpoints } - results := violation with input as input + inp := { "review": input_review_withoutendpoints } + results := violation with input as inp count(results) == 0 } test_input_endpoints_create_role_not_allow { - input := { "review": input_review_with_endpoints_create } - results := violation with input as input + inp := { "review": input_review_with_endpoints_create } + results := violation with input as inp count(results) == 1 } test_input_endpoints_update_role_not_allow { - input := { "review": input_review_with_endpoints_update } - results := violation with input as input + inp := { "review": input_review_with_endpoints_update } + results := violation with input as inp count(results) == 1 } test_input_endpoints_patch_role_not_allow { - input := { "review": input_review_with_endpoints_patch } - results := violation with input as input + inp := { "review": input_review_with_endpoints_patch } + results := violation with input as inp count(results) == 1 } test_input_endpoints_delete_role_allow { - input := { "review": input_review_with_endpoints_delete } - results := violation with input as input + inp := { "review": input_review_with_endpoints_delete } + results := violation with input as inp count(results) == 0 } diff --git a/src/general/block-loadbalancer-services/src_test.rego b/src/general/block-loadbalancer-services/src_test.rego index 1f2272756..208f6af98 100644 --- a/src/general/block-loadbalancer-services/src_test.rego +++ b/src/general/block-loadbalancer-services/src_test.rego @@ -1,7 +1,7 @@ package k8sblockloadbalancer test_block_load_balancer { - input := { + inp := { "review": { "kind": {"kind": "Service"}, "object": { @@ -16,11 +16,11 @@ test_block_load_balancer { } } } - result := violation with input as input + result := violation with input as inp count(result) == 1 } test_allow_other_service_types { - input := { + inp := { "review": { "kind": {"kind": "Service"}, "object": { @@ -35,6 +35,6 @@ test_allow_other_service_types { } } } - result := violation with input as input + result := violation with input as inp count(result) == 0 } diff --git a/src/general/block-nodeport-services/src_test.rego b/src/general/block-nodeport-services/src_test.rego index caf13bee7..c28c314ef 100644 --- a/src/general/block-nodeport-services/src_test.rego +++ b/src/general/block-nodeport-services/src_test.rego @@ -1,7 +1,7 @@ package k8sblocknodeport test_block_node_port { - input := { + inp := { "review": { "kind": {"kind": "Service"}, "object": { @@ -16,11 +16,11 @@ test_block_node_port { } } } - result := violation with input as input + result := violation with input as inp count(result) == 1 } test_allow_other_service_types { - input := { + inp := { "review": { "kind": {"kind": "Service"}, "object": { @@ -35,6 +35,6 @@ test_allow_other_service_types { } } } - result := violation with input as input + result := violation with input as inp count(result) == 0 } diff --git a/src/general/block-wildcard-ingress/src_test.rego b/src/general/block-wildcard-ingress/src_test.rego index 9e435988b..4030e8bcf 100644 --- a/src/general/block-wildcard-ingress/src_test.rego +++ b/src/general/block-wildcard-ingress/src_test.rego @@ -1,32 +1,32 @@ package K8sBlockWildcardIngress test_input_ingress_allowed_host { - input := { "review": input_review(input_ingress_allowed_host) } - results := violation with input as input + inp := { "review": input_review(input_ingress_allowed_host) } + results := violation with input as inp count(results) == 0 } test_input_ingress_disallowed_wildcard_host { - input := { "review": input_review(input_ingress_disallowed_wildcard_host) } - results := violation with input as input + inp := { "review": input_review(input_ingress_disallowed_wildcard_host) } + results := violation with input as inp count(results) == 1 } test_input_ingress_disallowed_empty_host { - input := { "review": input_review(input_ingress_disallowed_empty_host) } - results := violation with input as input + inp := { "review": input_review(input_ingress_disallowed_empty_host) } + results := violation with input as inp count(results) == 1 } test_input_ingress_disallowed_empty_host { - input := { "review": input_review(input_ingress_disallowed_empty_host) } - results := violation with input as input + inp := { "review": input_review(input_ingress_disallowed_empty_host) } + results := violation with input as inp count(results) == 1 } test_input_ingress_no_rules { - input := { "review": input_review(input_ingress_no_rules) } - results := violation with input as input + inp := { "review": input_review(input_ingress_no_rules) } + results := violation with input as inp count(results) == 1 } diff --git a/src/general/containerlimits/constraint.tmpl b/src/general/containerlimits/constraint.tmpl index 507029b46..33b5b791d 100644 --- a/src/general/containerlimits/constraint.tmpl +++ b/src/general/containerlimits/constraint.tmpl @@ -4,7 +4,7 @@ metadata: name: k8scontainerlimits annotations: metadata.gatekeeper.sh/title: "Container Limits" - metadata.gatekeeper.sh/version: 1.0.0 + metadata.gatekeeper.sh/version: 1.0.1 description: >- Requires containers to have memory and CPU limits set and constrains limits to be within the specified maximum values. diff --git a/src/general/containerlimits/src.rego b/src/general/containerlimits/src.rego index 9124c886b..53dcaa0c6 100644 --- a/src/general/containerlimits/src.rego +++ b/src/general/containerlimits/src.rego @@ -24,7 +24,7 @@ canonify_cpu(orig) = new { canonify_cpu(orig) = new { not is_number(orig) not endswith(orig, "m") - re_match("^[0-9]+(\\.[0-9]+)?$", orig) + regex.match("^[0-9]+(\\.[0-9]+)?$", orig) new := to_number(orig) * 1000 } @@ -121,7 +121,7 @@ canonify_mem(orig) = new { not is_number(orig) suffix := get_suffix(orig) raw := replace(orig, suffix, "") - re_match("^[0-9]+(\\.[0-9]+)?$", raw) + regex.match("^[0-9]+(\\.[0-9]+)?$", raw) new := to_number(raw) * mem_multiple(suffix) } diff --git a/src/general/containerlimits/src_test.rego b/src/general/containerlimits/src_test.rego index eb879cc72..d3f983870 100644 --- a/src/general/containerlimits/src_test.rego +++ b/src/general/containerlimits/src_test.rego @@ -1,187 +1,187 @@ package k8scontainerlimits test_input_no_violations_int { - input := {"review": review([ctr("a", 10, 20)]), "parameters": {"memory": 20, "cpu": 40}} - results := violation with input as input + inp := {"review": review([ctr("a", 10, 20)]), "parameters": {"memory": 20, "cpu": 40}} + results := violation with input as inp count(results) == 0 } test_input_no_violations_str { - input := {"review": review([ctr("a", "10", "20")]), "parameters": {"memory": "20", "cpu": "40"}} - results := violation with input as input + inp := {"review": review([ctr("a", "10", "20")]), "parameters": {"memory": "20", "cpu": "40"}} + results := violation with input as inp count(results) == 0 } test_input_no_violations_str_small { - input := {"review": review([ctr("a", "1", "2")]), "parameters": {"memory": "2", "cpu": "4"}} - results := violation with input as input + inp := {"review": review([ctr("a", "1", "2")]), "parameters": {"memory": "2", "cpu": "4"}} + results := violation with input as inp count(results) == 0 } test_input_no_violations_cpu_scale { - input := {"review": review([ctr("a", "1", "2m")]), "parameters": {"memory": "2", "cpu": "4"}} - results := violation with input as input + inp := {"review": review([ctr("a", "1", "2m")]), "parameters": {"memory": "2", "cpu": "4"}} + results := violation with input as inp count(results) == 0 } test_input_violations_int { - input := {"review": review([ctr("a", 10, 20)]), "parameters": {"memory": 5, "cpu": 10}} - results := violation with input as input + inp := {"review": review([ctr("a", 10, 20)]), "parameters": {"memory": 5, "cpu": 10}} + results := violation with input as inp count(results) == 2 } test_input_violations_mem_int_v_str { - input := {"review": review([ctr("a", 10, "4")]), "parameters": {"memory": "1000m", "cpu": "4"}} - results := violation with input as input + inp := {"review": review([ctr("a", 10, "4")]), "parameters": {"memory": "1000m", "cpu": "4"}} + results := violation with input as inp count(results) == 1 } test_input_violations_str { - input := {"review": review([ctr("a", "10", "20")]), "parameters": {"memory": "5", "cpu": "10"}} - results := violation with input as input + inp := {"review": review([ctr("a", "10", "20")]), "parameters": {"memory": "5", "cpu": "10"}} + results := violation with input as inp count(results) == 2 } test_input_violations_str_small { - input := {"review": review([ctr("a", "5", "6")]), "parameters": {"memory": "2", "cpu": "4"}} - results := violation with input as input + inp := {"review": review([ctr("a", "5", "6")]), "parameters": {"memory": "2", "cpu": "4"}} + results := violation with input as inp count(results) == 2 } test_input_violations_cpu_scale { - input := {"review": review([ctr("a", "1", "2")]), "parameters": {"memory": "2", "cpu": "4m"}} - results := violation with input as input + inp := {"review": review([ctr("a", "1", "2")]), "parameters": {"memory": "2", "cpu": "4m"}} + results := violation with input as inp count(results) == 1 } test_no_parse_cpu { - input := {"review": review([ctr("a", "1", "212asdf")]), "parameters": {"memory": "2", "cpu": "4m"}} - results := violation with input as input + inp := {"review": review([ctr("a", "1", "212asdf")]), "parameters": {"memory": "2", "cpu": "4m"}} + results := violation with input as inp count(results) == 1 } test_no_parse_ram { - input := {"review": review([ctr("a", "1asdf", "2")]), "parameters": {"memory": "2", "cpu": "4"}} - results := violation with input as input + inp := {"review": review([ctr("a", "1asdf", "2")]), "parameters": {"memory": "2", "cpu": "4"}} + results := violation with input as inp count(results) == 1 } test_1_bad_cpu { - input := {"review": review([ctr("a", "1", "2"), ctr("b", "1", "8")]), "parameters": {"memory": "2", "cpu": "4"}} - results := violation with input as input + inp := {"review": review([ctr("a", "1", "2"), ctr("b", "1", "8")]), "parameters": {"memory": "2", "cpu": "4"}} + results := violation with input as inp count(results) == 1 } test_2_bad_cpu { - input := {"review": review([ctr("a", "1", "9"), ctr("b", "1", "8")]), "parameters": {"memory": "2", "cpu": "4"}} - results := violation with input as input + inp := {"review": review([ctr("a", "1", "9"), ctr("b", "1", "8")]), "parameters": {"memory": "2", "cpu": "4"}} + results := violation with input as inp count(results) == 2 } test_1_bad_ram { - input := {"review": review([ctr("a", "1", "2"), ctr("b", "8", "2")]), "parameters": {"memory": "2", "cpu": "4"}} - results := violation with input as input + inp := {"review": review([ctr("a", "1", "2"), ctr("b", "8", "2")]), "parameters": {"memory": "2", "cpu": "4"}} + results := violation with input as inp count(results) == 1 } test_2_bad_ram { - input := {"review": review([ctr("a", "9", "2"), ctr("b", "8", "2")]), "parameters": {"memory": "2", "cpu": "4"}} - results := violation with input as input + inp := {"review": review([ctr("a", "9", "2"), ctr("b", "8", "2")]), "parameters": {"memory": "2", "cpu": "4"}} + results := violation with input as inp count(results) == 2 } test_no_ram_limit { - input := {"review": review([{"name": "a", "resources": {"limits": {"cpu": 1}}}]), "parameters": {"memory": "2", "cpu": "4"}} - results := violation with input as input + inp := {"review": review([{"name": "a", "resources": {"limits": {"cpu": 1}}}]), "parameters": {"memory": "2", "cpu": "4"}} + results := violation with input as inp count(results) == 1 } test_no_cpu_limit { - input := {"review": review([{"name": "a", "resources": {"limits": {"memory": 1}}}]), "parameters": {"memory": "2", "cpu": "4"}} - results := violation with input as input + inp := {"review": review([{"name": "a", "resources": {"limits": {"memory": 1}}}]), "parameters": {"memory": "2", "cpu": "4"}} + results := violation with input as inp count(results) == 1 } test_no_limit { - input := {"review": review([{"name": "a", "resources": {}}]), "parameters": {"memory": "2", "cpu": "4"}} - results := violation with input as input + inp := {"review": review([{"name": "a", "resources": {}}]), "parameters": {"memory": "2", "cpu": "4"}} + results := violation with input as inp count(results) == 1 } test_no_resources { - input := {"review": review([{"name": "a"}]), "parameters": {"memory": "2", "cpu": "4"}} - results := violation with input as input + inp := {"review": review([{"name": "a"}]), "parameters": {"memory": "2", "cpu": "4"}} + results := violation with input as inp count(results) == 1 } test_init_containers_checked { - input := {"review": init_review([ctr("a", "5", "5"), ctr("b", "5", "5")]), "parameters": {"memory": "2", "cpu": "4"}} - results := violation with input as input + inp := {"review": init_review([ctr("a", "5", "5"), ctr("b", "5", "5")]), "parameters": {"memory": "2", "cpu": "4"}} + results := violation with input as inp count(results) == 4 } # MEM SCALE TESTS test_input_no_violations_mem_K { - input := {"review": review([ctr("a", "1", "2")]), "parameters": {"memory": "1k", "cpu": "4"}} - results := violation with input as input + inp := {"review": review([ctr("a", "1", "2")]), "parameters": {"memory": "1k", "cpu": "4"}} + results := violation with input as inp count(results) == 0 } test_input_violations_mem_m { - input := {"review": review([ctr("a", "1", "2")]), "parameters": {"memory": "1m", "cpu": "4"}} - results := violation with input as input + inp := {"review": review([ctr("a", "1", "2")]), "parameters": {"memory": "1m", "cpu": "4"}} + results := violation with input as inp count(results) == 1 } test_input_violations_mem_K { - input := {"review": review([ctr("a", "1k", "2")]), "parameters": {"memory": "1", "cpu": "4"}} - results := violation with input as input + inp := {"review": review([ctr("a", "1k", "2")]), "parameters": {"memory": "1", "cpu": "4"}} + results := violation with input as inp count(results) == 1 } test_input_violations_mem_M { - input := {"review": review([ctr("a", "1M", "2")]), "parameters": {"memory": "1k", "cpu": "4"}} - results := violation with input as input + inp := {"review": review([ctr("a", "1M", "2")]), "parameters": {"memory": "1k", "cpu": "4"}} + results := violation with input as inp count(results) == 1 } test_input_violations_mem_G { - input := {"review": review([ctr("a", "1G", "2")]), "parameters": {"memory": "1M", "cpu": "4"}} - results := violation with input as input + inp := {"review": review([ctr("a", "1G", "2")]), "parameters": {"memory": "1M", "cpu": "4"}} + results := violation with input as inp count(results) == 1 } test_input_violations_mem_T { - input := {"review": review([ctr("a", "1T", "2")]), "parameters": {"memory": "1G", "cpu": "4"}} - results := violation with input as input + inp := {"review": review([ctr("a", "1T", "2")]), "parameters": {"memory": "1G", "cpu": "4"}} + results := violation with input as inp count(results) == 1 } test_input_violations_mem_P { - input := {"review": review([ctr("a", "1P", "2")]), "parameters": {"memory": "1T", "cpu": "4"}} - results := violation with input as input + inp := {"review": review([ctr("a", "1P", "2")]), "parameters": {"memory": "1T", "cpu": "4"}} + results := violation with input as inp count(results) == 1 } test_input_violations_mem_E { - input := {"review": review([ctr("a", "1E", "2")]), "parameters": {"memory": "1P", "cpu": "4"}} - results := violation with input as input + inp := {"review": review([ctr("a", "1E", "2")]), "parameters": {"memory": "1P", "cpu": "4"}} + results := violation with input as inp count(results) == 1 } test_input_violations_mem_Ki { - input := {"review": review([ctr("a", "1Ki", "2")]), "parameters": {"memory": "1", "cpu": "4"}} - results := violation with input as input + inp := {"review": review([ctr("a", "1Ki", "2")]), "parameters": {"memory": "1", "cpu": "4"}} + results := violation with input as inp count(results) == 1 } test_input_violations_mem_Mi { - input := {"review": review([ctr("a", "1Mi", "2")]), "parameters": {"memory": "1Ki", "cpu": "4"}} - results := violation with input as input + inp := {"review": review([ctr("a", "1Mi", "2")]), "parameters": {"memory": "1Ki", "cpu": "4"}} + results := violation with input as inp count(results) == 1 } test_input_violations_mem_Gi { - input := {"review": review([ctr("a", "1Gi", "2")]), "parameters": {"memory": "1Mi", "cpu": "4"}} - results := violation with input as input + inp := {"review": review([ctr("a", "1Gi", "2")]), "parameters": {"memory": "1Mi", "cpu": "4"}} + results := violation with input as inp count(results) == 1 } test_input_violations_decimal_mem_Gi { - input := {"review": review([ctr("a", "1Gi", "2")]), "parameters": {"memory": "1.5Mi", "cpu": "4"}} - results := violation with input as input + inp := {"review": review([ctr("a", "1Gi", "2")]), "parameters": {"memory": "1.5Mi", "cpu": "4"}} + results := violation with input as inp count(results) == 1 } test_input_violations_mem_Ti { - input := {"review": review([ctr("a", "1Ti", "2")]), "parameters": {"memory": "1Gi", "cpu": "4"}} - results := violation with input as input + inp := {"review": review([ctr("a", "1Ti", "2")]), "parameters": {"memory": "1Gi", "cpu": "4"}} + results := violation with input as inp count(results) == 1 } test_input_violations_mem_Pi { - input := {"review": review([ctr("a", "1Pi", "2")]), "parameters": {"memory": "1Ti", "cpu": "4"}} - results := violation with input as input + inp := {"review": review([ctr("a", "1Pi", "2")]), "parameters": {"memory": "1Ti", "cpu": "4"}} + results := violation with input as inp count(results) == 1 } test_input_violations_mem_Ei { - input := {"review": review([ctr("a", "1Ei", "2")]), "parameters": {"memory": "1Pi", "cpu": "4"}} - results := violation with input as input + inp := {"review": review([ctr("a", "1Ei", "2")]), "parameters": {"memory": "1Pi", "cpu": "4"}} + results := violation with input as inp count(results) == 1 } test_input_violations_mem_Ei_with_exemption { - input := {"review": review([ctr("a", "1Ei", "2")]), "parameters": {"exemptImages": ["nginx"], "memory": "1Pi", "cpu": "4"}} - results := violation with input as input + inp := {"review": review([ctr("a", "1Ei", "2")]), "parameters": {"exemptImages": ["nginx"], "memory": "1Pi", "cpu": "4"}} + results := violation with input as inp count(results) == 0 } diff --git a/src/general/containerrequests/constraint.tmpl b/src/general/containerrequests/constraint.tmpl index ea4189138..fb96b6d10 100644 --- a/src/general/containerrequests/constraint.tmpl +++ b/src/general/containerrequests/constraint.tmpl @@ -4,7 +4,7 @@ metadata: name: k8scontainerrequests annotations: metadata.gatekeeper.sh/title: "Container Requests" - metadata.gatekeeper.sh/version: 1.0.0 + metadata.gatekeeper.sh/version: 1.0.1 description: >- Requires containers to have memory and CPU requests set and constrains requests to be within the specified maximum values. diff --git a/src/general/containerrequests/src.rego b/src/general/containerrequests/src.rego index 79e1e65ab..94ac1f831 100644 --- a/src/general/containerrequests/src.rego +++ b/src/general/containerrequests/src.rego @@ -24,7 +24,7 @@ canonify_cpu(orig) = new { canonify_cpu(orig) = new { not is_number(orig) not endswith(orig, "m") - re_match("^[0-9]+(\\.[0-9]+)?$", orig) + regex.match("^[0-9]+(\\.[0-9]+)?$", orig) new := to_number(orig) * 1000 } @@ -121,7 +121,7 @@ canonify_mem(orig) = new { not is_number(orig) suffix := get_suffix(orig) raw := replace(orig, suffix, "") - re_match("^[0-9]+(\\.[0-9]+)?$", raw) + regex.match("^[0-9]+(\\.[0-9]+)?$", raw) new := to_number(raw) * mem_multiple(suffix) } diff --git a/src/general/containerrequests/src_test.rego b/src/general/containerrequests/src_test.rego index b6c8d7412..4479e825f 100644 --- a/src/general/containerrequests/src_test.rego +++ b/src/general/containerrequests/src_test.rego @@ -1,187 +1,187 @@ package k8scontainerrequests test_input_no_violations_int { - input := {"review": review([ctr("a", 10, 20)]), "parameters": {"memory": 20, "cpu": 40}} - results := violation with input as input + inp := {"review": review([ctr("a", 10, 20)]), "parameters": {"memory": 20, "cpu": 40}} + results := violation with input as inp count(results) == 0 } test_input_no_violations_str { - input := {"review": review([ctr("a", "10", "20")]), "parameters": {"memory": "20", "cpu": "40"}} - results := violation with input as input + inp := {"review": review([ctr("a", "10", "20")]), "parameters": {"memory": "20", "cpu": "40"}} + results := violation with input as inp count(results) == 0 } test_input_no_violations_str_small { - input := {"review": review([ctr("a", "1", "2")]), "parameters": {"memory": "2", "cpu": "4"}} - results := violation with input as input + inp := {"review": review([ctr("a", "1", "2")]), "parameters": {"memory": "2", "cpu": "4"}} + results := violation with input as inp count(results) == 0 } test_input_no_violations_cpu_scale { - input := {"review": review([ctr("a", "1", "2m")]), "parameters": {"memory": "2", "cpu": "4"}} - results := violation with input as input + inp := {"review": review([ctr("a", "1", "2m")]), "parameters": {"memory": "2", "cpu": "4"}} + results := violation with input as inp count(results) == 0 } test_input_violations_int { - input := {"review": review([ctr("a", 10, 20)]), "parameters": {"memory": 5, "cpu": 10}} - results := violation with input as input + inp := {"review": review([ctr("a", 10, 20)]), "parameters": {"memory": 5, "cpu": 10}} + results := violation with input as inp count(results) == 2 } test_input_violations_mem_int_v_str { - input := {"review": review([ctr("a", 10, "4")]), "parameters": {"memory": "1000m", "cpu": "4"}} - results := violation with input as input + inp := {"review": review([ctr("a", 10, "4")]), "parameters": {"memory": "1000m", "cpu": "4"}} + results := violation with input as inp count(results) == 1 } test_input_violations_str { - input := {"review": review([ctr("a", "10", "20")]), "parameters": {"memory": "5", "cpu": "10"}} - results := violation with input as input + inp := {"review": review([ctr("a", "10", "20")]), "parameters": {"memory": "5", "cpu": "10"}} + results := violation with input as inp count(results) == 2 } test_input_violations_str_small { - input := {"review": review([ctr("a", "5", "6")]), "parameters": {"memory": "2", "cpu": "4"}} - results := violation with input as input + inp := {"review": review([ctr("a", "5", "6")]), "parameters": {"memory": "2", "cpu": "4"}} + results := violation with input as inp count(results) == 2 } test_input_violations_cpu_scale { - input := {"review": review([ctr("a", "1", "2")]), "parameters": {"memory": "2", "cpu": "4m"}} - results := violation with input as input + inp := {"review": review([ctr("a", "1", "2")]), "parameters": {"memory": "2", "cpu": "4m"}} + results := violation with input as inp count(results) == 1 } test_no_parse_cpu { - input := {"review": review([ctr("a", "1", "212asdf")]), "parameters": {"memory": "2", "cpu": "4m"}} - results := violation with input as input + inp := {"review": review([ctr("a", "1", "212asdf")]), "parameters": {"memory": "2", "cpu": "4m"}} + results := violation with input as inp count(results) == 1 } test_no_parse_ram { - input := {"review": review([ctr("a", "1asdf", "2")]), "parameters": {"memory": "2", "cpu": "4"}} - results := violation with input as input + inp := {"review": review([ctr("a", "1asdf", "2")]), "parameters": {"memory": "2", "cpu": "4"}} + results := violation with input as inp count(results) == 1 } test_1_bad_cpu { - input := {"review": review([ctr("a", "1", "2"), ctr("b", "1", "8")]), "parameters": {"memory": "2", "cpu": "4"}} - results := violation with input as input + inp := {"review": review([ctr("a", "1", "2"), ctr("b", "1", "8")]), "parameters": {"memory": "2", "cpu": "4"}} + results := violation with input as inp count(results) == 1 } test_2_bad_cpu { - input := {"review": review([ctr("a", "1", "9"), ctr("b", "1", "8")]), "parameters": {"memory": "2", "cpu": "4"}} - results := violation with input as input + inp := {"review": review([ctr("a", "1", "9"), ctr("b", "1", "8")]), "parameters": {"memory": "2", "cpu": "4"}} + results := violation with input as inp count(results) == 2 } test_1_bad_ram { - input := {"review": review([ctr("a", "1", "2"), ctr("b", "8", "2")]), "parameters": {"memory": "2", "cpu": "4"}} - results := violation with input as input + inp := {"review": review([ctr("a", "1", "2"), ctr("b", "8", "2")]), "parameters": {"memory": "2", "cpu": "4"}} + results := violation with input as inp count(results) == 1 } test_2_bad_ram { - input := {"review": review([ctr("a", "9", "2"), ctr("b", "8", "2")]), "parameters": {"memory": "2", "cpu": "4"}} - results := violation with input as input + inp := {"review": review([ctr("a", "9", "2"), ctr("b", "8", "2")]), "parameters": {"memory": "2", "cpu": "4"}} + results := violation with input as inp count(results) == 2 } test_no_ram_request { - input := {"review": review([{"name": "a", "resources": {"requests": {"cpu": 1}}}]), "parameters": {"memory": "2", "cpu": "4"}} - results := violation with input as input + inp := {"review": review([{"name": "a", "resources": {"requests": {"cpu": 1}}}]), "parameters": {"memory": "2", "cpu": "4"}} + results := violation with input as inp count(results) == 1 } test_no_cpu_request { - input := {"review": review([{"name": "a", "resources": {"requests": {"memory": 1}}}]), "parameters": {"memory": "2", "cpu": "4"}} - results := violation with input as input + inp := {"review": review([{"name": "a", "resources": {"requests": {"memory": 1}}}]), "parameters": {"memory": "2", "cpu": "4"}} + results := violation with input as inp count(results) == 1 } test_no_request { - input := {"review": review([{"name": "a", "resources": {}}]), "parameters": {"memory": "2", "cpu": "4"}} - results := violation with input as input + inp := {"review": review([{"name": "a", "resources": {}}]), "parameters": {"memory": "2", "cpu": "4"}} + results := violation with input as inp count(results) == 1 } test_no_resources { - input := {"review": review([{"name": "a"}]), "parameters": {"memory": "2", "cpu": "4"}} - results := violation with input as input + inp := {"review": review([{"name": "a"}]), "parameters": {"memory": "2", "cpu": "4"}} + results := violation with input as inp count(results) == 1 } test_init_containers_checked { - input := {"review": init_review([ctr("a", "5", "5"), ctr("b", "5", "5")]), "parameters": {"memory": "2", "cpu": "4"}} - results := violation with input as input + inp := {"review": init_review([ctr("a", "5", "5"), ctr("b", "5", "5")]), "parameters": {"memory": "2", "cpu": "4"}} + results := violation with input as inp count(results) == 4 } # MEM SCALE TESTS test_input_no_violations_mem_K { - input := {"review": review([ctr("a", "1", "2")]), "parameters": {"memory": "1k", "cpu": "4"}} - results := violation with input as input + inp := {"review": review([ctr("a", "1", "2")]), "parameters": {"memory": "1k", "cpu": "4"}} + results := violation with input as inp count(results) == 0 } test_input_violations_mem_m { - input := {"review": review([ctr("a", "1", "2")]), "parameters": {"memory": "1m", "cpu": "4"}} - results := violation with input as input + inp := {"review": review([ctr("a", "1", "2")]), "parameters": {"memory": "1m", "cpu": "4"}} + results := violation with input as inp count(results) == 1 } test_input_violations_mem_K { - input := {"review": review([ctr("a", "1k", "2")]), "parameters": {"memory": "1", "cpu": "4"}} - results := violation with input as input + inp := {"review": review([ctr("a", "1k", "2")]), "parameters": {"memory": "1", "cpu": "4"}} + results := violation with input as inp count(results) == 1 } test_input_violations_mem_M { - input := {"review": review([ctr("a", "1M", "2")]), "parameters": {"memory": "1k", "cpu": "4"}} - results := violation with input as input + inp := {"review": review([ctr("a", "1M", "2")]), "parameters": {"memory": "1k", "cpu": "4"}} + results := violation with input as inp count(results) == 1 } test_input_violations_mem_G { - input := {"review": review([ctr("a", "1G", "2")]), "parameters": {"memory": "1M", "cpu": "4"}} - results := violation with input as input + inp := {"review": review([ctr("a", "1G", "2")]), "parameters": {"memory": "1M", "cpu": "4"}} + results := violation with input as inp count(results) == 1 } test_input_violations_mem_T { - input := {"review": review([ctr("a", "1T", "2")]), "parameters": {"memory": "1G", "cpu": "4"}} - results := violation with input as input + inp := {"review": review([ctr("a", "1T", "2")]), "parameters": {"memory": "1G", "cpu": "4"}} + results := violation with input as inp count(results) == 1 } test_input_violations_mem_P { - input := {"review": review([ctr("a", "1P", "2")]), "parameters": {"memory": "1T", "cpu": "4"}} - results := violation with input as input + inp := {"review": review([ctr("a", "1P", "2")]), "parameters": {"memory": "1T", "cpu": "4"}} + results := violation with input as inp count(results) == 1 } test_input_violations_mem_E { - input := {"review": review([ctr("a", "1E", "2")]), "parameters": {"memory": "1P", "cpu": "4"}} - results := violation with input as input + inp := {"review": review([ctr("a", "1E", "2")]), "parameters": {"memory": "1P", "cpu": "4"}} + results := violation with input as inp count(results) == 1 } test_input_violations_mem_Ki { - input := {"review": review([ctr("a", "1Ki", "2")]), "parameters": {"memory": "1", "cpu": "4"}} - results := violation with input as input + inp := {"review": review([ctr("a", "1Ki", "2")]), "parameters": {"memory": "1", "cpu": "4"}} + results := violation with input as inp count(results) == 1 } test_input_violations_mem_Mi { - input := {"review": review([ctr("a", "1Mi", "2")]), "parameters": {"memory": "1Ki", "cpu": "4"}} - results := violation with input as input + inp := {"review": review([ctr("a", "1Mi", "2")]), "parameters": {"memory": "1Ki", "cpu": "4"}} + results := violation with input as inp count(results) == 1 } test_input_violations_mem_Gi { - input := {"review": review([ctr("a", "1Gi", "2")]), "parameters": {"memory": "1Mi", "cpu": "4"}} - results := violation with input as input + inp := {"review": review([ctr("a", "1Gi", "2")]), "parameters": {"memory": "1Mi", "cpu": "4"}} + results := violation with input as inp count(results) == 1 } test_input_violations_decimal_mem_Gi { - input := {"review": review([ctr("a", "1Gi", "2")]), "parameters": {"memory": "1.5Mi", "cpu": "4"}} - results := violation with input as input + inp := {"review": review([ctr("a", "1Gi", "2")]), "parameters": {"memory": "1.5Mi", "cpu": "4"}} + results := violation with input as inp count(results) == 1 } test_input_violations_mem_Ti { - input := {"review": review([ctr("a", "1Ti", "2")]), "parameters": {"memory": "1Gi", "cpu": "4"}} - results := violation with input as input + inp := {"review": review([ctr("a", "1Ti", "2")]), "parameters": {"memory": "1Gi", "cpu": "4"}} + results := violation with input as inp count(results) == 1 } test_input_violations_mem_Pi { - input := {"review": review([ctr("a", "1Pi", "2")]), "parameters": {"memory": "1Ti", "cpu": "4"}} - results := violation with input as input + inp := {"review": review([ctr("a", "1Pi", "2")]), "parameters": {"memory": "1Ti", "cpu": "4"}} + results := violation with input as inp count(results) == 1 } test_input_violations_mem_Ei { - input := {"review": review([ctr("a", "1Ei", "2")]), "parameters": {"memory": "1Pi", "cpu": "4"}} - results := violation with input as input + inp := {"review": review([ctr("a", "1Ei", "2")]), "parameters": {"memory": "1Pi", "cpu": "4"}} + results := violation with input as inp count(results) == 1 } test_input_violations_mem_Ei_with_exemption { - input := {"review": review([ctr("a", "1Ei", "2")]), "parameters": {"exemptImages": ["nginx"], "memory": "1Pi", "cpu": "4"}} - results := violation with input as input + inp := {"review": review([ctr("a", "1Ei", "2")]), "parameters": {"exemptImages": ["nginx"], "memory": "1Pi", "cpu": "4"}} + results := violation with input as inp count(results) == 0 } diff --git a/src/general/containerresourceratios/constraint.tmpl b/src/general/containerresourceratios/constraint.tmpl index 4de6e9ad5..88a838d45 100644 --- a/src/general/containerresourceratios/constraint.tmpl +++ b/src/general/containerresourceratios/constraint.tmpl @@ -4,7 +4,7 @@ metadata: name: k8scontainerratios annotations: metadata.gatekeeper.sh/title: "Container Ratios" - metadata.gatekeeper.sh/version: 1.0.0 + metadata.gatekeeper.sh/version: 1.0.1 description: >- Sets a maximum ratio for container resource limits to requests. diff --git a/src/general/containerresourceratios/src.rego b/src/general/containerresourceratios/src.rego index a31366235..9d269e681 100644 --- a/src/general/containerresourceratios/src.rego +++ b/src/general/containerresourceratios/src.rego @@ -24,14 +24,14 @@ canonify_cpu(orig) = new { canonify_cpu(orig) = new { not is_number(orig) not endswith(orig, "m") - re_match("^[0-9]+$", orig) + regex.match("^[0-9]+$", orig) new := to_number(orig) * 1000 } canonify_cpu(orig) = new { not is_number(orig) not endswith(orig, "m") - re_match("^[0-9]+[.][0-9]+$", orig) + regex.match("^[0-9]+[.][0-9]+$", orig) new := to_number(orig) * 1000 } @@ -128,7 +128,7 @@ canonify_mem(orig) = new { not is_number(orig) suffix := get_suffix(orig) raw := replace(orig, suffix, "") - re_match("^[0-9]+(\\.[0-9]+)?$", raw) + regex.match("^[0-9]+(\\.[0-9]+)?$", raw) new := to_number(raw) * mem_multiple(suffix) } diff --git a/src/general/containerresourceratios/src_test.rego b/src/general/containerresourceratios/src_test.rego index e73bca378..1148390c9 100644 --- a/src/general/containerresourceratios/src_test.rego +++ b/src/general/containerresourceratios/src_test.rego @@ -1,269 +1,269 @@ package k8scontainerratios test_input_no_violations_int { - input := {"review": review([ctr("a", 10, 20, 5, 10)]), "parameters": {"ratio": 2}} - results := violation with input as input + inp := {"review": review([ctr("a", 10, 20, 5, 10)]), "parameters": {"ratio": 2}} + results := violation with input as inp trace(sprintf("results - <%v>", [results])) count(results) == 0 } test_input_no_violations_str { - input := {"review": review([ctr("a", "10", "20", "5", "10")]), "parameters": {"ratio": "2"}} - results := violation with input as input + inp := {"review": review([ctr("a", "10", "20", "5", "10")]), "parameters": {"ratio": "2"}} + results := violation with input as inp trace(sprintf("results - <%v>", [results])) count(results) == 0 } test_input_no_violations_str_small { - input := {"review": review([ctr("a", "1", "2", "1", "1")]), "parameters": {"ratio": "2"}} - results := violation with input as input + inp := {"review": review([ctr("a", "1", "2", "1", "1")]), "parameters": {"ratio": "2"}} + results := violation with input as inp trace(sprintf("results - <%v>", [results])) count(results) == 0 } test_input_no_violations_cpu_scale { - input := {"review": review([ctr("a", "2", "4m", "1", "2m")]), "parameters": {"ratio": "2"}} - results := violation with input as input + inp := {"review": review([ctr("a", "2", "4m", "1", "2m")]), "parameters": {"ratio": "2"}} + results := violation with input as inp trace(sprintf("results - <%v>", [results])) count(results) == 0 } test_input_no_violations_cpu_decimal { - input := {"review": review([ctr("a", "2", "3", "1", "1.5")]), "parameters": {"ratio": "2"}} - results := violation with input as input + inp := {"review": review([ctr("a", "2", "3", "1", "1.5")]), "parameters": {"ratio": "2"}} + results := violation with input as inp trace(sprintf("results - <%v>", [results])) count(results) == 0 } test_input_violations_int { - input := {"review": review([ctr("a", 20, 40, 5, 10)]), "parameters": {"ratio": 2}} - results := violation with input as input + inp := {"review": review([ctr("a", 20, 40, 5, 10)]), "parameters": {"ratio": 2}} + results := violation with input as inp trace(sprintf("results - <%v>", [results])) count(results) == 2 } test_input_violations_mem_int_v_str { - input := {"review": review([ctr("a", 1, "3", "1m", "1.5")]), "parameters": {"ratio": "2"}} - results := violation with input as input + inp := {"review": review([ctr("a", 1, "3", "1m", "1.5")]), "parameters": {"ratio": "2"}} + results := violation with input as inp trace(sprintf("results - <%v>", [results])) count(results) == 1 } test_input_violations_str { - input := {"review": review([ctr("a", "10", "20", "2", "4")]), "parameters": {"ratio": "2"}} - results := violation with input as input + inp := {"review": review([ctr("a", "10", "20", "2", "4")]), "parameters": {"ratio": "2"}} + results := violation with input as inp trace(sprintf("results - <%v>", [results])) count(results) == 2 } test_input_violations_str_small { - input := {"review": review([ctr("a", "5", "6", "1", "1")]), "parameters": {"ratio": "3"}} - results := violation with input as input + inp := {"review": review([ctr("a", "5", "6", "1", "1")]), "parameters": {"ratio": "3"}} + results := violation with input as inp count(results) == 2 } test_input_violations_cpu_scale { - input := {"review": review([ctr("a", "1", "2", "1", "4m")]), "parameters": {"ratio": "10"}} - results := violation with input as input + inp := {"review": review([ctr("a", "1", "2", "1", "4m")]), "parameters": {"ratio": "10"}} + results := violation with input as inp count(results) == 1 } test_input_violations_cpu_decimal { - input := {"review": review([ctr("a", "1", "2", "1", "0.5")]), "parameters": {"ratio": "2"}} - results := violation with input as input + inp := {"review": review([ctr("a", "1", "2", "1", "0.5")]), "parameters": {"ratio": "2"}} + results := violation with input as inp trace(sprintf("results - <%v>", [results])) count(results) == 1 } test_no_parse_cpu_limits { - input := {"review": review([ctr("a", "1", "212asdf", "2", "2")]), "parameters": {"raio": "4"}} - results := violation with input as input + inp := {"review": review([ctr("a", "1", "212asdf", "2", "2")]), "parameters": {"raio": "4"}} + results := violation with input as inp count(results) == 1 } test_no_parse_cpu_requests { - input := {"review": review([ctr("a", "1", "2", "2", "212asdf")]), "parameters": {"raio": "4"}} - results := violation with input as input + inp := {"review": review([ctr("a", "1", "2", "2", "212asdf")]), "parameters": {"raio": "4"}} + results := violation with input as inp trace(sprintf("results - <%v>", [results])) count(results) == 1 } test_no_parse_cpu_requests_and_limits { - input := {"review": review([ctr("a", "1", "212asdf", "2", "212asdf")]), "parameters": {"raio": "4"}} - results := violation with input as input + inp := {"review": review([ctr("a", "1", "212asdf", "2", "212asdf")]), "parameters": {"raio": "4"}} + results := violation with input as inp count(results) == 2 } test_no_parse_ram_limits { - input := {"review": review([ctr("a", "1asdf", "2", "1", "2")]), "parameters": {"ratio": "4"}} - results := violation with input as input + inp := {"review": review([ctr("a", "1asdf", "2", "1", "2")]), "parameters": {"ratio": "4"}} + results := violation with input as inp count(results) == 1 } test_no_parse_ram_requests { - input := {"review": review([ctr("a", "1", "2", "1asdf", "2")]), "parameters": {"ratio": "4"}} - results := violation with input as input + inp := {"review": review([ctr("a", "1", "2", "1asdf", "2")]), "parameters": {"ratio": "4"}} + results := violation with input as inp count(results) == 1 } test_no_parse_ram_requests_and_limits { - input := {"review": review([ctr("a", "1asdf", "2", "1asdf", "2")]), "parameters": {"ratio": "4"}} - results := violation with input as input + inp := {"review": review([ctr("a", "1asdf", "2", "1asdf", "2")]), "parameters": {"ratio": "4"}} + results := violation with input as inp count(results) == 2 } test_1_bad_cpu { - input := {"review": review([ctr("a", "1", "2", "1", "2"), ctr("b", "1", "8", "1", "2")]), "parameters": {"ratio": "2"}} - results := violation with input as input + inp := {"review": review([ctr("a", "1", "2", "1", "2"), ctr("b", "1", "8", "1", "2")]), "parameters": {"ratio": "2"}} + results := violation with input as inp count(results) == 1 } test_2_bad_cpu { - input := {"review": review([ctr("a", "1", "9", "1", "3"), ctr("b", "1", "8", "1", "2")]), "parameters": {"ratio": "2"}} - results := violation with input as input + inp := {"review": review([ctr("a", "1", "9", "1", "3"), ctr("b", "1", "8", "1", "2")]), "parameters": {"ratio": "2"}} + results := violation with input as inp count(results) == 2 } test_1_bad_ram { - input := {"review": review([ctr("a", "1", "2", "1" ,"2"), ctr("b", "8", "2", "2", "2")]), "parameters": {"ratio": "1"}} - results := violation with input as input + inp := {"review": review([ctr("a", "1", "2", "1" ,"2"), ctr("b", "8", "2", "2", "2")]), "parameters": {"ratio": "1"}} + results := violation with input as inp count(results) == 1 } test_2_bad_ram { - input := {"review": review([ctr("a", "9", "2", "3", "2"), ctr("b", "8", "2", "2", "2")]), "parameters": {"ratio": "2"}} - results := violation with input as input + inp := {"review": review([ctr("a", "9", "2", "3", "2"), ctr("b", "8", "2", "2", "2")]), "parameters": {"ratio": "2"}} + results := violation with input as inp count(results) == 2 } test_no_ram_limit { - input := {"review": review([{"name": "a", "resources": {"limits": {"cpu": 1}}}]), "parameters": {"ratio": "4"}} - results := violation with input as input + inp := {"review": review([{"name": "a", "resources": {"limits": {"cpu": 1}}}]), "parameters": {"ratio": "4"}} + results := violation with input as inp trace(sprintf("results - <%v>", [results])) count(results) == 2 } test_no_cpu_limit { - input := {"review": review([{"name": "a", "resources": {"limits": {"memory": 1}}}]), "parameters": {"ratio": "4"}} - results := violation with input as input + inp := {"review": review([{"name": "a", "resources": {"limits": {"memory": 1}}}]), "parameters": {"ratio": "4"}} + results := violation with input as inp count(results) == 2 } test_no_limit { - input := {"review": review([{"name": "a", "resources": {}}]), "parameters": {"ratio": "4"}} - results := violation with input as input + inp := {"review": review([{"name": "a", "resources": {}}]), "parameters": {"ratio": "4"}} + results := violation with input as inp count(results) == 2 } test_no_ram_request { - input := {"review": review([{"name": "a", "resources": {"requests": {"cpu": 1}}}]), "parameters": {"ratio": "4"}} - results := violation with input as input + inp := {"review": review([{"name": "a", "resources": {"requests": {"cpu": 1}}}]), "parameters": {"ratio": "4"}} + results := violation with input as inp trace(sprintf("results - <%v>", [results])) count(results) == 2 } test_no_cpu_request { - input := {"review": review([{"name": "a", "resources": {"requests": {"memory": 1}}}]), "parameters": {"ratio": "4"}} - results := violation with input as input + inp := {"review": review([{"name": "a", "resources": {"requests": {"memory": 1}}}]), "parameters": {"ratio": "4"}} + results := violation with input as inp count(results) == 2 } test_no_resources { - input := {"review": review([{"name": "a"}]), "parameters": {"ratio": "4"}} - results := violation with input as input + inp := {"review": review([{"name": "a"}]), "parameters": {"ratio": "4"}} + results := violation with input as inp trace(sprintf("results - <%v>", [results])) count(results) == 2 } test_init_containers_checked { - input := {"review": init_review([ctr("a", "5", "5", "1", "1"), ctr("b", "5", "5", "1", "1")]), "parameters": {"ratio": "4"}} - results := violation with input as input + inp := {"review": init_review([ctr("a", "5", "5", "1", "1"), ctr("b", "5", "5", "1", "1")]), "parameters": {"ratio": "4"}} + results := violation with input as inp count(results) == 4 } # MEM SCALE TESTS test_input_no_violations_mem_K { - input := {"review": review([ctr("a", "1k", "2", "1k", "2")]), "parameters": {"ratio": "4"}} - results := violation with input as input + inp := {"review": review([ctr("a", "1k", "2", "1k", "2")]), "parameters": {"ratio": "4"}} + results := violation with input as inp count(results) == 0 } test_input_violations_mem_K { - input := {"review": review([ctr("a", "4k", "2", "1k", "2")]), "parameters": {"ratio": "2"}} - results := violation with input as input + inp := {"review": review([ctr("a", "4k", "2", "1k", "2")]), "parameters": {"ratio": "2"}} + results := violation with input as inp count(results) == 1 } test_input_violations_mem_m { - input := {"review": review([ctr("a", "1", "2", "1m", "2")]), "parameters": {"ratio": "4"}} - results := violation with input as input + inp := {"review": review([ctr("a", "1", "2", "1m", "2")]), "parameters": {"ratio": "4"}} + results := violation with input as inp count(results) == 1 } test_input_violations_mem_M { - input := {"review": review([ctr("a", "1M", "2", "1k", "2")]), "parameters": {"ratio": "4"}} - results := violation with input as input + inp := {"review": review([ctr("a", "1M", "2", "1k", "2")]), "parameters": {"ratio": "4"}} + results := violation with input as inp count(results) == 1 } test_input_violations_mem_G { - input := {"review": review([ctr("a", "1G", "2", "1M", "1")]), "parameters": {"ratio": "4"}} - results := violation with input as input + inp := {"review": review([ctr("a", "1G", "2", "1M", "1")]), "parameters": {"ratio": "4"}} + results := violation with input as inp count(results) == 1 } test_input_violations_mem_T { - input := {"review": review([ctr("a", "1T", "2", "1G", "1")]), "parameters": {"ratio": "4"}} - results := violation with input as input + inp := {"review": review([ctr("a", "1T", "2", "1G", "1")]), "parameters": {"ratio": "4"}} + results := violation with input as inp count(results) == 1 } test_input_violations_mem_P { - input := {"review": review([ctr("a", "1P", "2", "1T", "2")]), "parameters": {"ratio": "4"}} - results := violation with input as input + inp := {"review": review([ctr("a", "1P", "2", "1T", "2")]), "parameters": {"ratio": "4"}} + results := violation with input as inp count(results) == 1 } test_input_violations_mem_E { - input := {"review": review([ctr("a", "1E", "2", "1P", "2")]), "parameters": {"ratio": "4"}} - results := violation with input as input + inp := {"review": review([ctr("a", "1E", "2", "1P", "2")]), "parameters": {"ratio": "4"}} + results := violation with input as inp count(results) == 1 } test_input_violations_mem_Ki { - input := {"review": review([ctr("a", "1Ki", "2", "1", "2")]), "parameters": {"ratio": "4"}} - results := violation with input as input + inp := {"review": review([ctr("a", "1Ki", "2", "1", "2")]), "parameters": {"ratio": "4"}} + results := violation with input as inp count(results) == 1 } test_input_violations_mem_Mi { - input := {"review": review([ctr("a", "1Mi", "2", "1Ki", "1")]), "parameters": {"ratio": "4"}} - results := violation with input as input + inp := {"review": review([ctr("a", "1Mi", "2", "1Ki", "1")]), "parameters": {"ratio": "4"}} + results := violation with input as inp count(results) == 1 } test_input_violations_mem_Gi { - input := {"review": review([ctr("a", "1Gi", "2", "1Mi", "2")]), "parameters": {"ratio": "4"}} - results := violation with input as input + inp := {"review": review([ctr("a", "1Gi", "2", "1Mi", "2")]), "parameters": {"ratio": "4"}} + results := violation with input as inp count(results) == 1 } test_input_violations_mem_Ti { - input := {"review": review([ctr("a", "1Ti", "2", "1Gi", "1")]), "parameters": {"ratio": "4"}} - results := violation with input as input + inp := {"review": review([ctr("a", "1Ti", "2", "1Gi", "1")]), "parameters": {"ratio": "4"}} + results := violation with input as inp count(results) == 1 } test_input_violations_mem_Pi { - input := {"review": review([ctr("a", "1Pi", "2", "1Ti", "1")]), "parameters": {"ratio": "4"}} - results := violation with input as input + inp := {"review": review([ctr("a", "1Pi", "2", "1Ti", "1")]), "parameters": {"ratio": "4"}} + results := violation with input as inp count(results) == 1 } test_input_violations_mem_Ei { - input := {"review": review([ctr("a", "1Ei", "2", "1Pi", "1")]), "parameters": {"ratio": "4"}} - results := violation with input as input + inp := {"review": review([ctr("a", "1Ei", "2", "1Pi", "1")]), "parameters": {"ratio": "4"}} + results := violation with input as inp count(results) == 1 } test_input_violations_mem_Ei_with_exemption { - input := {"review": review([ctr("a", "1Ei", "2", "1Pi", "1")]), "parameters": {"exemptImages": ["nginx"], "ratio": "4"}} - results := violation with input as input + inp := {"review": review([ctr("a", "1Ei", "2", "1Pi", "1")]), "parameters": {"exemptImages": ["nginx"], "ratio": "4"}} + results := violation with input as inp count(results) == 0 } ## cpuRatio tests test_input_no_violations_int_cpu_ratio_1 { - input := {"review": review([ctr("a", 5, 10, 5, 10)]), "parameters": {"ratio": 1, "cpuRatio": 1}} - results := violation with input as input + inp := {"review": review([ctr("a", 5, 10, 5, 10)]), "parameters": {"ratio": 1, "cpuRatio": 1}} + results := violation with input as inp trace(sprintf("results - <%v>", [results])) count(results) == 0 } test_input_violations_int_cpu_ratio_1 { - input := {"review": review([ctr("a", 30, 15, 5, 10)]), "parameters": {"ratio": 10, "cpuRatio": 1}} - results := violation with input as input + inp := {"review": review([ctr("a", 30, 15, 5, 10)]), "parameters": {"ratio": 10, "cpuRatio": 1}} + results := violation with input as inp trace(sprintf("results - <%v>", [results])) count(results) == 1 } test_input_no_violation_int_cpu_ratio_2 { - input := {"review": review([ctr("a", 5, 20, 5, 10)]), "parameters": {"ratio": 1, "cpuRatio": 2}} - results := violation with input as input + inp := {"review": review([ctr("a", 5, 20, 5, 10)]), "parameters": {"ratio": 1, "cpuRatio": 2}} + results := violation with input as inp trace(sprintf("results - <%v>", [results])) count(results) == 0 } test_input_violation_int_cpu_ratio_2 { - input := {"review": review([ctr("a", 5, 21, 5, 10)]), "parameters": {"ratio": 1, "cpuRatio": 2}} - results := violation with input as input + inp := {"review": review([ctr("a", 5, 21, 5, 10)]), "parameters": {"ratio": 1, "cpuRatio": 2}} + results := violation with input as inp trace(sprintf("results - <%v>", [results])) count(results) == 1 } test_input_violation_int_cpu_ratio_2_with_exemption { - input := {"review": review([ctr("a", 5, 21, 5, 10)]), "parameters": {"exemptImages": ["nginx"], "ratio": 1, "cpuRatio": 2}} - results := violation with input as input + inp := {"review": review([ctr("a", 5, 21, 5, 10)]), "parameters": {"exemptImages": ["nginx"], "ratio": 1, "cpuRatio": 2}} + results := violation with input as inp trace(sprintf("results - <%v>", [results])) count(results) == 0 } diff --git a/src/general/containerresources/src_test.rego b/src/general/containerresources/src_test.rego index 16191f335..355cb7b7a 100644 --- a/src/general/containerresources/src_test.rego +++ b/src/general/containerresources/src_test.rego @@ -2,259 +2,259 @@ package k8srequiredresources # "parameters": {"limits": ["cpu", "memory"], "requests": ["cpu", "memory"]} test_without_resources_violations { - input := {"review": review([ctr_without_resources("test")]), "parameters": {"limits": ["cpu", "memory"], "requests": ["cpu", "memory"]}} - results := violation with input as input + inp := {"review": review([ctr_without_resources("test")]), "parameters": {"limits": ["cpu", "memory"], "requests": ["cpu", "memory"]}} + results := violation with input as inp trace(sprintf("results - <%v>", [results])) count(results) == 2 } test_requests_cpu_violations { - input := {"review": review([ctr_requests_cpu("test", 1)]), "parameters": {"limits": ["cpu", "memory"], "requests": ["cpu", "memory"]}} - results := violation with input as input + inp := {"review": review([ctr_requests_cpu("test", 1)]), "parameters": {"limits": ["cpu", "memory"], "requests": ["cpu", "memory"]}} + results := violation with input as inp trace(sprintf("results - <%v>", [results])) count(results) == 2 } test_requests_memory_violations { - input := {"review": review([ctr_requests_memory("test", 1)]), "parameters": {"limits": ["cpu", "memory"], "requests": ["cpu", "memory"]}} - results := violation with input as input + inp := {"review": review([ctr_requests_memory("test", 1)]), "parameters": {"limits": ["cpu", "memory"], "requests": ["cpu", "memory"]}} + results := violation with input as inp trace(sprintf("results - <%v>", [results])) count(results) == 2 } test_requests_violations { - input := {"review": review([ctr_requests("test", 1)]), "parameters": {"limits": ["cpu", "memory"], "requests": ["cpu", "memory"]}} - results := violation with input as input + inp := {"review": review([ctr_requests("test", 1)]), "parameters": {"limits": ["cpu", "memory"], "requests": ["cpu", "memory"]}} + results := violation with input as inp trace(sprintf("results - <%v>", [results])) count(results) == 1 } test_limits_cpu_violations { - input := {"review": review([ctr_limits_cpu("test", 1)]), "parameters": {"limits": ["cpu", "memory"], "requests": ["cpu", "memory"]}} - results := violation with input as input + inp := {"review": review([ctr_limits_cpu("test", 1)]), "parameters": {"limits": ["cpu", "memory"], "requests": ["cpu", "memory"]}} + results := violation with input as inp trace(sprintf("results - <%v>", [results])) count(results) == 2 } test_limits_memory_violations { - input := {"review": review([ctr_limits_memory("test", 1)]), "parameters": {"limits": ["cpu", "memory"], "requests": ["cpu", "memory"]}} - results := violation with input as input + inp := {"review": review([ctr_limits_memory("test", 1)]), "parameters": {"limits": ["cpu", "memory"], "requests": ["cpu", "memory"]}} + results := violation with input as inp trace(sprintf("results - <%v>", [results])) count(results) == 2 } test_limits_violations { - input := {"review": review([ctr_limits("test", 1)]), "parameters": {"limits": ["cpu", "memory"], "requests": ["cpu", "memory"]}} - results := violation with input as input + inp := {"review": review([ctr_limits("test", 1)]), "parameters": {"limits": ["cpu", "memory"], "requests": ["cpu", "memory"]}} + results := violation with input as inp trace(sprintf("results - <%v>", [results])) count(results) == 1 } test_with_resources_no_violations { - input := {"review": review([ctr_with_resources("test", 1)]), "parameters": {"limits": ["cpu", "memory"], "requests": ["cpu", "memory"]}} - results := violation with input as input + inp := {"review": review([ctr_with_resources("test", 1)]), "parameters": {"limits": ["cpu", "memory"], "requests": ["cpu", "memory"]}} + results := violation with input as inp trace(sprintf("results - <%v>", [results])) count(results) == 0 } # "parameters": {"limits": ["memory"], "requests": ["cpu"]} test_without_resources_with_empty_requests_memory_no_violations { - input := {"review": review([ctr_without_resources("test")]), "parameters": {"limits": ["memory"], "requests": ["cpu"]}} - results := violation with input as input + inp := {"review": review([ctr_without_resources("test")]), "parameters": {"limits": ["memory"], "requests": ["cpu"]}} + results := violation with input as inp trace(sprintf("results - <%v>", [results])) count(results) == 2 } test_requests_cpu_with_empty_requests_memory_no_violations { - input := {"review": review([ctr_requests_cpu("test", 1)]), "parameters": {"limits": ["memory"], "requests": ["cpu"]}} - results := violation with input as input + inp := {"review": review([ctr_requests_cpu("test", 1)]), "parameters": {"limits": ["memory"], "requests": ["cpu"]}} + results := violation with input as inp trace(sprintf("results - <%v>", [results])) count(results) == 1 } test_requests_memory_with_empty_requests_memory_no_violations { - input := {"review": review([ctr_requests_memory("test", 1)]), "parameters": {"limits": ["memory"], "requests": ["cpu"]}} - results := violation with input as input + inp := {"review": review([ctr_requests_memory("test", 1)]), "parameters": {"limits": ["memory"], "requests": ["cpu"]}} + results := violation with input as inp trace(sprintf("results - <%v>", [results])) count(results) == 2 } test_requests_with_empty_requests_memory_no_violations { - input := {"review": review([ctr_requests("test", 1)]), "parameters": {"limits": ["memory"], "requests": ["cpu"]}} - results := violation with input as input + inp := {"review": review([ctr_requests("test", 1)]), "parameters": {"limits": ["memory"], "requests": ["cpu"]}} + results := violation with input as inp trace(sprintf("results - <%v>", [results])) count(results) == 1 } test_limits_cpu_with_empty_requests_memory_no_violations { - input := {"review": review([ctr_limits_cpu("test", 1)]), "parameters": {"limits": ["memory"], "requests": ["cpu"]}} - results := violation with input as input + inp := {"review": review([ctr_limits_cpu("test", 1)]), "parameters": {"limits": ["memory"], "requests": ["cpu"]}} + results := violation with input as inp trace(sprintf("results - <%v>", [results])) count(results) == 2 } test_limits_memory_with_empty_requests_memory_no_violations { - input := {"review": review([ctr_limits_memory("test", 1)]), "parameters": {"limits": ["memory"], "requests": ["cpu"]}} - results := violation with input as input + inp := {"review": review([ctr_limits_memory("test", 1)]), "parameters": {"limits": ["memory"], "requests": ["cpu"]}} + results := violation with input as inp trace(sprintf("results - <%v>", [results])) count(results) == 1 } test_limits_with_empty_requests_memory_no_violations { - input := {"review": review([ctr_limits("test", 1)]), "parameters": {"limits": ["memory"], "requests": ["cpu"]}} - results := violation with input as input + inp := {"review": review([ctr_limits("test", 1)]), "parameters": {"limits": ["memory"], "requests": ["cpu"]}} + results := violation with input as inp trace(sprintf("results - <%v>", [results])) count(results) == 1 } test_with_resources_with_empty_requests_memory_no_violations { - input := {"review": review([ctr_with_resources("test", 1)]), "parameters": {"limits": ["memory"], "requests": ["cpu"]}} - results := violation with input as input + inp := {"review": review([ctr_with_resources("test", 1)]), "parameters": {"limits": ["memory"], "requests": ["cpu"]}} + results := violation with input as inp trace(sprintf("results - <%v>", [results])) count(results) == 0 } # "parameters": {"limits": ["cpu"]} test_without_resources_with_empty_requests_and_limits_memory_no_violations { - input := {"review": review([ctr_without_resources("test")]), "parameters": {"limits": ["cpu"]}} - results := violation with input as input + inp := {"review": review([ctr_without_resources("test")]), "parameters": {"limits": ["cpu"]}} + results := violation with input as inp trace(sprintf("results - <%v>", [results])) count(results) == 1 } test_requests_cpu_with_empty_requests_and_limits_memory_no_violations { - input := {"review": review([ctr_requests_cpu("test", 1)]), "parameters": {"limits": ["cpu"]}} - results := violation with input as input + inp := {"review": review([ctr_requests_cpu("test", 1)]), "parameters": {"limits": ["cpu"]}} + results := violation with input as inp trace(sprintf("results - <%v>", [results])) count(results) == 1 } test_requests_memory_with_empty_requests_and_limits_memory_no_violations { - input := {"review": review([ctr_requests_memory("test", 1)]), "parameters": {"limits": ["cpu"]}} - results := violation with input as input + inp := {"review": review([ctr_requests_memory("test", 1)]), "parameters": {"limits": ["cpu"]}} + results := violation with input as inp trace(sprintf("results - <%v>", [results])) count(results) == 1 } test_requests_with_empty_requests_and_limits_memory_no_violations { - input := {"review": review([ctr_requests("test", 1)]), "parameters": {"limits": ["cpu"]}} - results := violation with input as input + inp := {"review": review([ctr_requests("test", 1)]), "parameters": {"limits": ["cpu"]}} + results := violation with input as inp trace(sprintf("results - <%v>", [results])) count(results) == 1 } test_limits_cpu_with_empty_requests_and_limits_memory_no_violations { - input := {"review": review([ctr_limits_cpu("test", 1)]), "parameters": {"limits": ["cpu"]}} - results := violation with input as input + inp := {"review": review([ctr_limits_cpu("test", 1)]), "parameters": {"limits": ["cpu"]}} + results := violation with input as inp trace(sprintf("results - <%v>", [results])) count(results) == 0 } test_limits_memory_with_empty_requests_and_limits_memory_no_violations { - input := {"review": review([ctr_limits_memory("test", 1)]), "parameters": {"limits": ["cpu"]}} - results := violation with input as input + inp := {"review": review([ctr_limits_memory("test", 1)]), "parameters": {"limits": ["cpu"]}} + results := violation with input as inp trace(sprintf("results - <%v>", [results])) count(results) == 1 } test_limits_with_empty_requests_and_limits_memory_no_violations { - input := {"review": review([ctr_limits("test", 1)]), "parameters": {"limits": ["cpu"]}} - results := violation with input as input + inp := {"review": review([ctr_limits("test", 1)]), "parameters": {"limits": ["cpu"]}} + results := violation with input as inp trace(sprintf("results - <%v>", [results])) count(results) == 0 } test_with_resources_with_empty_requests_and_limits_memory_no_violations { - input := {"review": review([ctr_with_resources("test", 1)]), "parameters": {"limits": ["cpu"]}} - results := violation with input as input + inp := {"review": review([ctr_with_resources("test", 1)]), "parameters": {"limits": ["cpu"]}} + results := violation with input as inp trace(sprintf("results - <%v>", [results])) count(results) == 0 } # "parameters": {"limits": [], "requests": []} test_without_resources_with_empty_limits_and_requests_no_violations { - input := {"review": review([ctr_without_resources("test")]), "parameters": {"limits": [], "requests": []}} - results := violation with input as input + inp := {"review": review([ctr_without_resources("test")]), "parameters": {"limits": [], "requests": []}} + results := violation with input as inp trace(sprintf("results - <%v>", [results])) count(results) == 0 } test_requests_cpu_with_empty_limits_and_requests_no_violations { - input := {"review": review([ctr_requests_cpu("test", 1)]), "parameters": {"limits": [], "requests": []}} - results := violation with input as input + inp := {"review": review([ctr_requests_cpu("test", 1)]), "parameters": {"limits": [], "requests": []}} + results := violation with input as inp trace(sprintf("results - <%v>", [results])) count(results) == 0 } test_requests_memory_with_empty_limits_and_requests_no_violations { - input := {"review": review([ctr_requests_memory("test", 1)]), "parameters": {"limits": [], "requests": []}} - results := violation with input as input + inp := {"review": review([ctr_requests_memory("test", 1)]), "parameters": {"limits": [], "requests": []}} + results := violation with input as inp trace(sprintf("results - <%v>", [results])) count(results) == 0 } test_requests_with_empty_limits_and_requests_no_violations { - input := {"review": review([ctr_requests("test", 1)]), "parameters": {"limits": [], "requests": []}} - results := violation with input as input + inp := {"review": review([ctr_requests("test", 1)]), "parameters": {"limits": [], "requests": []}} + results := violation with input as inp trace(sprintf("results - <%v>", [results])) count(results) == 0 } test_limits_cpu_with_empty_limits_and_requests_no_violations { - input := {"review": review([ctr_limits_cpu("test", 1)]), "parameters": {"limits": [], "requests": []}} - results := violation with input as input + inp := {"review": review([ctr_limits_cpu("test", 1)]), "parameters": {"limits": [], "requests": []}} + results := violation with input as inp trace(sprintf("results - <%v>", [results])) count(results) == 0 } test_limits_memory_with_empty_limits_and_requests_no_violations { - input := {"review": review([ctr_limits_memory("test", 1)]), "parameters": {"limits": [], "requests": []}} - results := violation with input as input + inp := {"review": review([ctr_limits_memory("test", 1)]), "parameters": {"limits": [], "requests": []}} + results := violation with input as inp trace(sprintf("results - <%v>", [results])) count(results) == 0 } test_limits_with_empty_limits_and_requests_no_violations { - input := {"review": review([ctr_limits("test", 1)]), "parameters": {"limits": [], "requests": []}} - results := violation with input as input + inp := {"review": review([ctr_limits("test", 1)]), "parameters": {"limits": [], "requests": []}} + results := violation with input as inp trace(sprintf("results - <%v>", [results])) count(results) == 0 } test_with_resources_with_empty_limits_and_requests_no_violations { - input := {"review": review([ctr_with_resources("test", 1)]), "parameters": {"limits": [], "requests": []}} - results := violation with input as input + inp := {"review": review([ctr_with_resources("test", 1)]), "parameters": {"limits": [], "requests": []}} + results := violation with input as inp trace(sprintf("results - <%v>", [results])) count(results) == 0 } # multiple containers, "parameters": {"limits": ["cpu", "memory"], "requests": ["cpu", "memory"]} test_multiple_without_resources_violations { - input := {"review": review([ctr_without_resources("test1"),ctr_without_resources("test2"),ctr_without_resources("test3")]), "parameters": {"limits": ["cpu", "memory"], "requests": ["cpu", "memory"]}} - results := violation with input as input + inp := {"review": review([ctr_without_resources("test1"),ctr_without_resources("test2"),ctr_without_resources("test3")]), "parameters": {"limits": ["cpu", "memory"], "requests": ["cpu", "memory"]}} + results := violation with input as inp trace(sprintf("results - <%v>", [results])) count(results) == 6 } test_multiple_with_resources_no_violations { - input := {"review": review([ctr_with_resources("test1", 1),ctr_with_resources("test2", 2),ctr_with_resources("test3", 3)]), "parameters": {"limits": ["cpu", "memory"], "requests": ["cpu", "memory"]}} - results := violation with input as input + inp := {"review": review([ctr_with_resources("test1", 1),ctr_with_resources("test2", 2),ctr_with_resources("test3", 3)]), "parameters": {"limits": ["cpu", "memory"], "requests": ["cpu", "memory"]}} + results := violation with input as inp trace(sprintf("results - <%v>", [results])) count(results) == 0 } # multiple containers test_multiple_with_init_violations_1 { - input := { + inp := { "review": review_with_init( [ - ctr_without_resources("test1"), - ctr_with_resources("test2", 2), + ctr_without_resources("test1"), + ctr_with_resources("test2", 2), ctr_limits_memory("test3", 3) ], [ - ctr_requests("test4", 1), - ctr_requests_memory("test5", 2), + ctr_requests("test4", 1), + ctr_requests_memory("test5", 2), ctr_limits_cpu("test6", 3) ] ), @@ -265,21 +265,21 @@ test_multiple_with_init_violations_1 { ] } } - results := violation with input as input + results := violation with input as inp trace(sprintf("results - <%v>", [results])) count(results) == 4 } test_multiple_with_init_no_violations { - input := { + inp := { "review": review_with_init( [ - ctr_with_resources("test1", 1), - ctr_requests("test2", 2), + ctr_with_resources("test1", 1), + ctr_requests("test2", 2), ], [ - ctr_with_resources("test3", 1), - ctr_requests("test4", 2), + ctr_with_resources("test3", 1), + ctr_requests("test4", 2), ] ), "parameters": { @@ -289,22 +289,22 @@ test_multiple_with_init_no_violations { ] } } - results := violation with input as input + results := violation with input as inp trace(sprintf("results - <%v>", [results])) count(results) == 0 } test_multiple_with_init_violations_2 { - input := { + inp := { "review": review_with_init( [ - ctr_without_resources("test1"), - ctr_limits_memory("test2", 2), + ctr_without_resources("test1"), + ctr_limits_memory("test2", 2), ctr_limits("test3", 3) ], [ - ctr_requests_cpu("test4", 1), - ctr_with_resources("test5", 2), + ctr_requests_cpu("test4", 1), + ctr_with_resources("test5", 2), ctr_limits_cpu("test6", 3) ] ), @@ -318,7 +318,7 @@ test_multiple_with_init_violations_2 { ] } } - results := violation with input as input + results := violation with input as inp trace(sprintf("results - <%v>", [results])) count(results) == 8 } diff --git a/src/general/disallowanonymous/src_test.rego b/src/general/disallowanonymous/src_test.rego index a4d5d2089..6a6c5759f 100644 --- a/src/general/disallowanonymous/src_test.rego +++ b/src/general/disallowanonymous/src_test.rego @@ -1,224 +1,224 @@ package k8sdisallowanonymous test_blank_subject_clusterrolebinding { - input := {"review": clusterrolebinding([{}], "role-2"), "parameters": {"allowedRoles": ["role-1"]}} - results := violation with input as input + inp := {"review": clusterrolebinding([{}], "role-2"), "parameters": {"allowedRoles": ["role-1"]}} + results := violation with input as inp count(results) == 0 } test_authenticated_group_clusterrolebinding { - input := {"review": clusterrolebinding([{"name": "system:authenticated", "kind": "Group"}], "role-2"), "parameters": {"allowedRoles": ["role-1"]}} - results := violation with input as input + inp := {"review": clusterrolebinding([{"name": "system:authenticated", "kind": "Group"}], "role-2"), "parameters": {"allowedRoles": ["role-1"]}} + results := violation with input as inp count(results) == 0 } test_non_anonymous_user_clusterrolebinding { - input := {"review": clusterrolebinding([{"name": "user-1", "kind": "User"}], "role-2"), "parameters": {"allowedRoles": ["role-1"]}} - results := violation with input as input + inp := {"review": clusterrolebinding([{"name": "user-1", "kind": "User"}], "role-2"), "parameters": {"allowedRoles": ["role-1"]}} + results := violation with input as inp count(results) == 0 } test_anonymous_user_clusterrolebinding { - input := {"review": clusterrolebinding([{"name": "system:anonymous", "kind": "User"}], "role-2"), "parameters": {"allowedRoles": ["role-1"]}} - results := violation with input as input + inp := {"review": clusterrolebinding([{"name": "system:anonymous", "kind": "User"}], "role-2"), "parameters": {"allowedRoles": ["role-1"]}} + results := violation with input as inp count(results) == 1 } test_allowed_role_anonymous_user_clusterrolebinding { - input := {"review": clusterrolebinding([{"name": "system:anonymous", "kind": "User"}], "role-2"), "parameters": {"allowedRoles": ["role-2"]}} - results := violation with input as input + inp := {"review": clusterrolebinding([{"name": "system:anonymous", "kind": "User"}], "role-2"), "parameters": {"allowedRoles": ["role-2"]}} + results := violation with input as inp count(results) == 0 } test_multiple_subjects_anonymous_user_clusterrolebinding { - input := {"review": clusterrolebinding([{"name": "system:anonymous", "kind": "User"}, {"name": "system:authenticated", "kind": "Group"}], "role-2"), "parameters": {"allowedRoles": ["role-1"]}} - results := violation with input as input + inp := {"review": clusterrolebinding([{"name": "system:anonymous", "kind": "User"}, {"name": "system:authenticated", "kind": "Group"}], "role-2"), "parameters": {"allowedRoles": ["role-1"]}} + results := violation with input as inp count(results) == 1 } test_allowed_role_multiple_subjects_anonymous_user_clusterrolebinding { - input := {"review": clusterrolebinding([{"name": "system:anonymous", "kind": "User"}, {"name": "system:authenticated", "kind": "Group"}], "role-2"), "parameters": {"allowedRoles": ["role-2"]}} - results := violation with input as input + inp := {"review": clusterrolebinding([{"name": "system:anonymous", "kind": "User"}, {"name": "system:authenticated", "kind": "Group"}], "role-2"), "parameters": {"allowedRoles": ["role-2"]}} + results := violation with input as inp count(results) == 0 } test_multiple_role_multiple_subjects_anonymous_user_clusterrolebinding { - input := {"review": clusterrolebinding([{"name": "system:anonymous", "kind": "User"}, {"name": "system:authenticated", "kind": "Group"}], "role-2"), "parameters": {"allowedRoles": ["role-1", "role-3"]}} - results := violation with input as input + inp := {"review": clusterrolebinding([{"name": "system:anonymous", "kind": "User"}, {"name": "system:authenticated", "kind": "Group"}], "role-2"), "parameters": {"allowedRoles": ["role-1", "role-3"]}} + results := violation with input as inp count(results) == 1 } test_allowed_multiple_role_multiple_subjects_anonymous_user_clusterrolebinding { - input := {"review": clusterrolebinding([{"name": "system:anonymous", "kind": "User"}, {"name": "system:authenticated", "kind": "Group"}], "role-2"), "parameters": {"allowedRoles": ["role-1", "role-2"]}} - results := violation with input as input + inp := {"review": clusterrolebinding([{"name": "system:anonymous", "kind": "User"}, {"name": "system:authenticated", "kind": "Group"}], "role-2"), "parameters": {"allowedRoles": ["role-1", "role-2"]}} + results := violation with input as inp count(results) == 0 } test_unauthenticated_group_clusterrolebinding { - input := {"review": clusterrolebinding([{"name": "system:unauthenticated", "kind": "Group"}], "role-2"), "parameters": {"allowedRoles": ["role-1"]}} - results := violation with input as input + inp := {"review": clusterrolebinding([{"name": "system:unauthenticated", "kind": "Group"}], "role-2"), "parameters": {"allowedRoles": ["role-1"]}} + results := violation with input as inp count(results) == 1 } test_allowed_role_unauthenticated_group_clusterrolebinding { - input := {"review": clusterrolebinding([{"name": "system:unauthenticated", "kind": "Group"}], "role-2"), "parameters": {"allowedRoles": ["role-2"]}} - results := violation with input as input + inp := {"review": clusterrolebinding([{"name": "system:unauthenticated", "kind": "Group"}], "role-2"), "parameters": {"allowedRoles": ["role-2"]}} + results := violation with input as inp count(results) == 0 } test_multiple_subjects_unauthenticated_group_clusterrolebinding { - input := {"review": clusterrolebinding([{"name": "system:unauthenticated", "kind": "Group"}, {"name": "system:authenticated", "kind": "Group"}], "role-2"), "parameters": {"allowedRoles": ["role-1"]}} - results := violation with input as input + inp := {"review": clusterrolebinding([{"name": "system:unauthenticated", "kind": "Group"}, {"name": "system:authenticated", "kind": "Group"}], "role-2"), "parameters": {"allowedRoles": ["role-1"]}} + results := violation with input as inp count(results) == 1 } test_allowed_role_multiple_subjects_unauthenticated_group_clusterrolebinding { - input := {"review": clusterrolebinding([{"name": "system:unauthenticated", "kind": "Group"}, {"name": "system:authenticated", "kind": "Group"}], "role-2"), "parameters": {"allowedRoles": ["role-2"]}} - results := violation with input as input + inp := {"review": clusterrolebinding([{"name": "system:unauthenticated", "kind": "Group"}, {"name": "system:authenticated", "kind": "Group"}], "role-2"), "parameters": {"allowedRoles": ["role-2"]}} + results := violation with input as inp count(results) == 0 } test_multiple_role_multiple_subjects_unauthenticated_group_clusterrolebinding { - input := {"review": clusterrolebinding([{"name": "system:unauthenticated", "kind": "Group"}, {"name": "system:authenticated", "kind": "Group"}], "role-2"), "parameters": {"allowedRoles": ["role-1", "role-3"]}} - results := violation with input as input + inp := {"review": clusterrolebinding([{"name": "system:unauthenticated", "kind": "Group"}, {"name": "system:authenticated", "kind": "Group"}], "role-2"), "parameters": {"allowedRoles": ["role-1", "role-3"]}} + results := violation with input as inp count(results) == 1 } test_allowed_multiple_role_multiple_subjects_unauthenticated_group_clusterrolebinding { - input := {"review": clusterrolebinding([{"name": "system:unauthenticated", "kind": "Group"}, {"name": "system:authenticated", "kind": "Group"}], "role-2"), "parameters": {"allowedRoles": ["role-1", "role-2"]}} - results := violation with input as input + inp := {"review": clusterrolebinding([{"name": "system:unauthenticated", "kind": "Group"}, {"name": "system:authenticated", "kind": "Group"}], "role-2"), "parameters": {"allowedRoles": ["role-1", "role-2"]}} + results := violation with input as inp count(results) == 0 } test_multiple_subjects_mix_clusterrolebinding { - input := {"review": clusterrolebinding([{"name": "system:unauthenticated", "kind": "Group"}, {"name": "system:anonymous", "kind": "User"}], "role-2"), "parameters": {"allowedRoles": ["role-1"]}} - results := violation with input as input + inp := {"review": clusterrolebinding([{"name": "system:unauthenticated", "kind": "Group"}, {"name": "system:anonymous", "kind": "User"}], "role-2"), "parameters": {"allowedRoles": ["role-1"]}} + results := violation with input as inp count(results) == 1 } test_allowed_role_multiple_subjects_mix_clusterrolebinding { - input := {"review": clusterrolebinding([{"name": "system:unauthenticated", "kind": "Group"}, {"name": "system:anonymous", "kind": "User"}], "role-2"), "parameters": {"allowedRoles": ["role-2"]}} - results := violation with input as input + inp := {"review": clusterrolebinding([{"name": "system:unauthenticated", "kind": "Group"}, {"name": "system:anonymous", "kind": "User"}], "role-2"), "parameters": {"allowedRoles": ["role-2"]}} + results := violation with input as inp count(results) == 0 } test_multiple_role_multiple_subjects_mix_clusterrolebinding { - input := {"review": clusterrolebinding([{"name": "system:unauthenticated", "kind": "Group"}, {"name": "system:anonymous", "kind": "User"}], "role-2"), "parameters": {"allowedRoles": ["role-1", "role-3"]}} - results := violation with input as input + inp := {"review": clusterrolebinding([{"name": "system:unauthenticated", "kind": "Group"}, {"name": "system:anonymous", "kind": "User"}], "role-2"), "parameters": {"allowedRoles": ["role-1", "role-3"]}} + results := violation with input as inp count(results) == 1 } test_allowed_multiple_role_multiple_subjects_mix_clusterrolebinding { - input := {"review": clusterrolebinding([{"name": "system:unauthenticated", "kind": "Group"}, {"name": "system:anonymous", "kind": "User"}], "role-2"), "parameters": {"allowedRoles": ["role-1", "role-2"]}} - results := violation with input as input + inp := {"review": clusterrolebinding([{"name": "system:unauthenticated", "kind": "Group"}, {"name": "system:anonymous", "kind": "User"}], "role-2"), "parameters": {"allowedRoles": ["role-1", "role-2"]}} + results := violation with input as inp count(results) == 0 } test_blank_subject_rolebinding { - input := {"review": rolebinding([{}], "role-2"), "parameters": {"allowedRoles": ["role-1"]}} - results := violation with input as input + inp := {"review": rolebinding([{}], "role-2"), "parameters": {"allowedRoles": ["role-1"]}} + results := violation with input as inp count(results) == 0 } test_non_anonymous_rolebinding { - input := {"review": rolebinding([{"name": "user-1", "kind": "User"}], "role-2"), "parameters": {"allowedRoles": ["role-1"]}} - results := violation with input as input + inp := {"review": rolebinding([{"name": "user-1", "kind": "User"}], "role-2"), "parameters": {"allowedRoles": ["role-1"]}} + results := violation with input as inp count(results) == 0 } test_anonymous_user_rolebinding { - input := {"review": rolebinding([{"name": "system:anonymous", "kind": "User"}], "role-2"), "parameters": {"allowedRoles": ["role-1"]}} - results := violation with input as input + inp := {"review": rolebinding([{"name": "system:anonymous", "kind": "User"}], "role-2"), "parameters": {"allowedRoles": ["role-1"]}} + results := violation with input as inp count(results) == 1 } test_allowed_role_anonymous_user_rolebinding { - input := {"review": rolebinding([{"name": "system:anonymous", "kind": "User"}], "role-2"), "parameters": {"allowedRoles": ["role-2"]}} - results := violation with input as input + inp := {"review": rolebinding([{"name": "system:anonymous", "kind": "User"}], "role-2"), "parameters": {"allowedRoles": ["role-2"]}} + results := violation with input as inp count(results) == 0 } test_multiple_subjects_anonymous_user_rolebinding { - input := {"review": rolebinding([{"name": "system:anonymous", "kind": "User"}, {"name": "system:authenticated", "kind": "Group"}], "role-2"), "parameters": {"allowedRoles": ["role-1"]}} - results := violation with input as input + inp := {"review": rolebinding([{"name": "system:anonymous", "kind": "User"}, {"name": "system:authenticated", "kind": "Group"}], "role-2"), "parameters": {"allowedRoles": ["role-1"]}} + results := violation with input as inp count(results) == 1 } test_allowed_role_multiple_subjects_anonymous_user_rolebinding { - input := {"review": rolebinding([{"name": "system:anonymous", "kind": "User"}, {"name": "system:authenticated", "kind": "Group"}], "role-2"), "parameters": {"allowedRoles": ["role-2"]}} - results := violation with input as input + inp := {"review": rolebinding([{"name": "system:anonymous", "kind": "User"}, {"name": "system:authenticated", "kind": "Group"}], "role-2"), "parameters": {"allowedRoles": ["role-2"]}} + results := violation with input as inp count(results) == 0 } test_multiple_role_multiple_subjects_anonymous_user_rolebinding { - input := {"review": rolebinding([{"name": "system:anonymous", "kind": "User"}, {"name": "system:authenticated", "kind": "Group"}], "role-2"), "parameters": {"allowedRoles": ["role-1", "role-3"]}} - results := violation with input as input + inp := {"review": rolebinding([{"name": "system:anonymous", "kind": "User"}, {"name": "system:authenticated", "kind": "Group"}], "role-2"), "parameters": {"allowedRoles": ["role-1", "role-3"]}} + results := violation with input as inp count(results) == 1 } test_allowed_multiple_role_multiple_subjects_anonymous_user_rolebinding { - input := {"review": rolebinding([{"name": "system:anonymous", "kind": "User"}, {"name": "system:authenticated", "kind": "Group"}], "role-2"), "parameters": {"allowedRoles": ["role-1", "role-2"]}} - results := violation with input as input + inp := {"review": rolebinding([{"name": "system:anonymous", "kind": "User"}, {"name": "system:authenticated", "kind": "Group"}], "role-2"), "parameters": {"allowedRoles": ["role-1", "role-2"]}} + results := violation with input as inp count(results) == 0 } test_unauthenticated_group_rolebinding { - input := {"review": rolebinding([{"name": "system:unauthenticated", "kind": "Group"}], "role-2"), "parameters": {"allowedRoles": ["role-1"]}} - results := violation with input as input + inp := {"review": rolebinding([{"name": "system:unauthenticated", "kind": "Group"}], "role-2"), "parameters": {"allowedRoles": ["role-1"]}} + results := violation with input as inp count(results) == 1 } test_allowed_role_unauthenticated_group_rolebinding { - input := {"review": rolebinding([{"name": "system:unauthenticated", "kind": "Group"}], "role-2"), "parameters": {"allowedRoles": ["role-2"]}} - results := violation with input as input + inp := {"review": rolebinding([{"name": "system:unauthenticated", "kind": "Group"}], "role-2"), "parameters": {"allowedRoles": ["role-2"]}} + results := violation with input as inp count(results) == 0 } test_multiple_subjects_unauthenticated_group_rolebinding { - input := {"review": rolebinding([{"name": "system:unauthenticated", "kind": "Group"}, {"name": "system:authenticated", "kind": "Group"}], "role-2"), "parameters": {"allowedRoles": ["role-1"]}} - results := violation with input as input + inp := {"review": rolebinding([{"name": "system:unauthenticated", "kind": "Group"}, {"name": "system:authenticated", "kind": "Group"}], "role-2"), "parameters": {"allowedRoles": ["role-1"]}} + results := violation with input as inp count(results) == 1 } test_allowed_role_multiple_subjects_unauthenticated_group_rolebinding { - input := {"review": rolebinding([{"name": "system:unauthenticated", "kind": "Group"}, {"name": "system:authenticated", "kind": "Group"}], "role-2"), "parameters": {"allowedRoles": ["role-2"]}} - results := violation with input as input + inp := {"review": rolebinding([{"name": "system:unauthenticated", "kind": "Group"}, {"name": "system:authenticated", "kind": "Group"}], "role-2"), "parameters": {"allowedRoles": ["role-2"]}} + results := violation with input as inp count(results) == 0 } test_multiple_role_multiple_subjects_unauthenticated_group_rolebinding { - input := {"review": rolebinding([{"name": "system:unauthenticated", "kind": "Group"}, {"name": "system:authenticated", "kind": "Group"}], "role-2"), "parameters": {"allowedRoles": ["role-1", "role-3"]}} - results := violation with input as input + inp := {"review": rolebinding([{"name": "system:unauthenticated", "kind": "Group"}, {"name": "system:authenticated", "kind": "Group"}], "role-2"), "parameters": {"allowedRoles": ["role-1", "role-3"]}} + results := violation with input as inp count(results) == 1 } test_allowed_multiple_role_multiple_subjects_unauthenticated_group_rolebinding { - input := {"review": rolebinding([{"name": "system:unauthenticated", "kind": "Group"}, {"name": "system:authenticated", "kind": "Group"}], "role-2"), "parameters": {"allowedRoles": ["role-1", "role-2"]}} - results := violation with input as input + inp := {"review": rolebinding([{"name": "system:unauthenticated", "kind": "Group"}, {"name": "system:authenticated", "kind": "Group"}], "role-2"), "parameters": {"allowedRoles": ["role-1", "role-2"]}} + results := violation with input as inp count(results) == 0 } test_multiple_subjects_mix_rolebinding { - input := {"review": rolebinding([{"name": "system:unauthenticated", "kind": "Group"}, {"name": "system:anonymous", "kind": "User"}], "role-2"), "parameters": {"allowedRoles": ["role-1"]}} - results := violation with input as input + inp := {"review": rolebinding([{"name": "system:unauthenticated", "kind": "Group"}, {"name": "system:anonymous", "kind": "User"}], "role-2"), "parameters": {"allowedRoles": ["role-1"]}} + results := violation with input as inp count(results) == 1 } test_allowed_role_multiple_subjects_mix_rolebinding { - input := {"review": rolebinding([{"name": "system:unauthenticated", "kind": "Group"}, {"name": "system:anonymous", "kind": "User"}], "role-2"), "parameters": {"allowedRoles": ["role-2"]}} - results := violation with input as input + inp := {"review": rolebinding([{"name": "system:unauthenticated", "kind": "Group"}, {"name": "system:anonymous", "kind": "User"}], "role-2"), "parameters": {"allowedRoles": ["role-2"]}} + results := violation with input as inp count(results) == 0 } test_multiple_role_multiple_subjects_mix_rolebinding { - input := {"review": rolebinding([{"name": "system:unauthenticated", "kind": "Group"}, {"name": "system:anonymous", "kind": "User"}], "role-2"), "parameters": {"allowedRoles": ["role-1", "role-3"]}} - results := violation with input as input + inp := {"review": rolebinding([{"name": "system:unauthenticated", "kind": "Group"}, {"name": "system:anonymous", "kind": "User"}], "role-2"), "parameters": {"allowedRoles": ["role-1", "role-3"]}} + results := violation with input as inp count(results) == 1 } test_allowed_multiple_role_multiple_subjects_mix_rolebinding { - input := {"review": rolebinding([{"name": "system:unauthenticated", "kind": "Group"}, {"name": "system:anonymous", "kind": "User"}], "role-2"), "parameters": {"allowedRoles": ["role-1", "role-2"]}} - results := violation with input as input + inp := {"review": rolebinding([{"name": "system:unauthenticated", "kind": "Group"}, {"name": "system:anonymous", "kind": "User"}], "role-2"), "parameters": {"allowedRoles": ["role-1", "role-2"]}} + results := violation with input as inp count(results) == 0 } diff --git a/src/general/disallowedrepos/src_test.rego b/src/general/disallowedrepos/src_test.rego index d13458af8..b05d7e62e 100644 --- a/src/general/disallowedrepos/src_test.rego +++ b/src/general/disallowedrepos/src_test.rego @@ -1,75 +1,75 @@ package k8sdisallowedrepos test_input_allowed_container { - input := { "review": input_review(input_container_allowed), "parameters": {"repos": ["disallowed"]}} - results := violation with input as input + inp := { "review": input_review(input_container_allowed), "parameters": {"repos": ["disallowed"]}} + results := violation with input as inp count(results) == 0 } test_input_allowed_container_x2 { - input := { "review": input_review(input_container_allowed), "parameters": {"repos": ["other", "disallowed"]}} - results := violation with input as input + inp := { "review": input_review(input_container_allowed), "parameters": {"repos": ["other", "disallowed"]}} + results := violation with input as inp count(results) == 0 } test_input_allowed_dual_container { - input := { "review": input_review(input_container_dual_allowed), "parameters": {"repos": ["disallowed"]}} - results := violation with input as input + inp := { "review": input_review(input_container_dual_allowed), "parameters": {"repos": ["disallowed"]}} + results := violation with input as inp count(results) == 0 } test_input_denied_container { - input := { "review": input_review(input_container_denied), "parameters": {"repos": ["disallowed"]}} - results := violation with input as input + inp := { "review": input_review(input_container_denied), "parameters": {"repos": ["disallowed"]}} + results := violation with input as inp count(results) == 1 } test_input_denied_container_x2 { - input := { "review": input_review(input_container_denied), "parameters": {"repos": ["other", "disallowed"]}} - results := violation with input as input + inp := { "review": input_review(input_container_denied), "parameters": {"repos": ["other", "disallowed"]}} + results := violation with input as inp count(results) == 1 } test_input_denied_dual_container { - input := { "review": input_review(input_container_dual_denied), "parameters": {"repos": ["disallowed"]}} - results := violation with input as input + inp := { "review": input_review(input_container_dual_denied), "parameters": {"repos": ["disallowed"]}} + results := violation with input as inp count(results) == 2 } test_input_denied_mixed_container { - input := { "review": input_review(array.concat(input_container_allowed, input_container_denied)), "parameters": {"repos": ["disallowed"]}} - results := violation with input as input + inp := { "review": input_review(array.concat(input_container_allowed, input_container_denied)), "parameters": {"repos": ["disallowed"]}} + results := violation with input as inp count(results) == 1 } # init containers test_input_allowed_initcontainer { - input := { "review": input_init_review(input_container_allowed), "parameters": {"repos": ["disallowed"]}} - results := violation with input as input + inp := { "review": input_init_review(input_container_allowed), "parameters": {"repos": ["disallowed"]}} + results := violation with input as inp count(results) == 0 } test_input_allowed_initcontainer_x2 { - input := { "review": input_init_review(input_container_allowed), "parameters": {"repos": ["other", "disallowed"]}} - results := violation with input as input + inp := { "review": input_init_review(input_container_allowed), "parameters": {"repos": ["other", "disallowed"]}} + results := violation with input as inp count(results) == 0 } test_input_allowed_dual_initcontainer { - input := { "review": input_init_review(input_container_dual_allowed), "parameters": {"repos": ["disallowed"]}} - results := violation with input as input + inp := { "review": input_init_review(input_container_dual_allowed), "parameters": {"repos": ["disallowed"]}} + results := violation with input as inp count(results) == 0 } test_input_denied_initcontainer { - input := { "review": input_init_review(input_container_denied), "parameters": {"repos": ["disallowed"]}} - results := violation with input as input + inp := { "review": input_init_review(input_container_denied), "parameters": {"repos": ["disallowed"]}} + results := violation with input as inp count(results) == 1 } test_input_denied_initcontainer_x2 { - input := { "review": input_init_review(input_container_denied), "parameters": {"repos": ["other", "disallowed"]}} - results := violation with input as input + inp := { "review": input_init_review(input_container_denied), "parameters": {"repos": ["other", "disallowed"]}} + results := violation with input as inp count(results) == 1 } test_input_denied_dual_initcontainer { - input := { "review": input_init_review(input_container_dual_denied), "parameters": {"repos": ["disallowed"]}} - results := violation with input as input + inp := { "review": input_init_review(input_container_dual_denied), "parameters": {"repos": ["disallowed"]}} + results := violation with input as inp count(results) == 2 } test_input_denied_mixed_initcontainer { - input := { "review": input_init_review(array.concat(input_container_allowed, input_container_denied)), "parameters": {"repos": ["allowed"]}} - results := violation with input as input + inp := { "review": input_init_review(array.concat(input_container_allowed, input_container_denied)), "parameters": {"repos": ["allowed"]}} + results := violation with input as inp count(results) == 1 } diff --git a/src/general/disallowedtags/constraint.tmpl b/src/general/disallowedtags/constraint.tmpl index 4e803e6e7..561d55206 100644 --- a/src/general/disallowedtags/constraint.tmpl +++ b/src/general/disallowedtags/constraint.tmpl @@ -4,7 +4,7 @@ metadata: name: k8sdisallowedtags annotations: metadata.gatekeeper.sh/title: "Disallow tags" - metadata.gatekeeper.sh/version: 1.0.0 + metadata.gatekeeper.sh/version: 1.0.1 description: >- Requires container images to have an image tag different from the ones in the specified list. diff --git a/src/general/disallowedtags/src.rego b/src/general/disallowedtags/src.rego index d35964fd7..de10aeb7e 100644 --- a/src/general/disallowedtags/src.rego +++ b/src/general/disallowedtags/src.rego @@ -5,16 +5,15 @@ import data.lib.exempt_container.is_exempt violation[{"msg": msg}] { container := input_containers[_] not is_exempt(container) - tags := [forbid | tag = input.parameters.tags[_] ; forbid = endswith(container.image, concat(":", ["", tag]))] - any(tags) + tags := [tag_with_prefix | tag := input.parameters.tags[_]; tag_with_prefix := concat(":", ["", tag])] + strings.any_suffix_match(container.image, tags) msg := sprintf("container <%v> uses a disallowed tag <%v>; disallowed tags are %v", [container.name, container.image, input.parameters.tags]) } violation[{"msg": msg}] { container := input_containers[_] not is_exempt(container) - tag := [contains(container.image, ":")] - not all(tag) + not contains(container.image, ":") msg := sprintf("container <%v> didn't specify an image tag <%v>", [container.name, container.image]) } diff --git a/src/general/disallowedtags/src_test.rego b/src/general/disallowedtags/src_test.rego index 71a8805b7..7bddec15f 100644 --- a/src/general/disallowedtags/src_test.rego +++ b/src/general/disallowedtags/src_test.rego @@ -1,110 +1,110 @@ package k8sdisallowedtags test_input_allowed_container { - input := { "review": input_review(input_container_allowed), "parameters": {"tags": ["latest", "testing"]}} - results := violation with input as input + inp := { "review": input_review(input_container_allowed), "parameters": {"tags": ["latest", "testing"]}} + results := violation with input as inp count(results) == 0 } test_input_allowed_dual_container { - input := { "review": input_review(input_container_dual_allowed), "parameters": {"tags": ["latest", "testing"]}} - results := violation with input as input + inp := { "review": input_review(input_container_dual_allowed), "parameters": {"tags": ["latest", "testing"]}} + results := violation with input as inp count(results) == 0 } test_input_denied_container_emtpy { - input := { "review": input_review(input_container_denied_empty), "parameters": {"tags": ["latest", "testing"]}} - results := violation with input as input + inp := { "review": input_review(input_container_denied_empty), "parameters": {"tags": ["latest", "testing"]}} + results := violation with input as inp count(results) == 1 } test_input_denied_container_latest { - input := { "review": input_review(input_container_denied_latest), "parameters": {"tags": ["latest", "testing"]}} - results := violation with input as input + inp := { "review": input_review(input_container_denied_latest), "parameters": {"tags": ["latest", "testing"]}} + results := violation with input as inp count(results) == 1 } test_input_denied_container_testing { - input := { "review": input_review(input_container_denied_testing), "parameters": {"tags": ["latest", "testing"]}} - results := violation with input as input + inp := { "review": input_review(input_container_denied_testing), "parameters": {"tags": ["latest", "testing"]}} + results := violation with input as inp count(results) == 1 } test_input_denied_dual_container_empty_tag { - input := { "review": input_review(array.concat(input_container_denied_empty, input_container_denied_latest)), "parameters": {"tags": ["latest", "testing"]}} - results := violation with input as input + inp := { "review": input_review(array.concat(input_container_denied_empty, input_container_denied_latest)), "parameters": {"tags": ["latest", "testing"]}} + results := violation with input as inp count(results) == 2 } test_input_denied_dual_container_2tags { - input := { "review": input_review(array.concat(input_container_denied_testing, input_container_denied_latest)), "parameters": {"tags": ["latest", "testing"]}} - results := violation with input as input + inp := { "review": input_review(array.concat(input_container_denied_testing, input_container_denied_latest)), "parameters": {"tags": ["latest", "testing"]}} + results := violation with input as inp count(results) == 2 } test_input_denied_mixed_container_empty { - input := { "review": input_review(array.concat(input_container_allowed, input_container_denied_empty)), "parameters": {"tags": ["latest", "testing"]}} - results := violation with input as input + inp := { "review": input_review(array.concat(input_container_allowed, input_container_denied_empty)), "parameters": {"tags": ["latest", "testing"]}} + results := violation with input as inp count(results) == 1 } test_input_denied_mixed_container_latest { - input := { "review": input_review(array.concat(input_container_allowed, input_container_denied_latest)), "parameters": {"tags": ["latest", "testing"]}} - results := violation with input as input + inp := { "review": input_review(array.concat(input_container_allowed, input_container_denied_latest)), "parameters": {"tags": ["latest", "testing"]}} + results := violation with input as inp count(results) == 1 } # init containers test_input_allowed_container { - input := { "review": input_init_review(input_container_allowed), "parameters": {"tags": ["latest", "testing"]}} - results := violation with input as input + inp := { "review": input_init_review(input_container_allowed), "parameters": {"tags": ["latest", "testing"]}} + results := violation with input as inp count(results) == 0 } test_input_allowed_dual_container { - input := { "review": input_init_review(input_container_dual_allowed), "parameters": {"tags": ["latest", "testing"]}} - results := violation with input as input + inp := { "review": input_init_review(input_container_dual_allowed), "parameters": {"tags": ["latest", "testing"]}} + results := violation with input as inp count(results) == 0 } test_input_denied_container_emtpy { - input := { "review": input_init_review(input_container_denied_empty), "parameters": {"tags": ["latest", "testing"]}} - results := violation with input as input + inp := { "review": input_init_review(input_container_denied_empty), "parameters": {"tags": ["latest", "testing"]}} + results := violation with input as inp count(results) == 1 } test_input_denied_container_latest { - input := { "review": input_init_review(input_container_denied_latest), "parameters": {"tags": ["latest", "testing"]}} - results := violation with input as input + inp := { "review": input_init_review(input_container_denied_latest), "parameters": {"tags": ["latest", "testing"]}} + results := violation with input as inp count(results) == 1 } test_input_denied_container_testing { - input := { "review": input_init_review(input_container_denied_testing), "parameters": {"tags": ["latest", "testing"]}} - results := violation with input as input + inp := { "review": input_init_review(input_container_denied_testing), "parameters": {"tags": ["latest", "testing"]}} + results := violation with input as inp count(results) == 1 } test_input_denied_dual_container_empty_tag { - input := { "review": input_init_review(array.concat(input_container_denied_empty, input_container_denied_latest)), "parameters": {"tags": ["latest", "testing"]}} - results := violation with input as input + inp := { "review": input_init_review(array.concat(input_container_denied_empty, input_container_denied_latest)), "parameters": {"tags": ["latest", "testing"]}} + results := violation with input as inp count(results) == 2 } test_input_denied_dual_container_2tags { - input := { "review": input_init_review(array.concat(input_container_denied_testing, input_container_denied_latest)), "parameters": {"tags": ["latest", "testing"]}} - results := violation with input as input + inp := { "review": input_init_review(array.concat(input_container_denied_testing, input_container_denied_latest)), "parameters": {"tags": ["latest", "testing"]}} + results := violation with input as inp count(results) == 2 } test_input_denied_mixed_container_empty { - input := { "review": input_init_review(array.concat(input_container_allowed, input_container_denied_empty)), "parameters": {"tags": ["latest", "testing"]}} - results := violation with input as input + inp := { "review": input_init_review(array.concat(input_container_allowed, input_container_denied_empty)), "parameters": {"tags": ["latest", "testing"]}} + results := violation with input as inp count(results) == 1 } test_input_denied_mixed_container_latest { - input := { "review": input_init_review(array.concat(input_container_allowed, input_container_denied_latest)), "parameters": {"tags": ["latest", "testing"]}} - results := violation with input as input + inp := { "review": input_init_review(array.concat(input_container_allowed, input_container_denied_latest)), "parameters": {"tags": ["latest", "testing"]}} + results := violation with input as inp count(results) == 1 } test_input_denied_mixed_container_with_some_exempt_image { - input := { "review": input_init_review(array.concat(input_container_exempt, input_container_denied_latest)), "parameters": {"tags": ["latest", "testing"], "exemptImages": ["exempt:latest"]}} - results := violation with input as input + inp := { "review": input_init_review(array.concat(input_container_exempt, input_container_denied_latest)), "parameters": {"tags": ["latest", "testing"], "exemptImages": ["exempt:latest"]}} + results := violation with input as inp count(results) == 2 } test_input_denied_dual_container_with_all_exempt_image { - input := { "review": input_init_review(array.concat(input_container_exempt, input_container_denied_latest)), "parameters": {"tags": ["latest", "testing"], "exemptImages": ["exempt:latest", "exempt:testing"]}} - results := violation with input as input + inp := { "review": input_init_review(array.concat(input_container_exempt, input_container_denied_latest)), "parameters": {"tags": ["latest", "testing"], "exemptImages": ["exempt:latest", "exempt:testing"]}} + results := violation with input as inp count(results) == 1 } test_input_allowed_dual_container_with_exempt_image { - input := { "review": input_init_review(input_container_exempt), "parameters": {"tags": ["latest", "testing"], "exemptImages": ["exempt:latest", "exempt:testing"]}} - results := violation with input as input + inp := { "review": input_init_review(input_container_exempt), "parameters": {"tags": ["latest", "testing"], "exemptImages": ["exempt:latest", "exempt:testing"]}} + results := violation with input as inp count(results) == 0 } diff --git a/src/general/disallowinteractive/src_test.rego b/src/general/disallowinteractive/src_test.rego index 78af2ca2d..5a408ae3d 100644 --- a/src/general/disallowinteractive/src_test.rego +++ b/src/general/disallowinteractive/src_test.rego @@ -1,48 +1,48 @@ package k8sdisallowinteractivetty test_input_container_not_tty_allowed { - input := { "review": input_review} - results := violation with input as input + inp := {"review": input_review} + results := violation with input as inp count(results) == 0 } test_input_container_stdin_not_allowed { - input := { "review": input_review_stdin} - results := violation with input as input + inp:= {"review": input_review_stdin} + results := violation with input as inp count(results) == 1 } test_input_container_tty_not_allowed { - input := { "review": input_review_tty} - results := violation with input as input + inp := {"review": input_review_tty} + results := violation with input as inp count(results) == 1 } test_input_one_container_with_exemption { - input := { "review": input_review_stdin, "parameters": {"exemptImages": ["one/*"]}} - results := violation with input as input + inp := {"review": input_review_stdin, "parameters": {"exemptImages": ["one/*"]}} + results := violation with input as inp count(results) == 0 } test_input_container_many_not_stdin_allowed { - input := { "review": input_review_many} - results := violation with input as input + inp := {"review": input_review_many} + results := violation with input as inp count(results) == 1 } test_input_container_many_mixed_stdin_not_allowed { - input := { "review": input_review_many_mixed} - results := violation with input as input + inp := {"review": input_review_many_mixed} + results := violation with input as inp count(results) == 2 } test_input_container_many_mixed_stdin_not_allowed_one_exempted { - input := { "review": input_review_many_mixed, "parameters": {"exemptImages": ["one/*"]}} - results := violation with input as input + inp := {"review": input_review_many_mixed, "parameters": {"exemptImages": ["one/*"]}} + results := violation with input as inp count(results) == 1 } test_input_container_many_mixed_stdin_not_allowed_all_exempted { - input := { "review": input_review_many_mixed, "parameters": {"exemptImages": ["one/*", "two/*", "three/*"]}} - results := violation with input as input + inp := {"review": input_review_many_mixed, "parameters": {"exemptImages": ["one/*", "two/*", "three/*"]}} + results := violation with input as inp count(results) == 0 } test_input_container_many_mixed_stdin_not_allowed_two { - input := { "review": input_review_many_mixed_two} - results := violation with input as input + inp := {"review": input_review_many_mixed_two} + results := violation with input as inp count(results) == 2 } @@ -149,7 +149,7 @@ input_containers_many = [ "name": "nginx2", "image": "three/nginx", "stdin": true - + }] input_containers_many_mixed = [ diff --git a/src/general/ephemeralstoragelimit/constraint.tmpl b/src/general/ephemeralstoragelimit/constraint.tmpl index 827b6bd52..488f8a47d 100644 --- a/src/general/ephemeralstoragelimit/constraint.tmpl +++ b/src/general/ephemeralstoragelimit/constraint.tmpl @@ -4,7 +4,7 @@ metadata: name: k8scontainerephemeralstoragelimit annotations: metadata.gatekeeper.sh/title: "Container ephemeral storage limit" - metadata.gatekeeper.sh/version: 1.0.1 + metadata.gatekeeper.sh/version: 1.0.2 description: >- Requires containers to have an ephemeral storage limit set and constrains the limit to be within the specified maximum values. diff --git a/src/general/ephemeralstoragelimit/src.rego b/src/general/ephemeralstoragelimit/src.rego index 88100fbf5..f7951ca66 100644 --- a/src/general/ephemeralstoragelimit/src.rego +++ b/src/general/ephemeralstoragelimit/src.rego @@ -108,7 +108,7 @@ canonify_storage(orig) = new { not is_number(orig) suffix := get_suffix(orig) raw := replace(orig, suffix, "") - re_match("^[0-9]+(\\.[0-9]+)?$", raw) + regex.match("^[0-9]+(\\.[0-9]+)?$", raw) new := to_number(raw) * storage_multiple(suffix) } diff --git a/src/general/ephemeralstoragelimit/src_test.rego b/src/general/ephemeralstoragelimit/src_test.rego index c2ede0c4d..fa3d60ac9 100644 --- a/src/general/ephemeralstoragelimit/src_test.rego +++ b/src/general/ephemeralstoragelimit/src_test.rego @@ -1,155 +1,155 @@ package k8scontainerephemeralstoragelimit test_input_no_violations_int { - input := {"review": review([ctr("a", 4096)]), "parameters": {"ephemeral-storage": "8192"}} - results := violation with input as input + inp := {"review": review([ctr("a", 4096)]), "parameters": {"ephemeral-storage": "8192"}} + results := violation with input as inp count(results) == 0 } test_input_no_violations_str { - input := {"review": review([ctr("a", "1Gi")]), "parameters": {"ephemeral-storage": "2Gi"}} - results := violation with input as input + inp := {"review": review([ctr("a", "1Gi")]), "parameters": {"ephemeral-storage": "2Gi"}} + results := violation with input as inp count(results) == 0 } test_input_no_violations_str_small { - input := {"review": review([ctr("a", "100")]), "parameters": {"ephemeral-storage": "2Gi"}} - results := violation with input as input + inp := {"review": review([ctr("a", "100")]), "parameters": {"ephemeral-storage": "2Gi"}} + results := violation with input as inp count(results) == 0 } test_input_violations_int { - input := {"review": review([ctr("a", 4096)]), "parameters": {"ephemeral-storage": "2048"}} - results := violation with input as input + inp := {"review": review([ctr("a", 4096)]), "parameters": {"ephemeral-storage": "2048"}} + results := violation with input as inp count(results) == 1 } test_input_violations_str { - input := {"review": review([ctr("a", "2.5Gi")]), "parameters": {"ephemeral-storage": "2Gi"}} - results := violation with input as input + inp := {"review": review([ctr("a", "2.5Gi")]), "parameters": {"ephemeral-storage": "2Gi"}} + results := violation with input as inp count(results) == 1 } test_input_violations_str_small { - input := {"review": review([ctr("a", "130")]), "parameters": {"ephemeral-storage": 128}} - results := violation with input as input + inp := {"review": review([ctr("a", "130")]), "parameters": {"ephemeral-storage": 128}} + results := violation with input as inp count(results) == 1 } test_no_parse_ephemeral_storage { - input := {"review": review([ctr("a", "123def")]), "parameters": {"ephemeral-storage": "2Gi"}} - results := violation with input as input + inp := {"review": review([ctr("a", "123def")]), "parameters": {"ephemeral-storage": "2Gi"}} + results := violation with input as inp count(results) == 1 } test_1_bad_eph { - input := {"review": review([ctr("a", "1Gi"), ctr("a", "3Gi")]), "parameters": {"ephemeral-storage": "2Gi"}} - results := violation with input as input + inp := {"review": review([ctr("a", "1Gi"), ctr("a", "3Gi")]), "parameters": {"ephemeral-storage": "2Gi"}} + results := violation with input as inp count(results) == 1 } test_2_bad_eph { - input := {"review": review([ctr("a", "2.5Gi"), ctr("a", "3Gi")]), "parameters": {"ephemeral-storage": "2Gi"}} - results := violation with input as input + inp := {"review": review([ctr("a", "2.5Gi"), ctr("a", "3Gi")]), "parameters": {"ephemeral-storage": "2Gi"}} + results := violation with input as inp count(results) == 2 } test_no_eph_limit { - input := {"review": review([{"name": "a", "resources": {"limits": {"cpu": 1}}}]), "parameters": {"ephemeral-storage": "2Gi"}} - results := violation with input as input + inp := {"review": review([{"name": "a", "resources": {"limits": {"cpu": 1}}}]), "parameters": {"ephemeral-storage": "2Gi"}} + results := violation with input as inp count(results) == 1 } test_no_limit { - input := {"review": review([{"name": "a", "resources": {}}]), "parameters": {"ephemeral-storage": "2Gi"}} - results := violation with input as input + inp := {"review": review([{"name": "a", "resources": {}}]), "parameters": {"ephemeral-storage": "2Gi"}} + results := violation with input as inp count(results) == 1 } test_no_resources { - input := {"review": review([{"name": "a"}]), "parameters": {"ephemeral-storage": "2Gi"}} - results := violation with input as input + inp := {"review": review([{"name": "a"}]), "parameters": {"ephemeral-storage": "2Gi"}} + results := violation with input as inp count(results) == 1 } test_init_containers_checked { - input := {"review": init_review([ctr("a", "2.2 Ti")]), "parameters": {"ephemeral-storage": "3Gi"}} - results := violation with input as input + inp := {"review": init_review([ctr("a", "2.2 Ti")]), "parameters": {"ephemeral-storage": "3Gi"}} + results := violation with input as inp count(results) == 1 } # # EPH SCALE TESTS test_input_no_violations_eph_k { - input := {"review": review([ctr("a", "100k")]), "parameters": {"ephemeral-storage": "2Gi"}} - results := violation with input as input + inp := {"review": review([ctr("a", "100k")]), "parameters": {"ephemeral-storage": "2Gi"}} + results := violation with input as inp count(results) == 0 } test_input_violations_eph_m { - input := {"review": review([ctr("a", "10000m")]), "parameters": {"ephemeral-storage": "9"}} - results := violation with input as input + inp := {"review": review([ctr("a", "10000m")]), "parameters": {"ephemeral-storage": "9"}} + results := violation with input as inp count(results) == 1 } test_input_violations_eph_K { - input := {"review": review([ctr("a", "1k")]), "parameters": {"ephemeral-storage": "999"}} - results := violation with input as input + inp := {"review": review([ctr("a", "1k")]), "parameters": {"ephemeral-storage": "999"}} + results := violation with input as inp count(results) == 1 } test_input_violations_eph_M { - input := {"review": review([ctr("a", "1M")]), "parameters": {"ephemeral-storage": 999999}} - results := violation with input as input + inp := {"review": review([ctr("a", "1M")]), "parameters": {"ephemeral-storage": 999999}} + results := violation with input as inp count(results) == 1 } test_input_violations_eph_G { - input := {"review": review([ctr("a", "1G")]), "parameters": {"ephemeral-storage": "999999999"}} - results := violation with input as input + inp := {"review": review([ctr("a", "1G")]), "parameters": {"ephemeral-storage": "999999999"}} + results := violation with input as inp count(results) == 1 } test_input_violations_eph_T { - input := {"review": review([ctr("a", "1T")]), "parameters": {"ephemeral-storage": "2Gi"}} - results := violation with input as input + inp := {"review": review([ctr("a", "1T")]), "parameters": {"ephemeral-storage": "2Gi"}} + results := violation with input as inp count(results) == 1 } test_input_violations_eph_P { - input := {"review": review([ctr("a", "1P")]), "parameters": {"ephemeral-storage": "2Gi"}} - results := violation with input as input + inp := {"review": review([ctr("a", "1P")]), "parameters": {"ephemeral-storage": "2Gi"}} + results := violation with input as inp count(results) == 1 } test_input_violations_eph_E { - input := {"review": review([ctr("a", "1E")]), "parameters": {"ephemeral-storage": "2Gi"}} - results := violation with input as input + inp := {"review": review([ctr("a", "1E")]), "parameters": {"ephemeral-storage": "2Gi"}} + results := violation with input as inp count(results) == 1 } test_input_violations_eph_Ki { - input := {"review": review([ctr("a", "1Ki")]), "parameters": {"ephemeral-storage": "1023"}} - results := violation with input as input + inp := {"review": review([ctr("a", "1Ki")]), "parameters": {"ephemeral-storage": "1023"}} + results := violation with input as inp count(results) == 1 } test_input_violations_eph_Mi { - input := {"review": review([ctr("a", "1Mi")]), "parameters": {"ephemeral-storage": "0.5Mi"}} - results := violation with input as input + inp := {"review": review([ctr("a", "1Mi")]), "parameters": {"ephemeral-storage": "0.5Mi"}} + results := violation with input as inp count(results) == 1 } test_input_violations_eph_Gi { - input := {"review": review([ctr("a", "1Gi")]), "parameters": {"ephemeral-storage": "0.22Gi"}} - results := violation with input as input + inp := {"review": review([ctr("a", "1Gi")]), "parameters": {"ephemeral-storage": "0.22Gi"}} + results := violation with input as inp count(results) == 1 } test_input_violations_decimal_eph_Gi { - input := {"review": review([ctr("a", "1.4Gi")]), "parameters": {"ephemeral-storage": "1Gi"}} - results := violation with input as input + inp := {"review": review([ctr("a", "1.4Gi")]), "parameters": {"ephemeral-storage": "1Gi"}} + results := violation with input as inp count(results) == 1 } test_input_violations_eph_Ti { - input := {"review": review([ctr("a", "1Ti")]), "parameters": {"ephemeral-storage": "2Gi"}} - results := violation with input as input + inp := {"review": review([ctr("a", "1Ti")]), "parameters": {"ephemeral-storage": "2Gi"}} + results := violation with input as inp count(results) == 1 } test_input_violations_eph_Pi { - input := {"review": review([ctr("a", "1Pi")]), "parameters": {"ephemeral-storage": "2Gi"}} - results := violation with input as input + inp := {"review": review([ctr("a", "1Pi")]), "parameters": {"ephemeral-storage": "2Gi"}} + results := violation with input as inp count(results) == 1 } test_input_violations_eph_Ei { - input := {"review": review([ctr("a", "1Ei")]), "parameters": {"ephemeral-storage": "2Gi"}} - results := violation with input as input + inp := {"review": review([ctr("a", "1Ei")]), "parameters": {"ephemeral-storage": "2Gi"}} + results := violation with input as inp count(results) == 1 } test_input_violations_eph_Ei_with_exemption { - input := {"review": review([ctr("a", "1Ei")]), "parameters": {"exemptImages": ["nginx"], "ephemeral-storage": "1Pi"}} - results := violation with input as input + inp := {"review": review([ctr("a", "1Ei")]), "parameters": {"exemptImages": ["nginx"], "ephemeral-storage": "1Pi"}} + results := violation with input as inp count(results) == 0 } test_update { - input := {"review": object.union(review([ctr("a", 4096)]), {"operation": "UPDATE"}), "parameters": {"ephemeral-storage": "2048"}} - results := violation with input as input + inp := {"review": object.union(review([ctr("a", 4096)]), {"operation": "UPDATE"}), "parameters": {"ephemeral-storage": "2048"}} + results := violation with input as inp count(results) == 0 } diff --git a/src/general/externalip/src_test.rego b/src/general/externalip/src_test.rego index 6f2211b17..f5e050afe 100644 --- a/src/general/externalip/src_test.rego +++ b/src/general/externalip/src_test.rego @@ -1,49 +1,49 @@ package k8sexternalips test_input_non_svc { - input := {"review": non_svc, "parameters": {"allowedIPs": ["1.2.3.4"]}} - results := violation with input as input + inp := {"review": non_svc, "parameters": {"allowedIPs": ["1.2.3.4"]}} + results := violation with input as inp count(results) == 0 } test_input_no_external_ip { - input := {"review": non_externalip_svc, "parameters": {"allowedIPs": ["1.2.3.4"]}} - results := violation with input as input + inp := {"review": non_externalip_svc, "parameters": {"allowedIPs": ["1.2.3.4"]}} + results := violation with input as inp count(results) == 0 } test_input_no_violations_externalip { - input := {"review": externalip_svc(["1.2.3.4"]), "parameters": {"allowedIPs": ["1.2.3.4"]}} - results := violation with input as input + inp := {"review": externalip_svc(["1.2.3.4"]), "parameters": {"allowedIPs": ["1.2.3.4"]}} + results := violation with input as inp count(results) == 0 } test_input_no_violations_externalip_multiple { - input := {"review": externalip_svc(["1.2.3.4", "203.0.113.0"]), "parameters": {"allowedIPs": ["1.1.1.1", "203.0.113.0", "1.2.3.4", "203.0.113.1"]}} - results := violation with input as input + inp := {"review": externalip_svc(["1.2.3.4", "203.0.113.0"]), "parameters": {"allowedIPs": ["1.1.1.1", "203.0.113.0", "1.2.3.4", "203.0.113.1"]}} + results := violation with input as inp count(results) == 0 } test_input_no_violations_empty { - input := {"review": externalip_svc([]), "parameters": {"allowedIPs": []}} - results := violation with input as input + inp := {"review": externalip_svc([]), "parameters": {"allowedIPs": []}} + results := violation with input as inp count(results) == 0 } test_input_violations_externalip { - input := {"review": externalip_svc(["203.0.113.0"]), "parameters": {"allowedIPs": ["1.1.1.1", "1.2.3.4"]}} - results := violation with input as input + inp := {"review": externalip_svc(["203.0.113.0"]), "parameters": {"allowedIPs": ["1.1.1.1", "1.2.3.4"]}} + results := violation with input as inp results count(results) == 1 } test_input_violations_none_allowed { - input := {"review": externalip_svc(["203.0.113.0"]), "parameters": {"allowedIPs": []}} - results := violation with input as input + inp := {"review": externalip_svc(["203.0.113.0"]), "parameters": {"allowedIPs": []}} + results := violation with input as inp count(results) == 1 } test_input_violations_partial { - input := {"review": externalip_svc(["1.2.3.4", "203.0.113.0"]), "parameters": {"allowedIPs": ["1.1.1.1", "1.2.3.4", "203.0.113.1"]}} - results := violation with input as input + inp := {"review": externalip_svc(["1.2.3.4", "203.0.113.0"]), "parameters": {"allowedIPs": ["1.1.1.1", "1.2.3.4", "203.0.113.1"]}} + results := violation with input as inp count(results) == 1 } test_input_violations_multiple { - input := {"review": externalip_svc(["1.2.3.4", "203.0.113.0"]), "parameters": {"allowedIPs": ["1.1.1.1", "203.0.113.1"]}} - results := violation with input as input + inp := {"review": externalip_svc(["1.2.3.4", "203.0.113.0"]), "parameters": {"allowedIPs": ["1.1.1.1", "203.0.113.1"]}} + results := violation with input as inp count(results) == 1 # Multiple failing IPs reported in single error message. } diff --git a/src/general/horizontalpodautoscaler/src_test.rego b/src/general/horizontalpodautoscaler/src_test.rego index 4100ab8db..6822cd787 100644 --- a/src/general/horizontalpodautoscaler/src_test.rego +++ b/src/general/horizontalpodautoscaler/src_test.rego @@ -2,7 +2,7 @@ package k8shorizontalpodautoscaler namespace := "namespace-1" -valid_scale_target_ref := { +valid_scale_target_ref := { "apiVersion": "apps/v1", "kind": "Deployment", "name": "deployment-1" @@ -27,58 +27,58 @@ deployment := { } test_input_hpa_min_replicas_outside_range { - input := {"review": input_hpa(2,5,valid_scale_target_ref), "parameters": input_parameters_valid_range} - results := violation with input as input + inp := {"review": input_hpa(2,5,valid_scale_target_ref), "parameters": input_parameters_valid_range} + results := violation with input as inp count(results) == 1 } test_input_hpa_max_replicas_outside_range { - input := {"review": input_hpa(4,7,valid_scale_target_ref), "parameters": input_parameters_valid_range} - results := violation with input as input + inp := {"review": input_hpa(4,7,valid_scale_target_ref), "parameters": input_parameters_valid_range} + results := violation with input as inp count(results) == 1 } test_input_hpa_replicas_within_range { - input := {"review": input_hpa(4,5,valid_scale_target_ref), "parameters": input_parameters_valid_range} - results := violation with input as input + inp := {"review": input_hpa(4,5,valid_scale_target_ref), "parameters": input_parameters_valid_range} + results := violation with input as inp count(results) == 0 } test_input_hpa_replicas_equal_range { - input := {"review": input_hpa(3,6,valid_scale_target_ref), "parameters": input_parameters_valid_range} - results := violation with input as input + inp := {"review": input_hpa(3,6,valid_scale_target_ref), "parameters": input_parameters_valid_range} + results := violation with input as inp count(results) == 0 } test_input_hpa_replicas_below_min_spread { - input := {"review": input_hpa(3,4,valid_scale_target_ref), "parameters": input_parameters_min_spread} - results := violation with input as input + inp := {"review": input_hpa(3,4,valid_scale_target_ref), "parameters": input_parameters_min_spread} + results := violation with input as inp count(results) == 1 } test_input_hpa_replicas_above_min_spread { - input := {"review": input_hpa(3,6,valid_scale_target_ref), "parameters": input_parameters_min_spread} - results := violation with input as input + inp := {"review": input_hpa(3,6,valid_scale_target_ref), "parameters": input_parameters_min_spread} + results := violation with input as inp count(results) == 0 } test_input_hpa_replicas_equal_min_spread { - input := {"review": input_hpa(4,6,valid_scale_target_ref), "parameters": input_parameters_min_spread} - results := violation with input as input + inp := {"review": input_hpa(4,6,valid_scale_target_ref), "parameters": input_parameters_min_spread} + results := violation with input as inp count(results) == 0 } test_input_hpa_invalid_scale_target{ - input := {"review": input_hpa(3,6,invalid_scale_target_ref), "parameters": input_parameters_enforce_scale_target_ref} + inp := {"review": input_hpa(3,6,invalid_scale_target_ref), "parameters": input_parameters_enforce_scale_target_ref} inv := inv_deployment(deployment) - results := violation with input as input with data.inventory as inv + results := violation with input as inp with data.inventory as inv count(results) == 1 } test_input_hpa_valid_scale_target{ - input := {"review": input_hpa(3,6,valid_scale_target_ref), "parameters": input_parameters_enforce_scale_target_ref} + inp := {"review": input_hpa(3,6,valid_scale_target_ref), "parameters": input_parameters_enforce_scale_target_ref} inv := inv_deployment(deployment) - results := violation with input as input with data.inventory as inv + results := violation with input as inp with data.inventory as inv count(results) == 0 } diff --git a/src/general/httpsonly/constraint.tmpl b/src/general/httpsonly/constraint.tmpl index 1ce8621e9..5eff2a7c4 100644 --- a/src/general/httpsonly/constraint.tmpl +++ b/src/general/httpsonly/constraint.tmpl @@ -4,7 +4,7 @@ metadata: name: k8shttpsonly annotations: metadata.gatekeeper.sh/title: "HTTPS Only" - metadata.gatekeeper.sh/version: 1.0.1 + metadata.gatekeeper.sh/version: 1.0.2 description: >- Requires Ingress resources to be HTTPS only. Ingress resources must include the `kubernetes.io/ingress.allow-http` annotation, set to `false`. diff --git a/src/general/httpsonly/src.rego b/src/general/httpsonly/src.rego index 0661b6e15..b6b58b298 100644 --- a/src/general/httpsonly/src.rego +++ b/src/general/httpsonly/src.rego @@ -2,19 +2,19 @@ package k8shttpsonly violation[{"msg": msg}] { input.review.object.kind == "Ingress" - re_match("^(extensions|networking.k8s.io)/", input.review.object.apiVersion) + regex.match("^(extensions|networking.k8s.io)/", input.review.object.apiVersion) ingress := input.review.object not https_complete(ingress) - not tls_is_optional(ingress) + not tls_is_optional msg := sprintf("Ingress should be https. tls configuration and allow-http=false annotation are required for %v", [ingress.metadata.name]) } violation[{"msg": msg}] { input.review.object.kind == "Ingress" - re_match("^(extensions|networking.k8s.io)/", input.review.object.apiVersion) + regex.match("^(extensions|networking.k8s.io)/", input.review.object.apiVersion) ingress := input.review.object not annotation_complete(ingress) - not tls_not_optional(ingress) + tls_is_optional msg := sprintf("Ingress should be https. The allow-http=false annotation is required for %v", [ingress.metadata.name]) } @@ -28,15 +28,7 @@ annotation_complete(ingress) = true { ingress.metadata.annotations["kubernetes.io/ingress.allow-http"] == "false" } -tls_is_optional(ingress) = true { +tls_is_optional { parameters := object.get(input, "parameters", {}) - tlsOptional := object.get(parameters, "tlsOptional", false) - is_boolean(tlsOptional) - true == tlsOptional -} - -tls_not_optional(ingress) = true { - parameters := object.get(input, "parameters", {}) - tlsOptional := object.get(parameters, "tlsOptional", false) - true != tlsOptional + object.get(parameters, "tlsOptional", false) == true } diff --git a/src/general/httpsonly/src_test.rego b/src/general/httpsonly/src_test.rego index 498480243..0c3cf3878 100644 --- a/src/general/httpsonly/src_test.rego +++ b/src/general/httpsonly/src_test.rego @@ -1,63 +1,63 @@ package k8shttpsonly test_http_disallowed { - input := {"review": review_ingress(annotation("false"), tls)} - results := violation with input as input + inp := {"review": review_ingress(annotation("false"), tls)} + results := violation with input as inp count(results) == 0 } test_boolean_annotation { - input := {"review": review_ingress(annotation(false), tls)} - results := violation with input as input + inp := {"review": review_ingress(annotation(false), tls)} + results := violation with input as inp count(results) == 1 } test_true_annotation { - input := {"review": review_ingress(annotation("true"), tls)} - results := violation with input as input + inp := {"review": review_ingress(annotation("true"), tls)} + results := violation with input as inp count(results) == 1 } test_missing_annotation { - input := {"review": review_ingress({}, tls)} - results := violation with input as input + inp := {"review": review_ingress({}, tls)} + results := violation with input as inp count(results) == 1 } test_empty_tls { - input := {"review": review_ingress({}, empty_tls)} - results := violation with input as input + inp := {"review": review_ingress({}, empty_tls)} + results := violation with input as inp count(results) == 1 } test_missing_tls { - input := {"review": review_ingress(annotation("false"), {})} - results := violation with input as input + inp := {"review": review_ingress(annotation("false"), {})} + results := violation with input as inp count(results) == 1 } test_missing_all { - input := {"review": review_ingress({}, {})} - results := violation with input as input + inp := {"review": review_ingress({}, {})} + results := violation with input as inp count(results) == 1 } test_tls_optional_missing_tls { - input := {"review": review_ingress(annotation("false"), {}), "parameters": {"tlsOptional": true}} - results := violation with input as input + inp := {"review": review_ingress(annotation("false"), {}), "parameters": {"tlsOptional": true}} + results := violation with input as inp count(results) == 0 } test_tls_optional_empty_tls { - input := {"review": review_ingress(annotation("false"), empty_tls), "parameters": {"tlsOptional": true}} - results := violation with input as input + inp := {"review": review_ingress(annotation("false"), empty_tls), "parameters": {"tlsOptional": true}} + results := violation with input as inp count(results) == 0 } test_tls_optional_with_tls { - input := {"review": review_ingress(annotation("false"), tls), "parameters": {"tlsOptional": true}} - results := violation with input as input + inp := {"review": review_ingress(annotation("false"), tls), "parameters": {"tlsOptional": true}} + results := violation with input as inp count(results) == 0 } test_tls_optional_true_annotation { - input := {"review": review_ingress(annotation("true"), {}), "parameters": {"tlsOptional": true}} - results := violation with input as input + inp := {"review": review_ingress(annotation("true"), {}), "parameters": {"tlsOptional": true}} + results := violation with input as inp count(results) == 1 } test_tls_optional_missing_annotation { - input := {"review": review_ingress({}, {}), "parameters": {"tlsOptional": true}} - results := violation with input as input + inp := {"review": review_ingress({}, {}), "parameters": {"tlsOptional": true}} + results := violation with input as inp count(results) == 1 } diff --git a/src/general/imagedigests/constraint.tmpl b/src/general/imagedigests/constraint.tmpl index df49d9146..2b9193c62 100644 --- a/src/general/imagedigests/constraint.tmpl +++ b/src/general/imagedigests/constraint.tmpl @@ -4,7 +4,7 @@ metadata: name: k8simagedigests annotations: metadata.gatekeeper.sh/title: "Image Digests" - metadata.gatekeeper.sh/version: 1.0.0 + metadata.gatekeeper.sh/version: 1.0.1 description: >- Requires container images to contain a digest. diff --git a/src/general/imagedigests/src.rego b/src/general/imagedigests/src.rego index a1fdd3836..0170f8c04 100644 --- a/src/general/imagedigests/src.rego +++ b/src/general/imagedigests/src.rego @@ -5,23 +5,20 @@ import data.lib.exempt_container.is_exempt violation[{"msg": msg}] { container := input.review.object.spec.containers[_] not is_exempt(container) - satisfied := [re_match("@[a-z0-9]+([+._-][a-z0-9]+)*:[a-zA-Z0-9=_-]+", container.image)] - not all(satisfied) + not regex.match("@[a-z0-9]+([+._-][a-z0-9]+)*:[a-zA-Z0-9=_-]+", container.image) msg := sprintf("container <%v> uses an image without a digest <%v>", [container.name, container.image]) } violation[{"msg": msg}] { container := input.review.object.spec.initContainers[_] not is_exempt(container) - satisfied := [re_match("@[a-z0-9]+([+._-][a-z0-9]+)*:[a-zA-Z0-9=_-]+", container.image)] - not all(satisfied) + not regex.match("@[a-z0-9]+([+._-][a-z0-9]+)*:[a-zA-Z0-9=_-]+", container.image) msg := sprintf("initContainer <%v> uses an image without a digest <%v>", [container.name, container.image]) } violation[{"msg": msg}] { container := input.review.object.spec.ephemeralContainers[_] not is_exempt(container) - satisfied := [re_match("@[a-z0-9]+([+._-][a-z0-9]+)*:[a-zA-Z0-9=_-]+", container.image)] - not all(satisfied) + not regex.match("@[a-z0-9]+([+._-][a-z0-9]+)*:[a-zA-Z0-9=_-]+", container.image) msg := sprintf("ephemeralContainer <%v> uses an image without a digest <%v>", [container.name, container.image]) } diff --git a/src/general/imagedigests/src_test.rego b/src/general/imagedigests/src_test.rego index 7023bb478..140845157 100644 --- a/src/general/imagedigests/src_test.rego +++ b/src/general/imagedigests/src_test.rego @@ -1,85 +1,85 @@ package k8simagedigests test_input_allowed_container { - input := { "review": input_review(input_container_allowed) } - results := violation with input as input + inp := { "review": input_review(input_container_allowed) } + results := violation with input as inp count(results) == 0 } test_input_allowed_container_with_tag_and_digest { - input := { "review": input_review(input_container_allowed_with_tag) } - results := violation with input as input + inp := { "review": input_review(input_container_allowed_with_tag) } + results := violation with input as inp count(results) == 0 } test_input_allowed_containers_with_registered_algorithms { - input := { "review": input_review(input_container_allowed_registered_algorithms) } - results := violation with input as input + inp := { "review": input_review(input_container_allowed_registered_algorithms) } + results := violation with input as inp count(results) == 0 } test_input_allowed_containers_with_unregistered_algorithms { - input := { "review": input_review(input_container_allowed_unregistered_algorithms) } - results := violation with input as input + inp := { "review": input_review(input_container_allowed_unregistered_algorithms) } + results := violation with input as inp count(results) == 0 } test_input_denied_container { - input := { "review": input_review(input_container_denied) } - results := violation with input as input + inp := { "review": input_review(input_container_denied) } + results := violation with input as inp count(results) == 1 } test_input_denied_dual_container { - input := { "review": input_review(input_container_dual_denied) } - results := violation with input as input + inp := { "review": input_review(input_container_dual_denied) } + results := violation with input as inp count(results) == 2 } test_input_denied_mixed_container { - input := { "review": input_review(array.concat(input_container_allowed, input_container_denied)) } - results := violation with input as input + inp := { "review": input_review(array.concat(input_container_allowed, input_container_denied)) } + results := violation with input as inp count(results) == 1 } test_input_denied_mixed_container_with_exemption { - input := { "review": input_review(array.concat(input_container_allowed, input_container_denied)), "parameters": {"exemptImages": ["denied/*"]} } - results := violation with input as input + inp := { "review": input_review(array.concat(input_container_allowed, input_container_denied)), "parameters": {"exemptImages": ["denied/*"]} } + results := violation with input as inp count(results) == 0 } # init containers test_input_init_allowed_container { - input := { "review": input_init_review(input_container_allowed) } - results := violation with input as input + inp := { "review": input_init_review(input_container_allowed) } + results := violation with input as inp count(results) == 0 } test_input_init_allowed_container_with_tag_and_digest { - input := { "review": input_init_review(input_container_allowed_with_tag) } - results := violation with input as input + inp := { "review": input_init_review(input_container_allowed_with_tag) } + results := violation with input as inp count(results) == 0 } test_input_init_allowed_containers_with_registered_algorithms { - input := { "review": input_init_review(input_container_allowed_registered_algorithms) } - results := violation with input as input + inp := { "review": input_init_review(input_container_allowed_registered_algorithms) } + results := violation with input as inp count(results) == 0 } test_input_init_allowed_containers_with_unregistered_algorithms { - input := { "review": input_init_review(input_container_allowed_unregistered_algorithms) } - results := violation with input as input + inp := { "review": input_init_review(input_container_allowed_unregistered_algorithms) } + results := violation with input as inp count(results) == 0 } test_input_init_denied_container { - input := { "review": input_init_review(input_container_denied) } - results := violation with input as input + inp := { "review": input_init_review(input_container_denied) } + results := violation with input as inp count(results) == 1 } test_input_init_denied_dual_container { - input := { "review": input_init_review(input_container_dual_denied) } - results := violation with input as input + inp := { "review": input_init_review(input_container_dual_denied) } + results := violation with input as inp count(results) == 2 } test_input_init_denied_mixed_container { - input := { "review": input_init_review(array.concat(input_container_allowed, input_container_denied)) } - results := violation with input as input + inp := { "review": input_init_review(array.concat(input_container_allowed, input_container_denied)) } + results := violation with input as inp count(results) == 1 } test_input_init_denied_mixed_container_with_exemption { - input := { "review": input_init_review(array.concat(input_container_allowed, input_container_denied)), "parameters": {"exemptImages": ["denied/*"]} } - results := violation with input as input + inp := { "review": input_init_review(array.concat(input_container_allowed, input_container_denied)), "parameters": {"exemptImages": ["denied/*"]} } + results := violation with input as inp count(results) == 0 } diff --git a/src/general/noupdateserviceaccount/constraint.tmpl b/src/general/noupdateserviceaccount/constraint.tmpl index 58a2c17e3..fa25c9b02 100644 --- a/src/general/noupdateserviceaccount/constraint.tmpl +++ b/src/general/noupdateserviceaccount/constraint.tmpl @@ -4,7 +4,7 @@ metadata: name: noupdateserviceaccount annotations: metadata.gatekeeper.sh/title: "Block updating Service Account" - metadata.gatekeeper.sh/version: 1.0.0 + metadata.gatekeeper.sh/version: 1.0.1 description: "Blocks updating the service account on resources that abstract over Pods. This policy is ignored in audit mode." spec: crd: diff --git a/src/general/noupdateserviceaccount/src.rego b/src/general/noupdateserviceaccount/src.rego index 8ba2ae9ae..53f8cf321 100644 --- a/src/general/noupdateserviceaccount/src.rego +++ b/src/general/noupdateserviceaccount/src.rego @@ -1,12 +1,14 @@ package noupdateserviceaccount -privileged(userInfo, allowedUsers, allowedGroups) { +privileged(userInfo, allowedUsers, _) { # Allow if the user is in allowedUsers. # Use object.get so omitted parameters can't cause policy bypass by # evaluating to undefined. username := object.get(userInfo, "username", "") allowedUsers[_] == username -} { +} + +privileged(userInfo, _, allowedGroups) { # Allow if the user's groups intersect allowedGroups. # Use object.get so omitted parameters can't cause policy bypass by # evaluating to undefined. diff --git a/src/general/noupdateserviceaccount/src_test.rego b/src/general/noupdateserviceaccount/src_test.rego index 7b447a61b..11eb2a52a 100644 --- a/src/general/noupdateserviceaccount/src_test.rego +++ b/src/general/noupdateserviceaccount/src_test.rego @@ -15,11 +15,11 @@ pod(sa_name) = obj { } test_deny_pod { - input := { + inp := { "review": update(pod("sa1"), pod("sa2"), {}), "parameters": {}, } - result := violation with input as input + result := violation with input as inp trace(sprintf("result: %v", [result])) result == policy_violation } @@ -37,11 +37,11 @@ rc(sa_name) = obj { } test_deny_rc { - input := { + inp := { "review": update(rc("sa1"), rc("sa2"), {}), "parameters": {}, } - result := violation with input as input + result := violation with input as inp trace(sprintf("result: %v", [result])) result == policy_violation } @@ -59,11 +59,11 @@ rs(sa_name) = obj { } test_deny_rs { - input := { + inp := { "review": update(rs("sa1"), rs("sa2"), {}), "parameters": {}, } - result := violation with input as input + result := violation with input as inp trace(sprintf("result: %v", [result])) result == policy_violation } @@ -81,11 +81,11 @@ deploy(sa_name) = obj { } test_deny_deploy { - input := { + inp := { "review": update(deploy("sa1"), deploy("sa2"), {}), "parameters": {}, } - result := violation with input as input + result := violation with input as inp trace(sprintf("result: %v", [result])) result == policy_violation } @@ -103,11 +103,11 @@ ss(sa_name) = obj { } test_deny_ss { - input := { + inp := { "review": update(ss("sa1"), ss("sa2"), {}), "parameters": {}, } - result := violation with input as input + result := violation with input as inp trace(sprintf("result: %v", [result])) result == policy_violation } @@ -125,11 +125,11 @@ ds(sa_name) = obj { } test_deny_ds { - input := { + inp := { "review": update(ds("sa1"), ds("sa2"), {}), "parameters": {}, } - result := violation with input as input + result := violation with input as inp trace(sprintf("result: %v", [result])) result == policy_violation } @@ -147,11 +147,11 @@ job(sa_name) = obj { } test_deny_job { - input := { + inp := { "review": update(job("sa1"), job("sa2"), {}), "parameters": {}, } - result := violation with input as input + result := violation with input as inp trace(sprintf("result: %v", [result])) result == policy_violation } @@ -173,11 +173,11 @@ cronjob(sa_name) = obj { } test_deny_cronjob { - input := { + inp := { "review": update(cronjob("sa1"), cronjob("sa2"), {}), "parameters": {}, } - result := violation with input as input + result := violation with input as inp trace(sprintf("result: %v", [result])) result == policy_violation } @@ -196,74 +196,74 @@ test_allow_unrelated { } } } - input := { + inp := { "review": update(a, b, {}), "parameters": {}, } - result := violation with input as input + result := violation with input as inp trace(sprintf("result: %v", [result])) count(result) == 0 } # Allow create and delete test_allow_create { - input := { + inp := { "review": create(deploy("sa1")), "parameters": {}, } - result := violation with input as input + result := violation with input as inp trace(sprintf("result: %v", [result])) count(result) == 0 } test_allow_delete { - input := { + inp := { "review": delete(deploy("sa1")), "parameters": {}, } - result := violation with input as input + result := violation with input as inp trace(sprintf("result: %v", [result])) count(result) == 0 } # Allowlist users and groups test_allow_users { - input := { + inp := { "review": update(deploy("sa1"), deploy("sa2"), {"username": "myuser"}), "parameters": allow(["myuser"], []), } - result := violation with input as input + result := violation with input as inp trace(sprintf("result: %v", [result])) count(result) == 0 } test_allow_groups { - input := { + inp := { "review": update(deploy("sa1"), deploy("sa2"), {"groups": ["mygroup"]}), "parameters": allow([], ["mygroup"]), } - result := violation with input as input + result := violation with input as inp trace(sprintf("result: %v", [result])) count(result) == 0 } # Malformed test_deny_missing_old { - input := { + inp := { "review": update({}, pod("sa"), {}), "parameters": {}, } - result := violation with input as input + result := violation with input as inp trace(sprintf("%v", [result])) result == missing_old_violation } test_deny_missing_new { - input := { + inp := { "review": update(pod("sa"), {}, {}), "parameters": {}, } - result := violation with input as input + result := violation with input as inp trace(sprintf("%v", [result])) result == missing_new_violation } diff --git a/src/general/poddisruptionbudget/src_test.rego b/src/general/poddisruptionbudget/src_test.rego index d45888eec..73f1327cf 100644 --- a/src/general/poddisruptionbudget/src_test.rego +++ b/src/general/poddisruptionbudget/src_test.rego @@ -8,42 +8,42 @@ match_labels := {"matchLabels": { }} test_input_pdb_0_max_unavailable { - input := {"review": input_pdb_max_unavailable(0)} - results := violation with input as input + inp := {"review": input_pdb_max_unavailable(0)} + results := violation with input as inp count(results) == 1 } test_input_pdb_1_max_unavailable { - input := {"review": input_pdb_max_unavailable(1)} - results := violation with input as input + inp := {"review": input_pdb_max_unavailable(1)} + results := violation with input as inp count(results) == 0 } test_input_deployment_1_replica_pdb_1_min_available { - input := {"review": input_deployment(1)} + inp := {"review": input_deployment(1)} inv := inv_pdb_min_available(1) - results := violation with input as input with data.inventory as inv + results := violation with input as inp with data.inventory as inv count(results) == 1 } test_input_deployment_2_replicas_pdb_1_min_available { - input := {"review": input_deployment(2)} + inp := {"review": input_deployment(2)} inv := inv_pdb_min_available(1) - results := violation with input as input with data.inventory as inv + results := violation with input as inp with data.inventory as inv count(results) == 0 } test_input_deployment_pdb_0_max_unavailable { - input := {"review": input_deployment(2)} + inp := {"review": input_deployment(2)} inv := inv_pdb_max_unavailable(0) - results := violation with input as input with data.inventory as inv + results := violation with input as inp with data.inventory as inv count(results) == 1 } test_input_deployment_pdb_1_max_unavailable { - input := {"review": input_deployment(2)} + inp := {"review": input_deployment(2)} inv := inv_pdb_max_unavailable(1) - results := violation with input as input with data.inventory as inv + results := violation with input as inp with data.inventory as inv count(results) == 0 } diff --git a/src/general/replicalimits/constraint.tmpl b/src/general/replicalimits/constraint.tmpl index 2b4dc9183..55a380360 100644 --- a/src/general/replicalimits/constraint.tmpl +++ b/src/general/replicalimits/constraint.tmpl @@ -4,7 +4,7 @@ metadata: name: k8sreplicalimits annotations: metadata.gatekeeper.sh/title: "Replica Limits" - metadata.gatekeeper.sh/version: 1.0.1 + metadata.gatekeeper.sh/version: 1.0.2 description: >- Requires that objects with the field `spec.replicas` (Deployments, ReplicaSets, etc.) specify a number of replicas within defined ranges. diff --git a/src/general/replicalimits/src.rego b/src/general/replicalimits/src.rego index 796000da2..066fe924b 100644 --- a/src/general/replicalimits/src.rego +++ b/src/general/replicalimits/src.rego @@ -10,7 +10,7 @@ violation[{"msg": msg}] { } input_replica_limit(spec) { - provided := input.review.object.spec.replicas + provided := spec.replicas count(input.parameters.ranges) > 0 range := input.parameters.ranges[_] value_within_range(range, provided) diff --git a/src/general/replicalimits/src_test.rego b/src/general/replicalimits/src_test.rego index 26a9a201b..5cb1f8a97 100644 --- a/src/general/replicalimits/src_test.rego +++ b/src/general/replicalimits/src_test.rego @@ -1,44 +1,44 @@ package k8sreplicalimits test_input_empty { - input := { "review": empty, "parameters": {}} - results := violation with input as input + inp := { "review": empty, "parameters": {}} + results := violation with input as inp count(results) == 0 } test_input_within_required_replicas { - input := { "review": review(6), "parameters": input_parameters_valid_range} - results := violation with input as input + inp := { "review": review(6), "parameters": input_parameters_valid_range} + results := violation with input as inp count(results) == 0 } test_input_exact_required_replicas_min { - input := { "review": review(5), "parameters": input_parameters_valid_range} - results := violation with input as input + inp := { "review": review(5), "parameters": input_parameters_valid_range} + results := violation with input as inp count(results) == 0 } test_input_exact_required_replicas_max { - input := { "review": review(35), "parameters": input_parameters_valid_range} - results := violation with input as input + inp := { "review": review(35), "parameters": input_parameters_valid_range} + results := violation with input as inp count(results) == 0 } test_input_not_enough_required_replicas { - input := { "review": review(1), "parameters": input_parameters_valid_range} - results := violation with input as input + inp := { "review": review(1), "parameters": input_parameters_valid_range} + results := violation with input as inp count(results) == 1 } test_input_too_many_replicas { - input := { "review": review(100), "parameters": input_parameters_valid_range} - results := violation with input as input + inp := { "review": review(100), "parameters": input_parameters_valid_range} + results := violation with input as inp count(results) == 1 } test_input_zero_replicas { - input := { "review": review(0), "parameters": input_parameters_zero_range} - results := violation with input as input + inp := { "review": review(0), "parameters": input_parameters_zero_range} + results := violation with input as inp count(results) == 0 } diff --git a/src/general/requiredannotations/constraint.tmpl b/src/general/requiredannotations/constraint.tmpl index 0f3a7d2bf..869ab9994 100644 --- a/src/general/requiredannotations/constraint.tmpl +++ b/src/general/requiredannotations/constraint.tmpl @@ -4,7 +4,7 @@ metadata: name: k8srequiredannotations annotations: metadata.gatekeeper.sh/title: "Required Annotations" - metadata.gatekeeper.sh/version: 1.0.0 + metadata.gatekeeper.sh/version: 1.0.1 description: >- Requires resources to contain specified annotations, with values matching provided regular expressions. diff --git a/src/general/requiredannotations/src.rego b/src/general/requiredannotations/src.rego index 248c6cbbe..f9f624a80 100644 --- a/src/general/requiredannotations/src.rego +++ b/src/general/requiredannotations/src.rego @@ -13,6 +13,6 @@ violation[{"msg": msg}] { expected := input.parameters.annotations[_] expected.key == key expected.allowedRegex != "" - not re_match(expected.allowedRegex, value) + not regex.match(expected.allowedRegex, value) msg := sprintf("Annotation <%v: %v> does not satisfy allowed regex: %v", [key, value, expected.allowedRegex]) } diff --git a/src/general/requiredannotations/src_test.rego b/src/general/requiredannotations/src_test.rego index de7de5e85..a9ab36b0b 100644 --- a/src/general/requiredannotations/src_test.rego +++ b/src/general/requiredannotations/src_test.rego @@ -1,63 +1,63 @@ package k8srequiredannotations test_input_no_required_annotations { - input := { "review": review({"some": "annotation"}), "parameters": {}} - results := violation with input as input + inp := { "review": review({"some": "annotation"}), "parameters": {}} + results := violation with input as inp count(results) == 0 } test_input_no_required_annotations { - input := { "review": empty, "parameters": {}} - results := violation with input as input + inp := { "review": empty, "parameters": {}} + results := violation with input as inp count(results) == 0 } test_input_has_annotation { - input := { "review": review({"some": "annotation"}), "parameters": {"annotations": [lbl("some", "annotation")]}} - results := violation with input as input + inp := { "review": review({"some": "annotation"}), "parameters": {"annotations": [lbl("some", "annotation")]}} + results := violation with input as inp count(results) == 0 } test_input_has_extra_annotation { - input := { "review": review({"some": "annotation", "new": "thing"}), "parameters": {"annotations": [lbl("some", "annotation")]}} - results := violation with input as input + inp := { "review": review({"some": "annotation", "new": "thing"}), "parameters": {"annotations": [lbl("some", "annotation")]}} + results := violation with input as inp count(results) == 0 } test_input_has_extra_annotation_req2 { - input := { "review": review({"some": "annotation", "new": "thing"}), "parameters": {"annotations": [lbl("some", "annotation"), lbl("new", "thing")]}} - results := violation with input as input + inp := { "review": review({"some": "annotation", "new": "thing"}), "parameters": {"annotations": [lbl("some", "annotation"), lbl("new", "thing")]}} + results := violation with input as inp count(results) == 0 } test_input_missing_annotation { - input := { "review": review({"some_other": "annotation"}), "parameters": {"annotations": [lbl("some", "annotation")]}} - results := violation with input as input + inp := { "review": review({"some_other": "annotation"}), "parameters": {"annotations": [lbl("some", "annotation")]}} + results := violation with input as inp count(results) == 1 } test_input_wrong_value { - input := { "review": review({"some": "annotation2"}), "parameters": {"annotations": [lbl("some", "annotation$")]}} - results := violation with input as input + inp := { "review": review({"some": "annotation2"}), "parameters": {"annotations": [lbl("some", "annotation$")]}} + results := violation with input as inp count(results) == 1 } test_input_one_missing { - input := { "review": review({"some": "annotation"}), "parameters": {"annotations": [lbl("some", "annotation"), lbl("other", "annotation")]}} - results := violation with input as input + inp := { "review": review({"some": "annotation"}), "parameters": {"annotations": [lbl("some", "annotation"), lbl("other", "annotation")]}} + results := violation with input as inp count(results) == 1 } test_input_wrong_empty { - input := { "review": empty, "parameters": {"annotations": [lbl("some", "label$")]}} - results := violation with input as input + inp := { "review": empty, "parameters": {"annotations": [lbl("some", "label$")]}} + results := violation with input as inp count(results) == 1 } test_input_two_missing { - input := { "review": empty, "parameters": {"annotations": [lbl("some", "annotation"), lbl("other", "annotation")]}} - results := violation with input as input + inp := { "review": empty, "parameters": {"annotations": [lbl("some", "annotation"), lbl("other", "annotation")]}} + results := violation with input as inp count(results) == 1 } test_input_two_wrong { - input := { "review": review({"some": "lbe", "other": "lbe"}), "parameters": {"annotations": [lbl("some", "annotation"), lbl("other", "annotation")]}} - results := violation with input as input + inp := { "review": review({"some": "lbe", "other": "lbe"}), "parameters": {"annotations": [lbl("some", "annotation"), lbl("other", "annotation")]}} + results := violation with input as inp count(results) == 2 } test_input_two_allowed { - input := { "review": review({"some": "gray", "other": "grey"}), "parameters": {"annotations": [lbl("some", "gr[ae]y"), lbl("other", "gr[ae]y")]}} - results := violation with input as input + inp := { "review": review({"some": "gray", "other": "grey"}), "parameters": {"annotations": [lbl("some", "gr[ae]y"), lbl("other", "gr[ae]y")]}} + results := violation with input as inp count(results) == 0 } diff --git a/src/general/requiredlabels/constraint.tmpl b/src/general/requiredlabels/constraint.tmpl index a667ac30a..0e368a4be 100644 --- a/src/general/requiredlabels/constraint.tmpl +++ b/src/general/requiredlabels/constraint.tmpl @@ -4,7 +4,7 @@ metadata: name: k8srequiredlabels annotations: metadata.gatekeeper.sh/title: "Required Labels" - metadata.gatekeeper.sh/version: 1.0.0 + metadata.gatekeeper.sh/version: 1.0.1 description: >- Requires resources to contain specified labels, with values matching provided regular expressions. diff --git a/src/general/requiredlabels/src.rego b/src/general/requiredlabels/src.rego index 606cda94b..df365ea88 100644 --- a/src/general/requiredlabels/src.rego +++ b/src/general/requiredlabels/src.rego @@ -1,13 +1,10 @@ package k8srequiredlabels -get_message(parameters, _default) = msg { +get_message(parameters, _default) := _default { not parameters.message - msg := _default } -get_message(parameters, _default) = msg { - msg := parameters.message -} +get_message(parameters, _) := parameters.message violation[{"msg": msg, "details": {"missing_labels": missing}}] { provided := {label | input.review.object.metadata.labels[label]} @@ -24,7 +21,7 @@ violation[{"msg": msg}] { expected.key == key # do not match if allowedRegex is not defined, or is an empty string expected.allowedRegex != "" - not re_match(expected.allowedRegex, value) + not regex.match(expected.allowedRegex, value) def_msg := sprintf("Label <%v: %v> does not satisfy allowed regex: %v", [key, value, expected.allowedRegex]) msg := get_message(input.parameters, def_msg) } diff --git a/src/general/requiredlabels/src_test.rego b/src/general/requiredlabels/src_test.rego index ce0199075..41b67a4a7 100644 --- a/src/general/requiredlabels/src_test.rego +++ b/src/general/requiredlabels/src_test.rego @@ -1,68 +1,68 @@ package k8srequiredlabels test_input_no_required_labels { - input := { "review": review({"some": "label"}), "parameters": {}} - results := violation with input as input + inp := { "review": review({"some": "label"}), "parameters": {}} + results := violation with input as inp count(results) == 0 } test_input_no_required_labels { - input := { "review": empty, "parameters": {}} - results := violation with input as input + inp := { "review": empty, "parameters": {}} + results := violation with input as inp count(results) == 0 } test_input_has_label { - input := { "review": review({"some": "label"}), "parameters": {"labels": [lbl("some", "label")]}} - results := violation with input as input + inp := { "review": review({"some": "label"}), "parameters": {"labels": [lbl("some", "label")]}} + results := violation with input as inp count(results) == 0 } test_input_has_extra_label { - input := { "review": review({"some": "label", "new": "thing"}), "parameters": {"labels": [lbl("some", "label")]}} - results := violation with input as input + inp := { "review": review({"some": "label", "new": "thing"}), "parameters": {"labels": [lbl("some", "label")]}} + results := violation with input as inp count(results) == 0 } test_input_has_extra_label_req2 { - input := { "review": review({"some": "label", "new": "thing"}), "parameters": {"labels": [lbl("some", "label"), lbl("new", "thing")]}} - results := violation with input as input + inp := { "review": review({"some": "label", "new": "thing"}), "parameters": {"labels": [lbl("some", "label"), lbl("new", "thing")]}} + results := violation with input as inp count(results) == 0 } test_input_missing_label { - input := { "review": review({"some_other": "label"}), "parameters": {"labels": [lbl("some", "label")]}} - results := violation with input as input + inp := { "review": review({"some_other": "label"}), "parameters": {"labels": [lbl("some", "label")]}} + results := violation with input as inp count(results) == 1 } test_input_wrong_value { - input := { "review": review({"some": "label2"}), "parameters": {"labels": [lbl("some", "label$")]}} - results := violation with input as input + inp := { "review": review({"some": "label2"}), "parameters": {"labels": [lbl("some", "label$")]}} + results := violation with input as inp count(results) == 1 } test_input_one_missing { - input := { "review": review({"some": "label"}), "parameters": {"labels": [lbl("some", "label"), lbl("other", "label")]}} - results := violation with input as input + inp := { "review": review({"some": "label"}), "parameters": {"labels": [lbl("some", "label"), lbl("other", "label")]}} + results := violation with input as inp count(results) == 1 } test_input_wrong_empty { - input := { "review": empty, "parameters": {"labels": [lbl("some", "label$")]}} - results := violation with input as input + inp := { "review": empty, "parameters": {"labels": [lbl("some", "label$")]}} + results := violation with input as inp count(results) == 1 } test_input_two_missing { - input := { "review": empty, "parameters": {"labels": [lbl("some", "label"), lbl("other", "label")]}} - results := violation with input as input + inp := { "review": empty, "parameters": {"labels": [lbl("some", "label"), lbl("other", "label")]}} + results := violation with input as inp count(results) == 1 } test_input_two_wrong { - input := { "review": review({"some": "lbe", "other": "lbe"}), "parameters": {"labels": [lbl("some", "label"), lbl("other", "label")]}} - results := violation with input as input + inp := { "review": review({"some": "lbe", "other": "lbe"}), "parameters": {"labels": [lbl("some", "label"), lbl("other", "label")]}} + results := violation with input as inp count(results) == 2 } test_input_two_allowed { - input := { "review": review({"some": "gray", "other": "grey"}), "parameters": {"labels": [lbl("some", "gr[ae]y"), lbl("other", "gr[ae]y")]}} - results := violation with input as input + inp := { "review": review({"some": "gray", "other": "grey"}), "parameters": {"labels": [lbl("some", "gr[ae]y"), lbl("other", "gr[ae]y")]}} + results := violation with input as inp count(results) == 0 } test_input_message { - input := { "review": review({"some": "label2"}), "parameters": {"message": "WRONG_VALUE", "labels": [lbl("some", "label$")]}} - results := violation with input as input + inp := { "review": review({"some": "label2"}), "parameters": {"message": "WRONG_VALUE", "labels": [lbl("some", "label$")]}} + results := violation with input as inp results[_].msg == "WRONG_VALUE" } diff --git a/src/general/requiredprobes/src_test.rego b/src/general/requiredprobes/src_test.rego index 0ad2676e2..e888e3500 100644 --- a/src/general/requiredprobes/src_test.rego +++ b/src/general/requiredprobes/src_test.rego @@ -1,362 +1,321 @@ package k8srequiredprobes test_one_ctr_no_violations { - kind := kinds[_] - input := {"review": review([{"name": "my-container","image": "my-image:latest","readinessProbe": {"tcpSocket": {"port":80}}, "livenessProbe": {"tcpSocket": {"port":80}}}]), + inp := {"review": review([{"name": "my-container","image": "my-image:latest","readinessProbe": {"tcpSocket": {"port":80}}, "livenessProbe": {"tcpSocket": {"port":80}}}]), "parameters": parameters} - results := violation with input as input + results := violation with input as inp count(results) == 0 } test_one_ctr_readiness_violation { - kind := kinds[_] - input := {"review": review([{"name": "my-container","image": "my-image:latest", "livenessProbe": {"tcpSocket": {"port":80}}}]), + inp := {"review": review([{"name": "my-container","image": "my-image:latest", "livenessProbe": {"tcpSocket": {"port":80}}}]), "parameters": parameters} - results := violation with input as input + results := violation with input as inp count(results) == 1 } test_one_ctr_liveness_violation { - kind := kinds[_] - input := {"review": review([{"name": "my-container","image": "my-image:latest", "readinessProbe": {"tcpSocket": {"port":80}}}]), + inp := {"review": review([{"name": "my-container","image": "my-image:latest", "readinessProbe": {"tcpSocket": {"port":80}}}]), "parameters": parameters} - results := violation with input as input + results := violation with input as inp count(results) == 1 } test_one_ctr_all_violations { - kind := kinds[_] - input := {"review": review([{"name": "my-container","image": "my-image:latest"}]), + inp := {"review": review([{"name": "my-container","image": "my-image:latest"}]), "parameters": parameters} - results := violation with input as input + results := violation with input as inp count(results) == 2 } test_two_ctrs_no_violations { - kind := kinds[_] - input := {"review": review([{"name": "my-container1","image": "my-image:latest","readinessProbe": {"tcpSocket": {"port":80}}, "livenessProbe": {"tcpSocket": {"port":80}}}, + inp := {"review": review([{"name": "my-container1","image": "my-image:latest","readinessProbe": {"tcpSocket": {"port":80}}, "livenessProbe": {"tcpSocket": {"port":80}}}, {"name": "my-container2","image": "my-image:latest","readinessProbe": {"tcpSocket": {"port":8080}}, "livenessProbe": {"tcpSocket": {"port":8080}}}]), "parameters": parameters} - results := violation with input as input + results := violation with input as inp count(results) == 0 } test_two_ctrs_all_violations_in_both { - kind := kinds[_] - input := {"review": review([{"name": "my-container1","image": "my-image:latest"}, + inp := {"review": review([{"name": "my-container1","image": "my-image:latest"}, {"name": "my-container2","image": "my-image:latest"}]), "parameters": parameters} - results := violation with input as input + results := violation with input as inp count(results) == 4 } test_two_ctrs_all_violations_in_ctr_one { - kind := kinds[_] - input := {"review": review([{"name": "my-container1","image": "my-image:latest"}, + inp := {"review": review([{"name": "my-container1","image": "my-image:latest"}, {"name": "my-container2","image": "my-image:latest", "readinessProbe": {"tcpSocket": {"port":80}}, "livenessProbe": {"tcpSocket": {"port":80}}}]), "parameters": parameters} - results := violation with input as input + results := violation with input as inp count(results) == 2 } test_two_ctrs_all_violations_in_ctr_two { - kind := kinds[_] - input := {"review": review([{"name": "my-container1","image": "my-image:latest", "readinessProbe": {"tcpSocket": {"port":80}}, "livenessProbe": {"tcpSocket": {"port":80}}}, + inp := {"review": review([{"name": "my-container1","image": "my-image:latest", "readinessProbe": {"tcpSocket": {"port":80}}, "livenessProbe": {"tcpSocket": {"port":80}}}, {"name": "my-container2","image": "my-image:latest"}]), "parameters": parameters} - results := violation with input as input + results := violation with input as inp count(results) == 2 } test_two_ctrs_readiness_violation_in_ctr_one { - kind := kinds[_] - input := {"review": review([{"name": "my-container1","image": "my-image:latest", "livenessProbe": {"tcpSocket": {"port":80}}}, + inp := {"review": review([{"name": "my-container1","image": "my-image:latest", "livenessProbe": {"tcpSocket": {"port":80}}}, {"name": "my-container2","image": "my-image:latest","readinessProbe": {"tcpSocket": {"port":8080}}, "livenessProbe": {"tcpSocket": {"port":8080}}}]), "parameters": parameters} - results := violation with input as input + results := violation with input as inp count(results) == 1 } test_two_ctrs_readiness_violation_in_ctr_two { - kind := kinds[_] - input := {"review": review([{"name": "my-container1","image": "my-image:latest", "readinessProbe": {"tcpSocket": {"port":8080}}, "livenessProbe": {"tcpSocket": {"port":8080}}}, + inp := {"review": review([{"name": "my-container1","image": "my-image:latest", "readinessProbe": {"tcpSocket": {"port":8080}}, "livenessProbe": {"tcpSocket": {"port":8080}}}, {"name": "my-container2","image": "my-image:latest", "livenessProbe": {"tcpSocket": {"port":80}}}]), "parameters": parameters} - results := violation with input as input + results := violation with input as inp count(results) == 1 } test_two_ctrs_readiness_violation_in_both { - kind := kinds[_] - input := {"review": review([{"name": "my-container1","image": "my-image:latest", "livenessProbe": {"tcpSocket": {"port":80}}}, + inp := {"review": review([{"name": "my-container1","image": "my-image:latest", "livenessProbe": {"tcpSocket": {"port":80}}}, {"name": "my-container2","image": "my-image:latest", "livenessProbe": {"tcpSocket": {"port":8080}}}]), "parameters": parameters} - results := violation with input as input + results := violation with input as inp count(results) == 2 } test_two_ctrs_liveness_violation_in_ctr_one { - kind := kinds[_] - input := {"review": review([{"name": "my-container1","image": "my-image:latest", "readinessProbe": {"tcpSocket": {"port":80}}}, + inp := {"review": review([{"name": "my-container1","image": "my-image:latest", "readinessProbe": {"tcpSocket": {"port":80}}}, {"name": "my-container2","image": "my-image:latest", "readinessProbe": {"tcpSocket": {"port":8080}}, "livenessProbe": {"tcpSocket": {"port":8080}}}]), "parameters": parameters} - results := violation with input as input + results := violation with input as inp count(results) == 1 } test_two_ctrs_liveness_violation_in_ctr_two { - kind := kinds[_] - input := {"review": review([{"name": "my-container1","image": "my-image:latest", "readinessProbe": {"tcpSocket": {"port":8080}}, "livenessProbe": {"tcpSocket": {"port":8080}}}, + inp := {"review": review([{"name": "my-container1","image": "my-image:latest", "readinessProbe": {"tcpSocket": {"port":8080}}, "livenessProbe": {"tcpSocket": {"port":8080}}}, {"name": "my-container2","image": "my-image:latest", "readinessProbe": {"tcpSocket": {"port":80}}}]), "parameters": parameters} - results := violation with input as input + results := violation with input as inp count(results) == 1 } test_two_ctrs_liveness_violation_in_both { - kind := kinds[_] - input := {"review": review([{"name": "my-container1","image": "my-image:latest", "readinessProbe": {"tcpSocket": {"port":8080}}}, + inp := {"review": review([{"name": "my-container1","image": "my-image:latest", "readinessProbe": {"tcpSocket": {"port":8080}}}, {"name": "my-container2","image": "my-image:latest", "readinessProbe": {"tcpSocket": {"port":80}}}]), "parameters": parameters} - results := violation with input as input + results := violation with input as inp count(results) == 2 } test_two_ctrs_readiness_in_one_liveness_in_two { - kind := kinds[_] - input := {"review": review([{"name": "my-container1","image": "my-image:latest", "livenessProbe": {"tcpSocket": {"port":80}}}, + inp := {"review": review([{"name": "my-container1","image": "my-image:latest", "livenessProbe": {"tcpSocket": {"port":80}}}, {"name": "my-container2","image": "my-image:latest","readinessProbe": {"tcpSocket": {"port":8080}}}]), "parameters": parameters} - results := violation with input as input + results := violation with input as inp count(results) == 2 } test_two_ctrs_liveness_in_one_readiness_in_two { - kind := kinds[_] - input := {"review": review([{"name": "my-container1","image": "my-image:latest", "readinessProbe": {"tcpSocket": {"port":80}}}, + inp := {"review": review([{"name": "my-container1","image": "my-image:latest", "readinessProbe": {"tcpSocket": {"port":80}}}, {"name": "my-container2","image": "my-image:latest", "livenessProbe": {"tcpSocket": {"port":8080}}}]), "parameters": parameters} - results := violation with input as input + results := violation with input as inp count(results) == 2 } test_two_ctrs_readiness_violation_in_ctr_one_all_violations_in_ctr_two { - kind := kinds[_] - input := {"review": review([{"name": "my-container1","image": "my-image:latest", "livenessProbe": {"tcpSocket": {"port":80}}}, + inp := {"review": review([{"name": "my-container1","image": "my-image:latest", "livenessProbe": {"tcpSocket": {"port":80}}}, {"name": "my-container2","image": "my-image:latest"}]), "parameters": parameters} - results := violation with input as input + results := violation with input as inp count(results) == 3 } test_two_ctrs_liveness_violation_in_ctr_one_all_violations_in_ctr_two { - kind := kinds[_] - input := {"review": review([{"name": "my-container1","image": "my-image:latest", "readinessProbe": {"tcpSocket": {"port":80}}}, + inp := {"review": review([{"name": "my-container1","image": "my-image:latest", "readinessProbe": {"tcpSocket": {"port":80}}}, {"name": "my-container2","image": "my-image:latest"}]), "parameters": parameters} - results := violation with input as input + results := violation with input as inp count(results) == 3 } test_two_ctrs_readiness_violation_in_ctr_two_all_violations_in_ctr_one { - kind := kinds[_] - input := {"review": review([{"name": "my-container1","image": "my-image:latest"}, + inp := {"review": review([{"name": "my-container1","image": "my-image:latest"}, {"name": "my-container2","image": "my-image:latest", "livenessProbe": {"tcpSocket": {"port":80}}}]), "parameters": parameters} - results := violation with input as input + results := violation with input as inp count(results) == 3 } test_two_ctrs_liveness_violation_in_ctr_two_all_violations_in_ctr_one { - kind := kinds[_] - input := {"review": review([{"name": "my-container1","image": "my-image:latest"}, + inp := {"review": review([{"name": "my-container1","image": "my-image:latest"}, {"name": "my-container2","image": "my-image:latest", "readinessProbe": {"tcpSocket": {"port":80}}}]), "parameters": parameters} - results := violation with input as input + results := violation with input as inp count(results) == 3 } test_one_ctr_empty_readiness_violation { - kind := kinds[_] - input := {"review": review([{"name": "my-container","image": "my-image:latest", "readinessProbe": {}, "livenessProbe": {"tcpSocket": {"port":80}}}]), + inp := {"review": review([{"name": "my-container","image": "my-image:latest", "readinessProbe": {}, "livenessProbe": {"tcpSocket": {"port":80}}}]), "parameters": parameters} - results := violation with input as input + results := violation with input as inp count(results) == 1 } test_one_ctr_empty_liveness_violation { - kind := kinds[_] - input := {"review": review([{"name": "my-container","image": "my-image:latest", "readinessProbe": {"tcpSocket": {"port":80}}, "livenessProbe": {}}]), + inp := {"review": review([{"name": "my-container","image": "my-image:latest", "readinessProbe": {"tcpSocket": {"port":80}}, "livenessProbe": {}}]), "parameters": parameters} - results := violation with input as input + results := violation with input as inp count(results) == 1 } test_one_ctr_empty_probes_violations { - kind := kinds[_] - input := {"review": review([{"name": "my-container","image": "my-image:latest", "readinessProbe": {}, "livenessProbe": {}}]), + inp := {"review": review([{"name": "my-container","image": "my-image:latest", "readinessProbe": {}, "livenessProbe": {}}]), "parameters": parameters} - results := violation with input as input + results := violation with input as inp count(results) == 2 } test_two_ctrs_empty_probes_violation_in_both { - kind := kinds[_] - input := {"review": review([{"name": "my-container1","image": "my-image:latest", "readinessProbe": {}, "livenessProbe": {}}, + inp := {"review": review([{"name": "my-container1","image": "my-image:latest", "readinessProbe": {}, "livenessProbe": {}}, {"name": "my-container2","image": "my-image:latest", "readinessProbe": {}, "livenessProbe": {}}]), "parameters": parameters} - results := violation with input as input + results := violation with input as inp count(results) == 4 } test_two_ctrs_empty_probes_violation_in_ctr_one { - kind := kinds[_] - input := {"review": review([{"name": "my-container1","image": "my-image:latest", "readinessProbe": {}, "livenessProbe": {}}, + inp := {"review": review([{"name": "my-container1","image": "my-image:latest", "readinessProbe": {}, "livenessProbe": {}}, {"name": "my-container2","image": "my-image:latest", "readinessProbe": {"tcpSocket": {"port":80}}, "livenessProbe": {"tcpSocket": {"port":80}}}]), "parameters": parameters} - results := violation with input as input + results := violation with input as inp count(results) == 2 } test_two_ctrs_empty_probes_violation_in_ctr_two { - kind := kinds[_] - input := {"review": review([{"name": "my-container1","image": "my-image:latest", "readinessProbe": {"tcpSocket": {"port":80}}, "livenessProbe": {"tcpSocket": {"port":80}}}, + inp := {"review": review([{"name": "my-container1","image": "my-image:latest", "readinessProbe": {"tcpSocket": {"port":80}}, "livenessProbe": {"tcpSocket": {"port":80}}}, {"name": "my-container2","image": "my-image:latest", "readinessProbe": {}, "livenessProbe": {}}]), "parameters": parameters} - results := violation with input as input + results := violation with input as inp count(results) == 2 } test_two_ctrs_empty_readiness_violation_in_ctr_one { - kind := kinds[_] - input := {"review": review([{"name": "my-container1","image": "my-image:latest", "livenessProbe": {"tcpSocket": {"port":80}}, "readinessProbe": {}}, + inp := {"review": review([{"name": "my-container1","image": "my-image:latest", "livenessProbe": {"tcpSocket": {"port":80}}, "readinessProbe": {}}, {"name": "my-container2","image": "my-image:latest","readinessProbe": {"tcpSocket": {"port":8080}}, "livenessProbe": {"tcpSocket": {"port":8080}}}]), "parameters": parameters} - results := violation with input as input + results := violation with input as inp count(results) == 1 } test_two_ctrs_empty_readiness_violation_in_ctr_two { - kind := kinds[_] - input := {"review": review([{"name": "my-container1","image": "my-image:latest", "readinessProbe": {"tcpSocket": {"port":8080}}, "livenessProbe": {"tcpSocket": {"port":8080}}}, + inp := {"review": review([{"name": "my-container1","image": "my-image:latest", "readinessProbe": {"tcpSocket": {"port":8080}}, "livenessProbe": {"tcpSocket": {"port":8080}}}, {"name": "my-container2","image": "my-image:latest", "readinessProbe": {}, "livenessProbe": {"tcpSocket": {"port":80}}}]), "parameters": parameters} - results := violation with input as input + results := violation with input as inp count(results) == 1 } test_two_ctrs_empty_readiness_violation_in_both { - kind := kinds[_] - input := {"review": review([{"name": "my-container1","image": "my-image:latest", "readinessProbe": {}, "livenessProbe": {"tcpSocket": {"port":80}}}, + inp := {"review": review([{"name": "my-container1","image": "my-image:latest", "readinessProbe": {}, "livenessProbe": {"tcpSocket": {"port":80}}}, {"name": "my-container2","image": "my-image:latest", "readinessProbe": {}, "livenessProbe": {"tcpSocket": {"port":8080}}}]), "parameters": parameters} - results := violation with input as input + results := violation with input as inp count(results) == 2 } test_two_ctrs_empty_liveness_violation_in_ctr_one { - kind := kinds[_] - input := {"review": review([{"name": "my-container1","image": "my-image:latest", "readinessProbe": {"tcpSocket": {"port":80}}, "livenessProbe": {}}, + inp := {"review": review([{"name": "my-container1","image": "my-image:latest", "readinessProbe": {"tcpSocket": {"port":80}}, "livenessProbe": {}}, {"name": "my-container2","image": "my-image:latest", "readinessProbe": {"tcpSocket": {"port":8080}}, "livenessProbe": {"tcpSocket": {"port":8080}}}]), "parameters": parameters} - results := violation with input as input + results := violation with input as inp count(results) == 1 } test_two_ctrs_empty_liveness_violation_in_ctr_two { - kind := kinds[_] - input := {"review": review([{"name": "my-container1","image": "my-image:latest", "readinessProbe": {"tcpSocket": {"port":8080}}, "livenessProbe": {"tcpSocket": {"port":8080}}}, + inp := {"review": review([{"name": "my-container1","image": "my-image:latest", "readinessProbe": {"tcpSocket": {"port":8080}}, "livenessProbe": {"tcpSocket": {"port":8080}}}, {"name": "my-container2","image": "my-image:latest", "readinessProbe": {"tcpSocket": {"port":80}}, "livenessProbe": {}}]), "parameters": parameters} - results := violation with input as input + results := violation with input as inp count(results) == 1 } test_two_ctrs_empty_liveness_violation_in_both { - kind := kinds[_] - input := {"review": review([{"name": "my-container1","image": "my-image:latest", "readinessProbe": {"tcpSocket": {"port":8080}}, "livenessProbe": {}}, + inp := {"review": review([{"name": "my-container1","image": "my-image:latest", "readinessProbe": {"tcpSocket": {"port":8080}}, "livenessProbe": {}}, {"name": "my-container2","image": "my-image:latest", "readinessProbe": {"tcpSocket": {"port":80}}, "livenessProbe": {}}]), "parameters": parameters} - results := violation with input as input + results := violation with input as inp count(results) == 2 } test_two_ctrs_empty_readiness_in_ctr_one_empty_liveness_in_ctr_two { - kind := kinds[_] - input := {"review": review([{"name": "my-container1","image": "my-image:latest", "readinessProbe":{}, "livenessProbe": {"tcpSocket": {"port":80}}}, + inp := {"review": review([{"name": "my-container1","image": "my-image:latest", "readinessProbe":{}, "livenessProbe": {"tcpSocket": {"port":80}}}, {"name": "my-container2","image": "my-image:latest", "readinessProbe": {"tcpSocket": {"port":8080}}, "livenessProbe": {}}]), "parameters": parameters} - results := violation with input as input + results := violation with input as inp count(results) == 2 } test_two_ctrs_empty_liveness_in_one_empty_readiness_in_two { - kind := kinds[_] - input := {"review": review([{"name": "my-container1","image": "my-image:latest", "readinessProbe": {"tcpSocket": {"port":80}}, "livenessProbe": {}}, + inp := {"review": review([{"name": "my-container1","image": "my-image:latest", "readinessProbe": {"tcpSocket": {"port":80}}, "livenessProbe": {}}, {"name": "my-container2","image": "my-image:latest", "readinessProbe": {}, "livenessProbe": {"tcpSocket": {"port":8080}}}]), "parameters": parameters} - results := violation with input as input + results := violation with input as inp count(results) == 2 } test_two_ctrs_empty_readiness_in_ctr_one_both_empty_probes_in_ctr_two { - kind := kinds[_] - input := {"review": review([{"name": "my-container1","image": "my-image:latest", "readinessProbe": {}, "livenessProbe": {"tcpSocket": {"port":80}}}, + inp := {"review": review([{"name": "my-container1","image": "my-image:latest", "readinessProbe": {}, "livenessProbe": {"tcpSocket": {"port":80}}}, {"name": "my-container2","image": "my-image:latest", "readinessProbe": {}, "livenessProbe": {}}]), "parameters": parameters} - results := violation with input as input + results := violation with input as inp count(results) == 3 } test_two_ctrs_empty_liveness_in_ctr_one_both_empty_probes_in_ctr_two { - kind := kinds[_] - input := {"review": review([{"name": "my-container1","image": "my-image:latest", "readinessProbe": {"tcpSocket": {"port":80}}, "livenessProbe": {}}, + inp := {"review": review([{"name": "my-container1","image": "my-image:latest", "readinessProbe": {"tcpSocket": {"port":80}}, "livenessProbe": {}}, {"name": "my-container2","image": "my-image:latest", "readinessProbe": {}, "livenessProbe": {}}]), "parameters": parameters} - results := violation with input as input + results := violation with input as inp count(results) == 3 } test_two_ctrs_empty_readiness_in_ctr_two_both_empty_probes_in_ctr_one { - kind := kinds[_] - input := {"review": review([{"name": "my-container1","image": "my-image:latest", "readinessProbe": {}, "livenessProbe": {}}, + inp := {"review": review([{"name": "my-container1","image": "my-image:latest", "readinessProbe": {}, "livenessProbe": {}}, {"name": "my-container2","image": "my-image:latest", "readinessProbe": {}, "livenessProbe": {"tcpSocket": {"port":80}}}]), "parameters": parameters} - results := violation with input as input + results := violation with input as inp count(results) == 3 } test_two_ctrs_empty_liveness_in_ctr_two_both_empty_probes_in_ctr_one { - kind := kinds[_] - input := {"review": review([{"name": "my-container1","image": "my-image:latest", "readinessProbe": {}, "livenessProbe": {}}, + inp := {"review": review([{"name": "my-container1","image": "my-image:latest", "readinessProbe": {}, "livenessProbe": {}}, {"name": "my-container2","image": "my-image:latest", "readinessProbe": {"tcpSocket": {"port":80}}, "livenessProbe": {}}]), "parameters": parameters} - results := violation with input as input + results := violation with input as inp count(results) == 3 } test_update { - kind := kinds[_] - input := {"review": object.union(review([{"name": "my-container","image": "my-image:latest", "livenessProbe": {"tcpSocket": {"port":80}}}]), {"operation": "UPDATE"}), + inp := {"review": object.union(review([{"name": "my-container","image": "my-image:latest", "livenessProbe": {"tcpSocket": {"port":80}}}]), {"operation": "UPDATE"}), "parameters": parameters} - results := violation with input as input + results := violation with input as inp count(results) == 0 } -review(containers) = obj { - obj = { - "kind": { - "kind": "Pod" - }, - "object": { - "metadata": { - "name": "some-name" - }, - "spec": { - "containers":containers - } - } +review(containers) := { + "kind": { + "kind": "Pod" + }, + "object": { + "metadata": { + "name": "some-name" + }, + "spec": { + "containers": containers } + } } parameters = {"probes": ["readinessProbe", "livenessProbe"], "probeTypes": ["tcpSocket", "httpGet", "exec"]} diff --git a/src/general/storageclass/src_test.rego b/src/general/storageclass/src_test.rego index 7a0e55b5c..4064c61d3 100644 --- a/src/general/storageclass/src_test.rego +++ b/src/general/storageclass/src_test.rego @@ -1,94 +1,94 @@ package k8sstorageclass test_input_denied_no_datasync { - input := { "review": input_review_pvc_name("fast"), "parameters": { "includeStorageClassesInMessage": true } } - results := violation with input as input with data.inventory as inv_nosync + inp := { "review": input_review_pvc_name("fast"), "parameters": { "includeStorageClassesInMessage": true } } + results := violation with input as inp with data.inventory as inv_nosync results[result] contains(result.msg, "misconfigured") } test_input_allowed_pvc_fast { - input := { "review": input_review_pvc_name("fast"), "parameters": { "includeStorageClassesInMessage": true } } - results := violation with input as input with data.inventory as inv + inp := { "review": input_review_pvc_name("fast"), "parameters": { "includeStorageClassesInMessage": true } } + results := violation with input as inp with data.inventory as inv count(results) == 0 } test_input_allowed_pvc_slow { - input := { "review": input_review_pvc_name("slow"), "parameters": { "includeStorageClassesInMessage": true } } - results := violation with input as input with data.inventory as inv + inp := { "review": input_review_pvc_name("slow"), "parameters": { "includeStorageClassesInMessage": true } } + results := violation with input as inp with data.inventory as inv count(results) == 0 } test_input_denied_pvc_bad_storageclassname { - input := { "review": input_review_pvc_name("other"), "parameters": { "includeStorageClassesInMessage": true } } - results := violation with input as input with data.inventory as inv + inp := { "review": input_review_pvc_name("other"), "parameters": { "includeStorageClassesInMessage": true } } + results := violation with input as inp with data.inventory as inv count(results) == 1 } test_input_denied_pvc_bad_storageclassname_excludestorageclassesinmessage { - input := { "review": input_review_pvc_name("other"), "parameters": { "includeStorageClassesInMessage": false } } - results := violation with input as input with data.inventory as inv + inp := { "review": input_review_pvc_name("other"), "parameters": { "includeStorageClassesInMessage": false } } + results := violation with input as inp with data.inventory as inv count(results) == 1 } test_input_denied_pvc_storageclassname_missing { - input := { "review": input_review_pvc_storageclassname_missing, "parameters": { "includeStorageClassesInMessage": true } } - results := violation with input as input with data.inventory as inv + inp := { "review": input_review_pvc_storageclassname_missing, "parameters": { "includeStorageClassesInMessage": true } } + results := violation with input as inp with data.inventory as inv count(results) == 1 } test_input_allowed_pvc_sc { - input := { "review": input_review_pvc_name("slow"), "parameters": { "includeStorageClassesInMessage": true, "allowedStorageClasses": ["slow"] } } - results := violation with input as input with data.inventory as inv + inp := { "review": input_review_pvc_name("slow"), "parameters": { "includeStorageClassesInMessage": true, "allowedStorageClasses": ["slow"] } } + results := violation with input as inp with data.inventory as inv count(results) == 0 } test_input_denied_pvc_sc { - input := { "review": input_review_pvc_name("slow"), "parameters": { "includeStorageClassesInMessage": true, "allowedStorageClasses": ["fast"] } } - results := violation with input as input with data.inventory as inv + inp := { "review": input_review_pvc_name("slow"), "parameters": { "includeStorageClassesInMessage": true, "allowedStorageClasses": ["fast"] } } + results := violation with input as inp with data.inventory as inv count(results) == 1 } test_input_allowed_pvc_mixed_sc { - input := { "review": input_review_pvc_name("slow"), "parameters": { "includeStorageClassesInMessage": true, "allowedStorageClasses": ["fast", "slow"] } } - results := violation with input as input with data.inventory as inv + inp := { "review": input_review_pvc_name("slow"), "parameters": { "includeStorageClassesInMessage": true, "allowedStorageClasses": ["fast", "slow"] } } + results := violation with input as inp with data.inventory as inv count(results) == 0 } test_input_denied_pvc_multiple_sc { - input := { "review": input_review_pvc_name("slow"), "parameters": { "includeStorageClassesInMessage": true, "allowedStorageClasses": ["other", "fast"] } } - results := violation with input as input with data.inventory as inv + inp := { "review": input_review_pvc_name("slow"), "parameters": { "includeStorageClassesInMessage": true, "allowedStorageClasses": ["other", "fast"] } } + results := violation with input as inp with data.inventory as inv count(results) == 1 } test_input_allowed_statefulset_fast { - input := { "review": input_review_statefulset_name("fast"), "parameters": { "includeStorageClassesInMessage": true } } - results := violation with input as input with data.inventory as inv + inp := { "review": input_review_statefulset_name("fast"), "parameters": { "includeStorageClassesInMessage": true } } + results := violation with input as inp with data.inventory as inv count(results) == 0 } test_input_allowed_statefulset_slow { - input := { "review": input_review_statefulset_name("slow"), "parameters": { "includeStorageClassesInMessage": true } } - results := violation with input as input with data.inventory as inv + inp := { "review": input_review_statefulset_name("slow"), "parameters": { "includeStorageClassesInMessage": true } } + results := violation with input as inp with data.inventory as inv count(results) == 0 } test_input_denied_statefulset_bad_storageclassname { - input := { "review": input_review_statefulset_name("other"), "parameters": { "includeStorageClassesInMessage": true } } - results := violation with input as input with data.inventory as inv + inp := { "review": input_review_statefulset_name("other"), "parameters": { "includeStorageClassesInMessage": true } } + results := violation with input as inp with data.inventory as inv count(results) == 1 } test_input_denied_statefulset_storageclassname_missing { - input := { "review": input_review_statefulset_storageclassname_missing, "parameters": { "includeStorageClassesInMessage": true } } - results := violation with input as input with data.inventory as inv + inp := { "review": input_review_statefulset_storageclassname_missing, "parameters": { "includeStorageClassesInMessage": true } } + results := violation with input as inp with data.inventory as inv count(results) == 1 } test_input_allowed_statefulset_sc { - input := { "review": input_review_statefulset_name("slow"), "parameters": { "includeStorageClassesInMessage": true, "allowedStorageClasses": ["slow"] } } - results := violation with input as input with data.inventory as inv + inp := { "review": input_review_statefulset_name("slow"), "parameters": { "includeStorageClassesInMessage": true, "allowedStorageClasses": ["slow"] } } + results := violation with input as inp with data.inventory as inv count(results) == 0 } test_input_denied_statefulset_sc { - input := { "review": input_review_statefulset_name("slow"), "parameters": { "includeStorageClassesInMessage": true, "allowedStorageClasses": ["fast"] } } - results := violation with input as input with data.inventory as inv + inp := { "review": input_review_statefulset_name("slow"), "parameters": { "includeStorageClassesInMessage": true, "allowedStorageClasses": ["fast"] } } + results := violation with input as inp with data.inventory as inv count(results) == 1 } test_input_allowed_statefulset_mixed_sc { - input := { "review": input_review_statefulset_name("slow"), "parameters": { "includeStorageClassesInMessage": true, "allowedStorageClasses": ["fast", "slow"] } } - results := violation with input as input with data.inventory as inv + inp := { "review": input_review_statefulset_name("slow"), "parameters": { "includeStorageClassesInMessage": true, "allowedStorageClasses": ["fast", "slow"] } } + results := violation with input as inp with data.inventory as inv count(results) == 0 } test_input_denied_statefulset_multiple_sc { - input := { "review": input_review_statefulset_name("slow"), "parameters": { "includeStorageClassesInMessage": true, "allowedStorageClasses": ["other","fast"] } } - results := violation with input as input with data.inventory as inv + inp := { "review": input_review_statefulset_name("slow"), "parameters": { "includeStorageClassesInMessage": true, "allowedStorageClasses": ["other","fast"] } } + results := violation with input as inp with data.inventory as inv count(results) == 1 } diff --git a/src/general/uniqueingresshost/constraint.tmpl b/src/general/uniqueingresshost/constraint.tmpl index e546c9098..e8fb572de 100644 --- a/src/general/uniqueingresshost/constraint.tmpl +++ b/src/general/uniqueingresshost/constraint.tmpl @@ -4,7 +4,7 @@ metadata: name: k8suniqueingresshost annotations: metadata.gatekeeper.sh/title: "Unique Ingress Host" - metadata.gatekeeper.sh/version: 1.0.3 + metadata.gatekeeper.sh/version: 1.0.4 metadata.gatekeeper.sh/requires-sync-data: | "[ [ diff --git a/src/general/uniqueingresshost/src.rego b/src/general/uniqueingresshost/src.rego index 899c17c12..24bb68d13 100644 --- a/src/general/uniqueingresshost/src.rego +++ b/src/general/uniqueingresshost/src.rego @@ -7,10 +7,10 @@ identical(obj, review) { violation[{"msg": msg}] { input.review.kind.kind == "Ingress" - re_match("^(extensions|networking.k8s.io)$", input.review.kind.group) + regex.match("^(extensions|networking.k8s.io)$", input.review.kind.group) host := input.review.object.spec.rules[_].host other := data.inventory.namespace[_][otherapiversion]["Ingress"][name] - re_match("^(extensions|networking.k8s.io)/.+$", otherapiversion) + regex.match("^(extensions|networking.k8s.io)/.+$", otherapiversion) other.spec.rules[_].host == host not identical(other, input.review) msg := sprintf("ingress host conflicts with an existing ingress <%v>", [host]) diff --git a/src/general/uniqueingresshost/src_test.rego b/src/general/uniqueingresshost/src_test.rego index b34ca1685..1368c4191 100644 --- a/src/general/uniqueingresshost/src_test.rego +++ b/src/general/uniqueingresshost/src_test.rego @@ -1,78 +1,78 @@ package k8suniqueingresshost test_no_data { - input := {"review": review(ingress("my-ingress", "prod", my_rules1, "extensions/v1beta1"), "extensions")} - results := violation with input as input + inp := {"review": review(ingress("my-ingress", "prod", my_rules1, "extensions/v1beta1"), "extensions")} + results := violation with input as inp count(results) == 0 } test_identical { - input := {"review": review(ingress("my-ingress", "prod", my_rules1, "extensions/v1beta1"), "extensions")} + inp := {"review": review(ingress("my-ingress", "prod", my_rules1, "extensions/v1beta1"), "extensions")} inv := inventory_data([ingress("my-ingress", "prod", my_rules1, "extensions/v1beta1")]) trace(sprintf("%v", [inv])) - results := violation with input as input with data.inventory as inv + results := violation with input as inp with data.inventory as inv trace(sprintf("%v", [results])) count(results) == 0 } test_collision { - input := {"review": review(ingress("my-ingress", "prod", my_rules1, "extensions/v1beta1"), "extensions")} + inp := {"review": review(ingress("my-ingress", "prod", my_rules1, "extensions/v1beta1"), "extensions")} inv := inventory_data([ingress("my-ingress", "prod2", my_rules1, "extensions/v1beta1")]) - results := violation with input as input with data.inventory as inv + results := violation with input as inp with data.inventory as inv count(results) == 1 } test_collision_with_multiple { - input := {"review": review(ingress("my-ingress", "prod", my_rules3, "extensions/v1beta1"), "extensions")} + inp := {"review": review(ingress("my-ingress", "prod", my_rules3, "extensions/v1beta1"), "extensions")} inv := inventory_data([ingress("my-ingress", "prod2", my_rules1, "extensions/v1beta1"), ingress("my-ingress1", "prod2", my_rules2, "extensions/v1beta1")]) - results := violation with input as input with data.inventory as inv + results := violation with input as inp with data.inventory as inv count(results) == 2 } test_no_collision { - input := {"review": review(ingress("my-ingress", "prod", my_rules1, "extensions/v1beta1"), "extensions")} + inp := {"review": review(ingress("my-ingress", "prod", my_rules1, "extensions/v1beta1"), "extensions")} inv := inventory_data([ingress("my-ingress", "prod2", my_rules2, "extensions/v1beta1")]) - results := violation with input as input with data.inventory as inv + results := violation with input as inp with data.inventory as inv count(results) == 0 } test_no_collision_with_multiple { - input := {"review": review(ingress("my-ingress", "prod", my_rules4, "extensions/v1beta1"), "extensions")} + inp := {"review": review(ingress("my-ingress", "prod", my_rules4, "extensions/v1beta1"), "extensions")} inv := inventory_data([ingress("my-ingress", "prod2", my_rules1, "extensions/v1beta1"), ingress("my-ingress", "prod3", my_rules2, "extensions/v1beta1")]) - results := violation with input as input with data.inventory as inv + results := violation with input as inp with data.inventory as inv count(results) == 0 } test_no_collision_with_multiple_apis { - input := {"review": review(ingress("my-ingress", "prod", my_rules4, "networking.k8s.io/v1beta1"), "networking.k8s.io")} + inp := {"review": review(ingress("my-ingress", "prod", my_rules4, "networking.k8s.io/v1beta1"), "networking.k8s.io")} inv := inventory_data2([ingress("my-ingress", "prod2", my_rules1, "networking.k8s.io/v1beta1"), ingress("my-ingress", "prod3", my_rules2, "networking.k8s.io/v1beta1")]) - results := violation with input as input with data.inventory as inv + results := violation with input as inp with data.inventory as inv count(results) == 0 } test_collision_with_multiple_apis { - input := {"review": review(ingress("my-ingress", "prod", my_rules3, "networking.k8s.io/v1beta1"), "networking.k8s.io")} + inp := {"review": review(ingress("my-ingress", "prod", my_rules3, "networking.k8s.io/v1beta1"), "networking.k8s.io")} inv := inventory_data2([ingress("my-ingress", "prod2", my_rules1, "networking.k8s.io/v1beta1"), ingress("my-ingress", "prod3", my_rules2, "networking.k8s.io/v1beta1")]) - results := violation with input as input with data.inventory as inv + results := violation with input as inp with data.inventory as inv count(results) == 2 } test_no_collision_with_multiple_bad_review_apis { - input := {"review": review(ingress("my-ingress", "prod", my_rules1, "app/v1beta1"), "app")} + inp := {"review": review(ingress("my-ingress", "prod", my_rules1, "app/v1beta1"), "app")} inv := inventory_data([ingress("my-ingress", "prod2", my_rules1, "extensions/v1beta1"), ingress("my-ingress", "prod3", my_rules2, "extensions/v1beta1")]) - results := violation with input as input with data.inventory as inv + results := violation with input as inp with data.inventory as inv count(results) == 0 } test_no_collision_with_multiple_bad_review_apis2 { - input := {"review": review(ingress("my-ingress", "prod", my_rules1, "test.extensions/v1beta1"), "test.extensions")} + inp := {"review": review(ingress("my-ingress", "prod", my_rules1, "test.extensions/v1beta1"), "test.extensions")} inv := inventory_data([ingress("my-ingress", "prod2", my_rules1, "extensions/v1beta1"), ingress("my-ingress", "prod3", my_rules2, "extensions/v1beta1")]) - results := violation with input as input with data.inventory as inv + results := violation with input as inp with data.inventory as inv count(results) == 0 } test_collision_with_multiple_apis_mixed { - input := {"review": review(ingress("my-ingress", "prod", my_rules1, "networking.k8s.io/v1beta1"), "networking.k8s.io")} + inp := {"review": review(ingress("my-ingress", "prod", my_rules1, "networking.k8s.io/v1beta1"), "networking.k8s.io")} inv := inventory_data([ingress("my-ingress", "prod2", my_rules1, "extensions/v1beta1"), ingress("my-ingress", "prod3", my_rules2, "extensions/v1beta1")]) - results := violation with input as input with data.inventory as inv + results := violation with input as inp with data.inventory as inv count(results) == 1 } test_no_collision_with_multiple_apis_slash { - input := {"review": review(ingress("my-ingress", "prod", my_rules1, "networking.k8s.io/v1beta1"), "networking.k8s.io")} + inp := {"review": review(ingress("my-ingress", "prod", my_rules1, "networking.k8s.io/v1beta1"), "networking.k8s.io")} inv := inventory_data1([ingress("my-ingress", "prod2", my_rules1, "extensions.something.io/v1beta1"), ingress("my-ingress", "prod3", my_rules2, "extensions.something.io/v1beta1")]) - results := violation with input as input with data.inventory as inv + results := violation with input as inp with data.inventory as inv count(results) == 0 } @@ -92,7 +92,7 @@ review(ing, group) = output { } my_rule(host) = { - "host": host, + "host": host, "http": { "paths": [{"backend": {"serviceName": "nginx", "servicePort": 80}}] }, diff --git a/src/general/uniqueserviceselector/src_test.rego b/src/general/uniqueserviceselector/src_test.rego index 316d635a3..84ac349fb 100644 --- a/src/general/uniqueserviceselector/src_test.rego +++ b/src/general/uniqueserviceselector/src_test.rego @@ -1,55 +1,55 @@ package k8suniqueserviceselector test_no_data { - input := {"review": review(service("my-service", "prod", {"a": "b"}))} - results := violation with input as input + inp := {"review": review(service("my-service", "prod", {"a": "b"}))} + results := violation with input as inp count(results) == 0 } test_identical { - input := {"review": review(service("my-service", "prod", {"a": "b"}))} + inp := {"review": review(service("my-service", "prod", {"a": "b"}))} inv := tmp_data([service("my-service", "prod", {"a": "b"})]) trace(sprintf("%v", [inv])) - results := violation with input as input with data.inventory as inv + results := violation with input as inp with data.inventory as inv trace(sprintf("%v", [results])) count(results) == 0 } test_collision { - input := {"review": review(service("my-service", "prod", {"a": "b"}))} + inp := {"review": review(service("my-service", "prod", {"a": "b"}))} inv := tmp_data([service("my-service", "prod2", {"a": "b"})]) - results := violation with input as input with data.inventory as inv + results := violation with input as inp with data.inventory as inv count(results) == 1 } test_collision_with_multiple { - input := {"review": review(service("my-service", "prod", {"a": "b"}))} + inp := {"review": review(service("my-service", "prod", {"a": "b"}))} inv := tmp_data([service("my-service", "prod2", {"a": "b"}), service("my-service", "prod3", {"a": "b"})]) - results := violation with input as input with data.inventory as inv + results := violation with input as inp with data.inventory as inv count(results) == 2 } test_no_collision { - input := {"review": review(service("my-service", "prod", {"a": "b"}))} + inp := {"review": review(service("my-service", "prod", {"a": "b"}))} inv := tmp_data([service("my-service", "prod2", {"a": "c"})]) - results := violation with input as input with data.inventory as inv + results := violation with input as inp with data.inventory as inv count(results) == 0 } test_no_collision_with_multiple { - input := {"review": review(service("my-service", "prod", {"a": "b"}))} + inp := {"review": review(service("my-service", "prod", {"a": "b"}))} inv := tmp_data([service("my-service", "prod2", {"a": "b2"}), service("my-service", "prod3", {"a": "b2"})]) - results := violation with input as input with data.inventory as inv + results := violation with input as inp with data.inventory as inv count(results) == 0 } test_compound_selector_collision { - input := {"review": review(service("my-service", "prod", {"r": "d", "a": "b"}))} + inp := {"review": review(service("my-service", "prod", {"r": "d", "a": "b"}))} inv := tmp_data([service("my-service", "prod2", {"a": "b", "r": "d"})]) - results := violation with input as input with data.inventory as inv + results := violation with input as inp with data.inventory as inv count(results) == 1 } test_no_service_selector { - input := {"review": review(service_without_selector("kubernetes", "default"))} + inp := {"review": review(service_without_selector("kubernetes", "default"))} inv := data_networkpolicy("default") - results := violation with input as input with data.inventory as inv + results := violation with input as inp with data.inventory as inv count(results) == 0 } diff --git a/src/general/verifydeprecatedapi/src_test.rego b/src/general/verifydeprecatedapi/src_test.rego index 37155123d..a8f6a27a5 100644 --- a/src/general/verifydeprecatedapi/src_test.rego +++ b/src/general/verifydeprecatedapi/src_test.rego @@ -1,14 +1,14 @@ package verifydeprecatedapi test_hpa_with_deprecated_api { - input := {"review": hpa("autoscaling/v2beta2"), "parameters": {"kvs": [{"deprecatedAPI": "autoscaling/v2beta2", "kinds": ["HorizontalPodAutoscaler"], "targetAPI": "autoscaling/v2"}], "k8sVersion": 1.26}} - results := violation with input as input + inp := {"review": hpa("autoscaling/v2beta2"), "parameters": {"kvs": [{"deprecatedAPI": "autoscaling/v2beta2", "kinds": ["HorizontalPodAutoscaler"], "targetAPI": "autoscaling/v2"}], "k8sVersion": 1.26}} + results := violation with input as inp count(results) == 0 } test_hpa_without_deprecated_api { - input := {"review": hpa("autoscaling/v2"), "parameters": {"kvs": [{"deprecatedAPI": "autoscaling/v2beta2", "kinds": ["HorizontalPodAutoscaler"], "targetAPI": "autoscaling/v2"}], "k8sVersion": 1.26}} - results := violation with input as input + inp := {"review": hpa("autoscaling/v2"), "parameters": {"kvs": [{"deprecatedAPI": "autoscaling/v2beta2", "kinds": ["HorizontalPodAutoscaler"], "targetAPI": "autoscaling/v2"}], "k8sVersion": 1.26}} + results := violation with input as inp count(results) == 0 } diff --git a/src/pod-security-policy/allow-privilege-escalation/src_test.rego b/src/pod-security-policy/allow-privilege-escalation/src_test.rego index a8e380d1f..8c1645675 100644 --- a/src/pod-security-policy/allow-privilege-escalation/src_test.rego +++ b/src/pod-security-policy/allow-privilege-escalation/src_test.rego @@ -1,48 +1,48 @@ package k8spspallowprivilegeescalationcontainer test_input_container_not_privilege_escalation_allowed { - input := { "review": input_review} - results := violation with input as input + inp := { "review": input_review} + results := violation with input as inp count(results) == 0 } test_input_container_privilege_escalation_not_allowed { - input := { "review": input_review_priv} - results := violation with input as input + inp := { "review": input_review_priv} + results := violation with input as inp count(results) == 1 } test_input_one_container_with_exemption { - input := { "review": input_review_priv, "parameters": {"exemptImages": ["one/*"]}} - results := violation with input as input + inp := { "review": input_review_priv, "parameters": {"exemptImages": ["one/*"]}} + results := violation with input as inp count(results) == 0 } test_input_container_many_not_privilege_escalation_allowed { - input := { "review": input_review_many} - results := violation with input as input + inp := { "review": input_review_many} + results := violation with input as inp count(results) == 2 } test_input_container_many_mixed_privilege_escalation_not_allowed { - input := { "review": input_review_many_mixed} - results := violation with input as input + inp := { "review": input_review_many_mixed} + results := violation with input as inp count(results) == 3 } test_input_container_many_mixed_privilege_escalation_not_allowed_one_exempted { - input := { "review": input_review_many_mixed, "parameters": {"exemptImages": ["one/*"]}} - results := violation with input as input + inp := { "review": input_review_many_mixed, "parameters": {"exemptImages": ["one/*"]}} + results := violation with input as inp count(results) == 2 } test_input_container_many_mixed_privilege_escalation_not_allowed_all_exempted { - input := { "review": input_review_many_mixed, "parameters": {"exemptImages": ["one/*", "two/*", "three/*"]}} - results := violation with input as input + inp := { "review": input_review_many_mixed, "parameters": {"exemptImages": ["one/*", "two/*", "three/*"]}} + results := violation with input as inp count(results) == 0 } test_input_container_many_mixed_privilege_escalation_not_allowed_two { - input := { "review": input_review_many_mixed_two} - results := violation with input as input + inp := { "review": input_review_many_mixed_two} + results := violation with input as inp count(results) == 2 } test_update { - input := { "review": object.union(input_review_priv, {"operation": "UPDATE"})} - results := violation with input as input + inp := { "review": object.union(input_review_priv, {"operation": "UPDATE"})} + results := violation with input as inp count(results) == 0 } @@ -140,7 +140,7 @@ input_containers_many = [ "securityContext": { "runAsUser": "1000" } - + }] input_containers_many_mixed = [ diff --git a/src/pod-security-policy/apparmor/src_test.rego b/src/pod-security-policy/apparmor/src_test.rego index dbed04d28..70c18fad1 100644 --- a/src/pod-security-policy/apparmor/src_test.rego +++ b/src/pod-security-policy/apparmor/src_test.rego @@ -1,68 +1,68 @@ package k8spspapparmor test_input_apparmor_allowed_empty { - input := { "review": input_review_container, "parameters": input_parameters_empty} - results := violation with input as input + inp := { "review": input_review_container, "parameters": input_parameters_empty} + results := violation with input as inp count(results) == 1 } test_input_apparmor_allowed_empty_but_exempted { - input := { "review": input_review_container, "parameters": input_parameters_exempt_container} - results := violation with input as input + inp := { "review": input_review_container, "parameters": input_parameters_exempt_container} + results := violation with input as inp count(results) == 1 } test_input_apparmor_not_allowed_no_annotation_empty { - input := { "review": input_review_no_annotation, "parameters": input_parameters_empty} - results := violation with input as input + inp := { "review": input_review_no_annotation, "parameters": input_parameters_empty} + results := violation with input as inp count(results) == 1 } test_input_apparmor_not_allowed_no_annotation { - input := { "review": input_review_no_annotation, "parameters": input_parameters_in_list} - results := violation with input as input + inp := { "review": input_review_no_annotation, "parameters": input_parameters_in_list} + results := violation with input as inp count(results) == 0 } test_input_apparmor_container_allowed_in_list { - input := { "review": input_review_container, "parameters": input_parameters_in_list} - results := violation with input as input + inp := { "review": input_review_container, "parameters": input_parameters_in_list} + results := violation with input as inp count(results) == 0 } test_input_apparmor_container_not_allowed_not_in_list { - input := { "review": input_review_container, "parameters": input_parameters_not_in_list} - results := violation with input as input + inp := { "review": input_review_container, "parameters": input_parameters_not_in_list} + results := violation with input as inp count(results) == 1 } test_input_apparmor_containers_allowed_in_list { - input := { "review": input_review_containers, "parameters": input_parameters_in_list} - results := violation with input as input + inp := { "review": input_review_containers, "parameters": input_parameters_in_list} + results := violation with input as inp count(results) == 0 } test_input_apparmor_containers_not_allowed_not_in_list { - input := { "review": input_review_containers, "parameters": input_parameters_not_in_list} - results := violation with input as input + inp := { "review": input_review_containers, "parameters": input_parameters_not_in_list} + results := violation with input as inp count(results) == 2 } test_input_apparmor_containers_allowed_in_list_mixed_no_annotation { - input := { "review": input_review_containers_missing_annotation, "parameters": input_parameters_in_list} - results := violation with input as input + inp := { "review": input_review_containers_missing_annotation, "parameters": input_parameters_in_list} + results := violation with input as inp count(results) == 0 } test_input_apparmor_containers_not_allowed_not_in_list_mixed_no_annotation { - input := { "review": input_review_containers_missing_annotation, "parameters": input_parameters_not_in_list} - results := violation with input as input + inp := { "review": input_review_containers_missing_annotation, "parameters": input_parameters_not_in_list} + results := violation with input as inp count(results) == 2 } test_input_apparmor_containers_not_allowed_not_in_list_mixed { - input := { "review": input_review_containers_mixed, "parameters": input_parameters_in_list} - results := violation with input as input + inp := { "review": input_review_containers_mixed, "parameters": input_parameters_in_list} + results := violation with input as inp count(results) == 1 } diff --git a/src/pod-security-policy/capabilities/constraint.tmpl b/src/pod-security-policy/capabilities/constraint.tmpl index 88bd9e262..9ca6bed26 100644 --- a/src/pod-security-policy/capabilities/constraint.tmpl +++ b/src/pod-security-policy/capabilities/constraint.tmpl @@ -4,7 +4,7 @@ metadata: name: k8spspcapabilities annotations: metadata.gatekeeper.sh/title: "Capabilities" - metadata.gatekeeper.sh/version: 1.0.1 + metadata.gatekeeper.sh/version: 1.0.2 description: >- Controls Linux capabilities on containers. Corresponds to the `allowedCapabilities` and `requiredDropCapabilities` fields in a diff --git a/src/pod-security-policy/capabilities/src.rego b/src/pod-security-policy/capabilities/src.rego index b60b26a3f..35038a95c 100644 --- a/src/pod-security-policy/capabilities/src.rego +++ b/src/pod-security-policy/capabilities/src.rego @@ -75,12 +75,9 @@ missing_drop_capabilities(container) { count(all - dropped) > 0 } -get_default(obj, param, _default) = out { - out = obj[param] -} +get_default(obj, param, _) := obj[param] -get_default(obj, param, _default) = out { +get_default(obj, param, _default) := _default { not obj[param] not obj[param] == false - out = _default } diff --git a/src/pod-security-policy/capabilities/src_test.rego b/src/pod-security-policy/capabilities/src_test.rego index 6158a3eea..4ab7bd0cc 100644 --- a/src/pod-security-policy/capabilities/src_test.rego +++ b/src/pod-security-policy/capabilities/src_test.rego @@ -1,281 +1,281 @@ package capabilities test_input_all_allowed { - input := { "review": input_review([cadd(["one", "two"])]), "parameters": {"allowedCapabilities": ["*"]}} - results := violation with input as input + inp := { "review": input_review([cadd(["one", "two"])]), "parameters": {"allowedCapabilities": ["*"]}} + results := violation with input as inp count(results) == 0 } test_input_all_allowed_container_x2 { - input := { "review": input_review([cadd(["one", "two"]), cadd(["three"])]), "parameters": {"allowedCapabilities": ["*"]}} - results := violation with input as input + inp := { "review": input_review([cadd(["one", "two"]), cadd(["three"])]), "parameters": {"allowedCapabilities": ["*"]}} + results := violation with input as inp count(results) == 0 } test_input_one_allowed { - input := { "review": input_review([cadd(["one"])]), "parameters": {"allowedCapabilities": ["one"]}} - results := violation with input as input + inp := { "review": input_review([cadd(["one"])]), "parameters": {"allowedCapabilities": ["one"]}} + results := violation with input as inp count(results) == 0 } test_input_one_allowed_container_x2 { - input := { "review": input_review([cadd(["one"]), cadd(["one"])]), "parameters": {"allowedCapabilities": ["one"]}} - results := violation with input as input + inp := { "review": input_review([cadd(["one"]), cadd(["one"])]), "parameters": {"allowedCapabilities": ["one"]}} + results := violation with input as inp count(results) == 0 } test_input_two_allowed_container_x2 { - input := { "review": input_review([cadd(["one"]), cadd(["two"])]), "parameters": {"allowedCapabilities": ["one", "two"]}} - results := violation with input as input + inp := { "review": input_review([cadd(["one"]), cadd(["two"])]), "parameters": {"allowedCapabilities": ["one", "two"]}} + results := violation with input as inp count(results) == 0 } test_input_two_allowed_two_used_container_x2 { - input := { "review": input_review([cadd(["one", "two"]), cadd(["one", "two"])]), "parameters": {"allowedCapabilities": ["one", "two"]}} - results := violation with input as input + inp := { "review": input_review([cadd(["one", "two"]), cadd(["one", "two"])]), "parameters": {"allowedCapabilities": ["one", "two"]}} + results := violation with input as inp count(results) == 0 } test_input_none_allowed { - input := { "review": input_review([cadd(["one"])]), "parameters": {"allowedCapabilities": []}} - results := violation with input as input + inp := { "review": input_review([cadd(["one"])]), "parameters": {"allowedCapabilities": []}} + results := violation with input as inp count(results) == 1 } test_input_none_allowed_undefined { - input := { "review": input_review([cadd(["one"])]), "parameters": {}} - results := violation with input as input + inp := { "review": input_review([cadd(["one"])]), "parameters": {}} + results := violation with input as inp count(results) == 1 } test_input_none_allowed_undefined_x2_x2 { - input := { "review": input_review([cadd(["one", "two"]), cadd(["three", "two"])]), "parameters": {}} - results := violation with input as input + inp := { "review": input_review([cadd(["one", "two"]), cadd(["three", "two"])]), "parameters": {}} + results := violation with input as inp trace(sprintf("results are: %v", [results])) count(results) == 2 } test_input_disallowed_x1 { - input := { "review": input_review([cadd(["three"])]), "parameters": {"allowedCapabilities": ["one", "two"]}} - results := violation with input as input + inp := { "review": input_review([cadd(["three"])]), "parameters": {"allowedCapabilities": ["one", "two"]}} + results := violation with input as inp count(results) == 1 } test_input_disallowed_x2_just_one { - input := { "review": input_review([cadd(["one"]), cadd(["three", "two"])]), "parameters": {"allowedCapabilities": ["one", "two"]}} - results := violation with input as input + inp := { "review": input_review([cadd(["one"]), cadd(["three", "two"])]), "parameters": {"allowedCapabilities": ["one", "two"]}} + results := violation with input as inp count(results) == 1 } test_input_disallowed_x2 { - input := { "review": input_review([cadd(["three"]), cadd(["three", "two"])]), "parameters": {"allowedCapabilities": ["one", "two"]}} - results := violation with input as input + inp := { "review": input_review([cadd(["three"]), cadd(["three", "two"])]), "parameters": {"allowedCapabilities": ["one", "two"]}} + results := violation with input as inp count(results) == 2 } test_input_disallowed_x2_but_exempt { - input := { "review": input_review([cadd(["three"]), cadd(["three", "two"])]), "parameters": {"allowedCapabilities": ["one", "two"], "exemptImages": ["nginx"]}} - results := violation with input as input + inp := { "review": input_review([cadd(["three"]), cadd(["three", "two"])]), "parameters": {"allowedCapabilities": ["one", "two"], "exemptImages": ["nginx"]}} + results := violation with input as inp count(results) == 0 } test_input_empty_drop { - input := { "review": input_review([cdrop(["one", "two"])]), "parameters": {"requiredDropCapabilities": []}} - results := violation with input as input + inp := { "review": input_review([cdrop(["one", "two"])]), "parameters": {"requiredDropCapabilities": []}} + results := violation with input as inp count(results) == 0 } test_input_all_dropped { - input := { "review": input_review([cdrop(["one", "two"])]), "parameters": {"requiredDropCapabilities": ["one", "two"]}} - results := violation with input as input + inp := { "review": input_review([cdrop(["one", "two"])]), "parameters": {"requiredDropCapabilities": ["one", "two"]}} + results := violation with input as inp count(results) == 0 } test_input_extra_dropped { - input := { "review": input_review([cdrop(["one", "two", "three"])]), "parameters": {"requiredDropCapabilities": ["one", "two"]}} - results := violation with input as input + inp := { "review": input_review([cdrop(["one", "two", "three"])]), "parameters": {"requiredDropCapabilities": ["one", "two"]}} + results := violation with input as inp count(results) == 0 } test_input_all_dropped_x2 { - input := { "review": input_review([cdrop(["one", "two"]), cdrop(["one", "two"])]), "parameters": {"requiredDropCapabilities": ["one", "two"]}} - results := violation with input as input + inp := { "review": input_review([cdrop(["one", "two"]), cdrop(["one", "two"])]), "parameters": {"requiredDropCapabilities": ["one", "two"]}} + results := violation with input as inp count(results) == 0 } test_input_missing_drop { - input := { "review": input_review([cdrop(["two"])]), "parameters": {"requiredDropCapabilities": ["one", "two"]}} - results := violation with input as input + inp := { "review": input_review([cdrop(["two"])]), "parameters": {"requiredDropCapabilities": ["one", "two"]}} + results := violation with input as inp count(results) == 1 } test_input_one_missing_drop_x2 { - input := { "review": input_review([cdrop(["one"]), cdrop(["one", "two"])]), "parameters": {"requiredDropCapabilities": ["one", "two"]}} - results := violation with input as input + inp := { "review": input_review([cdrop(["one"]), cdrop(["one", "two"])]), "parameters": {"requiredDropCapabilities": ["one", "two"]}} + results := violation with input as inp count(results) == 1 } test_input_missing_drop_x2 { - input := { "review": input_review([cdrop(["one"]), cdrop(["two"])]), "parameters": {"requiredDropCapabilities": ["one", "two"]}} - results := violation with input as input + inp := { "review": input_review([cdrop(["one"]), cdrop(["two"])]), "parameters": {"requiredDropCapabilities": ["one", "two"]}} + results := violation with input as inp count(results) == 2 } test_input_drop_undefined_x2 { - input := { "review": input_review([cadd([]), cadd([])]), "parameters": {"requiredDropCapabilities": ["one", "two"]}} - results := violation with input as input + inp := { "review": input_review([cadd([]), cadd([])]), "parameters": {"requiredDropCapabilities": ["one", "two"]}} + results := violation with input as inp count(results) == 2 } test_input_drop_undefined_x2_but_exempt { - input := { "review": input_review([cadd([]), cadd([])]), "parameters": {"requiredDropCapabilities": ["one", "two"], "exemptImages": ["nginx"]}} - results := violation with input as input + inp := { "review": input_review([cadd([]), cadd([])]), "parameters": {"requiredDropCapabilities": ["one", "two"], "exemptImages": ["nginx"]}} + results := violation with input as inp count(results) == 0 } test_input_drop_literal_all { - input := { "review": input_review([cdrop(["ALL"])]), "parameters": {"requiredDropCapabilities": ["one", "two"]}} - results := violation with input as input + inp := { "review": input_review([cdrop(["ALL"])]), "parameters": {"requiredDropCapabilities": ["one", "two"]}} + results := violation with input as inp count(results) == 0 } test_input_drop_literal_all_lower { - input := { "review": input_review([cdrop(["all"])]), "parameters": {"requiredDropCapabilities": ["one", "two"]}} - results := violation with input as input + inp := { "review": input_review([cdrop(["all"])]), "parameters": {"requiredDropCapabilities": ["one", "two"]}} + results := violation with input as inp count(results) == 0 } test_input_drop_literal_all_with_all_param { - input := { "review": input_review([cdrop(["ALL"])]), "parameters": {"requiredDropCapabilities": ["one", "ALL"]}} - results := violation with input as input + inp := { "review": input_review([cdrop(["ALL"])]), "parameters": {"requiredDropCapabilities": ["one", "ALL"]}} + results := violation with input as inp count(results) == 0 } test_input_drop_literal_all_x2 { - input := { "review": input_review([cdrop(["ALL", "two"])]), "parameters": {"requiredDropCapabilities": ["one", "two"]}} - results := violation with input as input + inp := { "review": input_review([cdrop(["ALL", "two"])]), "parameters": {"requiredDropCapabilities": ["one", "two"]}} + results := violation with input as inp count(results) == 0 } test_update { - input := { "review": object.union(input_review([cadd(["one"])]), {"operation": "UPDATE"}), "parameters": {"allowedCapabilities": []}} - results := violation with input as input + inp := { "review": object.union(input_review([cadd(["one"])]), {"operation": "UPDATE"}), "parameters": {"allowedCapabilities": []}} + results := violation with input as inp count(results) == 0 } # init containers test_input_all_allowed { - input := { "review": input_init_review([cadd(["one", "two"])]), "parameters": {"allowedCapabilities": ["*"]}} - results := violation with input as input + inp := { "review": input_init_review([cadd(["one", "two"])]), "parameters": {"allowedCapabilities": ["*"]}} + results := violation with input as inp count(results) == 0 } test_input_all_allowed_container_x2 { - input := { "review": input_init_review([cadd(["one", "two"]), cadd(["three"])]), "parameters": {"allowedCapabilities": ["*"]}} - results := violation with input as input + inp := { "review": input_init_review([cadd(["one", "two"]), cadd(["three"])]), "parameters": {"allowedCapabilities": ["*"]}} + results := violation with input as inp count(results) == 0 } test_input_one_allowed { - input := { "review": input_init_review([cadd(["one"])]), "parameters": {"allowedCapabilities": ["one"]}} - results := violation with input as input + inp := { "review": input_init_review([cadd(["one"])]), "parameters": {"allowedCapabilities": ["one"]}} + results := violation with input as inp count(results) == 0 } test_input_one_allowed_container_x2 { - input := { "review": input_init_review([cadd(["one"]), cadd(["one"])]), "parameters": {"allowedCapabilities": ["one"]}} - results := violation with input as input + inp := { "review": input_init_review([cadd(["one"]), cadd(["one"])]), "parameters": {"allowedCapabilities": ["one"]}} + results := violation with input as inp count(results) == 0 } test_input_two_allowed_container_x2 { - input := { "review": input_init_review([cadd(["one"]), cadd(["two"])]), "parameters": {"allowedCapabilities": ["one", "two"]}} - results := violation with input as input + inp := { "review": input_init_review([cadd(["one"]), cadd(["two"])]), "parameters": {"allowedCapabilities": ["one", "two"]}} + results := violation with input as inp count(results) == 0 } test_input_two_allowed_two_used_container_x2 { - input := { "review": input_init_review([cadd(["one", "two"]), cadd(["one", "two"])]), "parameters": {"allowedCapabilities": ["one", "two"]}} - results := violation with input as input + inp := { "review": input_init_review([cadd(["one", "two"]), cadd(["one", "two"])]), "parameters": {"allowedCapabilities": ["one", "two"]}} + results := violation with input as inp count(results) == 0 } test_input_none_allowed { - input := { "review": input_init_review([cadd(["one"])]), "parameters": {"allowedCapabilities": []}} - results := violation with input as input + inp := { "review": input_init_review([cadd(["one"])]), "parameters": {"allowedCapabilities": []}} + results := violation with input as inp count(results) == 1 } test_input_none_allowed_undefined { - input := { "review": input_init_review([cadd(["one"])]), "parameters": {}} - results := violation with input as input + inp := { "review": input_init_review([cadd(["one"])]), "parameters": {}} + results := violation with input as inp count(results) == 1 } test_input_none_allowed_undefined_x2_x2 { - input := { "review": input_init_review([cadd(["one", "two"]), cadd(["three", "two"])]), "parameters": {}} - results := violation with input as input + inp := { "review": input_init_review([cadd(["one", "two"]), cadd(["three", "two"])]), "parameters": {}} + results := violation with input as inp count(results) == 2 } test_input_disallowed_x1 { - input := { "review": input_init_review([cadd(["three"])]), "parameters": {"allowedCapabilities": ["one", "two"]}} - results := violation with input as input + inp := { "review": input_init_review([cadd(["three"])]), "parameters": {"allowedCapabilities": ["one", "two"]}} + results := violation with input as inp count(results) == 1 } test_input_disallowed_x2_just_one { - input := { "review": input_init_review([cadd(["one"]), cadd(["three", "two"])]), "parameters": {"allowedCapabilities": ["one", "two"]}} - results := violation with input as input + inp := { "review": input_init_review([cadd(["one"]), cadd(["three", "two"])]), "parameters": {"allowedCapabilities": ["one", "two"]}} + results := violation with input as inp count(results) == 1 } test_input_disallowed_x2 { - input := { "review": input_init_review([cadd(["three"]), cadd(["three", "two"])]), "parameters": {"allowedCapabilities": ["one", "two"]}} - results := violation with input as input + inp := { "review": input_init_review([cadd(["three"]), cadd(["three", "two"])]), "parameters": {"allowedCapabilities": ["one", "two"]}} + results := violation with input as inp count(results) == 2 } test_input_disallowed_x2_but_exempt { - input := { "review": input_init_review([cadd(["three"]), cadd(["three", "two"])]), "parameters": {"allowedCapabilities": ["one", "two"], "exemptImages": ["nginx"]}} - results := violation with input as input + inp := { "review": input_init_review([cadd(["three"]), cadd(["three", "two"])]), "parameters": {"allowedCapabilities": ["one", "two"], "exemptImages": ["nginx"]}} + results := violation with input as inp count(results) == 0 } test_input_empty_drop { - input := { "review": input_init_review([cdrop(["one", "two"])]), "parameters": {"requiredDropCapabilities": []}} - results := violation with input as input + inp := { "review": input_init_review([cdrop(["one", "two"])]), "parameters": {"requiredDropCapabilities": []}} + results := violation with input as inp count(results) == 0 } test_input_all_dropped { - input := { "review": input_init_review([cdrop(["one", "two"])]), "parameters": {"requiredDropCapabilities": ["one", "two"]}} - results := violation with input as input + inp := { "review": input_init_review([cdrop(["one", "two"])]), "parameters": {"requiredDropCapabilities": ["one", "two"]}} + results := violation with input as inp count(results) == 0 } test_input_extra_dropped { - input := { "review": input_init_review([cdrop(["one", "two", "three"])]), "parameters": {"requiredDropCapabilities": ["one", "two"]}} - results := violation with input as input + inp := { "review": input_init_review([cdrop(["one", "two", "three"])]), "parameters": {"requiredDropCapabilities": ["one", "two"]}} + results := violation with input as inp count(results) == 0 } test_input_all_dropped_x2 { - input := { "review": input_init_review([cdrop(["one", "two"]), cdrop(["one", "two"])]), "parameters": {"requiredDropCapabilities": ["one", "two"]}} - results := violation with input as input + inp := { "review": input_init_review([cdrop(["one", "two"]), cdrop(["one", "two"])]), "parameters": {"requiredDropCapabilities": ["one", "two"]}} + results := violation with input as inp count(results) == 0 } test_input_missing_drop { - input := { "review": input_init_review([cdrop(["two"])]), "parameters": {"requiredDropCapabilities": ["one", "two"]}} - results := violation with input as input + inp := { "review": input_init_review([cdrop(["two"])]), "parameters": {"requiredDropCapabilities": ["one", "two"]}} + results := violation with input as inp count(results) == 1 } test_input_one_missing_drop_x2 { - input := { "review": input_init_review([cdrop(["one"]), cdrop(["one", "two"])]), "parameters": {"requiredDropCapabilities": ["one", "two"]}} - results := violation with input as input + inp := { "review": input_init_review([cdrop(["one"]), cdrop(["one", "two"])]), "parameters": {"requiredDropCapabilities": ["one", "two"]}} + results := violation with input as inp count(results) == 1 } test_input_missing_drop_x2 { - input := { "review": input_init_review([cdrop(["one"]), cdrop(["two"])]), "parameters": {"requiredDropCapabilities": ["one", "two"]}} - results := violation with input as input + inp := { "review": input_init_review([cdrop(["one"]), cdrop(["two"])]), "parameters": {"requiredDropCapabilities": ["one", "two"]}} + results := violation with input as inp count(results) == 2 } test_input_drop_undefined_x2 { - input := { "review": input_init_review([cadd([]), cadd([])]), "parameters": {"requiredDropCapabilities": ["one", "two"]}} - results := violation with input as input + inp := { "review": input_init_review([cadd([]), cadd([])]), "parameters": {"requiredDropCapabilities": ["one", "two"]}} + results := violation with input as inp count(results) == 2 } test_input_drop_undefined_x2_but_exempt { - input := { "review": input_init_review([cadd([]), cadd([])]), "parameters": {"requiredDropCapabilities": ["one", "two"], "exemptImages": ["nginx"]}} - results := violation with input as input + inp := { "review": input_init_review([cadd([]), cadd([])]), "parameters": {"requiredDropCapabilities": ["one", "two"], "exemptImages": ["nginx"]}} + results := violation with input as inp count(results) == 0 } test_input_drop_literal_all { - input := { "review": input_init_review([cdrop(["ALL"])]), "parameters": {"requiredDropCapabilities": ["one", "two"]}} - results := violation with input as input + inp := { "review": input_init_review([cdrop(["ALL"])]), "parameters": {"requiredDropCapabilities": ["one", "two"]}} + results := violation with input as inp count(results) == 0 } test_input_drop_literal_all_lower { - input := { "review": input_init_review([cdrop(["all"])]), "parameters": {"requiredDropCapabilities": ["one", "two"]}} - results := violation with input as input + inp := { "review": input_init_review([cdrop(["all"])]), "parameters": {"requiredDropCapabilities": ["one", "two"]}} + results := violation with input as inp count(results) == 0 } test_input_drop_literal_all_with_all_param { - input := { "review": input_init_review([cdrop(["ALL"])]), "parameters": {"requiredDropCapabilities": ["one", "ALL"]}} - results := violation with input as input + inp := { "review": input_init_review([cdrop(["ALL"])]), "parameters": {"requiredDropCapabilities": ["one", "ALL"]}} + results := violation with input as inp count(results) == 0 } test_input_drop_literal_with_all_param { - input := { "review": input_init_review([cdrop(["one"])]), "parameters": {"requiredDropCapabilities": ["one", "ALL"]}} - results := violation with input as input + inp := { "review": input_init_review([cdrop(["one"])]), "parameters": {"requiredDropCapabilities": ["one", "ALL"]}} + results := violation with input as inp count(results) == 1 } test_input_drop_literal_all_x2 { - input := { "review": input_init_review([cdrop(["ALL", "two"])]), "parameters": {"requiredDropCapabilities": ["one", "two"]}} - results := violation with input as input + inp := { "review": input_init_review([cdrop(["ALL", "two"])]), "parameters": {"requiredDropCapabilities": ["one", "two"]}} + results := violation with input as inp count(results) == 0 } diff --git a/src/pod-security-policy/flexvolume-drivers/src_test.rego b/src/pod-security-policy/flexvolume-drivers/src_test.rego index 3b8eb69be..aa7d310b4 100644 --- a/src/pod-security-policy/flexvolume-drivers/src_test.rego +++ b/src/pod-security-policy/flexvolume-drivers/src_test.rego @@ -1,62 +1,62 @@ package k8spspflexvolumes test_input_flexvolume_empty_params { - input := { "review": input_review, "parameters": input_parameters_empty} - results := violation with input as input + inp := { "review": input_review, "parameters": input_parameters_empty} + results := violation with input as inp count(results) == 1 } test_input_flexvolume_many_empty_params{ - input := { "review": input_review_many, "parameters": input_parameters_empty} - results := violation with input as input + inp := { "review": input_review_many, "parameters": input_parameters_empty} + results := violation with input as inp count(results) == 2 } test_input_no_flexvolume_is_allowed { - input := { "review": input_review_no_flexvolume, "parameters": input_parameter_in_list} - results := violation with input as input + inp := { "review": input_review_no_flexvolume, "parameters": input_parameter_in_list} + results := violation with input as inp count(results) == 0 } test_input_flexvolume_allowed { - input := { "review": input_review, "parameters": input_parameter_in_list} - results := violation with input as input + inp := { "review": input_review, "parameters": input_parameter_in_list} + results := violation with input as inp count(results) == 0 } test_input_flexvolume_many_is_allowed { - input := { "review": input_review_many, "parameters": input_parameters_in_list} - results := violation with input as input + inp := { "review": input_review_many, "parameters": input_parameters_in_list} + results := violation with input as inp count(results) == 0 } test_input_flexvolume_many_is_allowed_no_flexvolume { - input := { "review": input_review_many_no_flexvolume, "parameters": input_parameters_in_list} - results := violation with input as input + inp := { "review": input_review_many_no_flexvolume, "parameters": input_parameters_in_list} + results := violation with input as inp count(results) == 0 } test_input_flexvolume_not_allowed { - input := { "review": input_review, "parameters": input_parameters_not_in_list} - results := violation with input as input + inp := { "review": input_review, "parameters": input_parameters_not_in_list} + results := violation with input as inp count(results) == 1 } test_input_flexvolume_many_not_allowed { - input := { "review": input_review_many_not_allowed, "parameters": input_parameters_not_in_list} - results := violation with input as input + inp := { "review": input_review_many_not_allowed, "parameters": input_parameters_not_in_list} + results := violation with input as inp count(results) == 2 } test_input_flexvolume_many_one_allowed { - input := { "review": input_review_many, "parameters": input_parameter_in_list} - results := violation with input as input + inp := { "review": input_review_many, "parameters": input_parameter_in_list} + results := violation with input as inp count(results) == 1 } test_input_flexvolume_many_mixed_allowed { - input := { "review": input_review_many, "parameters": input_parameters_not_in_list} - results := violation with input as input + inp := { "review": input_review_many, "parameters": input_parameters_not_in_list} + results := violation with input as inp count(results) == 1 } test_update { - input := { "review": object.union(input_review, {"operation": "UPDATE"}), "parameters": input_parameters_empty} - results := violation with input as input + inp := { "review": object.union(input_review, {"operation": "UPDATE"}), "parameters": input_parameters_empty} + results := violation with input as inp count(results) == 0 } diff --git a/src/pod-security-policy/forbidden-sysctls/constraint.tmpl b/src/pod-security-policy/forbidden-sysctls/constraint.tmpl index 91cecf030..87e4d23a9 100644 --- a/src/pod-security-policy/forbidden-sysctls/constraint.tmpl +++ b/src/pod-security-policy/forbidden-sysctls/constraint.tmpl @@ -4,7 +4,7 @@ metadata: name: k8spspforbiddensysctls annotations: metadata.gatekeeper.sh/title: "Forbidden Sysctls" - metadata.gatekeeper.sh/version: 1.1.2 + metadata.gatekeeper.sh/version: 1.1.3 description: >- Controls the `sysctl` profile used by containers. Corresponds to the `allowedUnsafeSysctls` and `forbiddenSysctls` fields in a PodSecurityPolicy. diff --git a/src/pod-security-policy/forbidden-sysctls/src.rego b/src/pod-security-policy/forbidden-sysctls/src.rego index 359dd44c7..135603aa1 100644 --- a/src/pod-security-policy/forbidden-sysctls/src.rego +++ b/src/pod-security-policy/forbidden-sysctls/src.rego @@ -21,7 +21,7 @@ violation[{"msg": msg, "details": {}}] { } # * may be used to forbid all sysctls -forbidden_sysctl(sysctl) { +forbidden_sysctl(_) { input.parameters.forbiddenSysctls[_] == "*" } @@ -36,7 +36,7 @@ forbidden_sysctl(sysctl) { } # * may be used to allow all sysctls -allowed_sysctl(sysctl) { +allowed_sysctl(_) { input.parameters.allowedSysctls[_] == "*" } diff --git a/src/pod-security-policy/forbidden-sysctls/src_test.rego b/src/pod-security-policy/forbidden-sysctls/src_test.rego index d2bd78027..07189ea47 100644 --- a/src/pod-security-policy/forbidden-sysctls/src_test.rego +++ b/src/pod-security-policy/forbidden-sysctls/src_test.rego @@ -1,116 +1,116 @@ package k8spspforbiddensysctls test_input_sysctls_forbidden_all { - input := { "review": input_review, "parameters": input_parameters_wildcard} - results := violation with input as input + inp := { "review": input_review, "parameters": input_parameters_wildcard} + results := violation with input as inp count(results) == 2 } test_input_sysctls_forbidden_in_list { - input := { "review": input_review, "parameters": input_parameters_in_list} - results := violation with input as input + inp := { "review": input_review, "parameters": input_parameters_in_list} + results := violation with input as inp count(results) == 2 } test_input_sysctls_forbidden_in_list_mixed { - input := { "review": input_review, "parameters": input_parameters_one_in_list} - results := violation with input as input + inp := { "review": input_review, "parameters": input_parameters_one_in_list} + results := violation with input as inp count(results) == 1 } test_input_sysctls_forbidden_not_in_list { - input := { "review": input_review, "parameters": input_parameters_not_in_list} - results := violation with input as input + inp := { "review": input_review, "parameters": input_parameters_not_in_list} + results := violation with input as inp count(results) == 0 } test_input_sysctls_forbidden_in_list_wildcard { - input := { "review": input_review, "parameters": input_parameters_in_list_wildcard} - results := violation with input as input + inp := { "review": input_review, "parameters": input_parameters_in_list_wildcard} + results := violation with input as inp count(results) == 2 } test_input_sysctls_forbidden_in_list_wildcard_mixed { - input := { "review": input_review, "parameters": input_parameters_one_in_list_wildcard} - results := violation with input as input + inp := { "review": input_review, "parameters": input_parameters_one_in_list_wildcard} + results := violation with input as inp count(results) == 1 } test_input_sysctls_forbidden_not_in_list_wildcard { - input := { "review": input_review, "parameters": input_parameters_not_in_list_wildcard} - results := violation with input as input + inp := { "review": input_review, "parameters": input_parameters_not_in_list_wildcard} + results := violation with input as inp count(results) == 0 } test_input_sysctls_empty_forbidden { - input := { "review": input_review, "parameters": input_parameters_empty} - results := violation with input as input + inp := { "review": input_review, "parameters": input_parameters_empty} + results := violation with input as inp count(results) == 0 } test_input_seccontext_empty_wildcard { - input := { "review": input_review_seccontext_empty, "parameters": input_parameters_wildcard} - results := violation with input as input + inp := { "review": input_review_seccontext_empty, "parameters": input_parameters_wildcard} + results := violation with input as inp count(results) == 0 } test_input_sysctls_empty_wildcard { - input := { "review": input_review_sysctls_empty, "parameters": input_parameters_wildcard} - results := violation with input as input + inp := { "review": input_review_sysctls_empty, "parameters": input_parameters_wildcard} + results := violation with input as inp count(results) == 0 } test_input_seccontext_null_wildcard { - input := { "review": input_review_seccontext_null, "parameters": input_parameters_wildcard} - results := violation with input as input + inp := { "review": input_review_seccontext_null, "parameters": input_parameters_wildcard} + results := violation with input as inp count(results) == 0 } test_input_seccontext_empty_empty_forbidden { - input := { "review": input_review_seccontext_empty, "parameters": input_parameters_empty} - results := violation with input as input + inp := { "review": input_review_seccontext_empty, "parameters": input_parameters_empty} + results := violation with input as inp count(results) == 0 } test_input_sysctls_empty_empty_forbidden { - input := { "review": input_review_sysctls_empty, "parameters": input_parameters_empty} - results := violation with input as input + inp := { "review": input_review_sysctls_empty, "parameters": input_parameters_empty} + results := violation with input as inp count(results) == 0 } test_input_seccontext_null_empty_forbidden { - input := { "review": input_review_seccontext_null, "parameters": input_parameters_empty} - results := violation with input as input + inp := { "review": input_review_seccontext_null, "parameters": input_parameters_empty} + results := violation with input as inp count(results) == 0 } test_input_init_sysctls_forbidden_all { - input := { "review": input_init_review, "parameters": input_parameters_wildcard} - results := violation with input as input + inp := { "review": input_init_review, "parameters": input_parameters_wildcard} + results := violation with input as inp count(results) == 2 } test_input_init_sysctls_forbidden_in_list { - input := { "review": input_init_review, "parameters": input_parameters_in_list} - results := violation with input as input + inp := { "review": input_init_review, "parameters": input_parameters_in_list} + results := violation with input as inp count(results) == 2 } test_input_init_sysctls_forbidden_in_list_mixed { - input := { "review": input_init_review, "parameters": input_parameters_one_in_list} - results := violation with input as input + inp := { "review": input_init_review, "parameters": input_parameters_one_in_list} + results := violation with input as inp count(results) == 1 } test_input_init_sysctls_forbidden_not_in_list { - input := { "review": input_init_review, "parameters": input_parameters_not_in_list} - results := violation with input as input + inp := { "review": input_init_review, "parameters": input_parameters_not_in_list} + results := violation with input as inp count(results) == 0 } test_input_sysctls_allowed_all { - input := { "review": input_review, "parameters": input_parameters_sysctls_allowed_all} - results := violation with input as input + inp := { "review": input_review, "parameters": input_parameters_sysctls_allowed_all} + results := violation with input as inp count(results) == 0 } @@ -118,44 +118,44 @@ test_input_sysctls_allowed_all { # This is in contrast to unspecified allowedSysctls which does not # place any restrictions by itself. test_input_sysctls_allowed_empty { - input := { "review": input_review, "parameters": input_parameters_sysctls_allowed_empty} - results := violation with input as input + inp := { "review": input_review, "parameters": input_parameters_sysctls_allowed_empty} + results := violation with input as inp count(results) == 2 } test_input_sysctls_allowed_exact { - input := { "review": input_review, "parameters": input_parameters_sysctls_allowed_exact} - results := violation with input as input + inp := { "review": input_review, "parameters": input_parameters_sysctls_allowed_exact} + results := violation with input as inp count(results) == 0 } test_input_sysctls_allowed_wildcards { - input := { "review": input_review, "parameters": input_parameters_sysctls_allowed_wildcards} - results := violation with input as input + inp := { "review": input_review, "parameters": input_parameters_sysctls_allowed_wildcards} + results := violation with input as inp count(results) == 0 } test_input_sysctls_some_allowed_exact { - input := { "review": input_review, "parameters": input_parameters_sysctls_some_allowed_exact} - results := violation with input as input + inp := { "review": input_review, "parameters": input_parameters_sysctls_some_allowed_exact} + results := violation with input as inp count(results) == 1 } test_input_sysctls_some_allowed_wildcards { - input := { "review": input_review, "parameters": input_parameters_sysctls_some_allowed_wildcards} - results := violation with input as input + inp := { "review": input_review, "parameters": input_parameters_sysctls_some_allowed_wildcards} + results := violation with input as inp count(results) == 1 } test_input_sysctls_allowed_and_forbidden { - input := { "review": input_review, "parameters": input_parameters_sysctls_allowed_and_forbidden} - results := violation with input as input + inp := { "review": input_review, "parameters": input_parameters_sysctls_allowed_and_forbidden} + results := violation with input as inp count(results) == 2 } test_update { - input := { "review": object.union(input_review, {"operation": "UPDATE"}), "parameters": input_parameters_wildcard} - results := violation with input as input + inp := { "review": object.union(input_review, {"operation": "UPDATE"}), "parameters": input_parameters_wildcard} + results := violation with input as inp count(results) == 0 } diff --git a/src/pod-security-policy/fsgroup/constraint.tmpl b/src/pod-security-policy/fsgroup/constraint.tmpl index 34a8b2a99..01e9f415d 100644 --- a/src/pod-security-policy/fsgroup/constraint.tmpl +++ b/src/pod-security-policy/fsgroup/constraint.tmpl @@ -4,7 +4,7 @@ metadata: name: k8spspfsgroup annotations: metadata.gatekeeper.sh/title: "FS Group" - metadata.gatekeeper.sh/version: 1.0.1 + metadata.gatekeeper.sh/version: 1.0.2 description: >- Controls allocating an FSGroup that owns the Pod's volumes. Corresponds to the `fsGroup` field in a PodSecurityPolicy. For more information, see diff --git a/src/pod-security-policy/fsgroup/src.rego b/src/pod-security-policy/fsgroup/src.rego index 23690a0de..2eb95cab7 100644 --- a/src/pod-security-policy/fsgroup/src.rego +++ b/src/pod-security-policy/fsgroup/src.rego @@ -11,7 +11,7 @@ violation[{"msg": msg, "details": {}}] { msg := sprintf("The provided pod spec fsGroup is not allowed, pod: %v. Allowed fsGroup: %v", [input.review.object.metadata.name, input.parameters]) } -input_fsGroup_allowed(spec) { +input_fsGroup_allowed(_) { # RunAsAny - No range is required. Allows any fsGroup ID to be specified. input.parameters.rule == "RunAsAny" } diff --git a/src/pod-security-policy/fsgroup/src_test.rego b/src/pod-security-policy/fsgroup/src_test.rego index 51fcf59f7..ab7be3d58 100644 --- a/src/pod-security-policy/fsgroup/src_test.rego +++ b/src/pod-security-policy/fsgroup/src_test.rego @@ -1,58 +1,58 @@ package k8spspfsgroup test_input_fsgroup_allowed_all { - input := { "review": input_review_with_fsgroup, "parameters": input_parameters_runasany} - results := violation with input as input + inp := { "review": input_review_with_fsgroup, "parameters": input_parameters_runasany} + results := violation with input as inp count(results) == 0 } test_input_no_fsgroup_allowed_all { - input := { "review": input_review, "parameters": input_parameters_runasany} - results := violation with input as input + inp := { "review": input_review, "parameters": input_parameters_runasany} + results := violation with input as inp count(results) == 0 } test_input_fsgroup_MustRunAs_allowed { - input := { "review": input_review_with_fsgroup, "parameters": input_parameters_in_list_mustrunas} - results := violation with input as input + inp := { "review": input_review_with_fsgroup, "parameters": input_parameters_in_list_mustrunas} + results := violation with input as inp count(results) == 0 } test_input_fsgroup_MustRunAs_not_allowed { - input := { "review": input_review_with_fsgroup, "parameters": input_parameters_in_list_mustrunas_outofrange} - results := violation with input as input + inp := { "review": input_review_with_fsgroup, "parameters": input_parameters_in_list_mustrunas_outofrange} + results := violation with input as inp count(results) > 0 } test_input_no_fsgroup_MustRunAs_not_allowed { - input := { "review": input_review, "parameters": input_parameters_in_list_mustrunas} - results := violation with input as input + inp := { "review": input_review, "parameters": input_parameters_in_list_mustrunas} + results := violation with input as inp count(results) > 0 } test_input_securitycontext_no_fsgroup_MustRunAs_not_allowed { - input := { "review": input_review_with_securitycontext_no_fsgroup, "parameters": input_parameters_in_list_mustrunas} - results := violation with input as input + inp := { "review": input_review_with_securitycontext_no_fsgroup, "parameters": input_parameters_in_list_mustrunas} + results := violation with input as inp count(results) > 0 } test_input_fsgroup_MayRunAs_allowed { - input := { "review": input_review_with_fsgroup, "parameters": input_parameters_in_list_mayrunas} - results := violation with input as input + inp := { "review": input_review_with_fsgroup, "parameters": input_parameters_in_list_mayrunas} + results := violation with input as inp count(results) == 0 } test_input_fsgroup_MayRunAs_not_allowed { - input := { "review": input_review_with_fsgroup, "parameters": input_parameters_in_list_mayrunas_outofrange} - results := violation with input as input + inp := { "review": input_review_with_fsgroup, "parameters": input_parameters_in_list_mayrunas_outofrange} + results := violation with input as inp count(results) > 0 } test_input_no_fsgroup_MayRunAs_allowed { - input := { "review": input_review, "parameters": input_parameters_in_list_mayrunas} - results := violation with input as input + inp := { "review": input_review, "parameters": input_parameters_in_list_mayrunas} + results := violation with input as inp count(results) == 0 } test_input_securitycontext_no_fsgroup_MayRunAs_allowed { - input := { "review": input_review_with_securitycontext_no_fsgroup, "parameters": input_parameters_in_list_mayrunas} - results := violation with input as input + inp := { "review": input_review_with_securitycontext_no_fsgroup, "parameters": input_parameters_in_list_mayrunas} + results := violation with input as inp count(results) == 0 } test_update { - input := { "review": object.union(input_review_with_fsgroup, {"operation": "UPDATE"}), "parameters": input_parameters_in_list_mustrunas_outofrange} - results := violation with input as input + inp := { "review": object.union(input_review_with_fsgroup, {"operation": "UPDATE"}), "parameters": input_parameters_in_list_mustrunas_outofrange} + results := violation with input as inp count(results) == 0 } diff --git a/src/pod-security-policy/host-filesystem/constraint.tmpl b/src/pod-security-policy/host-filesystem/constraint.tmpl index 39af451e1..d442ec331 100644 --- a/src/pod-security-policy/host-filesystem/constraint.tmpl +++ b/src/pod-security-policy/host-filesystem/constraint.tmpl @@ -4,7 +4,7 @@ metadata: name: k8spsphostfilesystem annotations: metadata.gatekeeper.sh/title: "Host Filesystem" - metadata.gatekeeper.sh/version: 1.0.1 + metadata.gatekeeper.sh/version: 1.0.2 description: >- Controls usage of the host filesystem. Corresponds to the `allowedHostPaths` field in a PodSecurityPolicy. For more information, diff --git a/src/pod-security-policy/host-filesystem/src.rego b/src/pod-security-policy/host-filesystem/src.rego index 53b140816..991c233f3 100644 --- a/src/pod-security-policy/host-filesystem/src.rego +++ b/src/pod-security-policy/host-filesystem/src.rego @@ -12,7 +12,7 @@ violation[{"msg": msg, "details": {}}] { msg := sprintf("HostPath volume %v is not allowed, pod: %v. Allowed path: %v", [volume, input.review.object.metadata.name, allowedPaths]) } -input_hostpath_violation(allowedPaths, volume) { +input_hostpath_violation(allowedPaths, _) { # An empty list means all host paths are blocked allowedPaths == [] } diff --git a/src/pod-security-policy/host-filesystem/src_test.rego b/src/pod-security-policy/host-filesystem/src_test.rego index 1e85733c3..1c6f632f1 100644 --- a/src/pod-security-policy/host-filesystem/src_test.rego +++ b/src/pod-security-policy/host-filesystem/src_test.rego @@ -1,136 +1,136 @@ package k8spsphostfilesystem test_input_hostpath_block_all { - input := { "review": input_review, "parameters": input_parameters_empty} - results := violation with input as input + inp := { "review": input_review, "parameters": input_parameters_empty} + results := violation with input as inp count(results) == 1 } test_input_hostpath_block_all_null_params { - input := { "review": input_review, "parameters": null } - results := violation with input as input + inp := { "review": input_review, "parameters": null } + results := violation with input as inp count(results) == 1 } test_input_hostpath_block_all_no_params { - input := { "review": input_review } - results := violation with input as input + inp := { "review": input_review } + results := violation with input as inp count(results) == 1 } test_input_hostpath_block_all { - input := { "review": input_review_many, "parameters": input_parameters_empty} - results := violation with input as input + inp := { "review": input_review_many, "parameters": input_parameters_empty} + results := violation with input as inp count(results) == 2 } test_input_hostpath_no_volumes { - input := { "review": input_review_no_volumes, "parameters": input_parameters_in_list} - results := violation with input as input + inp := { "review": input_review_no_volumes, "parameters": input_parameters_in_list} + results := violation with input as inp count(results) == 0 } test_input_hostpath_mixed_volumes { - input := { "review": input_review_many_mixed_volumes, "parameters": input_parameters_in_list} - results := violation with input as input + inp := { "review": input_review_many_mixed_volumes, "parameters": input_parameters_in_list} + results := violation with input as inp count(results) == 0 } test_input_hostpath_mixed_volumes_not_allowed { - input := { "review": input_review_many_mixed_volumes, "parameters": input_parameters_not_in_list} - results := violation with input as input + inp := { "review": input_review_many_mixed_volumes, "parameters": input_parameters_not_in_list} + results := violation with input as inp count(results) == 1 } test_input_hostpath_no_hostpath { - input := { "review": input_review_many_no_hostpath, "parameters": input_parameters_in_list} - results := violation with input as input + inp := { "review": input_review_many_no_hostpath, "parameters": input_parameters_in_list} + results := violation with input as inp count(results) == 0 } test_input_hostpath_allowed_readonly { - input := { "review": input_review_many, "parameters": input_parameters_in_list} - results := violation with input as input + inp := { "review": input_review_many, "parameters": input_parameters_in_list} + results := violation with input as inp count(results) == 0 } test_input_hostpath_not_allowed_readonly { - input := { "review": input_review, "parameters": input_parameters_not_in_list} - results := violation with input as input + inp := { "review": input_review, "parameters": input_parameters_not_in_list} + results := violation with input as inp count(results) == 1 } test_input_hostpath_many_not_allowed_readonly { - input := { "review": input_review_many, "parameters": input_parameters_not_in_list} - results := violation with input as input + inp := { "review": input_review_many, "parameters": input_parameters_not_in_list} + results := violation with input as inp count(results) == 2 } test_input_hostpath_allowed_writable_allowed { - input := { "review": input_review_writable, "parameters": input_parameters_in_list_writable} - results := violation with input as input + inp := { "review": input_review_writable, "parameters": input_parameters_in_list_writable} + results := violation with input as inp count(results) == 0 } test_input_hostpath_allowed_writable_not_allowed { - input := { "review": input_review_writable, "parameters": input_parameters_in_list} - results := violation with input as input + inp := { "review": input_review_writable, "parameters": input_parameters_in_list} + results := violation with input as inp count(results) == 1 } test_input_hostpath_not_allowed_writable { - input := { "review": input_review_writable, "parameters": input_parameters_not_in_list} - results := violation with input as input + inp := { "review": input_review_writable, "parameters": input_parameters_not_in_list} + results := violation with input as inp count(results) == 1 } test_input_hostpath_allowed_not_writable { - input := { "review": input_review, "parameters": input_parameters_in_list} - results := violation with input as input + inp := { "review": input_review, "parameters": input_parameters_in_list} + results := violation with input as inp count(results) == 1 } test_input_hostpath_allowed_is_writable { - input := { "review": input_review, "parameters": input_parameters_in_list_writable} - results := violation with input as input + inp := { "review": input_review, "parameters": input_parameters_in_list_writable} + results := violation with input as inp count(results) == 0 } test_input_hostpath_not_allowed_is_writable { - input := { "review": input_review, "parameters": input_parameters_not_in_list_writable} - results := violation with input as input + inp := { "review": input_review, "parameters": input_parameters_not_in_list_writable} + results := violation with input as inp count(results) == 1 } test_input_hostpath_not_allowed { - input := { "review": input_review, "parameters": input_parameters_not_in_list_writable} - results := violation with input as input + inp := { "review": input_review, "parameters": input_parameters_not_in_list_writable} + results := violation with input as inp count(results) == 1 } test_input_hostpath_allowed_readonly_mixed_parameters { - input := { "review": input_review_many_mixed_writable, "parameters": input_parameters_in_list} - results := violation with input as input + inp := { "review": input_review_many_mixed_writable, "parameters": input_parameters_in_list} + results := violation with input as inp count(results) == 1 } test_input_hostpath_allowed_readonly_mixed_parameters { - input := { "review": input_review_many_readonly, "parameters": input_parameters_in_list_mixed_writable} - results := violation with input as input + inp := { "review": input_review_many_readonly, "parameters": input_parameters_in_list_mixed_writable} + results := violation with input as inp count(results) == 0 } test_input_hostpath_allowed_mixed_writable_mixed_parameters { - input := { "review": input_review_many_mixed_writable, "parameters": input_parameters_in_list_mixed_writable} - results := violation with input as input + inp := { "review": input_review_many_mixed_writable, "parameters": input_parameters_in_list_mixed_writable} + results := violation with input as inp count(results) == 0 } test_update { - input := { "review": object.union(input_review, {"operation": "UPDATE"}), "parameters": input_parameters_empty} - results := violation with input as input + inp := { "review": object.union(input_review, {"operation": "UPDATE"}), "parameters": input_parameters_empty} + results := violation with input as inp count(results) == 0 } # Init Containers test_input_hostpath_allowed_readonly_init_containers { - input := { "review": input_init_review, "parameters": input_parameters_in_list} - results := violation with input as input + inp := { "review": input_init_review, "parameters": input_parameters_in_list} + results := violation with input as inp count(results) == 1 } test_input_hostpath_allowed_readonly_many_init_containers { - input := { "review": input_init_review_many, "parameters": input_parameters_in_list} - results := violation with input as input + inp := { "review": input_init_review_many, "parameters": input_parameters_in_list} + results := violation with input as inp count(results) == 0 } test_input_hostpath_not_allowed_readonly_init_containers { - input := { "review": input_init_review, "parameters": input_parameters_not_in_list} - results := violation with input as input + inp := { "review": input_init_review, "parameters": input_parameters_not_in_list} + results := violation with input as inp count(results) == 1 } test_input_hostpath_many_not_allowed_readonly_init_containers { - input := { "review": input_init_review_many, "parameters": input_parameters_not_in_list} - results := violation with input as input + inp := { "review": input_init_review_many, "parameters": input_parameters_not_in_list} + results := violation with input as inp count(results) == 2 } diff --git a/src/pod-security-policy/host-namespaces/src_test.rego b/src/pod-security-policy/host-namespaces/src_test.rego index f5c13e774..ebea77e21 100644 --- a/src/pod-security-policy/host-namespaces/src_test.rego +++ b/src/pod-security-policy/host-namespaces/src_test.rego @@ -1,28 +1,28 @@ package k8spsphostnamespace test_input_no_hostnamespace_allowed { - input := { "review": input_review} - results := violation with input as input + inp := { "review": input_review} + results := violation with input as inp count(results) == 0 } test_input_hostPID_not_allowed { - input := { "review": input_review_hostPID} - results := violation with input as input + inp := { "review": input_review_hostPID} + results := violation with input as inp count(results) > 0 } test_input_hostIPC_not_allowed { - input := { "review": input_review_hostIPC} - results := violation with input as input + inp := { "review": input_review_hostIPC} + results := violation with input as inp count(results) > 0 } test_input_hostnamespace_both_not_allowed { - input := { "review": input_review_hostnamespace_both} - results := violation with input as input + inp := { "review": input_review_hostnamespace_both} + results := violation with input as inp count(results) > 0 } test_update { - input := { "review": object.union(input_review_hostPID, {"operation": "UPDATE"})} - results := violation with input as input + inp := { "review": object.union(input_review_hostPID, {"operation": "UPDATE"})} + results := violation with input as inp count(results) == 0 } diff --git a/src/pod-security-policy/host-network-ports/constraint.tmpl b/src/pod-security-policy/host-network-ports/constraint.tmpl index abf6653c0..c8fd7a131 100644 --- a/src/pod-security-policy/host-network-ports/constraint.tmpl +++ b/src/pod-security-policy/host-network-ports/constraint.tmpl @@ -4,7 +4,7 @@ metadata: name: k8spsphostnetworkingports annotations: metadata.gatekeeper.sh/title: "Host Networking Ports" - metadata.gatekeeper.sh/version: 1.0.1 + metadata.gatekeeper.sh/version: 1.0.2 description: >- Controls usage of host network namespace by pod containers. Specific ports must be specified. Corresponds to the `hostNetwork` and diff --git a/src/pod-security-policy/host-network-ports/src.rego b/src/pod-security-policy/host-network-ports/src.rego index 1038815c8..524f6545c 100644 --- a/src/pod-security-policy/host-network-ports/src.rego +++ b/src/pod-security-policy/host-network-ports/src.rego @@ -16,12 +16,12 @@ input_share_hostnetwork(o) { o.spec.hostNetwork } -input_share_hostnetwork(o) { +input_share_hostnetwork(_) { hostPort := input_containers[_].ports[_].hostPort hostPort < input.parameters.min } -input_share_hostnetwork(o) { +input_share_hostnetwork(_) { hostPort := input_containers[_].ports[_].hostPort hostPort > input.parameters.max } diff --git a/src/pod-security-policy/host-network-ports/src_test.rego b/src/pod-security-policy/host-network-ports/src_test.rego index 0e54e11d4..5e23f6879 100644 --- a/src/pod-security-policy/host-network-ports/src_test.rego +++ b/src/pod-security-policy/host-network-ports/src_test.rego @@ -1,49 +1,49 @@ package k8spsphostnetworkingports test_input_no_hostnetwork_no_port_is_allowed { - input := { "review": input_review, "parameters": input_parameters_ports} - results := violation with input as input + inp := { "review": input_review, "parameters": input_parameters_ports} + results := violation with input as inp count(results) == 0 } test_input_no_hostnetwork_allowed_ports_is_allowed { - input := { "review": input_review_no_hostnetwork_allowed_ports, "parameters": input_parameters_ports} - results := violation with input as input + inp := { "review": input_review_no_hostnetwork_allowed_ports, "parameters": input_parameters_ports} + results := violation with input as inp count(results) == 0 } test_input_no_hostnetwork_container_ports_not_allowed { - input := { "review": input_review_no_hostnetwork_container_ports_outofrange, "parameters": input_parameters_ports} - results := violation with input as input + inp := { "review": input_review_no_hostnetwork_container_ports_outofrange, "parameters": input_parameters_ports} + results := violation with input as inp count(results) > 0 } test_input_with_hostnetwork_is_allowed { - input := { "review": input_review_with_hostnetwork_no_port, "parameters": input_parameters_ports} - results := violation with input as input + inp := { "review": input_review_with_hostnetwork_no_port, "parameters": input_parameters_ports} + results := violation with input as inp count(results) == 0 } test_input_with_hostnetwork_constraint_no_hostnetwork_not_allowed { - input := { "review": input_review_with_hostnetwork_no_port, "parameters": input_parameters_ports_no_hostnetwork} - results := violation with input as input + inp := { "review": input_review_with_hostnetwork_no_port, "parameters": input_parameters_ports_no_hostnetwork} + results := violation with input as inp count(results) > 0 } test_input_with_hostnetwork_constraint_no_hostnetwork_explicit { - input := { "review": input_review_no_hostnetwork_explicit, "parameters": input_parameters_ports_no_hostnetwork} - results := violation with input as input + inp := { "review": input_review_no_hostnetwork_explicit, "parameters": input_parameters_ports_no_hostnetwork} + results := violation with input as inp count(results) == 0 } test_input_with_hostnetwork_container_ports_not_allowed { - input := { "review": input_review_with_hostnetwork_port_outofrange, "parameters": input_parameters_ports} - results := violation with input as input + inp := { "review": input_review_with_hostnetwork_port_outofrange, "parameters": input_parameters_ports} + results := violation with input as inp count(results) == 1 } test_input_with_hostnetwork_container_ports_not_allowed_but_exempt { - input := { "review": input_review_with_hostnetwork_port_outofrange, "parameters": input_parameters_exempt} - results := violation with input as input + inp := { "review": input_review_with_hostnetwork_port_outofrange, "parameters": input_parameters_exempt} + results := violation with input as inp trace(sprintf("%v", [results])) count(results) == 0 } test_update { - input := { "review": object.union(input_review_no_hostnetwork_container_ports_outofrange, {"operation": "UPDATE"}), "parameters": input_parameters_ports} - results := violation with input as input + inp := { "review": object.union(input_review_no_hostnetwork_container_ports_outofrange, {"operation": "UPDATE"}), "parameters": input_parameters_ports} + results := violation with input as inp count(results) == 0 } @@ -172,7 +172,7 @@ input_parameters_ports_no_hostnetwork = { } input_parameters_exempt = { - "exemptImages": ["nginx"], + "exemptImages": ["nginx"], "hostNetwork": true, "min": 80, "max": 9000 diff --git a/src/pod-security-policy/privileged-containers/src_test.rego b/src/pod-security-policy/privileged-containers/src_test.rego index 4c1a462a2..c2b030e68 100644 --- a/src/pod-security-policy/privileged-containers/src_test.rego +++ b/src/pod-security-policy/privileged-containers/src_test.rego @@ -1,38 +1,38 @@ package k8spspprivileged test_input_container_not_privileged_allowed { - input := { "review": input_review} - results := violation with input as input + inp := { "review": input_review} + results := violation with input as inp count(results) == 0 } test_input_container_privileged_not_allowed { - input := { "review": input_review_priv} - results := violation with input as input + inp := { "review": input_review_priv} + results := violation with input as inp count(results) > 0 } test_input_container_many_not_privileged_allowed { - input := { "review": input_review_many} - results := violation with input as input + inp := { "review": input_review_many} + results := violation with input as inp count(results) == 0 } test_input_container_many_mixed_privileged_not_allowed { - input := { "review": input_review_many_mixed} - results := violation with input as input + inp := { "review": input_review_many_mixed} + results := violation with input as inp count(results) > 0 } test_input_container_many_mixed_privileged_not_allowed_two { - input := { "review": input_review_many_mixed_two} - results := violation with input as input + inp := { "review": input_review_many_mixed_two} + results := violation with input as inp count(results) == 2 } test_input_container_many_mixed_privileged_not_allowed_two_but_exempt { - input := { "review": input_review_many_mixed_two, "parameters": {"exemptImages": ["nginx"]}} - results := violation with input as input + inp := { "review": input_review_many_mixed_two, "parameters": {"exemptImages": ["nginx"]}} + results := violation with input as inp count(results) == 0 } test_update { - input := { "review": object.union(input_review_priv, {"operation": "UPDATE"})} - results := violation with input as input + inp := { "review": object.union(input_review_priv, {"operation": "UPDATE"})} + results := violation with input as inp count(results) == 0 } diff --git a/src/pod-security-policy/proc-mount/constraint.tmpl b/src/pod-security-policy/proc-mount/constraint.tmpl index b06f815b6..9491d7b45 100644 --- a/src/pod-security-policy/proc-mount/constraint.tmpl +++ b/src/pod-security-policy/proc-mount/constraint.tmpl @@ -4,7 +4,7 @@ metadata: name: k8spspprocmount annotations: metadata.gatekeeper.sh/title: "Proc Mount" - metadata.gatekeeper.sh/version: 1.0.2 + metadata.gatekeeper.sh/version: 1.0.3 description: >- Controls the allowed `procMount` types for the container. Corresponds to the `allowedProcMountTypes` field in a PodSecurityPolicy. For more diff --git a/src/pod-security-policy/proc-mount/src.rego b/src/pod-security-policy/proc-mount/src.rego index cf501c8bd..222b5caca 100644 --- a/src/pod-security-policy/proc-mount/src.rego +++ b/src/pod-security-policy/proc-mount/src.rego @@ -18,7 +18,7 @@ input_proc_mount_type_allowed(allowedProcMount, c) { allowedProcMount == "default" lower(c.securityContext.procMount) == "default" } -input_proc_mount_type_allowed(allowedProcMount, c) { +input_proc_mount_type_allowed(allowedProcMount, _) { allowedProcMount == "unmasked" } diff --git a/src/pod-security-policy/proc-mount/src_test.rego b/src/pod-security-policy/proc-mount/src_test.rego index 32452d8fb..c72c404d0 100644 --- a/src/pod-security-policy/proc-mount/src_test.rego +++ b/src/pod-security-policy/proc-mount/src_test.rego @@ -1,73 +1,73 @@ package k8spspprocmount test_input_container_not_proc_mount_allowed { - input := { "review": input_review, "parameters": input_parameters_default} - results := violation with input as input + inp := { "review": input_review, "parameters": input_parameters_default} + results := violation with input as inp count(results) == 0 } test_input_container_proc_mount_not_allowed { - input := { "review": input_review_unmasked, "parameters": input_parameters_default} - results := violation with input as input + inp := { "review": input_review_unmasked, "parameters": input_parameters_default} + results := violation with input as inp count(results) == 1 } test_input_container_proc_mount_not_allowed_null_param { - input := { "review": input_review_unmasked, "parameters": null } - results := violation with input as input + inp := { "review": input_review_unmasked, "parameters": null } + results := violation with input as inp count(results) == 1 } test_input_container_proc_mount_not_allowed_missing_param { - input := { "review": input_review_unmasked } - results := violation with input as input + inp := { "review": input_review_unmasked } + results := violation with input as inp count(results) == 1 } test_input_container_many_not_proc_mount_allowed { - input := { "review": input_review_many, "parameters": input_parameters_default} - results := violation with input as input + inp := { "review": input_review_many, "parameters": input_parameters_default} + results := violation with input as inp count(results) == 0 } test_input_container_many_mixed_proc_mount_not_allowed { - input := { "review": input_review_many_mixed, "parameters": input_parameters_default} - results := violation with input as input + inp := { "review": input_review_many_mixed, "parameters": input_parameters_default} + results := violation with input as inp count(results) == 1 } test_input_container_many_mixed_proc_mount_not_allowed_two { - input := { "review": input_review_many_mixed_two, "parameters": input_parameters_default} - results := violation with input as input + inp := { "review": input_review_many_mixed_two, "parameters": input_parameters_default} + results := violation with input as inp count(results) == 2 } test_input_container_many_mixed_proc_mount_not_allowed_two_but_exempt { - input := { "review": input_review_many_mixed_two, "parameters": input_parameters_exempt} - results := violation with input as input + inp := { "review": input_review_many_mixed_two, "parameters": input_parameters_exempt} + results := violation with input as inp count(results) == 0 } test_input_container_proc_mount_case_insensitive { - input := { "review": input_review, "parameters": input_parameters_default_lower} - results := violation with input as input + inp := { "review": input_review, "parameters": input_parameters_default_lower} + results := violation with input as inp count(results) == 0 } test_input_container_proc_mount_case_invalid_procMount { - input := { "review": input_review, "parameters": input_parameters_invalid_procMount} - results := violation with input as input + inp := { "review": input_review, "parameters": input_parameters_invalid_procMount} + results := violation with input as inp count(results) == 0 } test_input_container_not_proc_mount_unmasked { - input := { "review": input_review, "parameters": input_parameters_unmasked} - results := violation with input as input + inp := { "review": input_review, "parameters": input_parameters_unmasked} + results := violation with input as inp count(results) == 0 } test_input_container_proc_mount_unmasked { - input := { "review": input_review_unmasked, "parameters": input_parameters_unmasked} - results := violation with input as input + inp := { "review": input_review_unmasked, "parameters": input_parameters_unmasked} + results := violation with input as inp count(results) == 0 } test_input_container_many_mixed_proc_mount_allowed_two { - input := { "review": input_review_many_mixed_two, "parameters": input_parameters_unmasked} - results := violation with input as input + inp := { "review": input_review_many_mixed_two, "parameters": input_parameters_unmasked} + results := violation with input as inp count(results) == 0 } test_update { - input := { "review": object.union(input_review_unmasked, {"operation": "UPDATE"}), "parameters": input_parameters_default} - results := violation with input as input + inp := { "review": object.union(input_review_unmasked, {"operation": "UPDATE"}), "parameters": input_parameters_default} + results := violation with input as inp count(results) == 0 } diff --git a/src/pod-security-policy/read-only-root-filesystem/src_test.rego b/src/pod-security-policy/read-only-root-filesystem/src_test.rego index 348613859..d39073043 100644 --- a/src/pod-security-policy/read-only-root-filesystem/src_test.rego +++ b/src/pod-security-policy/read-only-root-filesystem/src_test.rego @@ -1,33 +1,33 @@ package k8spspreadonlyrootfilesystem test_input_container_not_readonlyrootfilesystem_allowed { - input := { "review": input_review} - results := violation with input as input + inp := { "review": input_review} + results := violation with input as inp count(results) == 1 } test_input_container_readonlyrootfilesystem_not_allowed { - input := { "review": input_review_ro} - results := violation with input as input + inp := { "review": input_review_ro} + results := violation with input as inp count(results) == 0 } test_input_container_many_mixed_readonlyrootfilesystem_not_allowed { - input := { "review": input_review_many_mixed} - results := violation with input as input + inp := { "review": input_review_many_mixed} + results := violation with input as inp count(results) == 2 } test_input_container_many_mixed_readonlyrootfilesystem_not_allowed_two { - input := { "review": input_review_many_mixed_two} - results := violation with input as input + inp := { "review": input_review_many_mixed_two} + results := violation with input as inp count(results) == 3 } test_input_container_many_mixed_readonlyrootfilesystem_not_allowed_two_but_exempt { - input := { "review": input_review_many_mixed_two, "parameters": {"exemptImages": ["nginx"]} } - results := violation with input as input + inp := { "review": input_review_many_mixed_two, "parameters": {"exemptImages": ["nginx"]} } + results := violation with input as inp count(results) == 0 } test_update { - input := { "review": object.union(input_review, {"operation": "UPDATE"})} - results := violation with input as input + inp := { "review": object.union(input_review, {"operation": "UPDATE"})} + results := violation with input as inp count(results) == 0 } diff --git a/src/pod-security-policy/seccomp/constraint.tmpl b/src/pod-security-policy/seccomp/constraint.tmpl index c350e216a..7a5c95538 100644 --- a/src/pod-security-policy/seccomp/constraint.tmpl +++ b/src/pod-security-policy/seccomp/constraint.tmpl @@ -4,7 +4,7 @@ metadata: name: k8spspseccomp annotations: metadata.gatekeeper.sh/title: "Seccomp" - metadata.gatekeeper.sh/version: 1.0.0 + metadata.gatekeeper.sh/version: 1.0.1 description: >- Controls the seccomp profile used by containers. Corresponds to the `seccomp.security.alpha.kubernetes.io/allowedProfileNames` annotation on diff --git a/src/pod-security-policy/seccomp/src.rego b/src/pod-security-policy/seccomp/src.rego index 53355d31a..61185ddb9 100644 --- a/src/pod-security-policy/seccomp/src.rego +++ b/src/pod-security-policy/seccomp/src.rego @@ -28,7 +28,7 @@ violation[{"msg": msg}] { msg := get_message(result.profile, result.file, name, result.location, allowed_profiles) } -get_message(profile, file, name, location, allowed_profiles) = message { +get_message(profile, _, name, location, allowed_profiles) = message { not profile == "Localhost" message := sprintf("Seccomp profile '%v' is not allowed for container '%v'. Found at: %v. Allowed profiles: %v", [profile, name, location, allowed_profiles]) } @@ -51,7 +51,7 @@ input_wildcard_allowed_files { } # Simple allowed Profiles -allowed_profile(profile, file, allowed) { +allowed_profile(profile, _, allowed) { not startswith(lower(profile), "localhost") profile == allowed[_] } @@ -66,20 +66,20 @@ allowed_profile(profile, file, allowed) { } # seccomp Localhost with wildcard -allowed_profile(profile, file, allowed) { +allowed_profile(profile, _, allowed) { profile == "Localhost" input_wildcard_allowed_files profile == allowed[_] } # annotation localhost with wildcard -allowed_profile(profile, file, allowed) { +allowed_profile(profile, _, allowed) { "localhost/*" == allowed[_] startswith(profile, "localhost/") } # annotation localhost without wildcard -allowed_profile(profile, file, allowed) { +allowed_profile(profile, _, allowed) { startswith(profile, "localhost/") profile == allowed[_] } diff --git a/src/pod-security-policy/seccomp/src_test.rego b/src/pod-security-policy/seccomp/src_test.rego index e2b32401a..161afa359 100644 --- a/src/pod-security-policy/seccomp/src_test.rego +++ b/src/pod-security-policy/seccomp/src_test.rego @@ -2,463 +2,463 @@ package k8spspseccomp # Annotation based seccomp with containers test_input_annotation_seccomp_empty_parameters { - input := {"review": get_object(pod_annotation, {}, single_container, {}), "parameters": input_parameters_empty} - results := violation with input as input + inp := {"review": get_object(pod_annotation, {}, single_container, {}), "parameters": input_parameters_empty} + results := violation with input as inp count(results) == 1 } test_input_annotation_seccomp_allowed_all { - input := {"review": get_object(pod_annotation, {}, single_container, {}), "parameters": input_parameters_wildcard} - results := violation with input as input + inp := {"review": get_object(pod_annotation, {}, single_container, {}), "parameters": input_parameters_wildcard} + results := violation with input as inp count(results) == 0 } test_input_annotation_seccomp_allowed_in_list { - input := {"review": get_object(pod_annotation, {}, single_container, {}), "parameters": input_parameter_in_list} - results := violation with input as input + inp := {"review": get_object(pod_annotation, {}, single_container, {}), "parameters": input_parameter_in_list} + results := violation with input as inp count(results) == 0 } test_input_annotation_seccomp_not_allowed_not_in_list { - input := {"review": get_object(pod_annotation, {}, single_container, {}), "parameters": input_parameters_not_in_list} - results := violation with input as input + inp := {"review": get_object(pod_annotation, {}, single_container, {}), "parameters": input_parameters_not_in_list} + results := violation with input as inp count(results) == 1 } test_input_annotation_seccomp_pod_multiple_empty_parameters { - input := {"review": get_object(pod_annotation, {}, multiple_containers, {}), "parameters": input_parameters_empty} - results := violation with input as input + inp := {"review": get_object(pod_annotation, {}, multiple_containers, {}), "parameters": input_parameters_empty} + results := violation with input as inp count(results) == 2 } test_input_annotation_seccomp_pod_multiple_allowed_all { - input := {"review": get_object(pod_annotation, {}, multiple_containers, {}), "parameters": input_parameters_wildcard} - results := violation with input as input + inp := {"review": get_object(pod_annotation, {}, multiple_containers, {}), "parameters": input_parameters_wildcard} + results := violation with input as inp count(results) == 0 } test_input_annotation_seccomp_pod_multiple_allowed_in_list { - input := {"review": get_object(pod_annotation, {}, multiple_containers, {}), "parameters": input_parameter_in_list} - results := violation with input as input + inp := {"review": get_object(pod_annotation, {}, multiple_containers, {}), "parameters": input_parameter_in_list} + results := violation with input as inp count(results) == 0 } test_input_annotation_seccomp_pod_multiple_not_allowed_not_in_list { - input := {"review": get_object(pod_annotation, {}, multiple_containers, {}), "parameters": input_parameters_not_in_list} - results := violation with input as input + inp := {"review": get_object(pod_annotation, {}, multiple_containers, {}), "parameters": input_parameters_not_in_list} + results := violation with input as inp count(results) == 2 } test_input_annotation_seccomp_container_allowed_all { - input := {"review": get_object(container_annotation, {}, single_container, {}), "parameters": input_parameters_wildcard} - results := violation with input as input + inp := {"review": get_object(container_annotation, {}, single_container, {}), "parameters": input_parameters_wildcard} + results := violation with input as inp count(results) == 0 } test_input_annotation_seccomp_container_allowed_in_list { - input := {"review": get_object(container_annotation, {}, single_container, {}), "parameters": input_parameter_in_list} - results := violation with input as input + inp := {"review": get_object(container_annotation, {}, single_container, {}), "parameters": input_parameter_in_list} + results := violation with input as inp count(results) == 0 } test_input_annotation_seccomp_container_not_allowed_not_in_list { - input := {"review": get_object(container_annotation, {}, single_container, {}), "parameters": input_parameters_not_in_list} - results := violation with input as input + inp := {"review": get_object(container_annotation, {}, single_container, {}), "parameters": input_parameters_not_in_list} + results := violation with input as inp count(results) == 1 } test_input_annotation_seccomp_containers_allowed_in_list { - input := {"review": get_object(container_annotations, {}, multiple_containers, {}), "parameters": input_parameter_in_list} - results := violation with input as input + inp := {"review": get_object(container_annotations, {}, multiple_containers, {}), "parameters": input_parameter_in_list} + results := violation with input as inp count(results) == 0 } test_input_annotation_seccomp_containers_not_allowed_not_in_list { - input := {"review": get_object(container_annotations, {}, multiple_containers, {}), "parameters": input_parameters_not_in_list} - results := violation with input as input + inp := {"review": get_object(container_annotations, {}, multiple_containers, {}), "parameters": input_parameters_not_in_list} + results := violation with input as inp count(results) == 2 } test_input_annotation_seccomp_containers_mixed { - input := {"review": get_object(container_annotations_mixed, {}, multiple_containers, {}), "parameters": input_parameter_in_list} - results := violation with input as input + inp := {"review": get_object(container_annotations_mixed, {}, multiple_containers, {}), "parameters": input_parameter_in_list} + results := violation with input as inp count(results) == 1 } test_input_annotation_seccomp_containers_mixed_missing { - input := {"review": get_object(container_annotation, {}, multiple_containers, {}), "parameters": input_parameter_in_list} - results := violation with input as input + inp := {"review": get_object(container_annotation, {}, multiple_containers, {}), "parameters": input_parameter_in_list} + results := violation with input as inp count(results) == 1 } test_input_annotation_seccomp_containers_allowed_in_list_multiple { - input := {"review": get_object(container_annotations_mixed, {}, multiple_containers, {}), "parameters": input_parameters_in_list} - results := violation with input as input + inp := {"review": get_object(container_annotations_mixed, {}, multiple_containers, {}), "parameters": input_parameters_in_list} + results := violation with input as inp count(results) == 0 } test_input_annotation_seccomp_pod_container { - input := {"review": get_object(pod_container_annotations, {}, multiple_containers, {}), "parameters": input_parameter_in_list} - results := violation with input as input + inp := {"review": get_object(pod_container_annotations, {}, multiple_containers, {}), "parameters": input_parameter_in_list} + results := violation with input as inp count(results) == 0 } test_input_annotation_seccomp_pod_container_not_allowed { - input := {"review": get_object(pod_container_annotations, {}, multiple_containers, {}), "parameters": input_parameters_not_in_list} - results := violation with input as input + inp := {"review": get_object(pod_container_annotations, {}, multiple_containers, {}), "parameters": input_parameters_not_in_list} + results := violation with input as inp count(results) == 2 } test_input_annotation_seccomp_pod_container_both_allowed { - input := {"review": get_object(pod_container_annotations_mixed, {}, multiple_containers, {}), "parameters": input_parameters_in_list} - results := violation with input as input + inp := {"review": get_object(pod_container_annotations_mixed, {}, multiple_containers, {}), "parameters": input_parameters_in_list} + results := violation with input as inp count(results) == 0 } test_input_annotation_seccomp_pod_container_mixed_allowed { - input := {"review": get_object(pod_container_annotations_mixed, {}, multiple_containers, {}), "parameters": input_parameter_in_list} - results := violation with input as input + inp := {"review": get_object(pod_container_annotations_mixed, {}, multiple_containers, {}), "parameters": input_parameter_in_list} + results := violation with input as inp count(results) == 1 } test_input_annotation_seccomp_pod_container_mixed_not_allowed { - input := {"review": get_object(pod_container_annotations_mixed, {}, multiple_containers, {}), "parameters": input_parameters_not_in_list} - results := violation with input as input + inp := {"review": get_object(pod_container_annotations_mixed, {}, multiple_containers, {}), "parameters": input_parameters_not_in_list} + results := violation with input as inp count(results) == 2 } test_input_annotation_seccomp_pod_container_both_allowed_reversed { - input := {"review": get_object(pod_container_annotations_mixed_rev, {}, multiple_containers, {}), "parameters": input_parameters_in_list} - results := violation with input as input + inp := {"review": get_object(pod_container_annotations_mixed_rev, {}, multiple_containers, {}), "parameters": input_parameters_in_list} + results := violation with input as inp count(results) == 0 } test_input_annotation_seccomp_pod_container_mixed_allowed_reversed { - input := {"review": get_object(pod_container_annotations_mixed_rev, {}, multiple_containers, {}), "parameters": input_parameter_in_list} - results := violation with input as input + inp := {"review": get_object(pod_container_annotations_mixed_rev, {}, multiple_containers, {}), "parameters": input_parameter_in_list} + results := violation with input as inp count(results) == 1 } test_input_annotation_seccomp_pod_container_mixed_not_allowed_reversed { - input := {"review": get_object(pod_container_annotations_mixed_rev, {}, multiple_containers, {}), "parameters": input_parameters_not_in_list} - results := violation with input as input + inp := {"review": get_object(pod_container_annotations_mixed_rev, {}, multiple_containers, {}), "parameters": input_parameters_not_in_list} + results := violation with input as inp count(results) == 2 } # Annotation based seccomp with init containers test_input_annotation_seccomp_pod_initcontainer_both_allowed { - input := {"review": get_object(pod_container_annotations_mixed, {}, {}, multiple_containers), "parameters": input_parameters_in_list} - results := violation with input as input + inp := {"review": get_object(pod_container_annotations_mixed, {}, {}, multiple_containers), "parameters": input_parameters_in_list} + results := violation with input as inp count(results) == 0 } test_input_annotation_seccomp_pod_initcontainer_mixed_allowed { - input := {"review": get_object(pod_container_annotations_mixed, {}, {}, multiple_containers), "parameters": input_parameter_in_list} - results := violation with input as input + inp := {"review": get_object(pod_container_annotations_mixed, {}, {}, multiple_containers), "parameters": input_parameter_in_list} + results := violation with input as inp count(results) == 1 } test_input_annotation_seccomp_pod_initcontainer_mixed_not_allowed { - input := {"review": get_object(pod_container_annotations_mixed, {}, {}, multiple_containers), "parameters": input_parameters_not_in_list} - results := violation with input as input + inp := {"review": get_object(pod_container_annotations_mixed, {}, {}, multiple_containers), "parameters": input_parameters_not_in_list} + results := violation with input as inp count(results) == 2 } # securityContext based seccomp with containers test_input_seccomp_empty_parameters { - input := {"review": get_object({}, context_runtimedefault, single_container, {}), "parameters": input_parameters_empty} - results := violation with input as input + inp := {"review": get_object({}, context_runtimedefault, single_container, {}), "parameters": input_parameters_empty} + results := violation with input as inp count(results) == 1 } test_input_seccomp_allowed_all { - input := {"review": get_object({}, context_runtimedefault, single_container, {}), "parameters": input_parameters_wildcard} - results := violation with input as input + inp := {"review": get_object({}, context_runtimedefault, single_container, {}), "parameters": input_parameters_wildcard} + results := violation with input as inp count(results) == 0 } test_input_seccomp_allowed_in_list { - input := {"review": get_object({}, context_runtimedefault, single_container, {}), "parameters": input_parameter_in_list} - results := violation with input as input + inp := {"review": get_object({}, context_runtimedefault, single_container, {}), "parameters": input_parameter_in_list} + results := violation with input as inp count(results) == 0 } test_input_seccomp_not_allowed_not_in_list { - input := {"review": get_object({}, context_runtimedefault, single_container, {}), "parameters": input_parameters_not_in_list} - results := violation with input as input + inp := {"review": get_object({}, context_runtimedefault, single_container, {}), "parameters": input_parameters_not_in_list} + results := violation with input as inp count(results) == 1 } test_input_seccomp_pod_multiple_empty_parameters { - input := {"review": get_object({}, context_runtimedefault, multiple_containers, {}), "parameters": input_parameters_empty} - results := violation with input as input + inp := {"review": get_object({}, context_runtimedefault, multiple_containers, {}), "parameters": input_parameters_empty} + results := violation with input as inp count(results) == 2 } test_input_seccomp_pod_multiple_allowed_all { - input := {"review": get_object({}, context_runtimedefault, multiple_containers, {}), "parameters": input_parameters_wildcard} - results := violation with input as input + inp := {"review": get_object({}, context_runtimedefault, multiple_containers, {}), "parameters": input_parameters_wildcard} + results := violation with input as inp count(results) == 0 } test_input_seccomp_pod_multiple_allowed_in_list { - input := {"review": get_object({}, context_runtimedefault, multiple_containers, {}), "parameters": input_parameter_in_list} - results := violation with input as input + inp := {"review": get_object({}, context_runtimedefault, multiple_containers, {}), "parameters": input_parameter_in_list} + results := violation with input as inp count(results) == 0 } test_input_seccomp_pod_multiple_not_allowed_not_in_list { - input := {"review": get_object({}, context_runtimedefault, multiple_containers, {}), "parameters": input_parameters_not_in_list} - results := violation with input as input + inp := {"review": get_object({}, context_runtimedefault, multiple_containers, {}), "parameters": input_parameters_not_in_list} + results := violation with input as inp count(results) == 2 } test_input_seccomp_pod_localhost_allowed_wrong_file { - input := {"review": get_object({}, context_localhost, single_container, {}), "parameters": input_parameters_sc} - results := violation with input as input + inp := {"review": get_object({}, context_localhost, single_container, {}), "parameters": input_parameters_sc} + results := violation with input as inp count(results) == 1 } test_input_seccomp_pod_localhost_allowed_no_specified_file { - input := {"review": get_object({}, context_localhost, single_container, {}), "parameters": input_parameters_sc_localhost_no_file} - results := violation with input as input + inp := {"review": get_object({}, context_localhost, single_container, {}), "parameters": input_parameters_sc_localhost_no_file} + results := violation with input as inp count(results) == 1 } test_input_seccomp_pod_localhost_allowed_wildcard_file { - input := {"review": get_object({}, context_localhost, single_container, {}), "parameters": input_parameters_sc_localhost_wildcard_file} - results := violation with input as input + inp := {"review": get_object({}, context_localhost, single_container, {}), "parameters": input_parameters_sc_localhost_wildcard_file} + results := violation with input as inp count(results) == 0 } test_input_seccomp_pod_localhost_allowed_annotation_wildcard_file { - input := {"review": get_object({}, context_localhost, single_container, {}), "parameters": input_parameters_localhost_wildcard} - results := violation with input as input + inp := {"review": get_object({}, context_localhost, single_container, {}), "parameters": input_parameters_localhost_wildcard} + results := violation with input as inp count(results) == 0 } test_input_seccomp_pod_localhost_allowed_both_wildcard_file { - input := {"review": get_object({}, context_localhost, single_container, {}), "parameters": input_parameters_localhost_wildcard_both} - results := violation with input as input + inp := {"review": get_object({}, context_localhost, single_container, {}), "parameters": input_parameters_localhost_wildcard_both} + results := violation with input as inp count(results) == 0 } test_input_seccomp_not_allowed_not_configured { - input := {"review": get_object({}, {}, single_container, {}), "parameters": input_parameter_in_list} - results := violation with input as input + inp := {"review": get_object({}, {}, single_container, {}), "parameters": input_parameter_in_list} + results := violation with input as inp count(results) == 1 } test_input_seccomp_not_allowed_multiple_not_configured { - input := {"review": get_object({}, {}, multiple_containers, {}), "parameters": input_parameter_in_list} - results := violation with input as input + inp := {"review": get_object({}, {}, multiple_containers, {}), "parameters": input_parameter_in_list} + results := violation with input as inp count(results) == 2 } test_input_seccomp_container_allowed_all { - input := {"review": get_object({}, {}, single_container_sc, {}), "parameters": input_parameters_wildcard} - results := violation with input as input + inp := {"review": get_object({}, {}, single_container_sc, {}), "parameters": input_parameters_wildcard} + results := violation with input as inp count(results) == 0 } test_input_seccomp_container_allowed_in_list { - input := {"review": get_object({}, {}, single_container_sc, {}), "parameters": input_parameter_in_list} - results := violation with input as input + inp := {"review": get_object({}, {}, single_container_sc, {}), "parameters": input_parameter_in_list} + results := violation with input as inp count(results) == 0 } test_input_seccomp_container_not_allowed_not_in_list { - input := {"review": get_object({}, {}, single_container_sc, {}), "parameters": input_parameters_not_in_list} - results := violation with input as input + inp := {"review": get_object({}, {}, single_container_sc, {}), "parameters": input_parameters_not_in_list} + results := violation with input as inp count(results) == 1 } test_input_seccomp_containers_allowed_in_list { - input := {"review": get_object({}, {}, multiple_containers_sc, {}), "parameters": input_parameter_in_list} - results := violation with input as input + inp := {"review": get_object({}, {}, multiple_containers_sc, {}), "parameters": input_parameter_in_list} + results := violation with input as inp count(results) == 0 } test_input_seccomp_containers_not_allowed_not_in_list { - input := {"review": get_object({}, {}, multiple_containers_sc, {}), "parameters": input_parameters_not_in_list} - results := violation with input as input + inp := {"review": get_object({}, {}, multiple_containers_sc, {}), "parameters": input_parameters_not_in_list} + results := violation with input as inp count(results) == 2 } test_input_seccomp_containers_mixed { - input := {"review": get_object({}, {}, multiple_containers_sc_mixed, {}), "parameters": input_parameter_in_list} - results := violation with input as input + inp := {"review": get_object({}, {}, multiple_containers_sc_mixed, {}), "parameters": input_parameter_in_list} + results := violation with input as inp count(results) == 1 } test_input_seccomp_containers_mixed_missing { - input := {"review": get_object({}, {}, multiple_containers_sc_missing, {}), "parameters": input_parameter_in_list} - results := violation with input as input + inp := {"review": get_object({}, {}, multiple_containers_sc_missing, {}), "parameters": input_parameter_in_list} + results := violation with input as inp count(results) == 1 } test_input_seccomp_containers_allowed_in_list_multiple { - input := {"review": get_object({}, {}, multiple_containers_sc_mixed, {}), "parameters": input_parameters_in_list} - results := violation with input as input + inp := {"review": get_object({}, {}, multiple_containers_sc_mixed, {}), "parameters": input_parameters_in_list} + results := violation with input as inp count(results) == 0 } test_input_seccomp_pod_container { - input := {"review": get_object({}, context_runtimedefault, multiple_containers_sc_missing, {}), "parameters": input_parameter_in_list} - results := violation with input as input + inp := {"review": get_object({}, context_runtimedefault, multiple_containers_sc_missing, {}), "parameters": input_parameter_in_list} + results := violation with input as inp count(results) == 0 } test_input_seccomp_pod_container_mixed_not_allowed_but_exempt { - input := {"review": get_object({}, context_runtimedefault, single_container, {}), "parameters": input_parameters_exempt} - results := violation with input as input + inp := {"review": get_object({}, context_runtimedefault, single_container, {}), "parameters": input_parameters_exempt} + results := violation with input as inp count(results) == 0 } test_input_seccomp_pod_container_not_allowed { - input := {"review": get_object({}, context_runtimedefault, multiple_containers_sc_missing, {}), "parameters": input_parameters_not_in_list} - results := violation with input as input + inp := {"review": get_object({}, context_runtimedefault, multiple_containers_sc_missing, {}), "parameters": input_parameters_not_in_list} + results := violation with input as inp count(results) == 2 } test_input_seccomp_pod_container_both_allowed { - input := {"review": get_object({}, context_localhost, multiple_containers_sc_missing, {}), "parameters": input_parameters_in_list} - results := violation with input as input + inp := {"review": get_object({}, context_localhost, multiple_containers_sc_missing, {}), "parameters": input_parameters_in_list} + results := violation with input as inp count(results) == 0 } test_input_seccomp_pod_container_mixed_allowed { - input := {"review": get_object({}, context_localhost, multiple_containers_sc_missing, {}), "parameters": input_parameter_in_list} - results := violation with input as input + inp := {"review": get_object({}, context_localhost, multiple_containers_sc_missing, {}), "parameters": input_parameter_in_list} + results := violation with input as inp count(results) == 1 } test_input_seccomp_pod_container_mixed_not_allowed { - input := {"review": get_object({}, context_localhost, multiple_containers_sc_missing, {}), "parameters": input_parameters_not_in_list} - results := violation with input as input + inp := {"review": get_object({}, context_localhost, multiple_containers_sc_missing, {}), "parameters": input_parameters_not_in_list} + results := violation with input as inp count(results) == 2 } # securityContext based seccomp with init containers test_input_seccomp_pod_initcontainer_both_allowed { - input := {"review": get_object({}, context_localhost, {}, multiple_containers_sc_missing), "parameters": input_parameters_in_list} - results := violation with input as input + inp := {"review": get_object({}, context_localhost, {}, multiple_containers_sc_missing), "parameters": input_parameters_in_list} + results := violation with input as inp count(results) == 0 } test_input_seccomp_pod_initcontainer_mixed_allowed { - input := {"review": get_object({}, context_localhost, {}, multiple_containers_sc_missing), "parameters": input_parameter_in_list} - results := violation with input as input + inp := {"review": get_object({}, context_localhost, {}, multiple_containers_sc_missing), "parameters": input_parameter_in_list} + results := violation with input as inp count(results) == 1 } test_input_seccomp_pod_initcontainer_mixed_not_allowed { - input := {"review": get_object({}, context_localhost, {}, multiple_containers_sc_missing), "parameters": input_parameters_not_in_list} - results := violation with input as input + inp := {"review": get_object({}, context_localhost, {}, multiple_containers_sc_missing), "parameters": input_parameters_not_in_list} + results := violation with input as inp count(results) == 2 } # Both annotation and securityContext based seccomp mixed test_input_both_seccomp_pod_context_container_annotation { - input := {"review": get_object(container_annotation_unconfined, context_runtimedefault, single_container, {}), "parameters": input_parameter_in_list} - results := violation with input as input + inp := {"review": get_object(container_annotation_unconfined, context_runtimedefault, single_container, {}), "parameters": input_parameter_in_list} + results := violation with input as inp count(results) == 0 } test_input_both_seccomp_pod_annotation_container_context { - input := {"review": get_object(pod_annotation_unconfined, {}, single_container_sc, {}), "parameters": input_parameter_in_list} - results := violation with input as input + inp := {"review": get_object(pod_annotation_unconfined, {}, single_container_sc, {}), "parameters": input_parameter_in_list} + results := violation with input as inp count(results) == 0 } test_input_both_seccomp_pod_context_and_annotation { - input := {"review": get_object(pod_annotation, context_runtimedefault, single_container, {}), "parameters": input_parameter_in_list} - results := violation with input as input + inp := {"review": get_object(pod_annotation, context_runtimedefault, single_container, {}), "parameters": input_parameter_in_list} + results := violation with input as inp count(results) == 0 } test_input_both_seccomp_container_context_and_annotation { - input := {"review": get_object(container_annotation, {}, single_container_sc, {}), "parameters": input_parameter_in_list} - results := violation with input as input + inp := {"review": get_object(container_annotation, {}, single_container_sc, {}), "parameters": input_parameter_in_list} + results := violation with input as inp count(results) == 0 } test_input_both_seccomp_pod_context_container_annotation_not_allowed { - input := {"review": get_object(container_annotation_unconfined, context_runtimedefault, single_container, {}), "parameters": input_parameters_not_in_list} - results := violation with input as input + inp := {"review": get_object(container_annotation_unconfined, context_runtimedefault, single_container, {}), "parameters": input_parameters_not_in_list} + results := violation with input as inp count(results) == 1 } test_input_both_seccomp_pod_annotation_container_context_not_allowed { - input := {"review": get_object(pod_annotation_unconfined, {}, single_container_sc, {}), "parameters": input_parameters_not_in_list} - results := violation with input as input + inp := {"review": get_object(pod_annotation_unconfined, {}, single_container_sc, {}), "parameters": input_parameters_not_in_list} + results := violation with input as inp count(results) == 1 } test_input_both_seccomp_pod_context_and_annotation_not_allowed { - input := {"review": get_object(pod_annotation, context_runtimedefault, single_container, {}), "parameters": input_parameters_not_in_list} - results := violation with input as input + inp := {"review": get_object(pod_annotation, context_runtimedefault, single_container, {}), "parameters": input_parameters_not_in_list} + results := violation with input as inp count(results) == 1 } test_input_both_seccomp_container_context_and_annotation_not_allowed { - input := {"review": get_object(container_annotation, {}, single_container_sc, {}), "parameters": input_parameters_not_in_list} - results := violation with input as input + inp := {"review": get_object(container_annotation, {}, single_container_sc, {}), "parameters": input_parameters_not_in_list} + results := violation with input as inp count(results) == 1 } test_input_both_seccomp_pod_context_container_annotation_multiple_mixed { - input := {"review": get_object(container_annotation, context_unconfined, multiple_containers_sc_missing, {}), "parameters": input_parameter_in_list} - results := violation with input as input + inp := {"review": get_object(container_annotation, context_unconfined, multiple_containers_sc_missing, {}), "parameters": input_parameter_in_list} + results := violation with input as inp count(results) == 1 } # Testing translation between annotation and securityContext test_translation_seccomp_allowed_annotation_all { - input := {"parameters": input_parameters_annotation} - output := get_allowed_profiles with input as input + inp := {"parameters": input_parameters_annotation} + output := get_allowed_profiles with input as inp output == allowed_full_translated } test_translation_seccomp_allowed_context_all { - input := {"parameters": input_parameters_sc} - output := get_allowed_profiles with input as input + inp := {"parameters": input_parameters_sc} + output := get_allowed_profiles with input as inp output == allowed_full_translated } test_translation_seccomp_allowed_context_localhost_wildcard_file { - input := {"parameters": input_parameters_sc_localhost_wildcard_file} - output := get_allowed_profiles with input as input + inp := {"parameters": input_parameters_sc_localhost_wildcard_file} + output := get_allowed_profiles with input as inp output == {"Localhost", "localhost/*"} } test_translation_seccomp_allowed_context_localhost_no_file { - input := {"parameters": input_parameters_sc_localhost_no_file} - output := get_allowed_profiles with input as input + inp := {"parameters": input_parameters_sc_localhost_no_file} + output := get_allowed_profiles with input as inp output == {"Localhost"} } test_input_translation_seccomp_annotation_match_allowed_context { - input := {"review": get_object(container_annotation, {}, single_container, {}), "parameters": input_parameters_sc} - results := violation with input as input + inp := {"review": get_object(container_annotation, {}, single_container, {}), "parameters": input_parameters_sc} + results := violation with input as inp count(results) == 0 } test_input_translation_seccomp_context_match_allowed_annotation { - input := {"review": get_object({}, {}, single_container_sc, {}), "parameters": input_parameters_annotation} - results := violation with input as input + inp := {"review": get_object({}, {}, single_container_sc, {}), "parameters": input_parameters_annotation} + results := violation with input as inp count(results) == 0 } test_input_translation_seccomp_context_localhost_allowed_annotation { - input := {"review": get_object({}, context_localhost1, single_container, {}), "parameters": input_parameters_annotation} - results := violation with input as input + inp := {"review": get_object({}, context_localhost1, single_container, {}), "parameters": input_parameters_annotation} + results := violation with input as inp count(results) == 0 } test_input_translation_seccomp_context_localhost_allowed_annotation_missing { - input := {"review": get_object({}, context_localhost, single_container, {}), "parameters": input_parameters_annotation} - results := violation with input as input + inp := {"review": get_object({}, context_localhost, single_container, {}), "parameters": input_parameters_annotation} + results := violation with input as inp count(results) == 1 } diff --git a/src/pod-security-policy/selinux/constraint.tmpl b/src/pod-security-policy/selinux/constraint.tmpl index 051b9c694..25da7db59 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.1 + metadata.gatekeeper.sh/version: 1.0.2 description: >- Defines an allow-list of seLinuxOptions configurations for pod containers. Corresponds to a PodSecurityPolicy requiring SELinux configs. diff --git a/src/pod-security-policy/selinux/src.rego b/src/pod-security-policy/selinux/src.rego index f11ededb9..0e6873bea 100644 --- a/src/pod-security-policy/selinux/src.rego +++ b/src/pod-security-policy/selinux/src.rego @@ -35,7 +35,7 @@ input_seLinuxOptions_allowed(options) { field_allowed(field, options, params) { params[field] == options[field] } -field_allowed(field, options, params) { +field_allowed(field, options, _) { not has_field(options, field) } diff --git a/src/pod-security-policy/selinux/src_test.rego b/src/pod-security-policy/selinux/src_test.rego index 8d796e8c7..6b0c4c739 100644 --- a/src/pod-security-policy/selinux/src_test.rego +++ b/src/pod-security-policy/selinux/src_test.rego @@ -1,141 +1,141 @@ package k8spspselinux test_input_seLinux_options_allowed_in_list { - input := { "review": input_review, "parameters": input_parameters_in_list} - results := violation with input as input + inp := { "review": input_review, "parameters": input_parameters_in_list} + results := violation with input as inp count(results) == 0 } test_input_seLinux_options_allowed_in_list_subset { - input := { "review": input_review, "parameters": input_parameters_in_list_subset} - results := violation with input as input + inp := { "review": input_review, "parameters": input_parameters_in_list_subset} + results := violation with input as inp count(results) == 1 } test_input_seLinux_options_allowed_in_list_split_list { - input := { "review": input_review, "parameters": input_parameters_in_list_split_two} - results := violation with input as input + inp := { "review": input_review, "parameters": input_parameters_in_list_split_two} + results := violation with input as inp count(results) == 1 } test_input_seLinux_option_not_allowed_not_in_list { - input := { "review": input_review, "parameters": input_parameters_not_in_list} - results := violation with input as input + inp := { "review": input_review, "parameters": input_parameters_not_in_list} + results := violation with input as inp count(results) == 1 } test_input_seLinux_options_empty { - input := { "review": input_review, "parameters": input_parameters_empty} - results := violation with input as input + inp := { "review": input_review, "parameters": input_parameters_empty} + results := violation with input as inp count(results) == 1 } test_input_seLinux_option_two_empty { - input := { "review": input_review_two , "parameters": input_parameters_empty} - results := violation with input as input + inp := { "review": input_review_two , "parameters": input_parameters_empty} + results := violation with input as inp count(results) == 1 } test_input_seLinux_options_no_security_context { - input := { "review": input_review_no_security_context, "parameters": input_parameters_in_list} - results := violation with input as input + inp := { "review": input_review_no_security_context, "parameters": input_parameters_in_list} + results := violation with input as inp count(results) == 0 } test_input_seLinux_options_two_allowed_in_list { - input := { "review": input_review_two, "parameters": input_parameters_in_list} - results := violation with input as input + inp := { "review": input_review_two, "parameters": input_parameters_in_list} + results := violation with input as inp count(results) == 0 } test_input_seLinux_options_two_subset_allowed_in_list { - input := { "review": input_review_two_subset, "parameters": input_parameters_in_list} - results := violation with input as input + inp := { "review": input_review_two_subset, "parameters": input_parameters_in_list} + results := violation with input as inp count(results) == 0 } test_input_seLinux_options_subset_allowed_in_list_subset { - input := { "review": input_review_two_subset, "parameters": input_parameters_in_list_subset} - results := violation with input as input + inp := { "review": input_review_two_subset, "parameters": input_parameters_in_list_subset} + results := violation with input as inp count(results) == 0 } test_input_seLinux_options_subset_allowed_in_list_split_subset { - input := { "review": input_review_two_subset, "parameters": input_parameters_in_list_split_subset} - results := violation with input as input + inp := { "review": input_review_two_subset, "parameters": input_parameters_in_list_split_subset} + results := violation with input as inp count(results) == 0 } test_input_seLinux_options_allowed_in_list_split_subset { - input := { "review": input_review, "parameters": input_parameters_in_list_split_subset} - results := violation with input as input + inp := { "review": input_review, "parameters": input_parameters_in_list_split_subset} + results := violation with input as inp count(results) == 1 } test_input_seLinux_options_two_subset_not_allowed_not_in_list { - input := { "review": input_review_two_subset, "parameters": input_parameters_not_in_list} - results := violation with input as input + inp := { "review": input_review_two_subset, "parameters": input_parameters_not_in_list} + results := violation with input as inp count(results) == 1 } test_input_seLinux_option_two_not_allowed_not_in_list { - input := { "review": input_review_two, "parameters": input_parameters_not_in_list} - results := violation with input as input + inp := { "review": input_review_two, "parameters": input_parameters_not_in_list} + results := violation with input as inp count(results) == 1 } test_input_seLinux_options_many_allowed_in_list { - input := { "review": input_review_many, "parameters": input_parameters_in_list} - results := violation with input as input + inp := { "review": input_review_many, "parameters": input_parameters_in_list} + results := violation with input as inp count(results) == 0 } test_input_seLinux_options_many_not_allowed_not_in_list { - input := { "review": input_review_many, "parameters": input_parameters_not_in_list} - results := violation with input as input + inp := { "review": input_review_many, "parameters": input_parameters_not_in_list} + results := violation with input as inp count(results) == 1 } test_input_seLinux_options_many_not_allowed_not_in_list_but_exempt { - input := { "review": input_review_many, "parameters": input_parameters_exempt} - results := violation with input as input + inp := { "review": input_review_many, "parameters": input_parameters_exempt} + results := violation with input as inp count(results) == 0 } test_input_seLinux_options_many_not_allowed_not_in_list_two { - input := { "review": input_review_many, "parameters": input_parameters_not_in_list_two} - results := violation with input as input + inp := { "review": input_review_many, "parameters": input_parameters_not_in_list_two} + results := violation with input as inp count(results) == 1 } test_input_seLinux_option_two_allowed_in_list_subset { - input := { "review": input_review_two , "parameters": input_parameters_in_list_subset} - results := violation with input as input + inp := { "review": input_review_two , "parameters": input_parameters_in_list_subset} + results := violation with input as inp count(results) == 1 } test_input_seLinux_option_two_not_allowed_not_in_list_subset { - input := { "review": input_review_two , "parameters": input_parameters_not_in_list_two} - results := violation with input as input + inp := { "review": input_review_two , "parameters": input_parameters_not_in_list_two} + results := violation with input as inp count(results) == 1 } test_input_seLinux_options_many_allowed_in_list_double_seccontext { - input := { "review": input_review_many_double_seccontext, "parameters": input_parameters_in_list} - results := violation with input as input + inp := { "review": input_review_many_double_seccontext, "parameters": input_parameters_in_list} + results := violation with input as inp count(results) == 0 } test_input_seLinux_options_many_not_allowed_not_in_list_double_seccontext { - input := { "review": input_review_many_double_seccontext, "parameters": input_parameters_not_in_list} - results := violation with input as input + inp := { "review": input_review_many_double_seccontext, "parameters": input_parameters_not_in_list} + results := violation with input as inp count(results) == 3 } test_input_seLinux_options_update { - input := { "review": object.union(input_review, {"operation": "UPDATE"}), "parameters": input_parameters_in_list_subset} - results := violation with input as input + inp := { "review": object.union(input_review, {"operation": "UPDATE"}), "parameters": input_parameters_in_list_subset} + results := violation with input as inp count(results) == 0 } diff --git a/src/pod-security-policy/users/constraint.tmpl b/src/pod-security-policy/users/constraint.tmpl index 2c503e343..29523b763 100644 --- a/src/pod-security-policy/users/constraint.tmpl +++ b/src/pod-security-policy/users/constraint.tmpl @@ -4,7 +4,7 @@ metadata: name: k8spspallowedusers annotations: metadata.gatekeeper.sh/title: "Allowed Users" - metadata.gatekeeper.sh/version: 1.0.1 + metadata.gatekeeper.sh/version: 1.0.2 description: >- Controls the user and group IDs of the container and some volumes. Corresponds to the `runAsUser`, `runAsGroup`, `supplementalGroups`, and diff --git a/src/pod-security-policy/users/src.rego b/src/pod-security-policy/users/src.rego index 4d28bafd2..decf44cf6 100644 --- a/src/pod-security-policy/users/src.rego +++ b/src/pod-security-policy/users/src.rego @@ -47,11 +47,11 @@ get_user_violation(params, container) = msg { msg := sprintf("Container %v is attempting to run without a required securityContext/runAsNonRoot or securityContext/runAsUser != 0", [container.name]) } -accept_users("RunAsAny", provided_user) {true} +accept_users("RunAsAny", _) -accept_users("MustRunAsNonRoot", provided_user) = res {res := provided_user != 0} +accept_users("MustRunAsNonRoot", provided_user) := provided_user != 0 -accept_users("MustRunAs", provided_user) = res { +accept_users("MustRunAs", provided_user) := res { ranges := input.parameters.runAsUser.ranges res := is_in_range(provided_user, ranges) } @@ -80,18 +80,15 @@ get_violation(field, params, container) = msg { msg := sprintf("Container %v is attempting to run without a required securityContext/%v. Allowed %v: %v", [container.name, field, field, params]) } -accept_value("RunAsAny", provided_value, ranges) {true} +accept_value("RunAsAny", _, _) -accept_value("MayRunAs", provided_value, ranges) = res { res := is_in_range(provided_value, ranges)} +accept_value("MayRunAs", provided_value, ranges) := is_in_range(provided_value, ranges) -accept_value("MustRunAs", provided_value, ranges) = res { res := is_in_range(provided_value, ranges)} +accept_value("MustRunAs", provided_value, ranges) := is_in_range(provided_value, ranges) # If container level is provided, that takes precedence -get_field_value(field, container, review) = out { - container_value := get_seccontext_field(field, container) - out := container_value -} +get_field_value(field, container, _) := get_seccontext_field(field, container) # If no container level exists, use pod level get_field_value(field, container, review) = out { diff --git a/src/pod-security-policy/users/src_test.rego b/src/pod-security-policy/users/src_test.rego index 6e5979c87..9c8c5e04f 100644 --- a/src/pod-security-policy/users/src_test.rego +++ b/src/pod-security-policy/users/src_test.rego @@ -39,431 +39,431 @@ package k8spspallowedusers ## RunAsUser ## test_user_one_container_run_as_rule_any { - input := { "review": review(null, [ctr("cont1", runAsUser(12))], null), "parameters": user_runasany } - results := violation with input as input + inp := { "review": review(null, [ctr("cont1", runAsUser(12))], null), "parameters": user_runasany } + results := violation with input as inp count(results) == 0 } test_user_one_container_run_as_rule_any_root_user { - input := { "review": review(null, [ctr("cont1", runAsUser(0))], null), "parameters": user_runasany } - results := violation with input as input + inp := { "review": review(null, [ctr("cont1", runAsUser(0))], null), "parameters": user_runasany } + results := violation with input as inp count(results) == 0 } test_user_one_container_run_as_rule_non_root_user_is_not_root { - input := { "review": review(null, [ctr("cont1", runAsUser(1))], null), "parameters": user_mustrunasnonroot } - results := violation with input as input + inp := { "review": review(null, [ctr("cont1", runAsUser(1))], null), "parameters": user_mustrunasnonroot } + results := violation with input as inp count(results) == 0 } test_user_one_container_run_as_rule_non_root_user_is_root { - input := { "review": review(null, [ctr("cont1", runAsUser(0))], null), "parameters": user_mustrunasnonroot } - results := violation with input as input + inp := { "review": review(null, [ctr("cont1", runAsUser(0))], null), "parameters": user_mustrunasnonroot } + results := violation with input as inp count(results) == 1 } test_user_one_container_run_as_rule_non_root_seccont_runasnonroot_user_is_not_defined { - input := { "review": review(null, [ctr("cont1", runAsNonRoot(true))], null), "parameters": user_mustrunasnonroot } - results := violation with input as input + inp := { "review": review(null, [ctr("cont1", runAsNonRoot(true))], null), "parameters": user_mustrunasnonroot } + results := violation with input as inp count(results) == 0 } test_user_one_container_run_as_rule_non_root_seccont_runasnonroot_user_is_root { - input := { "review": review(null, [ctr("cont1", object.union(runAsNonRoot(true),runAsUser(0)))], null), "parameters": user_mustrunasnonroot } - results := violation with input as input + inp := { "review": review(null, [ctr("cont1", object.union(runAsNonRoot(true),runAsUser(0)))], null), "parameters": user_mustrunasnonroot } + results := violation with input as inp count(results) == 1 } test_user_one_container_run_as_rule_non_root_seccont_runasnonroot_user_is_not_root { - input := { "review": review(null, [ctr("cont1", object.union(runAsNonRoot(true),runAsUser(10)))], null), "parameters": user_mustrunasnonroot } - results := violation with input as input + inp := { "review": review(null, [ctr("cont1", object.union(runAsNonRoot(true),runAsUser(10)))], null), "parameters": user_mustrunasnonroot } + results := violation with input as inp count(results) == 0 } test_user_one_container_run_as_rule_non_root_seccont_runasnonroot_is_false_user_is_not_defined { - input := { "review": review(null, [ctr("cont1", runAsNonRoot(false))], null), "parameters": user_mustrunasnonroot } - results := violation with input as input + inp := { "review": review(null, [ctr("cont1", runAsNonRoot(false))], null), "parameters": user_mustrunasnonroot } + results := violation with input as inp count(results) == 1 } test_user_one_container_run_as_rule_non_root_seccont_runasnonroot_is_false_user_is_not_root { - input := { "review": review(null, [ctr("cont1", object.union(runAsNonRoot(false),runAsUser(10)))], null), "parameters": user_mustrunasnonroot } - results := violation with input as input + inp := { "review": review(null, [ctr("cont1", object.union(runAsNonRoot(false),runAsUser(10)))], null), "parameters": user_mustrunasnonroot } + results := violation with input as inp count(results) == 0 } test_user_one_container_run_in_range_user_in_range { - input := { "review": review(null, [ctr("cont1", runAsUser(150))], null), "parameters": user_mustrunas_100_200 } - results := violation with input as input + inp := { "review": review(null, [ctr("cont1", runAsUser(150))], null), "parameters": user_mustrunas_100_200 } + results := violation with input as inp count(results) == 0 } test_user_one_container_run_in_range_user_out_of_range { - input := { "review": review(null, [ctr("cont1", runAsUser(10))], null), "parameters": user_mustrunas_100_200 } - results := violation with input as input + inp := { "review": review(null, [ctr("cont1", runAsUser(10))], null), "parameters": user_mustrunas_100_200 } + results := violation with input as inp count(results) == 1 } test_user_one_container_run_in_range_user_lower_edge_of_range { - input := { "review": review(null, [ctr("cont1", runAsUser(100))], null), "parameters": user_mustrunas_100_200 } - results := violation with input as input + inp := { "review": review(null, [ctr("cont1", runAsUser(100))], null), "parameters": user_mustrunas_100_200 } + results := violation with input as inp count(results) == 0 } test_user_one_container_run_in_range_user_upper_edge_of_range { - input := { "review": review(null, [ctr("cont1", runAsUser(200))], null), "parameters": user_mustrunas_100_200 } - results := violation with input as input + inp := { "review": review(null, [ctr("cont1", runAsUser(200))], null), "parameters": user_mustrunas_100_200 } + results := violation with input as inp count(results) == 0 } test_user_one_container_run_in_range_seccont_runasnonroot { - input := { "review": review(null, [ctr("cont1", runAsNonRoot(true))], null), "parameters": user_mustrunas_100_200 } - results := violation with input as input + inp := { "review": review(null, [ctr("cont1", runAsNonRoot(true))], null), "parameters": user_mustrunas_100_200 } + results := violation with input as inp count(results) == 1 } test_user_one_container_run_in_range_user_between_ranges { - input := { "review": review(null, [ctr("cont1", runAsUser(200))], null), "parameters": user_mustrunas_two_ranges } - results := violation with input as input + inp := { "review": review(null, [ctr("cont1", runAsUser(200))], null), "parameters": user_mustrunas_two_ranges } + results := violation with input as inp count(results) == 1 } test_user_one_container_run_in_range_user_between_ranges_but_exempt { - input := { "review": review(null, [ctr("cont1", runAsUser(200))], null), "parameters": object.union(user_mustrunas_two_ranges, {"exemptImages": ["nginx"]}) } - results := violation with input as input + inp := { "review": review(null, [ctr("cont1", runAsUser(200))], null), "parameters": object.union(user_mustrunas_two_ranges, {"exemptImages": ["nginx"]}) } + results := violation with input as inp count(results) == 0 } test_non_root_container_pod_conflict { - input := {"review": review({"runAsNonRoot": true}, [ctr("cont1", runAsNonRoot(false))], null), "parameters": user_mustrunasnonroot } - results := violation with input as input + inp := {"review": review({"runAsNonRoot": true}, [ctr("cont1", runAsNonRoot(false))], null), "parameters": user_mustrunasnonroot } + results := violation with input as inp count(results) == 1 } test_user_two_containers_run_as_rule_any { - input := { + inp := { "review": review(null, [ctr("cont1", runAsUser(1)), ctr("cont2", runAsUser(100))], null), "parameters": user_runasany } - results := violation with input as input + results := violation with input as inp count(results) == 0 } test_user_two_containers_run_as_rule_non_root_users_are_not_root { - input := { + inp := { "review": review(null, [ctr("cont1", runAsUser(1)), ctr("cont2", runAsUser(100))], null), "parameters": user_mustrunasnonroot } - results := violation with input as input + results := violation with input as inp count(results) == 0 } test_user_two_containers_run_as_rule_non_root_one_is_root { - input := { + inp := { "review": review(null, [ctr("cont1", runAsUser(1)), ctr("cont2", runAsUser(0))], null), "parameters": user_mustrunasnonroot } - results := violation with input as input + results := violation with input as inp count(results) == 1 } test_user_two_containers_run_as_rule_non_root_one_seccont_runasnonroot { - input := { + inp := { "review": review(null, [ctr("cont1", runAsUser(1)), ctr("cont2", runAsNonRoot(true))], null), "parameters": user_mustrunasnonroot } - results := violation with input as input + results := violation with input as inp count(results) == 0 } test_user_two_containers_run_as_rule_non_root_one_root_other_has_seccont_runasnonroot { - input := { + inp := { "review": review(null, [ctr("cont1", runAsUser(0)), ctr("cont2", runAsNonRoot(true))], null), "parameters": user_mustrunasnonroot } - results := violation with input as input + results := violation with input as inp count(results) == 1 } test_user_two_containers_run_in_range_both_in_range { - input := { + inp := { "review": review(null, [ctr("cont1", runAsUser(150)), ctr("cont2", runAsUser(103))], null), "parameters": user_mustrunas_100_200 } - results := violation with input as input + results := violation with input as inp count(results) == 0 } test_user_two_containers_run_in_range_one_in_range { - input := { + inp := { "review": review(null, [ctr("cont1", runAsUser(150)), ctr("cont2", runAsUser(13))], null), "parameters": user_mustrunas_100_200 } - results := violation with input as input + results := violation with input as inp count(results) == 1 } test_user_two_containers_run_in_range_neither_in_range_two_ranges { - input := { + inp := { "review": review(null, [ctr("cont1", runAsUser(150)), ctr("cont2", runAsUser(130))], null), "parameters": user_mustrunas_two_ranges } - results := violation with input as input + results := violation with input as inp count(results) == 2 } test_user_one_container_one_initcontainer_run_in_range_user_in_range { - input := { + inp := { "review": review(null, [ctr("cont1", runAsUser(150))], [ctr("init1", runAsUser(150))]), "parameters": user_mustrunas_100_200 } - results := violation with input as input + results := violation with input as inp count(results) == 0 } test_user_one_container_one_initcontainer_run_in_range_user_not_in_range { - input := { + inp := { "review": review(null, [ctr("cont1", runAsUser(150))], [ctr("init1", runAsUser(250))]), "parameters": user_mustrunas_100_200 } - results := violation with input as input + results := violation with input as inp count(results) == 1 } test_user_one_container_empty_security_context { - input := { "review": review(null, [ctr("cont1", {})], null), "parameters": user_mustrunas_100_200 } - results := violation with input as input + inp := { "review": review(null, [ctr("cont1", {})], null), "parameters": user_mustrunas_100_200 } + results := violation with input as inp count(results) == 1 } test_user_one_container_no_security_context { - input := { "review": review(null, [ctr("cont1", null)], null), "parameters": user_mustrunas_100_200 } - results := violation with input as input + inp := { "review": review(null, [ctr("cont1", null)], null), "parameters": user_mustrunas_100_200 } + results := violation with input as inp count(results) == 1 } test_user_one_container_no_security_context_RunAsAny { - input := { "review": review(null, [ctr("cont1", null)], null), "parameters": user_runasany } - results := violation with input as input + inp := { "review": review(null, [ctr("cont1", null)], null), "parameters": user_runasany } + results := violation with input as inp count(results) == 0 } test_user_one_container_empty_security_context_empty_pod_security_context { - input := { "review": review({}, [ctr("cont1", {})], null), "parameters": user_mustrunas_100_200 } - results := violation with input as input + inp := { "review": review({}, [ctr("cont1", {})], null), "parameters": user_mustrunas_100_200 } + results := violation with input as inp count(results) == 1 } test_user_one_container_no_security_context_no_pod_security_context { - input := { "review": review(null, [ctr("cont1", null)], null), "parameters": user_mustrunas_100_200 } - results := violation with input as input + inp := { "review": review(null, [ctr("cont1", null)], null), "parameters": user_mustrunas_100_200 } + results := violation with input as inp count(results) == 1 } test_user_one_container_pod_defined_null_container_run_in_range_user_in_range { - input := { "review": review(runAsUser(150), [ctr("cont1", null)], null), "parameters": user_mustrunas_100_200} - results := violation with input as input + inp := { "review": review(runAsUser(150), [ctr("cont1", null)], null), "parameters": user_mustrunas_100_200} + results := violation with input as inp count(results) == 0 } test_user_one_container_pod_defined_run_in_range_user_in_range { - input := { "review": review(runAsUser(150), [ctr("cont1", {})], null), "parameters": user_mustrunas_100_200} - results := violation with input as input + inp := { "review": review(runAsUser(150), [ctr("cont1", {})], null), "parameters": user_mustrunas_100_200} + results := violation with input as inp count(results) == 0 } test_user_one_container_pod_defined_run_in_range_user_not_in_range { - input := { "review": review(runAsUser(250), [ctr("cont1", {})], null), "parameters": user_mustrunas_100_200 } - results := violation with input as input + inp := { "review": review(runAsUser(250), [ctr("cont1", {})], null), "parameters": user_mustrunas_100_200 } + results := violation with input as inp count(results) == 1 } test_user_one_container_pod_defined_run_in_range_container_overrides_user_in_range { - input := { "review": review(runAsUser(250), [ctr("cont1", runAsUser(150))], null), "parameters": user_mustrunas_100_200 } - results := violation with input as input + inp := { "review": review(runAsUser(250), [ctr("cont1", runAsUser(150))], null), "parameters": user_mustrunas_100_200 } + results := violation with input as inp count(results) == 0 } test_user_one_container_pod_defined_run_in_range_container_overrides_user_not_in_range { - input := { "review": review(runAsUser(150), [ctr("cont1", runAsUser(250))], null), "parameters": user_mustrunas_100_200 } - results := violation with input as input + inp := { "review": review(runAsUser(150), [ctr("cont1", runAsUser(250))], null), "parameters": user_mustrunas_100_200 } + results := violation with input as inp count(results) == 1 } test_user_input_container_run_as_rule_any_ignore_ranges { - input := { + inp := { "review": review(null, [ctr("cont1", runAsUser(10))], null), "parameters": runAsUser(rule("RunAsAny", [range(100, 200)])) } - results := violation with input as input + results := violation with input as inp count(results) == 0 } test_user_input_container_run_as_rule_non_root_ignore_ranges { - input := { + inp := { "review": review(null, [ctr("cont1", runAsUser(10))], null), "parameters": runAsUser(rule("MustRunAsNonRoot", [range(100, 200)])) } - results := violation with input as input + results := violation with input as inp count(results) == 0 } test_user_input_container_run_as_rule_non_root_seccont_runasnonroot_ignore_ranges { - input := { + inp := { "review": review(null, [ctr("cont1", runAsNonRoot(true))], null), "parameters": runAsUser(rule("MustRunAsNonRoot", [range(100, 200)])) } - results := violation with input as input + results := violation with input as inp count(results) == 0 } ## runAsGroup ## test_group_one_container_run_as_rule_any { - input := { "review": review(null, [ctr("cont1", runAsGroup(12))], null), "parameters": group_runasany } - results := violation with input as input + inp := { "review": review(null, [ctr("cont1", runAsGroup(12))], null), "parameters": group_runasany } + results := violation with input as inp count(results) == 0 } test_group_one_container_run_as_rule_any_root_user { - input := { "review": review(null, [ctr("cont1", runAsGroup(0))], null), "parameters": group_runasany } - results := violation with input as input + inp := { "review": review(null, [ctr("cont1", runAsGroup(0))], null), "parameters": group_runasany } + results := violation with input as inp count(results) == 0 } test_group_one_container_run_in_range_user_in_range { - input := { "review": review(null, [ctr("cont1", runAsGroup(150))], null), "parameters": group_mustrunas_100_200 } - results := violation with input as input + inp := { "review": review(null, [ctr("cont1", runAsGroup(150))], null), "parameters": group_mustrunas_100_200 } + results := violation with input as inp count(results) == 0 } test_group_one_container_run_in_range_user_out_of_range { - input := { "review": review(null, [ctr("cont1", runAsGroup(10))], null), "parameters": group_mustrunas_100_200 } - results := violation with input as input + inp := { "review": review(null, [ctr("cont1", runAsGroup(10))], null), "parameters": group_mustrunas_100_200 } + results := violation with input as inp count(results) == 1 } test_group_one_container_run_in_range_user_lower_edge_of_range { - input := { "review": review(null, [ctr("cont1", runAsGroup(100))], null), "parameters": group_mustrunas_100_200 } - results := violation with input as input + inp := { "review": review(null, [ctr("cont1", runAsGroup(100))], null), "parameters": group_mustrunas_100_200 } + results := violation with input as inp count(results) == 0 } test_group_one_container_run_in_range_user_upper_edge_of_range { - input := { "review": review(null, [ctr("cont1", runAsGroup(200))], null), "parameters": group_mustrunas_100_200 } - results := violation with input as input + inp := { "review": review(null, [ctr("cont1", runAsGroup(200))], null), "parameters": group_mustrunas_100_200 } + results := violation with input as inp count(results) == 0 } test_group_one_container_run_in_range_user_between_ranges { - input := { "review": review(null, [ctr("cont1", runAsGroup(200))], null), "parameters": group_mustrunas_two_ranges } - results := violation with input as input + inp := { "review": review(null, [ctr("cont1", runAsGroup(200))], null), "parameters": group_mustrunas_two_ranges } + results := violation with input as inp count(results) == 1 } test_group_two_containers_run_as_rule_any { - input := { + inp := { "review": review(null, [ctr("cont1", runAsGroup(1)), ctr("cont2", runAsGroup(100))], null), "parameters": group_runasany } - results := violation with input as input + results := violation with input as inp count(results) == 0 } test_group_two_containers_run_in_range_both_in_range { - input := { + inp := { "review": review(null, [ctr("cont1", runAsGroup(150)), ctr("cont2", runAsGroup(103))], null), "parameters": group_mustrunas_100_200 } - results := violation with input as input + results := violation with input as inp count(results) == 0 } test_group_two_containers_run_in_range_one_in_range { - input := { + inp := { "review": review(null, [ctr("cont1", runAsGroup(150)), ctr("cont2", runAsGroup(13))], null), "parameters": group_mustrunas_100_200 } - results := violation with input as input + results := violation with input as inp count(results) == 1 } test_group_two_containers_run_in_range_neither_in_range_two_ranges { - input := { + inp := { "review": review(null, [ctr("cont1", runAsGroup(150)), ctr("cont2", runAsGroup(130))], null), "parameters": group_mustrunas_two_ranges } - results := violation with input as input + results := violation with input as inp count(results) == 2 } test_group_one_container_one_initcontainer_run_in_range_user_in_range { - input := { + inp := { "review": review(null, [ctr("cont1", runAsGroup(150))], [ctr("init1", runAsGroup(150))]), "parameters": group_mustrunas_100_200 } - results := violation with input as input + results := violation with input as inp count(results) == 0 } test_group_one_container_one_initcontainer_run_in_range_user_not_in_range { - input := { + inp := { "review": review(null, [ctr("cont1", runAsGroup(150))], [ctr("init1", runAsGroup(250))]), "parameters": group_mustrunas_100_200 } - results := violation with input as input + results := violation with input as inp count(results) == 1 } test_group_one_container_empty_security_context { - input := { "review": review(null, [ctr("cont1", {})], null), "parameters": group_mustrunas_100_200 } - results := violation with input as input + inp := { "review": review(null, [ctr("cont1", {})], null), "parameters": group_mustrunas_100_200 } + results := violation with input as inp count(results) == 1 } test_group_one_container_no_security_context { - input := { "review": review(null, [ctr("cont1", null)], null), "parameters": group_mustrunas_100_200 } - results := violation with input as input + inp := { "review": review(null, [ctr("cont1", null)], null), "parameters": group_mustrunas_100_200 } + results := violation with input as inp count(results) == 1 } test_group_one_container_no_security_context_RunAsAny { - input := { "review": review(null, [ctr("cont1", null)], null), "parameters": group_runasany } - results := violation with input as input + inp := { "review": review(null, [ctr("cont1", null)], null), "parameters": group_runasany } + results := violation with input as inp count(results) == 0 } test_group_one_container_empty_security_context_empty_pod_security_context { - input := { "review": review({}, [ctr("cont1", {})], null), "parameters": group_mustrunas_100_200 } - results := violation with input as input + inp := { "review": review({}, [ctr("cont1", {})], null), "parameters": group_mustrunas_100_200 } + results := violation with input as inp count(results) == 1 } test_group_one_container_no_security_context_no_pod_security_context { - input := { "review": review(null, [ctr("cont1", null)], null), "parameters": group_mustrunas_100_200 } - results := violation with input as input + inp := { "review": review(null, [ctr("cont1", null)], null), "parameters": group_mustrunas_100_200 } + results := violation with input as inp count(results) == 1 } test_group_one_container_pod_defined_null_container_run_in_range_user_in_range { - input := { "review": review(runAsGroup(150), [ctr("cont1", null)], null), "parameters": group_mustrunas_100_200} - results := violation with input as input + inp := { "review": review(runAsGroup(150), [ctr("cont1", null)], null), "parameters": group_mustrunas_100_200} + results := violation with input as inp count(results) == 0 } test_group_one_container_pod_defined_run_in_range_user_in_range { - input := { "review": review(runAsGroup(150), [ctr("cont1", {})], null), "parameters": group_mustrunas_100_200} - results := violation with input as input + inp := { "review": review(runAsGroup(150), [ctr("cont1", {})], null), "parameters": group_mustrunas_100_200} + results := violation with input as inp count(results) == 0 } test_group_one_container_pod_defined_run_in_range_user_not_in_range { - input := { "review": review(runAsGroup(250), [ctr("cont1", {})], null), "parameters": group_mustrunas_100_200 } - results := violation with input as input + inp := { "review": review(runAsGroup(250), [ctr("cont1", {})], null), "parameters": group_mustrunas_100_200 } + results := violation with input as inp count(results) == 1 } test_group_one_container_pod_defined_run_in_range_container_overrides_user_in_range { - input := { "review": review(runAsGroup(250), [ctr("cont1", runAsGroup(150))], null), "parameters": group_mustrunas_100_200 } - results := violation with input as input + inp := { "review": review(runAsGroup(250), [ctr("cont1", runAsGroup(150))], null), "parameters": group_mustrunas_100_200 } + results := violation with input as inp count(results) == 0 } test_group_one_container_pod_defined_run_in_range_container_overrides_user_not_in_range { - input := { "review": review(runAsGroup(150), [ctr("cont1", runAsGroup(250))], null), "parameters": group_mustrunas_100_200 } - results := violation with input as input + inp := { "review": review(runAsGroup(150), [ctr("cont1", runAsGroup(250))], null), "parameters": group_mustrunas_100_200 } + results := violation with input as inp count(results) == 1 } test_group_input_container_run_as_rule_any_ignore_ranges { - input := { + inp := { "review": review(null, [ctr("cont1", runAsGroup(10))], null), "parameters": runAsGroup(rule("RunAsAny", [range(100, 200)])) } - results := violation with input as input + results := violation with input as inp count(results) == 0 } test_group_one_container_empty_security_context_mayrun { - input := { "review": review(null, [ctr("cont1", {})], null), "parameters": group_mayrunas_100_200 } - results := violation with input as input + inp := { "review": review(null, [ctr("cont1", {})], null), "parameters": group_mayrunas_100_200 } + results := violation with input as inp count(results) == 0 } test_group_one_container_no_security_context_mayrun { - input := { "review": review(null, [ctr("cont1", null)], null), "parameters": group_mayrunas_100_200 } - results := violation with input as input + inp := { "review": review(null, [ctr("cont1", null)], null), "parameters": group_mayrunas_100_200 } + results := violation with input as inp count(results) == 0 } test_group_one_container_run_in_range_user_in_range_mayrun { - input := { "review": review(null, [ctr("cont1", runAsGroup(150))], null), "parameters": group_mayrunas_100_200 } - results := violation with input as input + inp := { "review": review(null, [ctr("cont1", runAsGroup(150))], null), "parameters": group_mayrunas_100_200 } + results := violation with input as inp count(results) == 0 } test_group_one_container_run_in_range_user_out_of_range_mayrun { - input := { "review": review(null, [ctr("cont1", runAsGroup(10))], null), "parameters": group_mayrunas_100_200 } - results := violation with input as input + inp := { "review": review(null, [ctr("cont1", runAsGroup(10))], null), "parameters": group_mayrunas_100_200 } + results := violation with input as inp count(results) == 1 } test_group_one_container_run_in_range_user_between_ranges_mayrun { - input := { "review": review(null, [ctr("cont1", runAsGroup(200))], null), "parameters": group_mayrunas_two_ranges } - results := violation with input as input + inp := { "review": review(null, [ctr("cont1", runAsGroup(200))], null), "parameters": group_mayrunas_two_ranges } + results := violation with input as inp count(results) == 1 } test_group_two_containers_run_in_range_neither_in_range_two_ranges_mayrun { - input := { + inp := { "review": review(null, [ctr("cont1", runAsGroup(150)), ctr("cont2", runAsGroup(130))], null), "parameters": group_mayrunas_two_ranges } - results := violation with input as input + results := violation with input as inp count(results) == 2 } test_group_one_container_pod_defined_run_in_range_container_overrides_user_in_range_mayrun { - input := { "review": review(runAsGroup(250), [ctr("cont1", runAsGroup(150))], null), "parameters": group_mayrunas_100_200 } - results := violation with input as input + inp := { "review": review(runAsGroup(250), [ctr("cont1", runAsGroup(150))], null), "parameters": group_mayrunas_100_200 } + results := violation with input as inp count(results) == 0 } test_group_one_container_pod_defined_run_in_range_container_overrides_user_not_in_range_mayrun { - input := { "review": review(runAsGroup(150), [ctr("cont1", runAsGroup(250))], null), "parameters": group_mayrunas_100_200 } - results := violation with input as input + inp := { "review": review(runAsGroup(150), [ctr("cont1", runAsGroup(250))], null), "parameters": group_mayrunas_100_200 } + results := violation with input as inp count(results) == 1 } @@ -471,134 +471,134 @@ test_group_one_container_pod_defined_run_in_range_container_overrides_user_not_i ## supplementalGroups ## test_supplemental_two_containers_run_as_rule_any { - input := { + inp := { "review": review(supplementalGroups([15]), [ctr("cont1", null), ctr("cont2", null)], null), "parameters": supplemental_runasany } - results := violation with input as input + results := violation with input as inp count(results) == 0 } test_supplemental_two_containers_run_in_range_both_in_range { - input := { + inp := { "review": review(supplementalGroups([150]), [ctr("cont1", null), ctr("cont2", null)], null), "parameters": supplemental_mustrunas_100_200 } - results := violation with input as input + results := violation with input as inp count(results) == 0 } test_supplemental_two_containers_run_in_range_neither_in_range_two_ranges { - input := { + inp := { "review": review(supplementalGroups([150]), [ctr("cont1", null), ctr("cont2", null)], null), "parameters": supplemental_mustrunas_two_ranges } - results := violation with input as input + results := violation with input as inp count(results) == 2 } test_supplemental_one_container_one_initcontainer_run_in_range_user_in_range { - input := { + inp := { "review": review(supplementalGroups([150]), [ctr("cont1", null)], [ctr("init1", null)]), "parameters": supplemental_mustrunas_100_200 } - results := violation with input as input + results := violation with input as inp count(results) == 0 } test_supplemental_one_container_one_initcontainer_run_in_range_user_not_in_range { - input := { + inp := { "review": review(supplementalGroups([250]), [ctr("cont1", null)], [ctr("init1", null)]), "parameters": supplemental_mustrunas_100_200 } - results := violation with input as input + results := violation with input as inp count(results) == 2 } test_supplemental_one_container_empty_security_context { - input := { "review": review(null, [ctr("cont1", {})], null), "parameters": supplemental_mustrunas_100_200 } - results := violation with input as input + inp := { "review": review(null, [ctr("cont1", {})], null), "parameters": supplemental_mustrunas_100_200 } + results := violation with input as inp count(results) == 1 } test_supplemental_one_container_no_security_context { - input := { "review": review(null, [ctr("cont1", null)], null), "parameters": supplemental_mustrunas_100_200 } - results := violation with input as input + inp := { "review": review(null, [ctr("cont1", null)], null), "parameters": supplemental_mustrunas_100_200 } + results := violation with input as inp count(results) == 1 } test_supplemental_one_container_no_security_context_RunAsAny { - input := { "review": review(null, [ctr("cont1", null)], null), "parameters": supplemental_runasany } - results := violation with input as input + inp := { "review": review(null, [ctr("cont1", null)], null), "parameters": supplemental_runasany } + results := violation with input as inp count(results) == 0 } test_supplemental_one_container_empty_security_context_empty_pod_security_context { - input := { "review": review({}, [ctr("cont1", {})], null), "parameters": supplemental_mustrunas_100_200 } - results := violation with input as input + inp := { "review": review({}, [ctr("cont1", {})], null), "parameters": supplemental_mustrunas_100_200 } + results := violation with input as inp count(results) == 1 } test_supplemental_one_container_no_security_context_no_pod_security_context { - input := { "review": review(null, [ctr("cont1", null)], null), "parameters": supplemental_mustrunas_100_200 } - results := violation with input as input + inp := { "review": review(null, [ctr("cont1", null)], null), "parameters": supplemental_mustrunas_100_200 } + results := violation with input as inp count(results) == 1 } test_supplemental_one_container_pod_defined_null_container_run_in_range_user_in_range { - input := { "review": review(supplementalGroups([150]), [ctr("cont1", null)], null), "parameters": supplemental_mustrunas_100_200} - results := violation with input as input + inp := { "review": review(supplementalGroups([150]), [ctr("cont1", null)], null), "parameters": supplemental_mustrunas_100_200} + results := violation with input as inp count(results) == 0 } test_supplemental_one_container_pod_defined_run_in_range_user_in_range { - input := { "review": review(supplementalGroups([150]), [ctr("cont1", {})], null), "parameters": supplemental_mustrunas_100_200} - results := violation with input as input + inp := { "review": review(supplementalGroups([150]), [ctr("cont1", {})], null), "parameters": supplemental_mustrunas_100_200} + results := violation with input as inp count(results) == 0 } test_supplemental_one_container_pod_defined_run_in_range_user_not_in_range { - input := { "review": review(supplementalGroups([250]), [ctr("cont1", {})], null), "parameters": supplemental_mustrunas_100_200 } - results := violation with input as input + inp := { "review": review(supplementalGroups([250]), [ctr("cont1", {})], null), "parameters": supplemental_mustrunas_100_200 } + results := violation with input as inp count(results) == 1 } test_supplemental_one_container_pod_defined_run_in_range_container_overrides_user_in_range { - input := { "review": review(supplementalGroups([250]), [ctr("cont1", supplementalGroups(150))], null), "parameters": supplemental_mustrunas_100_200 } - results := violation with input as input + inp := { "review": review(supplementalGroups([250]), [ctr("cont1", supplementalGroups(150))], null), "parameters": supplemental_mustrunas_100_200 } + results := violation with input as inp count(results) == 0 } test_supplemental_one_container_pod_defined_run_in_range_container_overrides_user_not_in_range { - input := { "review": review(supplementalGroups([150]), [ctr("cont1", supplementalGroups(250))], null), "parameters": supplemental_mustrunas_100_200 } - results := violation with input as input + inp := { "review": review(supplementalGroups([150]), [ctr("cont1", supplementalGroups(250))], null), "parameters": supplemental_mustrunas_100_200 } + results := violation with input as inp count(results) == 1 } test_supplemental_one_container_empty_security_context_mayrun { - input := { "review": review(null, [ctr("cont1", {})], null), "parameters": supplemental_mayrunas_100_200 } - results := violation with input as input + inp := { "review": review(null, [ctr("cont1", {})], null), "parameters": supplemental_mayrunas_100_200 } + results := violation with input as inp count(results) == 0 } test_supplemental_one_container_no_security_context_mayrun { - input := { "review": review(null, [ctr("cont1", null)], null), "parameters": supplemental_mayrunas_100_200 } - results := violation with input as input + inp := { "review": review(null, [ctr("cont1", null)], null), "parameters": supplemental_mayrunas_100_200 } + results := violation with input as inp count(results) == 0 } test_supplemental_two_containers_run_in_range_neither_in_range_mayrun { - input := { + inp := { "review": review(supplementalGroups([230]), [ctr("cont1", null), ctr("cont2", null)], null), "parameters": supplemental_mayrunas_two_ranges } - results := violation with input as input + results := violation with input as inp count(results) == 2 } test_supplemental_two_containers_run_in_range_both_in_range_mayrun { - input := { + inp := { "review": review(supplementalGroups([100]), [ctr("cont1", null), ctr("cont2", null)], null), "parameters": supplemental_mayrunas_two_ranges } - results := violation with input as input + results := violation with input as inp count(results) == 0 } test_supplemental_one_container_run_in_range_two_ranges_both_in_range { - input := { "review": review(supplementalGroups([120, 180]), [ctr("cont1", null)], null), "parameters": supplemental_mustrunas_100_200} - results := violation with input as input + inp := { "review": review(supplementalGroups([120, 180]), [ctr("cont1", null)], null), "parameters": supplemental_mustrunas_100_200} + results := violation with input as inp count(results) == 0 } test_supplemental_one_container_run_in_range_two_ranges_none_in_range { - input := { "review": review(supplementalGroups([120, 180]), [ctr("cont1", null)], null), "parameters": supplemental_mustrunas_100_200} - results := violation with input as input + inp := { "review": review(supplementalGroups([120, 180]), [ctr("cont1", null)], null), "parameters": supplemental_mustrunas_100_200} + results := violation with input as inp count(results) == 0 } test_supplemental_one_container_run_in_range_two_ranges_one_in_range { - input := { "review": review(supplementalGroups([150, 250]), [ctr("cont1", null)], null), "parameters": supplemental_mustrunas_100_200} - results := violation with input as input + inp := { "review": review(supplementalGroups([150, 250]), [ctr("cont1", null)], null), "parameters": supplemental_mustrunas_100_200} + results := violation with input as inp count(results) == 1 } @@ -606,111 +606,111 @@ test_supplemental_one_container_run_in_range_two_ranges_one_in_range { ## fsGroup ## test_fsgroup_two_containers_run_as_rule_any { - input := { + inp := { "review": review(fsGroup(15), [ctr("cont1", null), ctr("cont2", null)], null), "parameters": fsgroup_runasany } - results := violation with input as input + results := violation with input as inp count(results) == 0 } test_fsgroup_two_containers_run_in_range_both_in_range { - input := { + inp := { "review": review(fsGroup(150), [ctr("cont1", null), ctr("cont2", null)], null), "parameters": fsgroup_mustrunas_100_200 } - results := violation with input as input + results := violation with input as inp count(results) == 0 } test_fsgroup_two_containers_run_in_range_neither_in_range_two_ranges { - input := { + inp := { "review": review(fsGroup(150), [ctr("cont1", null), ctr("cont2", null)], null), "parameters": fsgroup_mustrunas_two_ranges } - results := violation with input as input + results := violation with input as inp count(results) == 2 } test_fsgroup_one_container_one_initcontainer_run_in_range_user_in_range { - input := { + inp := { "review": review(fsGroup(150), [ctr("cont1", null)], [ctr("init1", null)]), "parameters": fsgroup_mustrunas_100_200 } - results := violation with input as input + results := violation with input as inp count(results) == 0 } test_fsgroup_one_container_one_initcontainer_run_in_range_user_not_in_range { - input := { + inp := { "review": review(fsGroup(250), null, [ctr("init1", null)]), "parameters": fsgroup_mustrunas_100_200 } - results := violation with input as input + results := violation with input as inp count(results) == 1 } test_fsgroup_one_container_empty_security_context { - input := { "review": review(null, [ctr("cont1", {})], null), "parameters": fsgroup_mustrunas_100_200 } - results := violation with input as input + inp := { "review": review(null, [ctr("cont1", {})], null), "parameters": fsgroup_mustrunas_100_200 } + results := violation with input as inp count(results) == 1 } test_fsgroup_one_container_no_security_context { - input := { "review": review(null, [ctr("cont1", null)], null), "parameters": fsgroup_mustrunas_100_200 } - results := violation with input as input + inp := { "review": review(null, [ctr("cont1", null)], null), "parameters": fsgroup_mustrunas_100_200 } + results := violation with input as inp count(results) == 1 } test_fsgroup_one_container_no_security_context_RunAsAny { - input := { "review": review(null, [ctr("cont1", null)], null), "parameters": fsgroup_runasany } - results := violation with input as input + inp := { "review": review(null, [ctr("cont1", null)], null), "parameters": fsgroup_runasany } + results := violation with input as inp count(results) == 0 } test_fsgroup_one_container_empty_security_context_empty_pod_security_context { - input := { "review": review({}, [ctr("cont1", {})], null), "parameters": fsgroup_mustrunas_100_200 } - results := violation with input as input + inp := { "review": review({}, [ctr("cont1", {})], null), "parameters": fsgroup_mustrunas_100_200 } + results := violation with input as inp count(results) == 1 } test_fsgroup_one_container_no_security_context_no_pod_security_context { - input := { "review": review(null, [ctr("cont1", null)], null), "parameters": fsgroup_mustrunas_100_200 } - results := violation with input as input + inp := { "review": review(null, [ctr("cont1", null)], null), "parameters": fsgroup_mustrunas_100_200 } + results := violation with input as inp count(results) == 1 } test_fsgroup_one_container_pod_defined_null_container_run_in_range_user_in_range { - input := { "review": review(fsGroup(150), [ctr("cont1", null)], null), "parameters": fsgroup_mustrunas_100_200} - results := violation with input as input + inp := { "review": review(fsGroup(150), [ctr("cont1", null)], null), "parameters": fsgroup_mustrunas_100_200} + results := violation with input as inp count(results) == 0 } test_fsgroup_one_container_pod_defined_run_in_range_user_in_range { - input := { "review": review(fsGroup(150), [ctr("cont1", {})], null), "parameters": fsgroup_mustrunas_100_200} - results := violation with input as input + inp := { "review": review(fsGroup(150), [ctr("cont1", {})], null), "parameters": fsgroup_mustrunas_100_200} + results := violation with input as inp count(results) == 0 } test_fsgroup_one_container_pod_defined_run_in_range_user_not_in_range { - input := { "review": review(fsGroup(250), [ctr("cont1", {})], null), "parameters": fsgroup_mustrunas_100_200 } - results := violation with input as input + inp := { "review": review(fsGroup(250), [ctr("cont1", {})], null), "parameters": fsgroup_mustrunas_100_200 } + results := violation with input as inp count(results) == 1 } test_fsgroup_one_container_pod_defined_run_in_range_container_overrides_user_in_range { - input := { "review": review(fsGroup(250), [ctr("cont1", fsGroup(150))], null), "parameters": fsgroup_mustrunas_100_200 } - results := violation with input as input + inp := { "review": review(fsGroup(250), [ctr("cont1", fsGroup(150))], null), "parameters": fsgroup_mustrunas_100_200 } + results := violation with input as inp count(results) == 0 } test_fsgroup_one_container_pod_defined_run_in_range_container_overrides_user_not_in_range { - input := { "review": review(fsGroup(150), [ctr("cont1", fsGroup(250))], null), "parameters": fsgroup_mustrunas_100_200 } - results := violation with input as input + inp := { "review": review(fsGroup(150), [ctr("cont1", fsGroup(250))], null), "parameters": fsgroup_mustrunas_100_200 } + results := violation with input as inp count(results) == 1 } test_fsgroup_input_container_run_as_rule_any_ignore_ranges { - input := { + inp := { "review": review(null, [ctr("cont1", fsGroup(10))], null), "parameters": fsGroup(rule("RunAsAny", [range(100, 200)])) } - results := violation with input as input + results := violation with input as inp count(results) == 0 } test_fsgroup_one_container_empty_security_context_mayrun { - input := { "review": review(null, [ctr("cont1", {})], null), "parameters": fsgroup_mayrunas_100_200 } - results := violation with input as input + inp := { "review": review(null, [ctr("cont1", {})], null), "parameters": fsgroup_mayrunas_100_200 } + results := violation with input as inp count(results) == 0 } test_fsgroup_one_container_no_security_context_mayrun { - input := { "review": review(null, [ctr("cont1", null)], null), "parameters": fsgroup_mayrunas_100_200 } - results := violation with input as input + inp := { "review": review(null, [ctr("cont1", null)], null), "parameters": fsgroup_mayrunas_100_200 } + results := violation with input as inp count(results) == 0 } @@ -718,103 +718,103 @@ test_fsgroup_one_container_no_security_context_mayrun { ## Mixed Functionality ## test_mixed_runAsAny_all_non_root { - input := {"review": review(run_as_rule(12, 30, [50], 101), [ctr("cont1", null)], null), "parameters": mixed_runasany } - results := violation with input as input + inp := {"review": review(run_as_rule(12, 30, [50], 101), [ctr("cont1", null)], null), "parameters": mixed_runasany } + results := violation with input as inp count(results) == 0 } test_mixed_runAsAny_all_root { - input := {"review": review(run_as_rule(0, 0, [0], 0), [ctr("cont1", null)], null), "parameters": mixed_runasany } - results := violation with input as input + inp := {"review": review(run_as_rule(0, 0, [0], 0), [ctr("cont1", null)], null), "parameters": mixed_runasany } + results := violation with input as inp count(results) == 0 } test_mixed_pod_level_all_defined_all_in_range_mustrun { - input := {"review": review(run_as_rule(150, 150, [150], 150), [ctr("cont1", null)], null), "parameters": mixed_mustrunas_100_200 } - results := violation with input as input + inp := {"review": review(run_as_rule(150, 150, [150], 150), [ctr("cont1", null)], null), "parameters": mixed_mustrunas_100_200 } + results := violation with input as inp count(results) == 0 } test_mixed_pod_level_all_defined_none_in_range_mustrun { - input := {"review": review(run_as_rule(250, 250, [250], 250), [ctr("cont1", null)], null), "parameters": mixed_mustrunas_100_200 } - results := violation with input as input + inp := {"review": review(run_as_rule(250, 250, [250], 250), [ctr("cont1", null)], null), "parameters": mixed_mustrunas_100_200 } + results := violation with input as inp count(results) == 4 } test_mixed_pod_level_all_defined_mixed_in_range_mustrun { - input := {"review": review(run_as_rule(150, 150, [250], 250), [ctr("cont1", null)], null), "parameters": mixed_mustrunas_100_200 } - results := violation with input as input + inp := {"review": review(run_as_rule(150, 150, [250], 250), [ctr("cont1", null)], null), "parameters": mixed_mustrunas_100_200 } + results := violation with input as inp count(results) == 2 } test_mixed_container_level_all_defined_all_in_range_mustrun { - input := {"review": review(null, [ctr("cont1", run_as_rule(150, 150, [150], 150))], null), "parameters": mixed_mustrunas_100_200 } - results := violation with input as input + inp := {"review": review(null, [ctr("cont1", run_as_rule(150, 150, [150], 150))], null), "parameters": mixed_mustrunas_100_200 } + results := violation with input as inp count(results) == 0 } test_mixed_container_level_all_defined_none_in_range_mustrun { - input := {"review": review(null, [ctr("cont1", run_as_rule(250, 250, [250], 250))], null), "parameters": mixed_mustrunas_100_200 } - results := violation with input as input + inp := {"review": review(null, [ctr("cont1", run_as_rule(250, 250, [250], 250))], null), "parameters": mixed_mustrunas_100_200 } + results := violation with input as inp count(results) == 4 } test_mixed_container_level_all_defined_mixed_in_range_mustrun { - input := {"review": review(null, [ctr("cont1", run_as_rule(150, 150, [250], 250))], null), "parameters": mixed_mustrunas_100_200 } - results := violation with input as input + inp := {"review": review(null, [ctr("cont1", run_as_rule(150, 150, [250], 250))], null), "parameters": mixed_mustrunas_100_200 } + results := violation with input as inp count(results) == 2 } test_mixed_pod_level_all_defined_none_in_range_mayrun { - input := {"review": review(run_as_rule(250, 250, [250], 250), [ctr("cont1", null)], null), "parameters": mixed_mayrunas_100_200 } - results := violation with input as input + inp := {"review": review(run_as_rule(250, 250, [250], 250), [ctr("cont1", null)], null), "parameters": mixed_mayrunas_100_200 } + results := violation with input as inp count(results) == 3 } test_mixed_pod_level_all_defined_mixed_in_range_mayrun { - input := {"review": review(run_as_rule(150, 150, [250], 250), [ctr("cont1", null)], null), "parameters": mixed_mayrunas_100_200 } - results := violation with input as input + inp := {"review": review(run_as_rule(150, 150, [250], 250), [ctr("cont1", null)], null), "parameters": mixed_mayrunas_100_200 } + results := violation with input as inp count(results) == 2 } test_mixed_container_level_all_defined_all_in_range_mayrun { - input := {"review": review(null, [ctr("cont1", run_as_rule(150, 150, null, null))], null), "parameters": mixed_mayrunas_100_200 } - results := violation with input as input + inp := {"review": review(null, [ctr("cont1", run_as_rule(150, 150, null, null))], null), "parameters": mixed_mayrunas_100_200 } + results := violation with input as inp count(results) == 0 } test_mixed_container_level_all_defined_none_in_range_mayrun { - input := {"review": review(null, [ctr("cont1", run_as_rule(250, 250, null, null))], null), "parameters": mixed_mayrunas_100_200 } - results := violation with input as input + inp := {"review": review(null, [ctr("cont1", run_as_rule(250, 250, null, null))], null), "parameters": mixed_mayrunas_100_200 } + results := violation with input as inp count(results) == 1 } test_mixed_container_level_all_defined_mixed_in_range_mayrun { - input := {"review": review(null, [ctr("cont1", run_as_rule(150, 250, null, null))], null), "parameters": mixed_mayrunas_100_200 } - results := violation with input as input + inp := {"review": review(null, [ctr("cont1", run_as_rule(150, 250, null, null))], null), "parameters": mixed_mayrunas_100_200 } + results := violation with input as inp count(results) == 1 } test_mixed_pod_level_all_defined_none_in_range_mixed_rules { - input := {"review": review(run_as_rule(0, 0, 250, 250), [ctr("cont1", null)], null), "parameters": mixed_all_rules } - results := violation with input as input + inp := {"review": review(run_as_rule(0, 0, 250, 250), [ctr("cont1", null)], null), "parameters": mixed_all_rules } + results := violation with input as inp count(results) == 3 } # violation from MustRunAs SupplementalGroups and MayRunAs FSGroup, range within 100&200 test_mixed_pod_level_all_defined_mixed_in_range_mixed_rules { - input := {"review": review(run_as_rule(150, 150, 250, 250), [ctr("cont1", null)], null), "parameters": mixed_all_rules } - results := violation with input as input + inp := {"review": review(run_as_rule(150, 150, 250, 250), [ctr("cont1", null)], null), "parameters": mixed_all_rules } + results := violation with input as inp count(results) == 2 } # violation from no MustRunAs SupplementalGroups defined (can't define on container level) test_mixed_container_level_all_defined_all_in_range_mixed_rules { - input := {"review": review(null, [ctr("cont1", run_as_rule(150, 150, null, null))], null), "parameters": mixed_all_rules } - results := violation with input as input + inp := {"review": review(null, [ctr("cont1", run_as_rule(150, 150, null, null))], null), "parameters": mixed_all_rules } + results := violation with input as inp count(results) == 1 } # violation from MustRunAsNonRoot RunAsUser rule, and no MustRunAs SupplementalGroups defined (can't define on container level) test_mixed_container_level_all_defined_none_in_range_mixed_rules { - input := {"review": review(null, [ctr("cont1", run_as_rule(0, 0, null, null))], null), "parameters": mixed_all_rules } - results := violation with input as input + inp := {"review": review(null, [ctr("cont1", run_as_rule(0, 0, null, null))], null), "parameters": mixed_all_rules } + results := violation with input as inp count(results) == 2 } # violation from no MustRunAs SupplementalGroups defined (can't define on container level) test_mixed_container_level_all_defined_mixed_in_range_mixed_rules { - input := {"review": review(null, [ctr("cont1", run_as_rule(150, 150, null, null))], null), "parameters": mixed_all_rules } - results := violation with input as input + inp := {"review": review(null, [ctr("cont1", run_as_rule(150, 150, null, null))], null), "parameters": mixed_all_rules } + results := violation with input as inp count(results) == 1 } test_update { - input := {"review": object.union(review(null, [ctr("cont1", run_as_rule(150, 150, null, null))], null), {"operation": "UPDATE"}), "parameters": mixed_all_rules } - results := violation with input as input + inp := {"review": object.union(review(null, [ctr("cont1", run_as_rule(150, 150, null, null))], null), {"operation": "UPDATE"}), "parameters": mixed_all_rules } + results := violation with input as inp count(results) == 0 } @@ -866,13 +866,12 @@ run_as_rule(user, group, supplemental, fsgroup) = out { out = object.union(object.union(user_obj, group_obj), object.union(supplemental_obj, fsgroup_obj)) } -obj_if_exists(key, val) = out { - not is_null(val) - out := { key: val } +obj_if_exists(key, val) = {key: val} { + not is_null(val) } -obj_if_exists(key, val) = out { - is_null(val) - out := {} + +obj_if_exists(_, val) := {} { + is_null(val) } # Parameters diff --git a/src/pod-security-policy/volumes/constraint.tmpl b/src/pod-security-policy/volumes/constraint.tmpl index 40f87e2c3..0fe0567fe 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.1 + metadata.gatekeeper.sh/version: 1.0.2 description: >- Restricts mountable volume types to those specified by the user. Corresponds to the `volumes` field in a PodSecurityPolicy. For more diff --git a/src/pod-security-policy/volumes/src.rego b/src/pod-security-policy/volumes/src.rego index 2d10ecf3e..389e48a44 100644 --- a/src/pod-security-policy/volumes/src.rego +++ b/src/pod-security-policy/volumes/src.rego @@ -13,7 +13,7 @@ violation[{"msg": msg, "details": {}}] { } # * may be used to allow all volume types -input_volume_type_allowed(field) { +input_volume_type_allowed(_) { input.parameters.volumes[_] == "*" } diff --git a/src/pod-security-policy/volumes/src_test.rego b/src/pod-security-policy/volumes/src_test.rego index 841e79bf8..6d38babcf 100644 --- a/src/pod-security-policy/volumes/src_test.rego +++ b/src/pod-security-policy/volumes/src_test.rego @@ -1,75 +1,75 @@ package k8spspvolumetypes test_input_volume_type_allowed_all { - input := { "review": input_review, "parameters": input_parameters_wildcard} - results := violation with input as input + inp := { "review": input_review, "parameters": input_parameters_wildcard} + results := violation with input as inp count(results) == 0 } test_input_volume_type_allowed_all_many_volumes { - input := { "review": input_review_many, "parameters": input_parameters_wildcard} - results := violation with input as input + inp := { "review": input_review_many, "parameters": input_parameters_wildcard} + results := violation with input as inp count(results) == 0 } test_input_volume_type_none_allowed { - input := { "review": input_review, "parameters": input_parameters_empty} - results := violation with input as input + inp := { "review": input_review, "parameters": input_parameters_empty} + results := violation with input as inp count(results) == 1 } test_input_volume_type_none_allowed_many_volumes { - input := { "review": input_review_many, "parameters": input_parameters_empty} - results := violation with input as input + inp := { "review": input_review_many, "parameters": input_parameters_empty} + results := violation with input as inp count(results) == 2 } test_input_volume_type_allowed_all_no_volumes { - input := { "review": input_review_no_volumes, "parameters": input_parameters_wildcard} - results := violation with input as input + inp := { "review": input_review_no_volumes, "parameters": input_parameters_wildcard} + results := violation with input as inp count(results) == 0 } test_input_volume_type_none_allowed_no_volumes { - input := { "review": input_review_no_volumes, "parameters": input_parameters_empty} - results := violation with input as input + inp := { "review": input_review_no_volumes, "parameters": input_parameters_empty} + results := violation with input as inp count(results) == 0 } test_input_volume_type_allowed_in_list_no_volumes { - input := { "review": input_review_no_volumes, "parameters": input_parameters_in_list} - results := violation with input as input + inp := { "review": input_review_no_volumes, "parameters": input_parameters_in_list} + results := violation with input as inp count(results) == 0 } test_input_volume_type_allowed_in_list { - input := { "review": input_review, "parameters": input_parameters_in_list} - results := violation with input as input + inp := { "review": input_review, "parameters": input_parameters_in_list} + results := violation with input as inp count(results) == 0 } test_input_volume_type_allowed_not_in_list { - input := { "review": input_review, "parameters": input_parameters_not_in_list} - results := violation with input as input + inp := { "review": input_review, "parameters": input_parameters_not_in_list} + results := violation with input as inp count(results) == 1 } test_input_volume_type_allowed_in_list_many_volumes { - input := { "review": input_review_many, "parameters": input_parameters_in_list} - results := violation with input as input + inp := { "review": input_review_many, "parameters": input_parameters_in_list} + results := violation with input as inp count(results) == 0 } test_input_volume_type_allowed_not_all_in_list_many_volumes { - input := { "review": input_review_many, "parameters": input_parameters_not_in_list} - results := violation with input as input + inp := { "review": input_review_many, "parameters": input_parameters_not_in_list} + results := violation with input as inp count(results) == 2 } test_input_volume_type_allowed_in_list_many_volumes_mixed { - input := { "review": input_review_many, "parameters": input_parameters_mixed} - results := violation with input as input + inp := { "review": input_review_many, "parameters": input_parameters_mixed} + results := violation with input as inp count(results) == 1 } test_input_volume_type_update { - input := { "review": object.union(input_review, {"operation": "UPDATE"}), "parameters": input_parameters_empty} - results := violation with input as input + inp := { "review": object.union(input_review, {"operation": "UPDATE"}), "parameters": input_parameters_empty} + results := violation with input as inp count(results) == 0 } diff --git a/test.sh b/test.sh index 58708c43a..e747df3f0 100755 --- a/test.sh +++ b/test.sh @@ -2,6 +2,10 @@ set -eu +# Ensure OPA strict mode compliance +# https://www.openpolicyagent.org/docs/latest/policy-language/#strict-mode +opa check --strict src + for folder in src/*/* do # TODO: enforce coverage diff --git a/website/docs/validation/allowedrepos.md b/website/docs/validation/allowedrepos.md index 9700ec895..01afadbe8 100644 --- a/website/docs/validation/allowedrepos.md +++ b/website/docs/validation/allowedrepos.md @@ -16,7 +16,7 @@ metadata: name: k8sallowedrepos annotations: metadata.gatekeeper.sh/title: "Allowed Repositories" - metadata.gatekeeper.sh/version: 1.0.0 + metadata.gatekeeper.sh/version: 1.0.1 description: >- Requires container images to begin with a string from the specified list. spec: @@ -41,22 +41,19 @@ spec: violation[{"msg": msg}] { container := input.review.object.spec.containers[_] - satisfied := [good | repo = input.parameters.repos[_] ; good = startswith(container.image, repo)] - not any(satisfied) + not strings.any_prefix_match(container.image, input.parameters.repos) msg := sprintf("container <%v> has an invalid image repo <%v>, allowed repos are %v", [container.name, container.image, input.parameters.repos]) } violation[{"msg": msg}] { container := input.review.object.spec.initContainers[_] - satisfied := [good | repo = input.parameters.repos[_] ; good = startswith(container.image, repo)] - not any(satisfied) + not strings.any_prefix_match(container.image, input.parameters.repos) msg := sprintf("initContainer <%v> has an invalid image repo <%v>, allowed repos are %v", [container.name, container.image, input.parameters.repos]) } violation[{"msg": msg}] { container := input.review.object.spec.ephemeralContainers[_] - satisfied := [good | repo = input.parameters.repos[_] ; good = startswith(container.image, repo)] - not any(satisfied) + not strings.any_prefix_match(container.image, input.parameters.repos) msg := sprintf("ephemeralContainer <%v> has an invalid image repo <%v>, allowed repos are %v", [container.name, container.image, input.parameters.repos]) } diff --git a/website/docs/validation/capabilities.md b/website/docs/validation/capabilities.md index 33a9430da..791a226a8 100644 --- a/website/docs/validation/capabilities.md +++ b/website/docs/validation/capabilities.md @@ -16,7 +16,7 @@ metadata: name: k8spspcapabilities annotations: metadata.gatekeeper.sh/title: "Capabilities" - metadata.gatekeeper.sh/version: 1.0.1 + metadata.gatekeeper.sh/version: 1.0.2 description: >- Controls Linux capabilities on containers. Corresponds to the `allowedCapabilities` and `requiredDropCapabilities` fields in a @@ -137,14 +137,11 @@ spec: count(all - dropped) > 0 } - get_default(obj, param, _default) = out { - out = obj[param] - } + get_default(obj, param, _) := obj[param] - get_default(obj, param, _default) = out { + get_default(obj, param, _default) := _default { not obj[param] not obj[param] == false - out = _default } libs: - | diff --git a/website/docs/validation/containerlimits.md b/website/docs/validation/containerlimits.md index 0b5d5306f..f000c38fd 100644 --- a/website/docs/validation/containerlimits.md +++ b/website/docs/validation/containerlimits.md @@ -17,7 +17,7 @@ metadata: name: k8scontainerlimits annotations: metadata.gatekeeper.sh/title: "Container Limits" - metadata.gatekeeper.sh/version: 1.0.0 + metadata.gatekeeper.sh/version: 1.0.1 description: >- Requires containers to have memory and CPU limits set and constrains limits to be within the specified maximum values. @@ -78,7 +78,7 @@ spec: canonify_cpu(orig) = new { not is_number(orig) not endswith(orig, "m") - re_match("^[0-9]+(\\.[0-9]+)?$", orig) + regex.match("^[0-9]+(\\.[0-9]+)?$", orig) new := to_number(orig) * 1000 } @@ -175,7 +175,7 @@ spec: not is_number(orig) suffix := get_suffix(orig) raw := replace(orig, suffix, "") - re_match("^[0-9]+(\\.[0-9]+)?$", raw) + regex.match("^[0-9]+(\\.[0-9]+)?$", raw) new := to_number(raw) * mem_multiple(suffix) } diff --git a/website/docs/validation/containerrequests.md b/website/docs/validation/containerrequests.md index 49e4ca9f0..e1c7cbe55 100644 --- a/website/docs/validation/containerrequests.md +++ b/website/docs/validation/containerrequests.md @@ -17,7 +17,7 @@ metadata: name: k8scontainerrequests annotations: metadata.gatekeeper.sh/title: "Container Requests" - metadata.gatekeeper.sh/version: 1.0.0 + metadata.gatekeeper.sh/version: 1.0.1 description: >- Requires containers to have memory and CPU requests set and constrains requests to be within the specified maximum values. @@ -78,7 +78,7 @@ spec: canonify_cpu(orig) = new { not is_number(orig) not endswith(orig, "m") - re_match("^[0-9]+(\\.[0-9]+)?$", orig) + regex.match("^[0-9]+(\\.[0-9]+)?$", orig) new := to_number(orig) * 1000 } @@ -175,7 +175,7 @@ spec: not is_number(orig) suffix := get_suffix(orig) raw := replace(orig, suffix, "") - re_match("^[0-9]+(\\.[0-9]+)?$", raw) + regex.match("^[0-9]+(\\.[0-9]+)?$", raw) new := to_number(raw) * mem_multiple(suffix) } diff --git a/website/docs/validation/containerresourceratios.md b/website/docs/validation/containerresourceratios.md index fa20bcd8b..e2fb63447 100644 --- a/website/docs/validation/containerresourceratios.md +++ b/website/docs/validation/containerresourceratios.md @@ -17,7 +17,7 @@ metadata: name: k8scontainerratios annotations: metadata.gatekeeper.sh/title: "Container Ratios" - metadata.gatekeeper.sh/version: 1.0.0 + metadata.gatekeeper.sh/version: 1.0.1 description: >- Sets a maximum ratio for container resource limits to requests. @@ -81,14 +81,14 @@ spec: canonify_cpu(orig) = new { not is_number(orig) not endswith(orig, "m") - re_match("^[0-9]+$", orig) + regex.match("^[0-9]+$", orig) new := to_number(orig) * 1000 } canonify_cpu(orig) = new { not is_number(orig) not endswith(orig, "m") - re_match("^[0-9]+[.][0-9]+$", orig) + regex.match("^[0-9]+[.][0-9]+$", orig) new := to_number(orig) * 1000 } @@ -185,7 +185,7 @@ spec: not is_number(orig) suffix := get_suffix(orig) raw := replace(orig, suffix, "") - re_match("^[0-9]+(\\.[0-9]+)?$", raw) + regex.match("^[0-9]+(\\.[0-9]+)?$", raw) new := to_number(raw) * mem_multiple(suffix) } diff --git a/website/docs/validation/disallowedtags.md b/website/docs/validation/disallowedtags.md index dd0900c4e..656dad473 100644 --- a/website/docs/validation/disallowedtags.md +++ b/website/docs/validation/disallowedtags.md @@ -17,7 +17,7 @@ metadata: name: k8sdisallowedtags annotations: metadata.gatekeeper.sh/title: "Disallow tags" - metadata.gatekeeper.sh/version: 1.0.0 + metadata.gatekeeper.sh/version: 1.0.1 description: >- Requires container images to have an image tag different from the ones in the specified list. @@ -57,16 +57,15 @@ spec: violation[{"msg": msg}] { container := input_containers[_] not is_exempt(container) - tags := [forbid | tag = input.parameters.tags[_] ; forbid = endswith(container.image, concat(":", ["", tag]))] - any(tags) + tags := [tag_with_prefix | tag := input.parameters.tags[_]; tag_with_prefix := concat(":", ["", tag])] + strings.any_suffix_match(container.image, tags) msg := sprintf("container <%v> uses a disallowed tag <%v>; disallowed tags are %v", [container.name, container.image, input.parameters.tags]) } violation[{"msg": msg}] { container := input_containers[_] not is_exempt(container) - tag := [contains(container.image, ":")] - not all(tag) + not contains(container.image, ":") msg := sprintf("container <%v> didn't specify an image tag <%v>", [container.name, container.image]) } diff --git a/website/docs/validation/ephemeralstoragelimit.md b/website/docs/validation/ephemeralstoragelimit.md index c44abbbe6..954d10d52 100644 --- a/website/docs/validation/ephemeralstoragelimit.md +++ b/website/docs/validation/ephemeralstoragelimit.md @@ -17,7 +17,7 @@ metadata: name: k8scontainerephemeralstoragelimit annotations: metadata.gatekeeper.sh/title: "Container ephemeral storage limit" - metadata.gatekeeper.sh/version: 1.0.1 + metadata.gatekeeper.sh/version: 1.0.2 description: >- Requires containers to have an ephemeral storage limit set and constrains the limit to be within the specified maximum values. @@ -159,7 +159,7 @@ spec: not is_number(orig) suffix := get_suffix(orig) raw := replace(orig, suffix, "") - re_match("^[0-9]+(\\.[0-9]+)?$", raw) + regex.match("^[0-9]+(\\.[0-9]+)?$", raw) new := to_number(raw) * storage_multiple(suffix) } diff --git a/website/docs/validation/forbidden-sysctls.md b/website/docs/validation/forbidden-sysctls.md index 0891bc036..91d880e3b 100644 --- a/website/docs/validation/forbidden-sysctls.md +++ b/website/docs/validation/forbidden-sysctls.md @@ -16,7 +16,7 @@ metadata: name: k8spspforbiddensysctls annotations: metadata.gatekeeper.sh/title: "Forbidden Sysctls" - metadata.gatekeeper.sh/version: 1.1.2 + metadata.gatekeeper.sh/version: 1.1.3 description: >- Controls the `sysctl` profile used by containers. Corresponds to the `allowedUnsafeSysctls` and `forbiddenSysctls` fields in a PodSecurityPolicy. @@ -75,7 +75,7 @@ spec: } # * may be used to forbid all sysctls - forbidden_sysctl(sysctl) { + forbidden_sysctl(_) { input.parameters.forbiddenSysctls[_] == "*" } @@ -90,7 +90,7 @@ spec: } # * may be used to allow all sysctls - allowed_sysctl(sysctl) { + allowed_sysctl(_) { input.parameters.allowedSysctls[_] == "*" } diff --git a/website/docs/validation/fsgroup.md b/website/docs/validation/fsgroup.md index cc96a5599..cb0ddcfb4 100644 --- a/website/docs/validation/fsgroup.md +++ b/website/docs/validation/fsgroup.md @@ -16,7 +16,7 @@ metadata: name: k8spspfsgroup annotations: metadata.gatekeeper.sh/title: "FS Group" - metadata.gatekeeper.sh/version: 1.0.1 + metadata.gatekeeper.sh/version: 1.0.2 description: >- Controls allocating an FSGroup that owns the Pod's volumes. Corresponds to the `fsGroup` field in a PodSecurityPolicy. For more information, see @@ -70,7 +70,7 @@ spec: msg := sprintf("The provided pod spec fsGroup is not allowed, pod: %v. Allowed fsGroup: %v", [input.review.object.metadata.name, input.parameters]) } - input_fsGroup_allowed(spec) { + input_fsGroup_allowed(_) { # RunAsAny - No range is required. Allows any fsGroup ID to be specified. input.parameters.rule == "RunAsAny" } diff --git a/website/docs/validation/host-filesystem.md b/website/docs/validation/host-filesystem.md index e709f76e8..586115822 100644 --- a/website/docs/validation/host-filesystem.md +++ b/website/docs/validation/host-filesystem.md @@ -16,7 +16,7 @@ metadata: name: k8spsphostfilesystem annotations: metadata.gatekeeper.sh/title: "Host Filesystem" - metadata.gatekeeper.sh/version: 1.0.1 + metadata.gatekeeper.sh/version: 1.0.2 description: >- Controls usage of the host filesystem. Corresponds to the `allowedHostPaths` field in a PodSecurityPolicy. For more information, @@ -66,7 +66,7 @@ spec: msg := sprintf("HostPath volume %v is not allowed, pod: %v. Allowed path: %v", [volume, input.review.object.metadata.name, allowedPaths]) } - input_hostpath_violation(allowedPaths, volume) { + input_hostpath_violation(allowedPaths, _) { # An empty list means all host paths are blocked allowedPaths == [] } diff --git a/website/docs/validation/host-network-ports.md b/website/docs/validation/host-network-ports.md index 1debe644c..c322f7ab7 100644 --- a/website/docs/validation/host-network-ports.md +++ b/website/docs/validation/host-network-ports.md @@ -16,7 +16,7 @@ metadata: name: k8spsphostnetworkingports annotations: metadata.gatekeeper.sh/title: "Host Networking Ports" - metadata.gatekeeper.sh/version: 1.0.1 + metadata.gatekeeper.sh/version: 1.0.2 description: >- Controls usage of host network namespace by pod containers. Specific ports must be specified. Corresponds to the `hostNetwork` and @@ -77,12 +77,12 @@ spec: o.spec.hostNetwork } - input_share_hostnetwork(o) { + input_share_hostnetwork(_) { hostPort := input_containers[_].ports[_].hostPort hostPort < input.parameters.min } - input_share_hostnetwork(o) { + input_share_hostnetwork(_) { hostPort := input_containers[_].ports[_].hostPort hostPort > input.parameters.max } diff --git a/website/docs/validation/httpsonly.md b/website/docs/validation/httpsonly.md index 5d0775e1f..417dd9f12 100644 --- a/website/docs/validation/httpsonly.md +++ b/website/docs/validation/httpsonly.md @@ -17,7 +17,7 @@ metadata: name: k8shttpsonly annotations: metadata.gatekeeper.sh/title: "HTTPS Only" - metadata.gatekeeper.sh/version: 1.0.1 + metadata.gatekeeper.sh/version: 1.0.2 description: >- Requires Ingress resources to be HTTPS only. Ingress resources must include the `kubernetes.io/ingress.allow-http` annotation, set to `false`. @@ -52,19 +52,19 @@ spec: violation[{"msg": msg}] { input.review.object.kind == "Ingress" - re_match("^(extensions|networking.k8s.io)/", input.review.object.apiVersion) + regex.match("^(extensions|networking.k8s.io)/", input.review.object.apiVersion) ingress := input.review.object not https_complete(ingress) - not tls_is_optional(ingress) + not tls_is_optional msg := sprintf("Ingress should be https. tls configuration and allow-http=false annotation are required for %v", [ingress.metadata.name]) } violation[{"msg": msg}] { input.review.object.kind == "Ingress" - re_match("^(extensions|networking.k8s.io)/", input.review.object.apiVersion) + regex.match("^(extensions|networking.k8s.io)/", input.review.object.apiVersion) ingress := input.review.object not annotation_complete(ingress) - not tls_not_optional(ingress) + tls_is_optional msg := sprintf("Ingress should be https. The allow-http=false annotation is required for %v", [ingress.metadata.name]) } @@ -78,17 +78,9 @@ spec: ingress.metadata.annotations["kubernetes.io/ingress.allow-http"] == "false" } - tls_is_optional(ingress) = true { + tls_is_optional { parameters := object.get(input, "parameters", {}) - tlsOptional := object.get(parameters, "tlsOptional", false) - is_boolean(tlsOptional) - true == tlsOptional - } - - tls_not_optional(ingress) = true { - parameters := object.get(input, "parameters", {}) - tlsOptional := object.get(parameters, "tlsOptional", false) - true != tlsOptional + object.get(parameters, "tlsOptional", false) == true } ``` diff --git a/website/docs/validation/imagedigests.md b/website/docs/validation/imagedigests.md index f50884cba..6519bb5cc 100644 --- a/website/docs/validation/imagedigests.md +++ b/website/docs/validation/imagedigests.md @@ -17,7 +17,7 @@ metadata: name: k8simagedigests annotations: metadata.gatekeeper.sh/title: "Image Digests" - metadata.gatekeeper.sh/version: 1.0.0 + metadata.gatekeeper.sh/version: 1.0.1 description: >- Requires container images to contain a digest. @@ -55,24 +55,21 @@ spec: violation[{"msg": msg}] { container := input.review.object.spec.containers[_] not is_exempt(container) - satisfied := [re_match("@[a-z0-9]+([+._-][a-z0-9]+)*:[a-zA-Z0-9=_-]+", container.image)] - not all(satisfied) + not regex.match("@[a-z0-9]+([+._-][a-z0-9]+)*:[a-zA-Z0-9=_-]+", container.image) msg := sprintf("container <%v> uses an image without a digest <%v>", [container.name, container.image]) } violation[{"msg": msg}] { container := input.review.object.spec.initContainers[_] not is_exempt(container) - satisfied := [re_match("@[a-z0-9]+([+._-][a-z0-9]+)*:[a-zA-Z0-9=_-]+", container.image)] - not all(satisfied) + not regex.match("@[a-z0-9]+([+._-][a-z0-9]+)*:[a-zA-Z0-9=_-]+", container.image) msg := sprintf("initContainer <%v> uses an image without a digest <%v>", [container.name, container.image]) } violation[{"msg": msg}] { container := input.review.object.spec.ephemeralContainers[_] not is_exempt(container) - satisfied := [re_match("@[a-z0-9]+([+._-][a-z0-9]+)*:[a-zA-Z0-9=_-]+", container.image)] - not all(satisfied) + not regex.match("@[a-z0-9]+([+._-][a-z0-9]+)*:[a-zA-Z0-9=_-]+", container.image) msg := sprintf("ephemeralContainer <%v> uses an image without a digest <%v>", [container.name, container.image]) } libs: diff --git a/website/docs/validation/noupdateserviceaccount.md b/website/docs/validation/noupdateserviceaccount.md index 825bfcfe4..bacb4a075 100644 --- a/website/docs/validation/noupdateserviceaccount.md +++ b/website/docs/validation/noupdateserviceaccount.md @@ -16,7 +16,7 @@ metadata: name: noupdateserviceaccount annotations: metadata.gatekeeper.sh/title: "Block updating Service Account" - metadata.gatekeeper.sh/version: 1.0.0 + metadata.gatekeeper.sh/version: 1.0.1 description: "Blocks updating the service account on resources that abstract over Pods. This policy is ignored in audit mode." spec: crd: @@ -42,13 +42,15 @@ spec: rego: | package noupdateserviceaccount - privileged(userInfo, allowedUsers, allowedGroups) { + privileged(userInfo, allowedUsers, _) { # Allow if the user is in allowedUsers. # Use object.get so omitted parameters can't cause policy bypass by # evaluating to undefined. username := object.get(userInfo, "username", "") allowedUsers[_] == username - } { + } + + privileged(userInfo, _, allowedGroups) { # Allow if the user's groups intersect allowedGroups. # Use object.get so omitted parameters can't cause policy bypass by # evaluating to undefined. diff --git a/website/docs/validation/proc-mount.md b/website/docs/validation/proc-mount.md index 2fd4cf590..9eb1dd666 100644 --- a/website/docs/validation/proc-mount.md +++ b/website/docs/validation/proc-mount.md @@ -16,7 +16,7 @@ metadata: name: k8spspprocmount annotations: metadata.gatekeeper.sh/title: "Proc Mount" - metadata.gatekeeper.sh/version: 1.0.2 + metadata.gatekeeper.sh/version: 1.0.3 description: >- Controls the allowed `procMount` types for the container. Corresponds to the `allowedProcMountTypes` field in a PodSecurityPolicy. For more @@ -80,7 +80,7 @@ spec: allowedProcMount == "default" lower(c.securityContext.procMount) == "default" } - input_proc_mount_type_allowed(allowedProcMount, c) { + input_proc_mount_type_allowed(allowedProcMount, _) { allowedProcMount == "unmasked" } diff --git a/website/docs/validation/replicalimits.md b/website/docs/validation/replicalimits.md index 74e16a4dd..d2da9c9e0 100644 --- a/website/docs/validation/replicalimits.md +++ b/website/docs/validation/replicalimits.md @@ -16,7 +16,7 @@ metadata: name: k8sreplicalimits annotations: metadata.gatekeeper.sh/title: "Replica Limits" - metadata.gatekeeper.sh/version: 1.0.1 + metadata.gatekeeper.sh/version: 1.0.2 description: >- Requires that objects with the field `spec.replicas` (Deployments, ReplicaSets, etc.) specify a number of replicas within defined ranges. @@ -58,7 +58,7 @@ spec: } input_replica_limit(spec) { - provided := input.review.object.spec.replicas + provided := spec.replicas count(input.parameters.ranges) > 0 range := input.parameters.ranges[_] value_within_range(range, provided) diff --git a/website/docs/validation/requiredannotations.md b/website/docs/validation/requiredannotations.md index 13480fc9f..0dafa7901 100644 --- a/website/docs/validation/requiredannotations.md +++ b/website/docs/validation/requiredannotations.md @@ -16,7 +16,7 @@ metadata: name: k8srequiredannotations annotations: metadata.gatekeeper.sh/title: "Required Annotations" - metadata.gatekeeper.sh/version: 1.0.0 + metadata.gatekeeper.sh/version: 1.0.1 description: >- Requires resources to contain specified annotations, with values matching provided regular expressions. @@ -66,7 +66,7 @@ spec: expected := input.parameters.annotations[_] expected.key == key expected.allowedRegex != "" - not re_match(expected.allowedRegex, value) + not regex.match(expected.allowedRegex, value) msg := sprintf("Annotation <%v: %v> does not satisfy allowed regex: %v", [key, value, expected.allowedRegex]) } diff --git a/website/docs/validation/requiredlabels.md b/website/docs/validation/requiredlabels.md index 7086a6d51..e4bcc63ad 100644 --- a/website/docs/validation/requiredlabels.md +++ b/website/docs/validation/requiredlabels.md @@ -16,7 +16,7 @@ metadata: name: k8srequiredlabels annotations: metadata.gatekeeper.sh/title: "Required Labels" - metadata.gatekeeper.sh/version: 1.0.0 + metadata.gatekeeper.sh/version: 1.0.1 description: >- Requires resources to contain specified labels, with values matching provided regular expressions. @@ -53,14 +53,11 @@ spec: rego: | package k8srequiredlabels - get_message(parameters, _default) = msg { + get_message(parameters, _default) := _default { not parameters.message - msg := _default } - get_message(parameters, _default) = msg { - msg := parameters.message - } + get_message(parameters, _) := parameters.message violation[{"msg": msg, "details": {"missing_labels": missing}}] { provided := {label | input.review.object.metadata.labels[label]} @@ -77,7 +74,7 @@ spec: expected.key == key # do not match if allowedRegex is not defined, or is an empty string expected.allowedRegex != "" - not re_match(expected.allowedRegex, value) + not regex.match(expected.allowedRegex, value) def_msg := sprintf("Label <%v: %v> does not satisfy allowed regex: %v", [key, value, expected.allowedRegex]) msg := get_message(input.parameters, def_msg) } diff --git a/website/docs/validation/seccomp.md b/website/docs/validation/seccomp.md index 7fbe4fb59..b9b28087c 100644 --- a/website/docs/validation/seccomp.md +++ b/website/docs/validation/seccomp.md @@ -16,7 +16,7 @@ metadata: name: k8spspseccomp annotations: metadata.gatekeeper.sh/title: "Seccomp" - metadata.gatekeeper.sh/version: 1.0.0 + metadata.gatekeeper.sh/version: 1.0.1 description: >- Controls the seccomp profile used by containers. Corresponds to the `seccomp.security.alpha.kubernetes.io/allowedProfileNames` annotation on @@ -110,7 +110,7 @@ spec: msg := get_message(result.profile, result.file, name, result.location, allowed_profiles) } - get_message(profile, file, name, location, allowed_profiles) = message { + get_message(profile, _, name, location, allowed_profiles) = message { not profile == "Localhost" message := sprintf("Seccomp profile '%v' is not allowed for container '%v'. Found at: %v. Allowed profiles: %v", [profile, name, location, allowed_profiles]) } @@ -133,7 +133,7 @@ spec: } # Simple allowed Profiles - allowed_profile(profile, file, allowed) { + allowed_profile(profile, _, allowed) { not startswith(lower(profile), "localhost") profile == allowed[_] } @@ -148,20 +148,20 @@ spec: } # seccomp Localhost with wildcard - allowed_profile(profile, file, allowed) { + allowed_profile(profile, _, allowed) { profile == "Localhost" input_wildcard_allowed_files profile == allowed[_] } # annotation localhost with wildcard - allowed_profile(profile, file, allowed) { + allowed_profile(profile, _, allowed) { "localhost/*" == allowed[_] startswith(profile, "localhost/") } # annotation localhost without wildcard - allowed_profile(profile, file, allowed) { + allowed_profile(profile, _, allowed) { startswith(profile, "localhost/") profile == allowed[_] } diff --git a/website/docs/validation/selinux.md b/website/docs/validation/selinux.md index 3c33766b5..397718e43 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.1 + metadata.gatekeeper.sh/version: 1.0.2 description: >- Defines an allow-list of seLinuxOptions configurations for pod containers. Corresponds to a PodSecurityPolicy requiring SELinux configs. @@ -106,7 +106,7 @@ spec: field_allowed(field, options, params) { params[field] == options[field] } - field_allowed(field, options, params) { + field_allowed(field, options, _) { not has_field(options, field) } diff --git a/website/docs/validation/uniqueingresshost.md b/website/docs/validation/uniqueingresshost.md index d8b14494c..dc57f4853 100644 --- a/website/docs/validation/uniqueingresshost.md +++ b/website/docs/validation/uniqueingresshost.md @@ -17,7 +17,7 @@ metadata: name: k8suniqueingresshost annotations: metadata.gatekeeper.sh/title: "Unique Ingress Host" - metadata.gatekeeper.sh/version: 1.0.3 + metadata.gatekeeper.sh/version: 1.0.4 metadata.gatekeeper.sh/requires-sync-data: | "[ [ @@ -55,10 +55,10 @@ spec: violation[{"msg": msg}] { input.review.kind.kind == "Ingress" - re_match("^(extensions|networking.k8s.io)$", input.review.kind.group) + regex.match("^(extensions|networking.k8s.io)$", input.review.kind.group) host := input.review.object.spec.rules[_].host other := data.inventory.namespace[_][otherapiversion]["Ingress"][name] - re_match("^(extensions|networking.k8s.io)/.+$", otherapiversion) + regex.match("^(extensions|networking.k8s.io)/.+$", otherapiversion) other.spec.rules[_].host == host not identical(other, input.review) msg := sprintf("ingress host conflicts with an existing ingress <%v>", [host]) diff --git a/website/docs/validation/users.md b/website/docs/validation/users.md index 0b1ddfb77..1529b79bc 100644 --- a/website/docs/validation/users.md +++ b/website/docs/validation/users.md @@ -16,7 +16,7 @@ metadata: name: k8spspallowedusers annotations: metadata.gatekeeper.sh/title: "Allowed Users" - metadata.gatekeeper.sh/version: 1.0.1 + metadata.gatekeeper.sh/version: 1.0.2 description: >- Controls the user and group IDs of the container and some volumes. Corresponds to the `runAsUser`, `runAsGroup`, `supplementalGroups`, and @@ -194,11 +194,11 @@ spec: msg := sprintf("Container %v is attempting to run without a required securityContext/runAsNonRoot or securityContext/runAsUser != 0", [container.name]) } - accept_users("RunAsAny", provided_user) {true} + accept_users("RunAsAny", _) - accept_users("MustRunAsNonRoot", provided_user) = res {res := provided_user != 0} + accept_users("MustRunAsNonRoot", provided_user) := provided_user != 0 - accept_users("MustRunAs", provided_user) = res { + accept_users("MustRunAs", provided_user) := res { ranges := input.parameters.runAsUser.ranges res := is_in_range(provided_user, ranges) } @@ -227,18 +227,15 @@ spec: msg := sprintf("Container %v is attempting to run without a required securityContext/%v. Allowed %v: %v", [container.name, field, field, params]) } - accept_value("RunAsAny", provided_value, ranges) {true} + accept_value("RunAsAny", _, _) - accept_value("MayRunAs", provided_value, ranges) = res { res := is_in_range(provided_value, ranges)} + accept_value("MayRunAs", provided_value, ranges) := is_in_range(provided_value, ranges) - accept_value("MustRunAs", provided_value, ranges) = res { res := is_in_range(provided_value, ranges)} + accept_value("MustRunAs", provided_value, ranges) := is_in_range(provided_value, ranges) # If container level is provided, that takes precedence - get_field_value(field, container, review) = out { - container_value := get_seccontext_field(field, container) - out := container_value - } + get_field_value(field, container, _) := get_seccontext_field(field, container) # If no container level exists, use pod level get_field_value(field, container, review) = out { diff --git a/website/docs/validation/volumes.md b/website/docs/validation/volumes.md index f2b8042bd..7b032e9da 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.1 + metadata.gatekeeper.sh/version: 1.0.2 description: >- Restricts mountable volume types to those specified by the user. Corresponds to the `volumes` field in a PodSecurityPolicy. For more @@ -60,7 +60,7 @@ spec: } # * may be used to allow all volume types - input_volume_type_allowed(field) { + input_volume_type_allowed(_) { input.parameters.volumes[_] == "*" }