Unique Service Selector
An example OPA Gatekeeper policy that helps enforce a requirement where services must have globally unique selectors.
# Constraint Template
apiVersion: templates.gatekeeper.sh/v1beta1
kind: ConstraintTemplate
metadata:
name: k8suniqueserviceselector
spec:
crd:
spec:
names:
kind: K8sUniqueServiceSelector
targets:
- target: admission.k8s.gatekeeper.sh
rego: |
package k8suniqueserviceselector
make_apiversion(kind) = apiVersion {
g := kind.group
v := kind.version
g != ""
apiVersion = sprintf("%v/%v", [g, v])
}
make_apiversion(kind) = apiVersion {
kind.group == ""
apiVersion = kind.version
}
identical(obj, review) {
obj.metadata.namespace == review.namespace
obj.metadata.name == review.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_selector := flatten_selector(input.review.object)
other := data.inventory.namespace[namespace][_][_][name]
not identical(other, input.review)
other_selector := flatten_selector(other)
input_selector == other_selector
msg := sprintf("same selector as service <%v> in namespace <%v>", [name, namespace])
}
---
# Constraint
apiVersion: constraints.gatekeeper.sh/v1beta1
kind: K8sUniqueServiceSelector
metadata:
name: unique-service-selector
Note
For this policy to work, you need to enable data replication as described here