pkg/safeguards/lib/manifests/v2.0.0/unique-service-selectors/template.yaml (64 lines of code) (raw):
apiVersion: templates.gatekeeper.sh/v1beta1
kind: ConstraintTemplate
metadata:
name: k8sazurev1uniqueserviceselector
annotations:
metadata.gatekeeper.sh/title: "Unique Service Selectors"
metadata.gatekeeper.sh/version: 1.0.0
metadata.gatekeeper.sh/requires-sync-data: |
"[
[
{
"groups": [""],
"versions": ["v1"],
"kinds": ["Service"]
}
]
]"
description: >-
Requires Services to have unique selectors within a namespace.
Selectors are considered the same if they have identical keys and values.
Selectors may share a key/value pair so long as there is at least one
distinct key/value pair between them.
https://kubernetes.io/docs/concepts/services-networking/service/#defining-a-service
spec:
crd:
spec:
names:
kind: K8sAzureV1UniqueServiceSelector
targets:
- target: admission.k8s.gatekeeper.sh
rego: |
package k8sazurev1uniqueserviceselector
make_apiversion(kind) = apiVersion {
g := kind.group
v := kind.version
g != ""
apiVersion = sprintf("%s/%s", [g, v])
}
make_apiversion(kind) = apiVersion {
kind.group == ""
apiVersion = kind.version
}
identical(obj, review) {
obj.metadata.namespace == review.object.metadata.namespace
obj.metadata.name == review.object.metadata.name
obj.kind == review.kind.kind
obj.apiVersion == make_apiversion(review.kind)
}
flatten_selector(obj) = flattened {
selectors := [s | s = concat(":", [key, val]); val = obj.spec.selector[key]]
flattened := concat(",", sort(selectors))
}
violation[{"msg": msg}] {
input.review.kind.kind == "Service"
input.review.kind.version == "v1"
input.review.kind.group == ""
input_namespace := input.review.object.metadata.namespace
input_selector := flatten_selector(input.review.object)
other := data.inventory.namespace[input_namespace]["v1"].Service[_]
not identical(other, input.review)
other_selector := flatten_selector(other)
input_selector == other_selector
msg := sprintf("same selector as service <%s> in namespace <%s>", [other.metadata.name, input_namespace])
}