diff --git a/artifacthub/library/pod-security-policy/fsgroup/1.1.0/README.md b/artifacthub/library/pod-security-policy/fsgroup/1.1.0/README.md new file mode 100644 index 0000000000..b70d94d454 --- /dev/null +++ b/artifacthub/library/pod-security-policy/fsgroup/1.1.0/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.1.0/artifacthub-pkg.yml b/artifacthub/library/pod-security-policy/fsgroup/1.1.0/artifacthub-pkg.yml new file mode 100644 index 0000000000..cea8494c35 --- /dev/null +++ b/artifacthub/library/pod-security-policy/fsgroup/1.1.0/artifacthub-pkg.yml @@ -0,0 +1,22 @@ +version: 1.1.0 +name: k8spspfsgroup +displayName: FS Group +createdAt: "2024-05-11T00:52:05Z" +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: f0713e26915694de463897cb6106668df57fabf174499aecfc87fa21567644aa +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.1.0/template.yaml + ``` +provider: + name: Gatekeeper Library diff --git a/artifacthub/library/pod-security-policy/fsgroup/1.1.0/kustomization.yaml b/artifacthub/library/pod-security-policy/fsgroup/1.1.0/kustomization.yaml new file mode 100644 index 0000000000..7d70d11b71 --- /dev/null +++ b/artifacthub/library/pod-security-policy/fsgroup/1.1.0/kustomization.yaml @@ -0,0 +1,2 @@ +resources: + - template.yaml diff --git a/artifacthub/library/pod-security-policy/fsgroup/1.1.0/samples/psp-fsgroup/constraint.yaml b/artifacthub/library/pod-security-policy/fsgroup/1.1.0/samples/psp-fsgroup/constraint.yaml new file mode 100644 index 0000000000..4eb14fe3c2 --- /dev/null +++ b/artifacthub/library/pod-security-policy/fsgroup/1.1.0/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.1.0/samples/psp-fsgroup/example_allowed.yaml b/artifacthub/library/pod-security-policy/fsgroup/1.1.0/samples/psp-fsgroup/example_allowed.yaml new file mode 100644 index 0000000000..17d3274c32 --- /dev/null +++ b/artifacthub/library/pod-security-policy/fsgroup/1.1.0/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.1.0/samples/psp-fsgroup/example_disallowed.yaml b/artifacthub/library/pod-security-policy/fsgroup/1.1.0/samples/psp-fsgroup/example_disallowed.yaml new file mode 100644 index 0000000000..9caf7c0a31 --- /dev/null +++ b/artifacthub/library/pod-security-policy/fsgroup/1.1.0/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.1.0/samples/psp-fsgroup/update.yaml b/artifacthub/library/pod-security-policy/fsgroup/1.1.0/samples/psp-fsgroup/update.yaml new file mode 100644 index 0000000000..c0de7258a1 --- /dev/null +++ b/artifacthub/library/pod-security-policy/fsgroup/1.1.0/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.1.0/suite.yaml b/artifacthub/library/pod-security-policy/fsgroup/1.1.0/suite.yaml new file mode 100644 index 0000000000..cb102e785e --- /dev/null +++ b/artifacthub/library/pod-security-policy/fsgroup/1.1.0/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.1.0/template.yaml b/artifacthub/library/pod-security-policy/fsgroup/1.1.0/template.yaml new file mode 100644 index 0000000000..06a7f7dec0 --- /dev/null +++ b/artifacthub/library/pod-security-policy/fsgroup/1.1.0/template.yaml @@ -0,0 +1,119 @@ +apiVersion: templates.gatekeeper.sh/v1 +kind: ConstraintTemplate +metadata: + name: k8spspfsgroup + annotations: + metadata.gatekeeper.sh/title: "FS Group" + metadata.gatekeeper.sh/version: 1.1.0 + 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 + code: + - engine: K8sNativeValidation + source: + variables: + - name: fsGroup + expression: '!has(object.spec.securityContext) ? "" : !has(object.spec.securityContext.fsGroup) ? "" : object.spec.securityContext.fsGroup' + - name: input_fsGroup_allowed + expression: | + !has(variables.params.rule) ? true : variables.params.rule == "RunAsAny" ? true : variables.params.rule == "MayRunAs" && variables.fsGroup == "" ? true : (variables.params.rule == "MayRunAs" || variables.params.rule == "MustRunAs") && has(variables.params.ranges) && size(variables.params.ranges) > 0 ? variables.params.ranges.all(range, range.min <= variables.fsGroup && range.max >= variables.fsGroup) : false + validations: + - expression: '(has(request.operation) && request.operation == "UPDATE") || variables.input_fsGroup_allowed' + messageExpression: '"The provided pod spec fsGroup is not allowed, pod: " + object.metadata.name + ". Allowed fsGroup: " + variables.params.rule' + - engine: Rego + source: + 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/library/pod-security-policy/fsgroup/samples/psp-fsgroup/constraint2.yaml b/library/pod-security-policy/fsgroup/samples/psp-fsgroup/constraint2.yaml new file mode 100644 index 0000000000..eb6e4f3504 --- /dev/null +++ b/library/pod-security-policy/fsgroup/samples/psp-fsgroup/constraint2.yaml @@ -0,0 +1,11 @@ +apiVersion: constraints.gatekeeper.sh/v1beta1 +kind: K8sPSPFSGroup +metadata: + name: psp-fsgroup +spec: + match: + kinds: + - apiGroups: [""] + kinds: ["Pod"] + parameters: + rule: "MustRunAs" #"MustRunAs" #"MayRunAs", "RunAsAny" diff --git a/library/pod-security-policy/fsgroup/samples/psp-fsgroup/constraint3.yaml b/library/pod-security-policy/fsgroup/samples/psp-fsgroup/constraint3.yaml new file mode 100644 index 0000000000..2d4ab8a6df --- /dev/null +++ b/library/pod-security-policy/fsgroup/samples/psp-fsgroup/constraint3.yaml @@ -0,0 +1,11 @@ +apiVersion: constraints.gatekeeper.sh/v1beta1 +kind: K8sPSPFSGroup +metadata: + name: psp-fsgroup +spec: + match: + kinds: + - apiGroups: [""] + kinds: ["Pod"] + parameters: + rule: "MayRunAs" #"MustRunAs" #"MayRunAs", "RunAsAny" diff --git a/library/pod-security-policy/fsgroup/samples/psp-fsgroup/example_allowed.yaml b/library/pod-security-policy/fsgroup/samples/psp-fsgroup/example_allowed.yaml index 17d3274c32..c5f697269f 100644 --- a/library/pod-security-policy/fsgroup/samples/psp-fsgroup/example_allowed.yaml +++ b/library/pod-security-policy/fsgroup/samples/psp-fsgroup/example_allowed.yaml @@ -1,7 +1,7 @@ apiVersion: v1 kind: Pod metadata: - name: fsgroup-disallowed + name: fsgroup-allowed spec: securityContext: fsGroup: 500 # directory will have group ID 500 diff --git a/library/pod-security-policy/fsgroup/samples/psp-fsgroup/example_allowed2.yaml b/library/pod-security-policy/fsgroup/samples/psp-fsgroup/example_allowed2.yaml new file mode 100644 index 0000000000..206dc2ae43 --- /dev/null +++ b/library/pod-security-policy/fsgroup/samples/psp-fsgroup/example_allowed2.yaml @@ -0,0 +1,15 @@ +apiVersion: v1 +kind: Pod +metadata: + name: fsgroup-allowed +spec: + 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/library/pod-security-policy/fsgroup/suite.yaml b/library/pod-security-policy/fsgroup/suite.yaml index cb102e785e..25a3890246 100644 --- a/library/pod-security-policy/fsgroup/suite.yaml +++ b/library/pod-security-policy/fsgroup/suite.yaml @@ -15,7 +15,27 @@ tests: object: samples/psp-fsgroup/example_allowed.yaml assertions: - violations: no + - name: example-allowed2-nofsgroup + object: samples/psp-fsgroup/example_allowed2.yaml + assertions: + - violations: no - name: update object: samples/psp-fsgroup/update.yaml assertions: - violations: no + - name: fsgroup2 + template: template.yaml + constraint: samples/psp-fsgroup/constraint2.yaml + cases: + - name: example-allowed-is-disallowed-constraint2 + object: samples/psp-fsgroup/example_allowed2.yaml + assertions: + - violations: yes + - name: fsgroup3 + template: template.yaml + constraint: samples/psp-fsgroup/constraint3.yaml + cases: + - name: example-allowed-constraint3 + object: samples/psp-fsgroup/example_allowed2.yaml + assertions: + - violations: no diff --git a/library/pod-security-policy/fsgroup/template.yaml b/library/pod-security-policy/fsgroup/template.yaml index 4e1b9449af..06a7f7dec0 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.2 + metadata.gatekeeper.sh/version: 1.1.0 description: >- Controls allocating an FSGroup that owns the Pod's volumes. Corresponds to the `fsGroup` field in a PodSecurityPolicy. For more information, see @@ -44,62 +44,76 @@ spec: type: integer targets: - target: admission.k8s.gatekeeper.sh - rego: | - package k8spspfsgroup + code: + - engine: K8sNativeValidation + source: + variables: + - name: fsGroup + expression: '!has(object.spec.securityContext) ? "" : !has(object.spec.securityContext.fsGroup) ? "" : object.spec.securityContext.fsGroup' + - name: input_fsGroup_allowed + expression: | + !has(variables.params.rule) ? true : variables.params.rule == "RunAsAny" ? true : variables.params.rule == "MayRunAs" && variables.fsGroup == "" ? true : (variables.params.rule == "MayRunAs" || variables.params.rule == "MustRunAs") && has(variables.params.ranges) && size(variables.params.ranges) > 0 ? variables.params.ranges.all(range, range.min <= variables.fsGroup && range.max >= variables.fsGroup) : false + validations: + - expression: '(has(request.operation) && request.operation == "UPDATE") || variables.input_fsGroup_allowed' + messageExpression: '"The provided pod spec fsGroup is not allowed, pod: " + object.metadata.name + ". Allowed fsGroup: " + variables.params.rule' + - engine: Rego + source: + rego: | + package k8spspfsgroup - import data.lib.exclude_update.is_update + import data.lib.exclude_update.is_update - violation[{"msg": msg, "details": {}}] { - # spec.securityContext.fsGroup field is immutable. - not is_update(input.review) + 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]) - } + 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 + 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" - } + is_update(review) { + review.operation == "UPDATE" + } diff --git a/src/pod-security-policy/fsgroup/constraint.tmpl b/src/pod-security-policy/fsgroup/constraint.tmpl index 01e9f415d5..783cb8efc1 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.2 + metadata.gatekeeper.sh/version: 1.1.0 description: >- Controls allocating an FSGroup that owns the Pod's volumes. Corresponds to the `fsGroup` field in a PodSecurityPolicy. For more information, see @@ -44,8 +44,14 @@ spec: type: integer targets: - target: admission.k8s.gatekeeper.sh - rego: | -{{ file.Read "src/pod-security-policy/fsgroup/src.rego" | strings.Indent 8 | strings.TrimSuffix "\n" }} - libs: - - | -{{ file.Read "src/pod-security-policy/fsgroup/lib_exclude_update.rego" | strings.Indent 10 | strings.TrimSuffix "\n" }} + code: + - engine: K8sNativeValidation + source: +{{ file.Read "src/pod-security-policy/fsgroup/src.cel" | strings.Indent 10 | strings.TrimSuffix "\n" }} + - engine: Rego + source: + rego: | +{{ file.Read "src/pod-security-policy/fsgroup/src.rego" | strings.Indent 12 | strings.TrimSuffix "\n" }} + libs: + - | +{{ file.Read "src/pod-security-policy/fsgroup/lib_exclude_update.rego" | strings.Indent 14 | strings.TrimSuffix "\n" }} diff --git a/src/pod-security-policy/fsgroup/src.cel b/src/pod-security-policy/fsgroup/src.cel new file mode 100644 index 0000000000..22a14338d2 --- /dev/null +++ b/src/pod-security-policy/fsgroup/src.cel @@ -0,0 +1,9 @@ +variables: +- name: fsGroup + expression: '!has(object.spec.securityContext) ? "" : !has(object.spec.securityContext.fsGroup) ? "" : object.spec.securityContext.fsGroup' +- name: input_fsGroup_allowed + expression: | + !has(variables.params.rule) ? true : variables.params.rule == "RunAsAny" ? true : variables.params.rule == "MayRunAs" && variables.fsGroup == "" ? true : (variables.params.rule == "MayRunAs" || variables.params.rule == "MustRunAs") && has(variables.params.ranges) && size(variables.params.ranges) > 0 ? variables.params.ranges.all(range, range.min <= variables.fsGroup && range.max >= variables.fsGroup) : false +validations: +- expression: '(has(request.operation) && request.operation == "UPDATE") || variables.input_fsGroup_allowed' + messageExpression: '"The provided pod spec fsGroup is not allowed, pod: " + object.metadata.name + ". Allowed fsGroup: " + variables.params.rule' \ No newline at end of file diff --git a/website/docs/validation/fsgroup.md b/website/docs/validation/fsgroup.md index 35e1b035e0..da13fde015 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.2 + metadata.gatekeeper.sh/version: 1.1.0 description: >- Controls allocating an FSGroup that owns the Pod's volumes. Corresponds to the `fsGroup` field in a PodSecurityPolicy. For more information, see @@ -56,65 +56,79 @@ spec: 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" - } + code: + - engine: K8sNativeValidation + source: + variables: + - name: fsGroup + expression: '!has(object.spec.securityContext) ? "" : !has(object.spec.securityContext.fsGroup) ? "" : object.spec.securityContext.fsGroup' + - name: input_fsGroup_allowed + expression: | + !has(variables.params.rule) ? true : variables.params.rule == "RunAsAny" ? true : variables.params.rule == "MayRunAs" && variables.fsGroup == "" ? true : (variables.params.rule == "MayRunAs" || variables.params.rule == "MustRunAs") && has(variables.params.ranges) && size(variables.params.ranges) > 0 ? variables.params.ranges.all(range, range.min <= variables.fsGroup && range.max >= variables.fsGroup) : false + validations: + - expression: '(has(request.operation) && request.operation == "UPDATE") || variables.input_fsGroup_allowed' + messageExpression: '"The provided pod spec fsGroup is not allowed, pod: " + object.metadata.name + ". Allowed fsGroup: " + variables.params.rule' + - engine: Rego + source: + 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" + } ```