Skip to content

Commit

Permalink
feat(general/restrict-prioriy-classes): add a policy to allow for the…
Browse files Browse the repository at this point in the history
… restriction of priority classes. (#51)

* feat(general/restrict-prioriy-classes): add a policy to allow for the restriction of priority classes.

* fix: update names.

* fix: typo.

* fix: use an array.

* fix: comment out to fix ci.

* feat: add no priority class test.

* doc: add extra comments.
  • Loading branch information
Justin Bertrand authored Jun 28, 2023
1 parent 3748e8a commit 6b97721
Show file tree
Hide file tree
Showing 6 changed files with 172 additions and 24 deletions.
50 changes: 50 additions & 0 deletions general/restrict-priority-classes/examples/constraint.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
apiVersion: constraints.gatekeeper.sh/v1beta1
kind: RestrictPriorityClasses
metadata:
name: restrict-priority-classes-solution-critical
annotations:
kubernetes.io/description: |
Restricts the types of priority classes that can be used by solution builders of critical priority.
spec:
match:
kinds:
- apiGroups: [""]
kinds: ["Pod"]
namespaceSelector:
matchExpressions:
- key: project.statcan.gc.ca/purpose
operator: In
values: ["solution"]
- key: project.statcan.gc.ca/priority
operator: In
values: ["critical"]
parameters:
# The names of the priority classes that can be used.
priorityClassNames:
- 'business-value-medium'
- 'business-value-critical'
# ---
# apiVersion: constraints.gatekeeper.sh/v1beta1
# kind: RestrictPriorityClasses
# metadata:
# name: restrict-priority-classes-solution-medium
# annotations:
# kubernetes.io/description: |
# Restricts the types of priority classes that can be used by solution builders of medium priority.
# spec:
# match:
# kinds:
# - apiGroups: [""]
# kinds: ["Pod"]
# namespaceSelector:
# matchExpressions:
# - key: project.statcan.gc.ca/purpose
# operator: In
# values: ["solution"]
# - key: project.statcan.gc.ca/priority
# operator: In
# values: ["medium"]
# parameters:
# # The names of the priority classes that can be used.
# priorityClassNames:
# - 'business-value-medium'
12 changes: 12 additions & 0 deletions general/restrict-priority-classes/kustomization.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
# ----------------------------------------------------
# apiVersion and kind of Kustomization
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization

# Each entry in this list must resolve to an existing
# resource definition in YAML. These are the resource
# files that kustomize reads, modifies and emits as a
# YAML string, with resources separated by document
# markers ("---").
resources:
- template.yaml
16 changes: 16 additions & 0 deletions general/restrict-priority-classes/rego/src.rego
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
# This policy restricts the priority classes that
# can be used by Pods.
package restrictpriorityclasses

# Create a set of the priority class names
priority_class_names := {name | name := input.parameters.priorityClassNames[_]}

violation[{"msg": msg}] {
priority_class_name := input.review.object.spec.priorityClassName

# Check intersection of sets.
# If empty, is in violation.
priority_class_names & {priority_class_name} == set()

msg := sprintf("pod %s is using an unapproved priority class %q. Available priority classes are %v.", [input.review.object.metadata.name, priority_class_name, priority_class_names])
}
33 changes: 33 additions & 0 deletions general/restrict-priority-classes/rego/src_test.rego
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
package restrictpriorityclasses

names := ["priority-low", "priority-high"]

test_allowed_names {
priority_class_name := "priority-low"
pod_name := "test-pod"

result := violation with input.parameters.priorityClassNames as names with input.review.object.spec.priorityClassName as priority_class_name with input.review.object.metadata.name as pod_name

# No results mean there is no violation.
result == set()
}

test_unallowed_names {
priority_class_name := "priority-med"
pod_name := "test-pod"

result := violation with input.parameters.priorityClassNames as names with input.review.object.spec.priorityClassName as priority_class_name with input.review.object.metadata.name as pod_name

# A result means there is a violation.
result != set()
}

test_no_names {
priority_class_name := ""
pod_name := "test-pod"

result := violation with input.parameters.priorityClassNames as names with input.review.object.spec.priorityClassName as priority_class_name with input.review.object.metadata.name as pod_name

# A result means there is a violation.
result != set()
}
38 changes: 38 additions & 0 deletions general/restrict-priority-classes/template.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
apiVersion: templates.gatekeeper.sh/v1beta1
kind: ConstraintTemplate
metadata:
name: restrictpriorityclasses
annotations:
kubernetes.io/description: Restrict which priority classes can be used by a namespace.
spec:
crd:
spec:
names:
kind: RestrictPriorityClasses
validation:
openAPIV3Schema:
type: object
properties:
priorityClassNames:
type: array
items:
type: string
targets:
- target: admission.k8s.gatekeeper.sh
rego: |-
# This policy restricts the priority classes that
# can be used by Pods.
package restrictpriorityclasses
# Create a set of the priority class names
priority_class_names := {name | name := input.parameters.priorityClassNames[_]}
violation[{"msg": msg}] {
priority_class_name := input.review.object.spec.priorityClassName
# Check intersection of sets.
# If empty, is in violation.
priority_class_names & {priority_class_name} == set()
msg := sprintf("pod %s is using an unapproved priority class %q. Available priority classes are %v.", [input.review.object.metadata.name, priority_class_name, priority_class_names])
}
47 changes: 23 additions & 24 deletions pod-security-policy/metadata-restrictions/template.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ spec:
type: object
properties:
key:
description: "A key that maps to a value."
description: "A key that maps to a value."
type: string
fallback:
description: "Represents the default value for the key if one isn't chosen."
Expand Down Expand Up @@ -64,45 +64,44 @@ spec:
type: string
targets:
- target: admission.k8s.gatekeeper.sh
rego: |
rego: |-
package metadatarestrictions
same(a, b) {
a == b
a == b
}
# Allowed values
violation[{"msg": msg}] {
restriction := input.parameters[kind][_]
input.review.object.metadata[kind][restriction.key]
count(restriction.allowedValues) == 0
count(restriction.allowedRegex) == 0
msg := sprintf("%s %q not allowed", [kind, restriction.key])
restriction := input.parameters[kind][_]
input.review.object.metadata[kind][restriction.key]
count(restriction.allowedValues) == 0
count(restriction.allowedRegex) == 0
msg := sprintf("%s %q not allowed", [kind, restriction.key])
}
violation[{"msg": msg}] {
val := input.review.object.metadata[kind][key]
restriction := input.parameters[kind][_]
restriction.key == key
count(array.concat(restriction.allowedValues,restriction.allowedRegex)) > 0
foundValues := [foundValues | foundValues = restriction.allowedValues[_] == val]
foundRegex := [foundRegex | foundRegex = regex.match(restriction.allowedRegex[regex], val)]
not any(array.concat(foundValues,foundRegex))
val := input.review.object.metadata[kind][key]
restriction := input.parameters[kind][_]
restriction.key == key
count(array.concat(restriction.allowedValues,restriction.allowedRegex)) > 0
foundValues := [foundValues | foundValues = restriction.allowedValues[_] == val]
foundRegex := [foundRegex | foundRegex = regex.match(restriction.allowedRegex[regex], val)]
not any(array.concat(foundValues,foundRegex))
msg := sprintf("%s %q value %q not allowed, allowed values/regex: %v", [kind, key, val, array.concat(restriction.allowedValues,restriction.allowedRegex)])
msg := sprintf("%s %q value %q not allowed, allowed values/regex: %v", [kind, key, val, array.concat(restriction.allowedValues,restriction.allowedRegex)])
}
# Immutability
violation[{"msg": msg}] {
input.review.operation == "UPDATE"
input.review.operation == "UPDATE"
restriction := input.parameters[kind][_]
restriction.immutable
newval := object.get(input.review.object.metadata[kind], restriction.key, restriction.fallback)
oldval := object.get(input.review.oldObject.metadata[kind], restriction.key, restriction.fallback)
restriction := input.parameters[kind][_]
restriction.immutable
newval := object.get(input.review.object.metadata[kind], restriction.key, restriction.fallback)
oldval := object.get(input.review.oldObject.metadata[kind], restriction.key, restriction.fallback)
not same(newval, oldval)
not same(newval, oldval)
msg := sprintf("label %q is immutable: %q -> %q not permitted", [restriction.key, oldval, newval])
msg := sprintf("label %q is immutable: %q -> %q not permitted", [restriction.key, oldval, newval])
}

0 comments on commit 6b97721

Please sign in to comment.