apiVersion: templates.gatekeeper.sh/v1 kind: ConstraintTemplate metadata: name: k8suniqueingresshost annotations: metadata.gatekeeper.sh/title: "Unique Ingress Host" metadata.gatekeeper.sh/version: 1.0.4 metadata.gatekeeper.sh/requires-sync-data: | "[ [ { "groups": ["extensions"], "versions": ["v1beta1"], "kinds": ["Ingress"] }, { "groups": ["networking.k8s.io"], "versions": ["v1beta1", "v1"], "kinds": ["Ingress"] } ] ]" description: >- Requires all Ingress rule hosts to be unique. Does not handle hostname wildcards: https://kubernetes.io/docs/concepts/services-networking/ingress/ spec: crd: spec: names: kind: K8sUniqueIngressHost targets: - target: admission.k8s.gatekeeper.sh rego: | package k8suniqueingresshost identical(obj, review) { obj.metadata.namespace == review.object.metadata.namespace obj.metadata.name == review.object.metadata.name } violation[{"msg": msg}] { input.review.kind.kind == "Ingress" regex.match("^(extensions|networking.k8s.io)$", input.review.kind.group) host := input.review.object.spec.rules[_].host other := data.inventory.namespace[_][otherapiversion]["Ingress"][name] regex.match("^(extensions|networking.k8s.io)/.+$", otherapiversion) other.spec.rules[_].host == host not identical(other, input.review) msg := sprintf("ingress host conflicts with an existing ingress <%v>", [host]) }