diff --git a/cluster/manifests/01-admission-control/hostname-policy.yaml b/cluster/manifests/01-admission-control/hostname-policy.yaml new file mode 100644 index 0000000000..36d069a361 --- /dev/null +++ b/cluster/manifests/01-admission-control/hostname-policy.yaml @@ -0,0 +1,56 @@ +# {{ if or (eq .Cluster.ConfigItems.ingresses_validation "enabled") (eq .Cluster.ConfigItems.routegroups_validation "enabled") }} +# {{ $hosted_zone_parent_domain := slice (split .Values.hosted_zone ".") 1 | join "." }} +apiVersion: admissionregistration.k8s.io/v1 +kind: ValidatingAdmissionPolicy +metadata: + name: hostname-policy.teapot.zalan.do + annotations: + kubernetes.io/description: | + Validates that Ingress and RouteGroup hosts are in {{ .Values.hosted_zone }} domain. +spec: + failurePolicy: Fail + matchConstraints: + resourceRules: + # {{ if eq .Cluster.ConfigItems.ingresses_validation "enabled" }} + - apiGroups: ["networking.k8s.io"] + apiVersions: ["v1"] + operations: ["CREATE", "UPDATE"] + resources: ["ingresses"] + # {{ end }} + # {{ if eq .Cluster.ConfigItems.routegroups_validation "enabled" }} + - apiGroups: ["zalando.org"] + apiVersions: ["v1"] + operations: ["CREATE", "UPDATE"] + resources: ["routegroups"] + # {{ end }} + matchConditions: + # exclude owned resources, e.g. created by StackSet and FabricGateway controllers. + - name: exclude-owned-resources + expression: | + !has(object.metadata.ownerReferences) + validations: + # {{ if eq .Cluster.ConfigItems.ingresses_validation "enabled" }} + - message: Ingress host must be in {{ .Values.hosted_zone }} domain + expression: | + object.kind == "Ingress" && + object.spec.rules + .exists(r, r.host.endsWith(".{{ $hosted_zone_parent_domain }}") && !r.host.endsWith(".{{ .Values.hosted_zone }}")) + reason: Invalid + # {{ end }} + # {{ if eq .Cluster.ConfigItems.routegroups_validation "enabled" }} + - message: RouteGroup host must be in {{ .Values.hosted_zone }} domain + expression: | + object.kind == "RouteGroup" && + object.spec.hosts + .exists(h, h.endsWith(".{{ $hosted_zone_parent_domain }}") && !h.endsWith(".{{ .Values.hosted_zone }}")) + reason: Invalid + # {{ end }} +--- +apiVersion: admissionregistration.k8s.io/v1 +kind: ValidatingAdmissionPolicyBinding +metadata: + name: hostname-policy-binding.teapot.zalan.do +spec: + policyName: hostname-policy.teapot.zalan.do + validationActions: [Deny] +# {{ end }} diff --git a/cluster/manifests/deletions.yaml b/cluster/manifests/deletions.yaml index 401057c9a8..fbe2cb5507 100644 --- a/cluster/manifests/deletions.yaml +++ b/cluster/manifests/deletions.yaml @@ -320,3 +320,10 @@ post_apply: kind: Service namespace: kube-system {{- end }} + +# {{ if and (ne .Cluster.ConfigItems.ingresses_validation "enabled") (ne .Cluster.ConfigItems.routegroups_validation "enabled") }} +- kind: ValidatingAdmissionPolicyBinding + name: hostname-policy-binding.teapot.zalan.do +- kind: ValidatingAdmissionPolicy + name: hostname-policy.teapot.zalan.do +# {{ end }}