From 2348432e13a8f89ca9cadbc6f6c135f24dcd21c8 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..ae8bc302cc --- /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 }}")) + + # 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 }}")) + + # 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 }}