From 3ae69ac9c296d5d0d172874a5108eae95de67bba Mon Sep 17 00:00:00 2001 From: Alexander Yastrebov Date: Wed, 23 Oct 2024 14:13:30 +0200 Subject: [PATCH] admission-control: validate that Ingress and RouteGroup hosts in hosted zone domain Add ValidatingAdmissionPolicies that validates Ingress and RouteGroup hosts from hosted zone parent domain are in hosted zone domain. E.g. for hosted zone `foo.bar.test` its parent domain is `bar.test` and therefore Ingress and RouteGroup hosts from `bar.test` domain must also be in `foo.bar.test` domain. Signed-off-by: Alexander Yastrebov --- .../01-admission-control/host-policy.yaml | 93 +++++++++++++++++++ cluster/manifests/deletions.yaml | 14 +++ 2 files changed, 107 insertions(+) create mode 100644 cluster/manifests/01-admission-control/host-policy.yaml diff --git a/cluster/manifests/01-admission-control/host-policy.yaml b/cluster/manifests/01-admission-control/host-policy.yaml new file mode 100644 index 0000000000..0a16364d59 --- /dev/null +++ b/cluster/manifests/01-admission-control/host-policy.yaml @@ -0,0 +1,93 @@ +# {{ $hosted_zone_parent_domain := slice (split .Values.hosted_zone ".") 1 | join "." }} + +# {{ if eq .Cluster.ConfigItems.ingresses_validation "enabled" }} +--- +apiVersion: admissionregistration.k8s.io/v1 +kind: ValidatingAdmissionPolicy +metadata: + name: ingress-host-policy.teapot.zalan.do + annotations: + kubernetes.io/description: | + Validates that Ingress hosts from {{ $hosted_zone_parent_domain }} domain are in {{ .Values.hosted_zone }} domain. +spec: + failurePolicy: Fail + matchConstraints: + resourceRules: + - apiGroups: ["networking.k8s.io"] + apiVersions: ["v1"] + operations: ["CREATE", "UPDATE"] + resources: ["ingresses"] + matchConditions: + # exclude owned resources, e.g. created by StackSet and FabricGateway controllers. + - name: exclude-owned-resources + expression: | + !has(object.metadata.ownerReferences) + validations: + - expression: | + object.spec.rules + .map(r, r.host) + .filter(h, h.endsWith(".{{ $hosted_zone_parent_domain }}")) + .all(h, h.endsWith(".{{ .Values.hosted_zone }}")) + reason: Invalid + # show the first invalid host in the error message + messageExpression: | + "Ingress host must be in {{ .Values.hosted_zone }} domain but " + + object.spec.rules + .map(r, r.host) + .filter(h, h.endsWith(".{{ $hosted_zone_parent_domain }}")) + .filter(h, !h.endsWith(".{{ .Values.hosted_zone }}"))[0] + + " found" +--- +apiVersion: admissionregistration.k8s.io/v1 +kind: ValidatingAdmissionPolicyBinding +metadata: + name: ingress-host-policy-binding.teapot.zalan.do +spec: + policyName: ingress-host-policy.teapot.zalan.do + validationActions: [Deny] +# {{ end }} + +# {{ if eq .Cluster.ConfigItems.routegroups_validation "enabled" }} +--- +apiVersion: admissionregistration.k8s.io/v1 +kind: ValidatingAdmissionPolicy +metadata: + name: routegroup-host-policy.teapot.zalan.do + annotations: + kubernetes.io/description: | + Validates that RouteGroup hosts from {{ $hosted_zone_parent_domain }} domain are in {{ .Values.hosted_zone }} domain. +spec: + failurePolicy: Fail + matchConstraints: + resourceRules: + - apiGroups: ["zalando.org"] + apiVersions: ["v1"] + operations: ["CREATE", "UPDATE"] + resources: ["routegroups"] + matchConditions: + # exclude owned resources, e.g. created by StackSet and FabricGateway controllers. + - name: exclude-owned-resources + expression: | + !has(object.metadata.ownerReferences) + validations: + - expression: | + object.spec.hosts + .filter(h, h.endsWith(".{{ $hosted_zone_parent_domain }}")) + .all(h, h.endsWith(".{{ .Values.hosted_zone }}")) + reason: Invalid + # show the first invalid host in the error message + messageExpression: | + "RouteGroup host must be in {{ .Values.hosted_zone }} domain but " + + object.spec.hosts + .filter(h, h.endsWith(".{{ $hosted_zone_parent_domain }}")) + .filter(h, !h.endsWith(".{{ .Values.hosted_zone }}"))[0] + + " found" +--- +apiVersion: admissionregistration.k8s.io/v1 +kind: ValidatingAdmissionPolicyBinding +metadata: + name: routegroup-host-policy-binding.teapot.zalan.do +spec: + policyName: routegroup-host-policy.teapot.zalan.do + validationActions: [Deny] +# {{ end }} diff --git a/cluster/manifests/deletions.yaml b/cluster/manifests/deletions.yaml index 401057c9a8..980817f66d 100644 --- a/cluster/manifests/deletions.yaml +++ b/cluster/manifests/deletions.yaml @@ -320,3 +320,17 @@ post_apply: kind: Service namespace: kube-system {{- end }} + +# {{ if ne .Cluster.ConfigItems.ingresses_validation "enabled" }} +- kind: ValidatingAdmissionPolicyBinding + name: ingress-host-policy-binding.teapot.zalan.do +- kind: ValidatingAdmissionPolicy + name: ingress-host-policy.teapot.zalan.do +# {{ end }} + +# {{ if ne .Cluster.ConfigItems.routegroups_validation "enabled" }} +- kind: ValidatingAdmissionPolicyBinding + name: routegroup-host-policy-binding.teapot.zalan.do +- kind: ValidatingAdmissionPolicy + name: routegroup-host-policy.teapot.zalan.do +# {{ end }}