pkg/safeguards/lib/manifests/v1.0.0/disallowed-bad-pod-disruption-budgets/template.yaml (91 lines of code) (raw):
apiVersion: templates.gatekeeper.sh/v1beta1
kind: ConstraintTemplate
metadata:
name: k8sazurev1disallowedbadpoddisruptionbudgets
annotations:
metadata.gatekeeper.sh/title: "Pod Disruption Budget"
metadata.gatekeeper.sh/version: 1.0.0
metadata.gatekeeper.sh/requires-sync-data: |
"[
[
{
"groups": ["policy"],
"versions": ["v1"],
"kinds": ["PodDisruptionBudget"]
},
{
"groups": ["apps"],
"versions": ["v1"],
"kinds": ["StatefulSet", "ReplicaSet", "Deployment"]
}
]
]"
description: Prevents customers from applying bad Pod Disruption Budgets
spec:
crd:
spec:
names:
kind: K8sAzureV1DisallowedBadPodDisruptionBudgets
targets:
- target: admission.k8s.gatekeeper.sh
rego: |
package k8sazurev1disallowedbadpoddisruptionbudgets
violation[{"msg": msg}] {
input.review.kind.kind == "PodDisruptionBudget"
pdb := input.review.object
not valid_pdb_max_unavailable(pdb)
msg := sprintf(
"PodDisruptionBudget <%s> has maxUnavailable of 0, only positive integers are allowed for maxUnavailable",
[pdb.metadata.name]
)
}
violation[{"msg": msg}] {
obj := input.review.object
pdb := data.inventory.namespace[obj.metadata.namespace]["policy/v1"].PodDisruptionBudget[_]
obj.spec.selector.matchLabels == pdb.spec.selector.matchLabels
not valid_pdb_max_unavailable(pdb)
msg := sprintf(
"%s <%s> has been selected by PodDisruptionBudget <%s> but has maxUnavailable of 0, only positive integers are allowed for maxUnavailable",
[obj.kind, obj.metadata.name, pdb.metadata.name]
)
}
violation[{"msg": msg}] {
obj := input.review.object
pdb := data.inventory.namespace[obj.metadata.namespace]["policy/v1"].PodDisruptionBudget[_]
obj.spec.selector.matchLabels == pdb.spec.selector.matchLabels
not valid_pdb_min_available(obj, pdb)
msg := sprintf("%s <%s> has %d replica(s) but PodDisruptionBudget <%s> has minAvailable of %d, only positive integers less than %d are allowed for minAvailable",
[obj.kind, obj.metadata.name, obj.spec.replicas, pdb.metadata.name, pdb.spec.minAvailable, obj.spec.replicas])
}
violation[{"msg":msg}] {
input.review.kind.kind == "PodDisruptionBudget"
pdb := input.review.object
matchingDeploys := {x | x.spec.selector.matchLabels == pdb.spec.selector.matchLabels; x = data.inventory.namespace[pdb.metadata.namespace]["apps/v1"].Deployment[_]}
deploy := matchingDeploys[_]
not valid_pdb_min_available(deploy, pdb)
msg := sprintf("PodDisruptionBudget %s specifies minAvailable of %d, but matching Deployment %s has %d replicas. minAvailable should be less than %d",[pdb.metadata.name,pdb.spec.minAvailable,deploy.metadata.name,deploy.spec.replicas,deploy.spec.replicas])
}
violation[{"msg":msg}] {
input.review.kind.kind == "PodDisruptionBudget"
pdb := input.review.object
matchingSS := {x | x.spec.selector.matchLabels == pdb.spec.selector.matchLabels; x = data.inventory.namespace[pdb.metadata.namespace]["apps/v1"].StatefulSet[_]}
ss := matchingSS[_]
not valid_pdb_min_available(ss, pdb)
msg := sprintf("PodDisruptionBudget %s specifies minAvailable of %d, but matching StatefulSet %s has %d replicas. minAvailable should be less than %d",[pdb.metadata.name,pdb.spec.minAvailable,ss.metadata.name,ss.spec.replicas,ss.spec.replicas])
}
violation[{"msg":msg}] {
input.review.kind.kind == "PodDisruptionBudget"
pdb := input.review.object
matchingRS := {x | x.spec.selector.matchLabels == pdb.spec.selector.matchLabels; x = data.inventory.namespace[pdb.metadata.namespace]["apps/v1"].ReplicaSet[_]}
rs := matchingRS[_]
not valid_pdb_min_available(rs, pdb)
msg := sprintf("PodDisruptionBudget %s specifies minAvailable of %d, but matching ReplicaSet %s has %d replicas. minAvailable should be less than %d",[pdb.metadata.name,pdb.spec.minAvailable,rs.metadata.name,rs.spec.replicas,rs.spec.replicas])
}
valid_pdb_min_available(obj, pdb) {
# default to -1 if minAvailable is not set so valid_pdb_min_available is always true
# for objects with >= 0 replicas. If minAvailable defaults to >= 0, objects with
# replicas field might violate this constraint if they are equal to the default set here
min_available := object.get(pdb.spec, "minAvailable", -1)
obj.spec.replicas > min_available
}
valid_pdb_max_unavailable(pdb) {
# default to 1 if maxUnavailable is not set so valid_pdb_max_unavailable always returns true.
# If maxUnavailable defaults to 0, it violates this constraint because all pods needs to be
# available and no pods can be evicted voluntarily
max_unavailable := object.get(pdb.spec, "maxUnavailable", 1)
max_unavailable > 0
}