diff --git a/artifacthub/library/pod-security-policy/users/1.1.0/artifacthub-pkg.yml b/artifacthub/library/pod-security-policy/users/1.1.0/artifacthub-pkg.yml index 354e2921f..9f7011ec9 100644 --- a/artifacthub/library/pod-security-policy/users/1.1.0/artifacthub-pkg.yml +++ b/artifacthub/library/pod-security-policy/users/1.1.0/artifacthub-pkg.yml @@ -3,7 +3,7 @@ name: k8spspallowedusers displayName: Allowed Users createdAt: "2024-05-30T00:06:50Z" 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: 89647a76a0f751668fd9ef9630c8a2ddf6fda516eadd14067a3fd98988e13210 +digest: b2ee8625cdff505db43a6c1cd1148bebac7f0281d150ddb6b1e589f7c1d621e6 license: Apache-2.0 homeURL: https://open-policy-agent.github.io/gatekeeper-library/website/users keywords: diff --git a/artifacthub/library/pod-security-policy/users/1.1.0/template.yaml b/artifacthub/library/pod-security-policy/users/1.1.0/template.yaml index 85d556481..7f6ebde96 100644 --- a/artifacthub/library/pod-security-policy/users/1.1.0/template.yaml +++ b/artifacthub/library/pod-security-policy/users/1.1.0/template.yaml @@ -157,40 +157,120 @@ spec: variables.exemptImagePrefixes.exists(exemption, string(container.image).startsWith(exemption))) - name: podRunAsUser expression: | - variables.anyObject.kind == "Pod" && has(variables.anyObject.spec.securityContext) && has(variables.anyObject.spec.securityContext.runAsUser) ? variables.anyObject.spec.securityContext.runAsUser : null + has(variables.anyObject.spec.securityContext) && has(variables.anyObject.spec.securityContext.runAsUser) ? variables.anyObject.spec.securityContext.runAsUser : null - name: podSupplementalGroups expression: | - variables.anyObject.kind == "Pod" && has(variables.anyObject.spec.securityContext) && has(variables.anyObject.spec.securityContext.supplementalGroups) ? variables.anyObject.spec.securityContext.supplementalGroups : null + has(variables.anyObject.spec.securityContext) && has(variables.anyObject.spec.securityContext.supplementalGroups) ? variables.anyObject.spec.securityContext.supplementalGroups : null - name: podRunAsGroup expression: | - variables.anyObject.kind == "Pod" && has(variables.anyObject.spec.securityContext) && has(variables.anyObject.spec.securityContext.runAsGroup) ? variables.anyObject.spec.securityContext.runAsGroup : null + has(variables.anyObject.spec.securityContext) && has(variables.anyObject.spec.securityContext.runAsGroup) ? variables.anyObject.spec.securityContext.runAsGroup : null - name: podFsGroup expression: | - variables.anyObject.kind == "Pod" && has(variables.anyObject.spec.securityContext) && has(variables.anyObject.spec.securityContext.fsGroup) ? variables.anyObject.spec.securityContext.fsGroup : null + has(variables.anyObject.spec.securityContext) && has(variables.anyObject.spec.securityContext.fsGroup) ? variables.anyObject.spec.securityContext.fsGroup : null - name: nonExemptContainers expression: | (variables.containers + variables.initContainers + variables.ephemeralContainers).filter(container, !(container.image in variables.exemptImages)) - name: missingRunAsNonRootGlobal expression: | - !has(variables.anyObject.securityContext) || ((!has(variables.anyObject.securityContext.runAsNonRoot) || !variables.anyObject.securityContext.runAsNonRoot) && (!has(variables.anyObject.securityContext.runAsUser) || variables.anyObject.securityContext.runAsUser == 0)) + !has(variables.anyObject.securityContext) || ((!has(variables.anyObject.securityContext.runAsNonRoot) || + !variables.anyObject.securityContext.runAsNonRoot) && (!has(variables.anyObject.securityContext.runAsUser) || + variables.anyObject.securityContext.runAsUser == 0)) - name: violatingMustOrMayRunAsUser expression: | - has(variables.params.runAsUser) && has(variables.params.runAsUser.rule) && variables.params.runAsUser.rule == "MustRunAs" ? variables.nonExemptContainers.filter(container, (!has(container.securityContext) || !has(container.securityContext.runAsUser)) && variables.podRunAsUser == null).map(container, "Container " + container.name + " is attempting to run without a required securityContext/runAsUser") + variables.nonExemptContainers.filter(container, (has(container.securityContext) && has(container.securityContext.runAsUser) ? !variables.params.runAsUser.ranges.exists(range, container.securityContext.runAsUser >= range.min && container.securityContext.runAsUser <= range.max) : variables.podRunAsUser != null && !variables.params.runAsUser.ranges.exists(range, variables.podRunAsUser >= range.min && variables.podRunAsUser <= range.max))).map(container, "Container " + container.name + " is attempting to run as disallowed user. Allowed runAsUser: {ranges: [" + variables.params.runAsUser.ranges.map(range, "{max: " + string(range.max) + ", min: " + string(range.min) + "}").join(", ") + ", rule: " + variables.params.runAsUser.rule + "}") : [] + has(variables.params.runAsUser) && has(variables.params.runAsUser.rule) && variables.params.runAsUser.rule == "MustRunAs" ? + variables.nonExemptContainers.filter(container, + (!has(container.securityContext) || !has(container.securityContext.runAsUser)) && variables.podRunAsUser == null + ).map(container, "Container " + container.name + " is attempting to run without a required securityContext/runAsUser") + + variables.nonExemptContainers.filter(container, + (has(container.securityContext) && has(container.securityContext.runAsUser) ? + !variables.params.runAsUser.ranges.exists(range, + container.securityContext.runAsUser >= range.min && container.securityContext.runAsUser <= range.max) : + variables.podRunAsUser != null && !variables.params.runAsUser.ranges.exists(range, + variables.podRunAsUser >= range.min && variables.podRunAsUser <= range.max) + ) + ).map(container, + "Container " + container.name + " is attempting to run as disallowed user. Allowed runAsUser: {ranges: [" + + variables.params.runAsUser.ranges.map(range, "{max: " + string(range.max) + ", min: " + string(range.min) + "}").join(", ") + + ", rule: " + variables.params.runAsUser.rule + "}" + ) : + [] - name: violatingMustOrMayRunAsGroup expression: | - has(variables.params.runAsGroup) && has(variables.params.runAsGroup.rule) && (variables.params.runAsGroup.rule == "MustRunAs" || variables.params.runAsGroup.rule == "MayRunAs") ? variables.nonExemptContainers.filter(container, (!has(container.securityContext) || !has(container.securityContext.runAsGroup)) && variables.podRunAsGroup == null).map(container, "Container " + container.name + " is attempting to run without a required securityContext/runAsGroup. Allowed runAsGroup: {ranges: [" + variables.params.runAsGroup.ranges.map(range, "{max: " + string(range.max) + ", min: " + string(range.min) + "}").join(", ") + ", rule: " + variables.params.runAsGroup.rule + "}") + variables.nonExemptContainers.filter(container, (has(container.securityContext) && has(container.securityContext.runAsGroup)) ? !variables.params.runAsGroup.ranges.exists(range, container.securityContext.runAsGroup >= range.min && container.securityContext.runAsGroup <= range.max) : variables.podRunAsGroup != null && !variables.params.runAsGroup.ranges.exists(range, variables.podRunAsGroup >= range.min && variables.podRunAsGroup <= range.max)).map(container, "Container " + container.name + " is attempting to run as disallowed group. Allowed runAsGroup: {ranges: [" + variables.params.runAsGroup.ranges.map(range, "{max: " + string(range.max) + ", min: " + string(range.min) + "}").join(", ") + ", rule: " + variables.params.runAsGroup.rule + "}") : [] + has(variables.params.runAsGroup) && has(variables.params.runAsGroup.rule) && (variables.params.runAsGroup.rule == "MustRunAs" || variables.params.runAsGroup.rule == "MayRunAs") ? + variables.nonExemptContainers.filter(container, + (!has(container.securityContext) || !has(container.securityContext.runAsGroup)) && variables.podRunAsGroup == null + ).map(container, + "Container " + container.name + " is attempting to run without a required securityContext/runAsGroup. Allowed runAsGroup: {ranges: [" + + variables.params.runAsGroup.ranges.map(range, "{max: " + string(range.max) + ", min: " + string(range.min) + "}").join(", ") + ", rule: " + + variables.params.runAsGroup.rule + "}" + ) + + variables.nonExemptContainers.filter(container, + (has(container.securityContext) && has(container.securityContext.runAsGroup)) ? + !variables.params.runAsGroup.ranges.exists(range, + container.securityContext.runAsGroup >= range.min && container.securityContext.runAsGroup <= range.max) : + variables.podRunAsGroup != null && !variables.params.runAsGroup.ranges.exists(range, + variables.podRunAsGroup >= range.min && variables.podRunAsGroup <= range.max) + ).map(container, + "Container " + container.name + " is attempting to run as disallowed group. Allowed runAsGroup: {ranges: [" + + variables.params.runAsGroup.ranges.map(range, "{max: " + string(range.max) + ", min: " + string(range.min) + "}").join(", ") + + ", rule: " + variables.params.runAsGroup.rule + "}" + ) : + [] - name: violatingMustOrMayRunAsFsGroup expression: | - has(variables.params.fsGroup) && has(variables.params.fsGroup.rule) && (variables.params.fsGroup.rule == "MustRunAs" || variables.params.fsGroup.rule == "MayRunAs" )? variables.nonExemptContainers.filter(container, (!has(container.securityContext) || !has(container.securityContext.fsGroup)) && variables.podFsGroup == null).map(container, "Container " + container.name + " is attempting to run without a required securityContext/fsGroup. Allowed fsGroup: {ranges: [" + variables.params.fsGroup.ranges.map(range, "{max: " + string(range.max) + ", min: " + string(range.min) + "}").join(", ") + ", rule: " + variables.params.fsGroup.rule + "}") + variables.nonExemptContainers.filter(container, (has(container.securityContext) && has(container.securityContext.fsGroup)) ? !variables.params.fsGroup.ranges.exists(range, container.securityContext.fsGroup >= range.min && container.securityContext.fsGroup <= range.max) : variables.podFsGroup != null && !variables.params.fsGroup.ranges.exists(range, variables.podFsGroup >= range.min && variables.podFsGroup <= range.max)).map(container, "Container " + container.name + " is attempting to run as disallowed fsGroup. Allowed fsGroup: {ranges: [" + variables.params.fsGroup.ranges.map(range, "{max: " + string(range.max) + ", min: " + string(range.min) + "}").join(", ") + ", rule: " + variables.params.fsGroup.rule + "}") : [] + has(variables.params.fsGroup) && has(variables.params.fsGroup.rule) && (variables.params.fsGroup.rule == "MustRunAs" || variables.params.fsGroup.rule == "MayRunAs" ) ? + variables.nonExemptContainers.filter(container, + (!has(container.securityContext) || !has(container.securityContext.fsGroup)) && variables.podFsGroup == null + ).map(container, + "Container " + container.name + " is attempting to run without a required securityContext/fsGroup. Allowed fsGroup: {ranges: [" + + variables.params.fsGroup.ranges.map(range, "{max: " + string(range.max) + ", min: " + string(range.min) + "}").join(", ") + + ", rule: " + variables.params.fsGroup.rule + "}" + ) + + variables.nonExemptContainers.filter(container, (has(container.securityContext) && has(container.securityContext.fsGroup)) ? + !variables.params.fsGroup.ranges.exists(range, + container.securityContext.fsGroup >= range.min && container.securityContext.fsGroup <= range.max) : + variables.podFsGroup != null && !variables.params.fsGroup.ranges.exists(range, + variables.podFsGroup >= range.min && variables.podFsGroup <= range.max) + ).map(container, "Container " + container.name + " is attempting to run as disallowed fsGroup. Allowed fsGroup: {ranges: [" + + variables.params.fsGroup.ranges.map(range, "{max: " + string(range.max) + ", min: " + string(range.min) + "}").join(", ") + + ", rule: " + variables.params.fsGroup.rule + "}") + : [] - name: violatingMustOrMayRunAsSupplementalGroups expression: | - has(variables.params.supplementalGroups) && has(variables.params.supplementalGroups.rule) && (variables.params.supplementalGroups.rule == "MustRunAs" || variables.params.supplementalGroups.rule == "MayRunAs") ? variables.nonExemptContainers.filter(container, (!has(container.securityContext) || !has(container.securityContext.supplementalGroups)) && variables.podSupplementalGroups == null).map(container, "Container " + container.name + " is attempting to run without a required securityContext/supplementalGroups. Allowed supplementalGroups: {ranges: [" + variables.params.supplementalGroups.ranges.map(range, "{max: " + string(range.max) + ", min: " + string(range.min) + "}").join(", ") + ", rule: " + variables.params.supplementalGroups.rule + "}") + variables.nonExemptContainers.filter(container, (has(container.securityContext) && has(container.securityContext.supplementalGroups)) ? !variables.params.supplementalGroups.ranges.exists(range, container.securityContext.supplementalGroups.all(gp, gp >= range.min && gp <= range.max)) : variables.podSupplementalGroups != null && !variables.params.supplementalGroups.ranges.exists(range, variables.podSupplementalGroups.all(gp, gp >= range.min && gp <= range.max))).map(container, "Container " + container.name + " is attempting to run with disallowed supplementalGroups. Allowed supplementalGroups: {ranges: [" + variables.params.supplementalGroups.ranges.map(range, "{max: " + string(range.max) + ", min: " + string(range.min) + "}").join(", ") + ", rule: " + variables.params.supplementalGroups.rule + "}") : [] + has(variables.params.supplementalGroups) && has(variables.params.supplementalGroups.rule) && (variables.params.supplementalGroups.rule == "MustRunAs" || variables.params.supplementalGroups.rule == "MayRunAs") ? + variables.nonExemptContainers.filter(container, + (!has(container.securityContext) || !has(container.securityContext.supplementalGroups)) && variables.podSupplementalGroups == null + ).map(container, + "Container " + container.name + " is attempting to run without a required securityContext/supplementalGroups. Allowed supplementalGroups: {ranges: [" + + variables.params.supplementalGroups.ranges.map(range, "{max: " + string(range.max) + ", min: " + string(range.min) + "}").join(", ") + + ", rule: " + variables.params.supplementalGroups.rule + "}" + ) + + variables.nonExemptContainers.filter(container, + (has(container.securityContext) && has(container.securityContext.supplementalGroups)) ? + !variables.params.supplementalGroups.ranges.exists(range, + container.securityContext.supplementalGroups.all(gp, gp >= range.min && gp <= range.max)) : + variables.podSupplementalGroups != null && !variables.params.supplementalGroups.ranges.exists(range, + variables.podSupplementalGroups.all(gp, gp >= range.min && gp <= range.max)) + ).map(container, + "Container " + container.name + " is attempting to run with disallowed supplementalGroups. Allowed supplementalGroups: {ranges: [" + + variables.params.supplementalGroups.ranges.map(range, "{max: " + string(range.max) + ", min: " + string(range.min) + "}").join(", ") + + ", rule: " + variables.params.supplementalGroups.rule + "}") + : [] - name: violatingMustRunAsNonRoot expression: | - variables.nonExemptContainers.filter(container, (has(variables.params.runAsUser) && has(variables.params.runAsUser.rule) && variables.params.runAsUser.rule == "MustRunAsNonRoot") && (!has(container.securityContext) || (!has(container.securityContext.runAsNonRoot) || !container.securityContext.runAsNonRoot) && (!has(container.securityContext.runAsUser) || container.securityContext.runAsUser == 0)) && variables.missingRunAsNonRootGlobal).map(container, "Container " + container.name + " is attempting to run without a required securityContext/runAsNonRoot or securityContext/runAsUser != 0") + variables.nonExemptContainers.filter(container, + (has(variables.params.runAsUser) && has(variables.params.runAsUser.rule) && variables.params.runAsUser.rule == "MustRunAsNonRoot") && + (!has(container.securityContext) || (!has(container.securityContext.runAsNonRoot) || !container.securityContext.runAsNonRoot) && + (!has(container.securityContext.runAsUser) || container.securityContext.runAsUser == 0)) && variables.missingRunAsNonRootGlobal + ).map(container, + "Container " + container.name + " is attempting to run without a required securityContext/runAsNonRoot or securityContext/runAsUser != 0") - name: violations expression: | - variables.violatingMustRunAsNonRoot + variables.violatingMustOrMayRunAsUser + variables.violatingMustOrMayRunAsGroup + variables.violatingMustOrMayRunAsFsGroup + variables.violatingMustOrMayRunAsSupplementalGroups + variables.violatingMustRunAsNonRoot + + variables.violatingMustOrMayRunAsUser + + variables.violatingMustOrMayRunAsGroup + + variables.violatingMustOrMayRunAsFsGroup + + variables.violatingMustOrMayRunAsSupplementalGroups validations: - expression: '(has(request.operation) && request.operation == "UPDATE") || size(variables.violations) == 0' messageExpression: 'variables.violations.join(", ")' @@ -292,7 +372,6 @@ spec: # 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 } diff --git a/library/pod-security-policy/users/template.yaml b/library/pod-security-policy/users/template.yaml index 85d556481..7f6ebde96 100644 --- a/library/pod-security-policy/users/template.yaml +++ b/library/pod-security-policy/users/template.yaml @@ -157,40 +157,120 @@ spec: variables.exemptImagePrefixes.exists(exemption, string(container.image).startsWith(exemption))) - name: podRunAsUser expression: | - variables.anyObject.kind == "Pod" && has(variables.anyObject.spec.securityContext) && has(variables.anyObject.spec.securityContext.runAsUser) ? variables.anyObject.spec.securityContext.runAsUser : null + has(variables.anyObject.spec.securityContext) && has(variables.anyObject.spec.securityContext.runAsUser) ? variables.anyObject.spec.securityContext.runAsUser : null - name: podSupplementalGroups expression: | - variables.anyObject.kind == "Pod" && has(variables.anyObject.spec.securityContext) && has(variables.anyObject.spec.securityContext.supplementalGroups) ? variables.anyObject.spec.securityContext.supplementalGroups : null + has(variables.anyObject.spec.securityContext) && has(variables.anyObject.spec.securityContext.supplementalGroups) ? variables.anyObject.spec.securityContext.supplementalGroups : null - name: podRunAsGroup expression: | - variables.anyObject.kind == "Pod" && has(variables.anyObject.spec.securityContext) && has(variables.anyObject.spec.securityContext.runAsGroup) ? variables.anyObject.spec.securityContext.runAsGroup : null + has(variables.anyObject.spec.securityContext) && has(variables.anyObject.spec.securityContext.runAsGroup) ? variables.anyObject.spec.securityContext.runAsGroup : null - name: podFsGroup expression: | - variables.anyObject.kind == "Pod" && has(variables.anyObject.spec.securityContext) && has(variables.anyObject.spec.securityContext.fsGroup) ? variables.anyObject.spec.securityContext.fsGroup : null + has(variables.anyObject.spec.securityContext) && has(variables.anyObject.spec.securityContext.fsGroup) ? variables.anyObject.spec.securityContext.fsGroup : null - name: nonExemptContainers expression: | (variables.containers + variables.initContainers + variables.ephemeralContainers).filter(container, !(container.image in variables.exemptImages)) - name: missingRunAsNonRootGlobal expression: | - !has(variables.anyObject.securityContext) || ((!has(variables.anyObject.securityContext.runAsNonRoot) || !variables.anyObject.securityContext.runAsNonRoot) && (!has(variables.anyObject.securityContext.runAsUser) || variables.anyObject.securityContext.runAsUser == 0)) + !has(variables.anyObject.securityContext) || ((!has(variables.anyObject.securityContext.runAsNonRoot) || + !variables.anyObject.securityContext.runAsNonRoot) && (!has(variables.anyObject.securityContext.runAsUser) || + variables.anyObject.securityContext.runAsUser == 0)) - name: violatingMustOrMayRunAsUser expression: | - has(variables.params.runAsUser) && has(variables.params.runAsUser.rule) && variables.params.runAsUser.rule == "MustRunAs" ? variables.nonExemptContainers.filter(container, (!has(container.securityContext) || !has(container.securityContext.runAsUser)) && variables.podRunAsUser == null).map(container, "Container " + container.name + " is attempting to run without a required securityContext/runAsUser") + variables.nonExemptContainers.filter(container, (has(container.securityContext) && has(container.securityContext.runAsUser) ? !variables.params.runAsUser.ranges.exists(range, container.securityContext.runAsUser >= range.min && container.securityContext.runAsUser <= range.max) : variables.podRunAsUser != null && !variables.params.runAsUser.ranges.exists(range, variables.podRunAsUser >= range.min && variables.podRunAsUser <= range.max))).map(container, "Container " + container.name + " is attempting to run as disallowed user. Allowed runAsUser: {ranges: [" + variables.params.runAsUser.ranges.map(range, "{max: " + string(range.max) + ", min: " + string(range.min) + "}").join(", ") + ", rule: " + variables.params.runAsUser.rule + "}") : [] + has(variables.params.runAsUser) && has(variables.params.runAsUser.rule) && variables.params.runAsUser.rule == "MustRunAs" ? + variables.nonExemptContainers.filter(container, + (!has(container.securityContext) || !has(container.securityContext.runAsUser)) && variables.podRunAsUser == null + ).map(container, "Container " + container.name + " is attempting to run without a required securityContext/runAsUser") + + variables.nonExemptContainers.filter(container, + (has(container.securityContext) && has(container.securityContext.runAsUser) ? + !variables.params.runAsUser.ranges.exists(range, + container.securityContext.runAsUser >= range.min && container.securityContext.runAsUser <= range.max) : + variables.podRunAsUser != null && !variables.params.runAsUser.ranges.exists(range, + variables.podRunAsUser >= range.min && variables.podRunAsUser <= range.max) + ) + ).map(container, + "Container " + container.name + " is attempting to run as disallowed user. Allowed runAsUser: {ranges: [" + + variables.params.runAsUser.ranges.map(range, "{max: " + string(range.max) + ", min: " + string(range.min) + "}").join(", ") + + ", rule: " + variables.params.runAsUser.rule + "}" + ) : + [] - name: violatingMustOrMayRunAsGroup expression: | - has(variables.params.runAsGroup) && has(variables.params.runAsGroup.rule) && (variables.params.runAsGroup.rule == "MustRunAs" || variables.params.runAsGroup.rule == "MayRunAs") ? variables.nonExemptContainers.filter(container, (!has(container.securityContext) || !has(container.securityContext.runAsGroup)) && variables.podRunAsGroup == null).map(container, "Container " + container.name + " is attempting to run without a required securityContext/runAsGroup. Allowed runAsGroup: {ranges: [" + variables.params.runAsGroup.ranges.map(range, "{max: " + string(range.max) + ", min: " + string(range.min) + "}").join(", ") + ", rule: " + variables.params.runAsGroup.rule + "}") + variables.nonExemptContainers.filter(container, (has(container.securityContext) && has(container.securityContext.runAsGroup)) ? !variables.params.runAsGroup.ranges.exists(range, container.securityContext.runAsGroup >= range.min && container.securityContext.runAsGroup <= range.max) : variables.podRunAsGroup != null && !variables.params.runAsGroup.ranges.exists(range, variables.podRunAsGroup >= range.min && variables.podRunAsGroup <= range.max)).map(container, "Container " + container.name + " is attempting to run as disallowed group. Allowed runAsGroup: {ranges: [" + variables.params.runAsGroup.ranges.map(range, "{max: " + string(range.max) + ", min: " + string(range.min) + "}").join(", ") + ", rule: " + variables.params.runAsGroup.rule + "}") : [] + has(variables.params.runAsGroup) && has(variables.params.runAsGroup.rule) && (variables.params.runAsGroup.rule == "MustRunAs" || variables.params.runAsGroup.rule == "MayRunAs") ? + variables.nonExemptContainers.filter(container, + (!has(container.securityContext) || !has(container.securityContext.runAsGroup)) && variables.podRunAsGroup == null + ).map(container, + "Container " + container.name + " is attempting to run without a required securityContext/runAsGroup. Allowed runAsGroup: {ranges: [" + + variables.params.runAsGroup.ranges.map(range, "{max: " + string(range.max) + ", min: " + string(range.min) + "}").join(", ") + ", rule: " + + variables.params.runAsGroup.rule + "}" + ) + + variables.nonExemptContainers.filter(container, + (has(container.securityContext) && has(container.securityContext.runAsGroup)) ? + !variables.params.runAsGroup.ranges.exists(range, + container.securityContext.runAsGroup >= range.min && container.securityContext.runAsGroup <= range.max) : + variables.podRunAsGroup != null && !variables.params.runAsGroup.ranges.exists(range, + variables.podRunAsGroup >= range.min && variables.podRunAsGroup <= range.max) + ).map(container, + "Container " + container.name + " is attempting to run as disallowed group. Allowed runAsGroup: {ranges: [" + + variables.params.runAsGroup.ranges.map(range, "{max: " + string(range.max) + ", min: " + string(range.min) + "}").join(", ") + + ", rule: " + variables.params.runAsGroup.rule + "}" + ) : + [] - name: violatingMustOrMayRunAsFsGroup expression: | - has(variables.params.fsGroup) && has(variables.params.fsGroup.rule) && (variables.params.fsGroup.rule == "MustRunAs" || variables.params.fsGroup.rule == "MayRunAs" )? variables.nonExemptContainers.filter(container, (!has(container.securityContext) || !has(container.securityContext.fsGroup)) && variables.podFsGroup == null).map(container, "Container " + container.name + " is attempting to run without a required securityContext/fsGroup. Allowed fsGroup: {ranges: [" + variables.params.fsGroup.ranges.map(range, "{max: " + string(range.max) + ", min: " + string(range.min) + "}").join(", ") + ", rule: " + variables.params.fsGroup.rule + "}") + variables.nonExemptContainers.filter(container, (has(container.securityContext) && has(container.securityContext.fsGroup)) ? !variables.params.fsGroup.ranges.exists(range, container.securityContext.fsGroup >= range.min && container.securityContext.fsGroup <= range.max) : variables.podFsGroup != null && !variables.params.fsGroup.ranges.exists(range, variables.podFsGroup >= range.min && variables.podFsGroup <= range.max)).map(container, "Container " + container.name + " is attempting to run as disallowed fsGroup. Allowed fsGroup: {ranges: [" + variables.params.fsGroup.ranges.map(range, "{max: " + string(range.max) + ", min: " + string(range.min) + "}").join(", ") + ", rule: " + variables.params.fsGroup.rule + "}") : [] + has(variables.params.fsGroup) && has(variables.params.fsGroup.rule) && (variables.params.fsGroup.rule == "MustRunAs" || variables.params.fsGroup.rule == "MayRunAs" ) ? + variables.nonExemptContainers.filter(container, + (!has(container.securityContext) || !has(container.securityContext.fsGroup)) && variables.podFsGroup == null + ).map(container, + "Container " + container.name + " is attempting to run without a required securityContext/fsGroup. Allowed fsGroup: {ranges: [" + + variables.params.fsGroup.ranges.map(range, "{max: " + string(range.max) + ", min: " + string(range.min) + "}").join(", ") + + ", rule: " + variables.params.fsGroup.rule + "}" + ) + + variables.nonExemptContainers.filter(container, (has(container.securityContext) && has(container.securityContext.fsGroup)) ? + !variables.params.fsGroup.ranges.exists(range, + container.securityContext.fsGroup >= range.min && container.securityContext.fsGroup <= range.max) : + variables.podFsGroup != null && !variables.params.fsGroup.ranges.exists(range, + variables.podFsGroup >= range.min && variables.podFsGroup <= range.max) + ).map(container, "Container " + container.name + " is attempting to run as disallowed fsGroup. Allowed fsGroup: {ranges: [" + + variables.params.fsGroup.ranges.map(range, "{max: " + string(range.max) + ", min: " + string(range.min) + "}").join(", ") + + ", rule: " + variables.params.fsGroup.rule + "}") + : [] - name: violatingMustOrMayRunAsSupplementalGroups expression: | - has(variables.params.supplementalGroups) && has(variables.params.supplementalGroups.rule) && (variables.params.supplementalGroups.rule == "MustRunAs" || variables.params.supplementalGroups.rule == "MayRunAs") ? variables.nonExemptContainers.filter(container, (!has(container.securityContext) || !has(container.securityContext.supplementalGroups)) && variables.podSupplementalGroups == null).map(container, "Container " + container.name + " is attempting to run without a required securityContext/supplementalGroups. Allowed supplementalGroups: {ranges: [" + variables.params.supplementalGroups.ranges.map(range, "{max: " + string(range.max) + ", min: " + string(range.min) + "}").join(", ") + ", rule: " + variables.params.supplementalGroups.rule + "}") + variables.nonExemptContainers.filter(container, (has(container.securityContext) && has(container.securityContext.supplementalGroups)) ? !variables.params.supplementalGroups.ranges.exists(range, container.securityContext.supplementalGroups.all(gp, gp >= range.min && gp <= range.max)) : variables.podSupplementalGroups != null && !variables.params.supplementalGroups.ranges.exists(range, variables.podSupplementalGroups.all(gp, gp >= range.min && gp <= range.max))).map(container, "Container " + container.name + " is attempting to run with disallowed supplementalGroups. Allowed supplementalGroups: {ranges: [" + variables.params.supplementalGroups.ranges.map(range, "{max: " + string(range.max) + ", min: " + string(range.min) + "}").join(", ") + ", rule: " + variables.params.supplementalGroups.rule + "}") : [] + has(variables.params.supplementalGroups) && has(variables.params.supplementalGroups.rule) && (variables.params.supplementalGroups.rule == "MustRunAs" || variables.params.supplementalGroups.rule == "MayRunAs") ? + variables.nonExemptContainers.filter(container, + (!has(container.securityContext) || !has(container.securityContext.supplementalGroups)) && variables.podSupplementalGroups == null + ).map(container, + "Container " + container.name + " is attempting to run without a required securityContext/supplementalGroups. Allowed supplementalGroups: {ranges: [" + + variables.params.supplementalGroups.ranges.map(range, "{max: " + string(range.max) + ", min: " + string(range.min) + "}").join(", ") + + ", rule: " + variables.params.supplementalGroups.rule + "}" + ) + + variables.nonExemptContainers.filter(container, + (has(container.securityContext) && has(container.securityContext.supplementalGroups)) ? + !variables.params.supplementalGroups.ranges.exists(range, + container.securityContext.supplementalGroups.all(gp, gp >= range.min && gp <= range.max)) : + variables.podSupplementalGroups != null && !variables.params.supplementalGroups.ranges.exists(range, + variables.podSupplementalGroups.all(gp, gp >= range.min && gp <= range.max)) + ).map(container, + "Container " + container.name + " is attempting to run with disallowed supplementalGroups. Allowed supplementalGroups: {ranges: [" + + variables.params.supplementalGroups.ranges.map(range, "{max: " + string(range.max) + ", min: " + string(range.min) + "}").join(", ") + + ", rule: " + variables.params.supplementalGroups.rule + "}") + : [] - name: violatingMustRunAsNonRoot expression: | - variables.nonExemptContainers.filter(container, (has(variables.params.runAsUser) && has(variables.params.runAsUser.rule) && variables.params.runAsUser.rule == "MustRunAsNonRoot") && (!has(container.securityContext) || (!has(container.securityContext.runAsNonRoot) || !container.securityContext.runAsNonRoot) && (!has(container.securityContext.runAsUser) || container.securityContext.runAsUser == 0)) && variables.missingRunAsNonRootGlobal).map(container, "Container " + container.name + " is attempting to run without a required securityContext/runAsNonRoot or securityContext/runAsUser != 0") + variables.nonExemptContainers.filter(container, + (has(variables.params.runAsUser) && has(variables.params.runAsUser.rule) && variables.params.runAsUser.rule == "MustRunAsNonRoot") && + (!has(container.securityContext) || (!has(container.securityContext.runAsNonRoot) || !container.securityContext.runAsNonRoot) && + (!has(container.securityContext.runAsUser) || container.securityContext.runAsUser == 0)) && variables.missingRunAsNonRootGlobal + ).map(container, + "Container " + container.name + " is attempting to run without a required securityContext/runAsNonRoot or securityContext/runAsUser != 0") - name: violations expression: | - variables.violatingMustRunAsNonRoot + variables.violatingMustOrMayRunAsUser + variables.violatingMustOrMayRunAsGroup + variables.violatingMustOrMayRunAsFsGroup + variables.violatingMustOrMayRunAsSupplementalGroups + variables.violatingMustRunAsNonRoot + + variables.violatingMustOrMayRunAsUser + + variables.violatingMustOrMayRunAsGroup + + variables.violatingMustOrMayRunAsFsGroup + + variables.violatingMustOrMayRunAsSupplementalGroups validations: - expression: '(has(request.operation) && request.operation == "UPDATE") || size(variables.violations) == 0' messageExpression: 'variables.violations.join(", ")' @@ -292,7 +372,6 @@ spec: # 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 } diff --git a/src/pod-security-policy/users/src.cel b/src/pod-security-policy/users/src.cel index 99a5adcf2..1f3f38271 100644 --- a/src/pod-security-policy/users/src.cel +++ b/src/pod-security-policy/users/src.cel @@ -20,40 +20,120 @@ variables: variables.exemptImagePrefixes.exists(exemption, string(container.image).startsWith(exemption))) - name: podRunAsUser expression: | - variables.anyObject.kind == "Pod" && has(variables.anyObject.spec.securityContext) && has(variables.anyObject.spec.securityContext.runAsUser) ? variables.anyObject.spec.securityContext.runAsUser : null + has(variables.anyObject.spec.securityContext) && has(variables.anyObject.spec.securityContext.runAsUser) ? variables.anyObject.spec.securityContext.runAsUser : null - name: podSupplementalGroups expression: | - variables.anyObject.kind == "Pod" && has(variables.anyObject.spec.securityContext) && has(variables.anyObject.spec.securityContext.supplementalGroups) ? variables.anyObject.spec.securityContext.supplementalGroups : null + has(variables.anyObject.spec.securityContext) && has(variables.anyObject.spec.securityContext.supplementalGroups) ? variables.anyObject.spec.securityContext.supplementalGroups : null - name: podRunAsGroup expression: | - variables.anyObject.kind == "Pod" && has(variables.anyObject.spec.securityContext) && has(variables.anyObject.spec.securityContext.runAsGroup) ? variables.anyObject.spec.securityContext.runAsGroup : null + has(variables.anyObject.spec.securityContext) && has(variables.anyObject.spec.securityContext.runAsGroup) ? variables.anyObject.spec.securityContext.runAsGroup : null - name: podFsGroup expression: | - variables.anyObject.kind == "Pod" && has(variables.anyObject.spec.securityContext) && has(variables.anyObject.spec.securityContext.fsGroup) ? variables.anyObject.spec.securityContext.fsGroup : null + has(variables.anyObject.spec.securityContext) && has(variables.anyObject.spec.securityContext.fsGroup) ? variables.anyObject.spec.securityContext.fsGroup : null - name: nonExemptContainers expression: | (variables.containers + variables.initContainers + variables.ephemeralContainers).filter(container, !(container.image in variables.exemptImages)) - name: missingRunAsNonRootGlobal expression: | - !has(variables.anyObject.securityContext) || ((!has(variables.anyObject.securityContext.runAsNonRoot) || !variables.anyObject.securityContext.runAsNonRoot) && (!has(variables.anyObject.securityContext.runAsUser) || variables.anyObject.securityContext.runAsUser == 0)) + !has(variables.anyObject.securityContext) || ((!has(variables.anyObject.securityContext.runAsNonRoot) || + !variables.anyObject.securityContext.runAsNonRoot) && (!has(variables.anyObject.securityContext.runAsUser) || + variables.anyObject.securityContext.runAsUser == 0)) - name: violatingMustOrMayRunAsUser expression: | - has(variables.params.runAsUser) && has(variables.params.runAsUser.rule) && variables.params.runAsUser.rule == "MustRunAs" ? variables.nonExemptContainers.filter(container, (!has(container.securityContext) || !has(container.securityContext.runAsUser)) && variables.podRunAsUser == null).map(container, "Container " + container.name + " is attempting to run without a required securityContext/runAsUser") + variables.nonExemptContainers.filter(container, (has(container.securityContext) && has(container.securityContext.runAsUser) ? !variables.params.runAsUser.ranges.exists(range, container.securityContext.runAsUser >= range.min && container.securityContext.runAsUser <= range.max) : variables.podRunAsUser != null && !variables.params.runAsUser.ranges.exists(range, variables.podRunAsUser >= range.min && variables.podRunAsUser <= range.max))).map(container, "Container " + container.name + " is attempting to run as disallowed user. Allowed runAsUser: {ranges: [" + variables.params.runAsUser.ranges.map(range, "{max: " + string(range.max) + ", min: " + string(range.min) + "}").join(", ") + ", rule: " + variables.params.runAsUser.rule + "}") : [] + has(variables.params.runAsUser) && has(variables.params.runAsUser.rule) && variables.params.runAsUser.rule == "MustRunAs" ? + variables.nonExemptContainers.filter(container, + (!has(container.securityContext) || !has(container.securityContext.runAsUser)) && variables.podRunAsUser == null + ).map(container, "Container " + container.name + " is attempting to run without a required securityContext/runAsUser") + + variables.nonExemptContainers.filter(container, + (has(container.securityContext) && has(container.securityContext.runAsUser) ? + !variables.params.runAsUser.ranges.exists(range, + container.securityContext.runAsUser >= range.min && container.securityContext.runAsUser <= range.max) : + variables.podRunAsUser != null && !variables.params.runAsUser.ranges.exists(range, + variables.podRunAsUser >= range.min && variables.podRunAsUser <= range.max) + ) + ).map(container, + "Container " + container.name + " is attempting to run as disallowed user. Allowed runAsUser: {ranges: [" + + variables.params.runAsUser.ranges.map(range, "{max: " + string(range.max) + ", min: " + string(range.min) + "}").join(", ") + + ", rule: " + variables.params.runAsUser.rule + "}" + ) : + [] - name: violatingMustOrMayRunAsGroup expression: | - has(variables.params.runAsGroup) && has(variables.params.runAsGroup.rule) && (variables.params.runAsGroup.rule == "MustRunAs" || variables.params.runAsGroup.rule == "MayRunAs") ? variables.nonExemptContainers.filter(container, (!has(container.securityContext) || !has(container.securityContext.runAsGroup)) && variables.podRunAsGroup == null).map(container, "Container " + container.name + " is attempting to run without a required securityContext/runAsGroup. Allowed runAsGroup: {ranges: [" + variables.params.runAsGroup.ranges.map(range, "{max: " + string(range.max) + ", min: " + string(range.min) + "}").join(", ") + ", rule: " + variables.params.runAsGroup.rule + "}") + variables.nonExemptContainers.filter(container, (has(container.securityContext) && has(container.securityContext.runAsGroup)) ? !variables.params.runAsGroup.ranges.exists(range, container.securityContext.runAsGroup >= range.min && container.securityContext.runAsGroup <= range.max) : variables.podRunAsGroup != null && !variables.params.runAsGroup.ranges.exists(range, variables.podRunAsGroup >= range.min && variables.podRunAsGroup <= range.max)).map(container, "Container " + container.name + " is attempting to run as disallowed group. Allowed runAsGroup: {ranges: [" + variables.params.runAsGroup.ranges.map(range, "{max: " + string(range.max) + ", min: " + string(range.min) + "}").join(", ") + ", rule: " + variables.params.runAsGroup.rule + "}") : [] + has(variables.params.runAsGroup) && has(variables.params.runAsGroup.rule) && (variables.params.runAsGroup.rule == "MustRunAs" || variables.params.runAsGroup.rule == "MayRunAs") ? + variables.nonExemptContainers.filter(container, + (!has(container.securityContext) || !has(container.securityContext.runAsGroup)) && variables.podRunAsGroup == null + ).map(container, + "Container " + container.name + " is attempting to run without a required securityContext/runAsGroup. Allowed runAsGroup: {ranges: [" + + variables.params.runAsGroup.ranges.map(range, "{max: " + string(range.max) + ", min: " + string(range.min) + "}").join(", ") + ", rule: " + + variables.params.runAsGroup.rule + "}" + ) + + variables.nonExemptContainers.filter(container, + (has(container.securityContext) && has(container.securityContext.runAsGroup)) ? + !variables.params.runAsGroup.ranges.exists(range, + container.securityContext.runAsGroup >= range.min && container.securityContext.runAsGroup <= range.max) : + variables.podRunAsGroup != null && !variables.params.runAsGroup.ranges.exists(range, + variables.podRunAsGroup >= range.min && variables.podRunAsGroup <= range.max) + ).map(container, + "Container " + container.name + " is attempting to run as disallowed group. Allowed runAsGroup: {ranges: [" + + variables.params.runAsGroup.ranges.map(range, "{max: " + string(range.max) + ", min: " + string(range.min) + "}").join(", ") + + ", rule: " + variables.params.runAsGroup.rule + "}" + ) : + [] - name: violatingMustOrMayRunAsFsGroup expression: | - has(variables.params.fsGroup) && has(variables.params.fsGroup.rule) && (variables.params.fsGroup.rule == "MustRunAs" || variables.params.fsGroup.rule == "MayRunAs" )? variables.nonExemptContainers.filter(container, (!has(container.securityContext) || !has(container.securityContext.fsGroup)) && variables.podFsGroup == null).map(container, "Container " + container.name + " is attempting to run without a required securityContext/fsGroup. Allowed fsGroup: {ranges: [" + variables.params.fsGroup.ranges.map(range, "{max: " + string(range.max) + ", min: " + string(range.min) + "}").join(", ") + ", rule: " + variables.params.fsGroup.rule + "}") + variables.nonExemptContainers.filter(container, (has(container.securityContext) && has(container.securityContext.fsGroup)) ? !variables.params.fsGroup.ranges.exists(range, container.securityContext.fsGroup >= range.min && container.securityContext.fsGroup <= range.max) : variables.podFsGroup != null && !variables.params.fsGroup.ranges.exists(range, variables.podFsGroup >= range.min && variables.podFsGroup <= range.max)).map(container, "Container " + container.name + " is attempting to run as disallowed fsGroup. Allowed fsGroup: {ranges: [" + variables.params.fsGroup.ranges.map(range, "{max: " + string(range.max) + ", min: " + string(range.min) + "}").join(", ") + ", rule: " + variables.params.fsGroup.rule + "}") : [] + has(variables.params.fsGroup) && has(variables.params.fsGroup.rule) && (variables.params.fsGroup.rule == "MustRunAs" || variables.params.fsGroup.rule == "MayRunAs" ) ? + variables.nonExemptContainers.filter(container, + (!has(container.securityContext) || !has(container.securityContext.fsGroup)) && variables.podFsGroup == null + ).map(container, + "Container " + container.name + " is attempting to run without a required securityContext/fsGroup. Allowed fsGroup: {ranges: [" + + variables.params.fsGroup.ranges.map(range, "{max: " + string(range.max) + ", min: " + string(range.min) + "}").join(", ") + + ", rule: " + variables.params.fsGroup.rule + "}" + ) + + variables.nonExemptContainers.filter(container, (has(container.securityContext) && has(container.securityContext.fsGroup)) ? + !variables.params.fsGroup.ranges.exists(range, + container.securityContext.fsGroup >= range.min && container.securityContext.fsGroup <= range.max) : + variables.podFsGroup != null && !variables.params.fsGroup.ranges.exists(range, + variables.podFsGroup >= range.min && variables.podFsGroup <= range.max) + ).map(container, "Container " + container.name + " is attempting to run as disallowed fsGroup. Allowed fsGroup: {ranges: [" + + variables.params.fsGroup.ranges.map(range, "{max: " + string(range.max) + ", min: " + string(range.min) + "}").join(", ") + + ", rule: " + variables.params.fsGroup.rule + "}") + : [] - name: violatingMustOrMayRunAsSupplementalGroups expression: | - has(variables.params.supplementalGroups) && has(variables.params.supplementalGroups.rule) && (variables.params.supplementalGroups.rule == "MustRunAs" || variables.params.supplementalGroups.rule == "MayRunAs") ? variables.nonExemptContainers.filter(container, (!has(container.securityContext) || !has(container.securityContext.supplementalGroups)) && variables.podSupplementalGroups == null).map(container, "Container " + container.name + " is attempting to run without a required securityContext/supplementalGroups. Allowed supplementalGroups: {ranges: [" + variables.params.supplementalGroups.ranges.map(range, "{max: " + string(range.max) + ", min: " + string(range.min) + "}").join(", ") + ", rule: " + variables.params.supplementalGroups.rule + "}") + variables.nonExemptContainers.filter(container, (has(container.securityContext) && has(container.securityContext.supplementalGroups)) ? !variables.params.supplementalGroups.ranges.exists(range, container.securityContext.supplementalGroups.all(gp, gp >= range.min && gp <= range.max)) : variables.podSupplementalGroups != null && !variables.params.supplementalGroups.ranges.exists(range, variables.podSupplementalGroups.all(gp, gp >= range.min && gp <= range.max))).map(container, "Container " + container.name + " is attempting to run with disallowed supplementalGroups. Allowed supplementalGroups: {ranges: [" + variables.params.supplementalGroups.ranges.map(range, "{max: " + string(range.max) + ", min: " + string(range.min) + "}").join(", ") + ", rule: " + variables.params.supplementalGroups.rule + "}") : [] + has(variables.params.supplementalGroups) && has(variables.params.supplementalGroups.rule) && (variables.params.supplementalGroups.rule == "MustRunAs" || variables.params.supplementalGroups.rule == "MayRunAs") ? + variables.nonExemptContainers.filter(container, + (!has(container.securityContext) || !has(container.securityContext.supplementalGroups)) && variables.podSupplementalGroups == null + ).map(container, + "Container " + container.name + " is attempting to run without a required securityContext/supplementalGroups. Allowed supplementalGroups: {ranges: [" + + variables.params.supplementalGroups.ranges.map(range, "{max: " + string(range.max) + ", min: " + string(range.min) + "}").join(", ") + + ", rule: " + variables.params.supplementalGroups.rule + "}" + ) + + variables.nonExemptContainers.filter(container, + (has(container.securityContext) && has(container.securityContext.supplementalGroups)) ? + !variables.params.supplementalGroups.ranges.exists(range, + container.securityContext.supplementalGroups.all(gp, gp >= range.min && gp <= range.max)) : + variables.podSupplementalGroups != null && !variables.params.supplementalGroups.ranges.exists(range, + variables.podSupplementalGroups.all(gp, gp >= range.min && gp <= range.max)) + ).map(container, + "Container " + container.name + " is attempting to run with disallowed supplementalGroups. Allowed supplementalGroups: {ranges: [" + + variables.params.supplementalGroups.ranges.map(range, "{max: " + string(range.max) + ", min: " + string(range.min) + "}").join(", ") + + ", rule: " + variables.params.supplementalGroups.rule + "}") + : [] - name: violatingMustRunAsNonRoot expression: | - variables.nonExemptContainers.filter(container, (has(variables.params.runAsUser) && has(variables.params.runAsUser.rule) && variables.params.runAsUser.rule == "MustRunAsNonRoot") && (!has(container.securityContext) || (!has(container.securityContext.runAsNonRoot) || !container.securityContext.runAsNonRoot) && (!has(container.securityContext.runAsUser) || container.securityContext.runAsUser == 0)) && variables.missingRunAsNonRootGlobal).map(container, "Container " + container.name + " is attempting to run without a required securityContext/runAsNonRoot or securityContext/runAsUser != 0") + variables.nonExemptContainers.filter(container, + (has(variables.params.runAsUser) && has(variables.params.runAsUser.rule) && variables.params.runAsUser.rule == "MustRunAsNonRoot") && + (!has(container.securityContext) || (!has(container.securityContext.runAsNonRoot) || !container.securityContext.runAsNonRoot) && + (!has(container.securityContext.runAsUser) || container.securityContext.runAsUser == 0)) && variables.missingRunAsNonRootGlobal + ).map(container, + "Container " + container.name + " is attempting to run without a required securityContext/runAsNonRoot or securityContext/runAsUser != 0") - name: violations expression: | - variables.violatingMustRunAsNonRoot + variables.violatingMustOrMayRunAsUser + variables.violatingMustOrMayRunAsGroup + variables.violatingMustOrMayRunAsFsGroup + variables.violatingMustOrMayRunAsSupplementalGroups + variables.violatingMustRunAsNonRoot + + variables.violatingMustOrMayRunAsUser + + variables.violatingMustOrMayRunAsGroup + + variables.violatingMustOrMayRunAsFsGroup + + variables.violatingMustOrMayRunAsSupplementalGroups validations: - expression: '(has(request.operation) && request.operation == "UPDATE") || size(variables.violations) == 0' messageExpression: 'variables.violations.join(", ")' \ No newline at end of file diff --git a/src/pod-security-policy/users/src.rego b/src/pod-security-policy/users/src.rego index decf44cf6..87565d9fc 100644 --- a/src/pod-security-policy/users/src.rego +++ b/src/pod-security-policy/users/src.rego @@ -93,7 +93,6 @@ 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 } diff --git a/website/docs/validation/users.md b/website/docs/validation/users.md index da252dd66..33751c9ec 100644 --- a/website/docs/validation/users.md +++ b/website/docs/validation/users.md @@ -169,40 +169,120 @@ spec: variables.exemptImagePrefixes.exists(exemption, string(container.image).startsWith(exemption))) - name: podRunAsUser expression: | - variables.anyObject.kind == "Pod" && has(variables.anyObject.spec.securityContext) && has(variables.anyObject.spec.securityContext.runAsUser) ? variables.anyObject.spec.securityContext.runAsUser : null + has(variables.anyObject.spec.securityContext) && has(variables.anyObject.spec.securityContext.runAsUser) ? variables.anyObject.spec.securityContext.runAsUser : null - name: podSupplementalGroups expression: | - variables.anyObject.kind == "Pod" && has(variables.anyObject.spec.securityContext) && has(variables.anyObject.spec.securityContext.supplementalGroups) ? variables.anyObject.spec.securityContext.supplementalGroups : null + has(variables.anyObject.spec.securityContext) && has(variables.anyObject.spec.securityContext.supplementalGroups) ? variables.anyObject.spec.securityContext.supplementalGroups : null - name: podRunAsGroup expression: | - variables.anyObject.kind == "Pod" && has(variables.anyObject.spec.securityContext) && has(variables.anyObject.spec.securityContext.runAsGroup) ? variables.anyObject.spec.securityContext.runAsGroup : null + has(variables.anyObject.spec.securityContext) && has(variables.anyObject.spec.securityContext.runAsGroup) ? variables.anyObject.spec.securityContext.runAsGroup : null - name: podFsGroup expression: | - variables.anyObject.kind == "Pod" && has(variables.anyObject.spec.securityContext) && has(variables.anyObject.spec.securityContext.fsGroup) ? variables.anyObject.spec.securityContext.fsGroup : null + has(variables.anyObject.spec.securityContext) && has(variables.anyObject.spec.securityContext.fsGroup) ? variables.anyObject.spec.securityContext.fsGroup : null - name: nonExemptContainers expression: | (variables.containers + variables.initContainers + variables.ephemeralContainers).filter(container, !(container.image in variables.exemptImages)) - name: missingRunAsNonRootGlobal expression: | - !has(variables.anyObject.securityContext) || ((!has(variables.anyObject.securityContext.runAsNonRoot) || !variables.anyObject.securityContext.runAsNonRoot) && (!has(variables.anyObject.securityContext.runAsUser) || variables.anyObject.securityContext.runAsUser == 0)) + !has(variables.anyObject.securityContext) || ((!has(variables.anyObject.securityContext.runAsNonRoot) || + !variables.anyObject.securityContext.runAsNonRoot) && (!has(variables.anyObject.securityContext.runAsUser) || + variables.anyObject.securityContext.runAsUser == 0)) - name: violatingMustOrMayRunAsUser expression: | - has(variables.params.runAsUser) && has(variables.params.runAsUser.rule) && variables.params.runAsUser.rule == "MustRunAs" ? variables.nonExemptContainers.filter(container, (!has(container.securityContext) || !has(container.securityContext.runAsUser)) && variables.podRunAsUser == null).map(container, "Container " + container.name + " is attempting to run without a required securityContext/runAsUser") + variables.nonExemptContainers.filter(container, (has(container.securityContext) && has(container.securityContext.runAsUser) ? !variables.params.runAsUser.ranges.exists(range, container.securityContext.runAsUser >= range.min && container.securityContext.runAsUser <= range.max) : variables.podRunAsUser != null && !variables.params.runAsUser.ranges.exists(range, variables.podRunAsUser >= range.min && variables.podRunAsUser <= range.max))).map(container, "Container " + container.name + " is attempting to run as disallowed user. Allowed runAsUser: {ranges: [" + variables.params.runAsUser.ranges.map(range, "{max: " + string(range.max) + ", min: " + string(range.min) + "}").join(", ") + ", rule: " + variables.params.runAsUser.rule + "}") : [] + has(variables.params.runAsUser) && has(variables.params.runAsUser.rule) && variables.params.runAsUser.rule == "MustRunAs" ? + variables.nonExemptContainers.filter(container, + (!has(container.securityContext) || !has(container.securityContext.runAsUser)) && variables.podRunAsUser == null + ).map(container, "Container " + container.name + " is attempting to run without a required securityContext/runAsUser") + + variables.nonExemptContainers.filter(container, + (has(container.securityContext) && has(container.securityContext.runAsUser) ? + !variables.params.runAsUser.ranges.exists(range, + container.securityContext.runAsUser >= range.min && container.securityContext.runAsUser <= range.max) : + variables.podRunAsUser != null && !variables.params.runAsUser.ranges.exists(range, + variables.podRunAsUser >= range.min && variables.podRunAsUser <= range.max) + ) + ).map(container, + "Container " + container.name + " is attempting to run as disallowed user. Allowed runAsUser: {ranges: [" + + variables.params.runAsUser.ranges.map(range, "{max: " + string(range.max) + ", min: " + string(range.min) + "}").join(", ") + + ", rule: " + variables.params.runAsUser.rule + "}" + ) : + [] - name: violatingMustOrMayRunAsGroup expression: | - has(variables.params.runAsGroup) && has(variables.params.runAsGroup.rule) && (variables.params.runAsGroup.rule == "MustRunAs" || variables.params.runAsGroup.rule == "MayRunAs") ? variables.nonExemptContainers.filter(container, (!has(container.securityContext) || !has(container.securityContext.runAsGroup)) && variables.podRunAsGroup == null).map(container, "Container " + container.name + " is attempting to run without a required securityContext/runAsGroup. Allowed runAsGroup: {ranges: [" + variables.params.runAsGroup.ranges.map(range, "{max: " + string(range.max) + ", min: " + string(range.min) + "}").join(", ") + ", rule: " + variables.params.runAsGroup.rule + "}") + variables.nonExemptContainers.filter(container, (has(container.securityContext) && has(container.securityContext.runAsGroup)) ? !variables.params.runAsGroup.ranges.exists(range, container.securityContext.runAsGroup >= range.min && container.securityContext.runAsGroup <= range.max) : variables.podRunAsGroup != null && !variables.params.runAsGroup.ranges.exists(range, variables.podRunAsGroup >= range.min && variables.podRunAsGroup <= range.max)).map(container, "Container " + container.name + " is attempting to run as disallowed group. Allowed runAsGroup: {ranges: [" + variables.params.runAsGroup.ranges.map(range, "{max: " + string(range.max) + ", min: " + string(range.min) + "}").join(", ") + ", rule: " + variables.params.runAsGroup.rule + "}") : [] + has(variables.params.runAsGroup) && has(variables.params.runAsGroup.rule) && (variables.params.runAsGroup.rule == "MustRunAs" || variables.params.runAsGroup.rule == "MayRunAs") ? + variables.nonExemptContainers.filter(container, + (!has(container.securityContext) || !has(container.securityContext.runAsGroup)) && variables.podRunAsGroup == null + ).map(container, + "Container " + container.name + " is attempting to run without a required securityContext/runAsGroup. Allowed runAsGroup: {ranges: [" + + variables.params.runAsGroup.ranges.map(range, "{max: " + string(range.max) + ", min: " + string(range.min) + "}").join(", ") + ", rule: " + + variables.params.runAsGroup.rule + "}" + ) + + variables.nonExemptContainers.filter(container, + (has(container.securityContext) && has(container.securityContext.runAsGroup)) ? + !variables.params.runAsGroup.ranges.exists(range, + container.securityContext.runAsGroup >= range.min && container.securityContext.runAsGroup <= range.max) : + variables.podRunAsGroup != null && !variables.params.runAsGroup.ranges.exists(range, + variables.podRunAsGroup >= range.min && variables.podRunAsGroup <= range.max) + ).map(container, + "Container " + container.name + " is attempting to run as disallowed group. Allowed runAsGroup: {ranges: [" + + variables.params.runAsGroup.ranges.map(range, "{max: " + string(range.max) + ", min: " + string(range.min) + "}").join(", ") + + ", rule: " + variables.params.runAsGroup.rule + "}" + ) : + [] - name: violatingMustOrMayRunAsFsGroup expression: | - has(variables.params.fsGroup) && has(variables.params.fsGroup.rule) && (variables.params.fsGroup.rule == "MustRunAs" || variables.params.fsGroup.rule == "MayRunAs" )? variables.nonExemptContainers.filter(container, (!has(container.securityContext) || !has(container.securityContext.fsGroup)) && variables.podFsGroup == null).map(container, "Container " + container.name + " is attempting to run without a required securityContext/fsGroup. Allowed fsGroup: {ranges: [" + variables.params.fsGroup.ranges.map(range, "{max: " + string(range.max) + ", min: " + string(range.min) + "}").join(", ") + ", rule: " + variables.params.fsGroup.rule + "}") + variables.nonExemptContainers.filter(container, (has(container.securityContext) && has(container.securityContext.fsGroup)) ? !variables.params.fsGroup.ranges.exists(range, container.securityContext.fsGroup >= range.min && container.securityContext.fsGroup <= range.max) : variables.podFsGroup != null && !variables.params.fsGroup.ranges.exists(range, variables.podFsGroup >= range.min && variables.podFsGroup <= range.max)).map(container, "Container " + container.name + " is attempting to run as disallowed fsGroup. Allowed fsGroup: {ranges: [" + variables.params.fsGroup.ranges.map(range, "{max: " + string(range.max) + ", min: " + string(range.min) + "}").join(", ") + ", rule: " + variables.params.fsGroup.rule + "}") : [] + has(variables.params.fsGroup) && has(variables.params.fsGroup.rule) && (variables.params.fsGroup.rule == "MustRunAs" || variables.params.fsGroup.rule == "MayRunAs" ) ? + variables.nonExemptContainers.filter(container, + (!has(container.securityContext) || !has(container.securityContext.fsGroup)) && variables.podFsGroup == null + ).map(container, + "Container " + container.name + " is attempting to run without a required securityContext/fsGroup. Allowed fsGroup: {ranges: [" + + variables.params.fsGroup.ranges.map(range, "{max: " + string(range.max) + ", min: " + string(range.min) + "}").join(", ") + + ", rule: " + variables.params.fsGroup.rule + "}" + ) + + variables.nonExemptContainers.filter(container, (has(container.securityContext) && has(container.securityContext.fsGroup)) ? + !variables.params.fsGroup.ranges.exists(range, + container.securityContext.fsGroup >= range.min && container.securityContext.fsGroup <= range.max) : + variables.podFsGroup != null && !variables.params.fsGroup.ranges.exists(range, + variables.podFsGroup >= range.min && variables.podFsGroup <= range.max) + ).map(container, "Container " + container.name + " is attempting to run as disallowed fsGroup. Allowed fsGroup: {ranges: [" + + variables.params.fsGroup.ranges.map(range, "{max: " + string(range.max) + ", min: " + string(range.min) + "}").join(", ") + + ", rule: " + variables.params.fsGroup.rule + "}") + : [] - name: violatingMustOrMayRunAsSupplementalGroups expression: | - has(variables.params.supplementalGroups) && has(variables.params.supplementalGroups.rule) && (variables.params.supplementalGroups.rule == "MustRunAs" || variables.params.supplementalGroups.rule == "MayRunAs") ? variables.nonExemptContainers.filter(container, (!has(container.securityContext) || !has(container.securityContext.supplementalGroups)) && variables.podSupplementalGroups == null).map(container, "Container " + container.name + " is attempting to run without a required securityContext/supplementalGroups. Allowed supplementalGroups: {ranges: [" + variables.params.supplementalGroups.ranges.map(range, "{max: " + string(range.max) + ", min: " + string(range.min) + "}").join(", ") + ", rule: " + variables.params.supplementalGroups.rule + "}") + variables.nonExemptContainers.filter(container, (has(container.securityContext) && has(container.securityContext.supplementalGroups)) ? !variables.params.supplementalGroups.ranges.exists(range, container.securityContext.supplementalGroups.all(gp, gp >= range.min && gp <= range.max)) : variables.podSupplementalGroups != null && !variables.params.supplementalGroups.ranges.exists(range, variables.podSupplementalGroups.all(gp, gp >= range.min && gp <= range.max))).map(container, "Container " + container.name + " is attempting to run with disallowed supplementalGroups. Allowed supplementalGroups: {ranges: [" + variables.params.supplementalGroups.ranges.map(range, "{max: " + string(range.max) + ", min: " + string(range.min) + "}").join(", ") + ", rule: " + variables.params.supplementalGroups.rule + "}") : [] + has(variables.params.supplementalGroups) && has(variables.params.supplementalGroups.rule) && (variables.params.supplementalGroups.rule == "MustRunAs" || variables.params.supplementalGroups.rule == "MayRunAs") ? + variables.nonExemptContainers.filter(container, + (!has(container.securityContext) || !has(container.securityContext.supplementalGroups)) && variables.podSupplementalGroups == null + ).map(container, + "Container " + container.name + " is attempting to run without a required securityContext/supplementalGroups. Allowed supplementalGroups: {ranges: [" + + variables.params.supplementalGroups.ranges.map(range, "{max: " + string(range.max) + ", min: " + string(range.min) + "}").join(", ") + + ", rule: " + variables.params.supplementalGroups.rule + "}" + ) + + variables.nonExemptContainers.filter(container, + (has(container.securityContext) && has(container.securityContext.supplementalGroups)) ? + !variables.params.supplementalGroups.ranges.exists(range, + container.securityContext.supplementalGroups.all(gp, gp >= range.min && gp <= range.max)) : + variables.podSupplementalGroups != null && !variables.params.supplementalGroups.ranges.exists(range, + variables.podSupplementalGroups.all(gp, gp >= range.min && gp <= range.max)) + ).map(container, + "Container " + container.name + " is attempting to run with disallowed supplementalGroups. Allowed supplementalGroups: {ranges: [" + + variables.params.supplementalGroups.ranges.map(range, "{max: " + string(range.max) + ", min: " + string(range.min) + "}").join(", ") + + ", rule: " + variables.params.supplementalGroups.rule + "}") + : [] - name: violatingMustRunAsNonRoot expression: | - variables.nonExemptContainers.filter(container, (has(variables.params.runAsUser) && has(variables.params.runAsUser.rule) && variables.params.runAsUser.rule == "MustRunAsNonRoot") && (!has(container.securityContext) || (!has(container.securityContext.runAsNonRoot) || !container.securityContext.runAsNonRoot) && (!has(container.securityContext.runAsUser) || container.securityContext.runAsUser == 0)) && variables.missingRunAsNonRootGlobal).map(container, "Container " + container.name + " is attempting to run without a required securityContext/runAsNonRoot or securityContext/runAsUser != 0") + variables.nonExemptContainers.filter(container, + (has(variables.params.runAsUser) && has(variables.params.runAsUser.rule) && variables.params.runAsUser.rule == "MustRunAsNonRoot") && + (!has(container.securityContext) || (!has(container.securityContext.runAsNonRoot) || !container.securityContext.runAsNonRoot) && + (!has(container.securityContext.runAsUser) || container.securityContext.runAsUser == 0)) && variables.missingRunAsNonRootGlobal + ).map(container, + "Container " + container.name + " is attempting to run without a required securityContext/runAsNonRoot or securityContext/runAsUser != 0") - name: violations expression: | - variables.violatingMustRunAsNonRoot + variables.violatingMustOrMayRunAsUser + variables.violatingMustOrMayRunAsGroup + variables.violatingMustOrMayRunAsFsGroup + variables.violatingMustOrMayRunAsSupplementalGroups + variables.violatingMustRunAsNonRoot + + variables.violatingMustOrMayRunAsUser + + variables.violatingMustOrMayRunAsGroup + + variables.violatingMustOrMayRunAsFsGroup + + variables.violatingMustOrMayRunAsSupplementalGroups validations: - expression: '(has(request.operation) && request.operation == "UPDATE") || size(variables.violations) == 0' messageExpression: 'variables.violations.join(", ")' @@ -304,7 +384,6 @@ spec: # 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 }