From 781e38bb43eb7a3ea98d434fd2210473285f0433 Mon Sep 17 00:00:00 2001 From: Seth Malaki Date: Mon, 15 Jun 2026 09:48:52 +0100 Subject: [PATCH] fix(crds): install applicationlayer WAF CRDs in both CRD modes The applicationlayer.projectcalico.org WAF CRDs (WAFPolicy, GlobalWAFPolicy, WAFPlugin, GlobalWAFPlugin, WAFValidationPolicy, GlobalWAFValidationPolicy) were bundled into the v3.projectcalico.org datastore CRD source directory, so the operator installed them only in v3-CRD mode. On a standard apiserver-backed install the operator runs in v1-CRD mode and skipped them entirely, and the aggregated apiserver does not serve the applicationlayer.projectcalico.org group, so the kinds were unavailable and the kube-controllers WAF reconcilers could not start their informers. Gateway WAF was therefore unusable on any standard install. applicationlayer.projectcalico.org is a distinct, CRD-only API group with a single v3 schema (not the crd.projectcalico.org <-> projectcalico.org rename), so it is now handled the same way as policy.networking.k8s.io: synced into its own CRD source directory and installed unconditionally in both v1-CRD and v3-CRD modes via a dedicated getApplicationLayerCRDSource(). (cherry picked from commit 9595dc98edb8e1a5bb2f2557cc7ad973a4df373c) --- Makefile | 8 +++++ pkg/imports/crds/crds.go | 30 ++++++++++++++++++- pkg/imports/crds/crds_test.go | 19 ++++++++++++ ...er.projectcalico.org_globalwafplugins.yaml | 0 ...r.projectcalico.org_globalwafpolicies.yaml | 0 ...alico.org_globalwafvalidationpolicies.yaml | 0 ...ionlayer.projectcalico.org_wafplugins.yaml | 0 ...onlayer.projectcalico.org_wafpolicies.yaml | 0 ...ojectcalico.org_wafvalidationpolicies.yaml | 0 9 files changed, 56 insertions(+), 1 deletion(-) rename pkg/imports/crds/enterprise/{v3.projectcalico.org => applicationlayer.projectcalico.org}/applicationlayer.projectcalico.org_globalwafplugins.yaml (100%) rename pkg/imports/crds/enterprise/{v3.projectcalico.org => applicationlayer.projectcalico.org}/applicationlayer.projectcalico.org_globalwafpolicies.yaml (100%) rename pkg/imports/crds/enterprise/{v3.projectcalico.org => applicationlayer.projectcalico.org}/applicationlayer.projectcalico.org_globalwafvalidationpolicies.yaml (100%) rename pkg/imports/crds/enterprise/{v3.projectcalico.org => applicationlayer.projectcalico.org}/applicationlayer.projectcalico.org_wafplugins.yaml (100%) rename pkg/imports/crds/enterprise/{v3.projectcalico.org => applicationlayer.projectcalico.org}/applicationlayer.projectcalico.org_wafpolicies.yaml (100%) rename pkg/imports/crds/enterprise/{v3.projectcalico.org => applicationlayer.projectcalico.org}/applicationlayer.projectcalico.org_wafvalidationpolicies.yaml (100%) diff --git a/Makefile b/Makefile index 25b738e59e..eb14417b9d 100644 --- a/Makefile +++ b/Makefile @@ -412,6 +412,7 @@ deploy-crds: kubectl $(BINDIR)/kubectl apply -f pkg/imports/crds/calico/policy.networking.k8s.io/ && \ $(BINDIR)/kubectl apply -f pkg/imports/crds/enterprise/v1.crd.projectcalico.org/ && \ $(BINDIR)/kubectl apply -f pkg/imports/crds/enterprise/policy.networking.k8s.io/ && \ + $(BINDIR)/kubectl apply -f pkg/imports/crds/enterprise/applicationlayer.projectcalico.org/ && \ $(BINDIR)/kubectl apply -f pkg/imports/crds/enterprise/01-crd-eck-bundle.yaml && \ $(BINDIR)/kubectl create -f deploy/crds/prometheus @@ -634,6 +635,7 @@ define prep_local_crds mkdir -p pkg/imports/crds/$(product)/v1.crd.projectcalico.org/ mkdir -p pkg/imports/crds/$(product)/v3.projectcalico.org/ mkdir -p pkg/imports/crds/$(product)/policy.networking.k8s.io/ + mkdir -p pkg/imports/crds/$(product)/applicationlayer.projectcalico.org/ mkdir -p pkg/imports/admission/$(product) mkdir -p .crds/$(product) endef @@ -663,6 +665,11 @@ define copy_k8s_policy_crds @mv pkg/imports/crds/$(product)/v1.crd.projectcalico.org/policy.networking.k8s.io_* pkg/imports/crds/$(product)/policy.networking.k8s.io/ 2>/dev/null; true @echo "Moved $(product) K8s policy CRDs to dedicated directory" endef +define copy_applicationlayer_crds + $(eval product := $(1)) + @mv pkg/imports/crds/$(product)/v3.projectcalico.org/applicationlayer.projectcalico.org_* pkg/imports/crds/$(product)/applicationlayer.projectcalico.org/ 2>/dev/null; true + @echo "Moved $(product) ApplicationLayer CRDs to dedicated directory" +endef define copy_eck_crds $(eval dir := $(1)) $(eval product := $(2)) @@ -713,6 +720,7 @@ update-enterprise-crds: fetch-enterprise-crds $(call copy_v1_crds,$(ENTERPRISE_CRDS_DIR),"enterprise") $(call copy_v3_crds, $(ENTERPRISE_CRDS_DIR),"enterprise") $(call copy_k8s_policy_crds,"enterprise") + $(call copy_applicationlayer_crds,"enterprise") $(call copy_eck_crds,$(ENTERPRISE_CRDS_DIR),"enterprise") $(call copy_admission_policies,$(ENTERPRISE_CRDS_DIR),"enterprise") diff --git a/pkg/imports/crds/crds.go b/pkg/imports/crds/crds.go index 8f86dd2e91..255626f62a 100644 --- a/pkg/imports/crds/crds.go +++ b/pkg/imports/crds/crds.go @@ -147,6 +147,34 @@ func getK8sPolicyCRDSource(variant opv1.ProductVariant) map[string][]byte { return ret } +// getApplicationLayerCRDSource returns the applicationlayer.projectcalico.org CRDs +// (the gateway WAF kinds). This is a distinct, CRD-only API group that is not served +// by the aggregated apiserver and has a single v3 schema, so - unlike the +// projectcalico.org datastore CRDs - it is installed in both v1-CRD and v3-CRD modes. +// Enterprise only. +func getApplicationLayerCRDSource() map[string][]byte { + ret := map[string][]byte{} + dir := "enterprise/applicationlayer.projectcalico.org" + entries, err := enterpriseCRDFiles.ReadDir(dir) + if err != nil { + panic(fmt.Sprintf("Failed to read ApplicationLayer CRDs: %v", err)) + } + + for _, entry := range entries { + b, err := enterpriseCRDFiles.ReadFile(path.Join(dir, entry.Name())) + if err != nil { + panic(fmt.Sprintf("Failed to read ApplicationLayer CRD %s: %v", entry.Name(), err)) + } + + crds := bytes.Split(b, []byte("\n---")) + for i, crd := range crds { + ret[fmt.Sprintf("%s_%d", entry.Name(), i)] = crd + } + } + + return ret +} + func getOperatorCRDSource(variant opv1.ProductVariant) map[string][]byte { ret := map[string][]byte{} entries, err := operatorCRDFiles.ReadDir("operator") @@ -204,7 +232,7 @@ func GetCRDs(variant opv1.ProductVariant, v3 bool) []*apiextenv1.CustomResourceD crds = calicoCRDs } else { if len(enterpriseCRDs) == 0 { - enterpriseCRDs = convertYamlsToCRDs(getEnterpriseCRDSource(v3), getK8sPolicyCRDSource(variant), getOperatorCRDSource(variant)) + enterpriseCRDs = convertYamlsToCRDs(getEnterpriseCRDSource(v3), getK8sPolicyCRDSource(variant), getOperatorCRDSource(variant), getApplicationLayerCRDSource()) } crds = enterpriseCRDs } diff --git a/pkg/imports/crds/crds_test.go b/pkg/imports/crds/crds_test.go index b258ba0d77..083b3efb2a 100644 --- a/pkg/imports/crds/crds_test.go +++ b/pkg/imports/crds/crds_test.go @@ -63,6 +63,25 @@ var _ = Describe("test crds pkg", func() { Expect(crdNames).To(HaveKey("adminnetworkpolicies.policy.networking.k8s.io")) Expect(crdNames).To(HaveKey("baselineadminnetworkpolicies.policy.networking.k8s.io")) }) + + It(fmt.Sprintf("includes applicationlayer WAF CRDs for Enterprise in both CRD modes (v3=%t)", v3), func() { + enterpriseCRDs = nil + crds := GetCRDs(opv1.CalicoEnterprise, v3) + crdNames := map[string]bool{} + for _, crd := range crds { + crdNames[crd.Name] = true + } + // The applicationlayer.projectcalico.org group is CRD-only (not served by the + // aggregated apiserver) and has a single v3 schema, so its CRDs must install in + // both v1-CRD and v3-CRD modes - otherwise gateway WAF is unusable on standard + // apiserver-backed installs. + Expect(crdNames).To(HaveKey("wafpolicies.applicationlayer.projectcalico.org")) + Expect(crdNames).To(HaveKey("globalwafpolicies.applicationlayer.projectcalico.org")) + Expect(crdNames).To(HaveKey("wafplugins.applicationlayer.projectcalico.org")) + Expect(crdNames).To(HaveKey("globalwafplugins.applicationlayer.projectcalico.org")) + Expect(crdNames).To(HaveKey("wafvalidationpolicies.applicationlayer.projectcalico.org")) + Expect(crdNames).To(HaveKey("globalwafvalidationpolicies.applicationlayer.projectcalico.org")) + }) } It("can parse Operator CRDs used with calico", func() { diff --git a/pkg/imports/crds/enterprise/v3.projectcalico.org/applicationlayer.projectcalico.org_globalwafplugins.yaml b/pkg/imports/crds/enterprise/applicationlayer.projectcalico.org/applicationlayer.projectcalico.org_globalwafplugins.yaml similarity index 100% rename from pkg/imports/crds/enterprise/v3.projectcalico.org/applicationlayer.projectcalico.org_globalwafplugins.yaml rename to pkg/imports/crds/enterprise/applicationlayer.projectcalico.org/applicationlayer.projectcalico.org_globalwafplugins.yaml diff --git a/pkg/imports/crds/enterprise/v3.projectcalico.org/applicationlayer.projectcalico.org_globalwafpolicies.yaml b/pkg/imports/crds/enterprise/applicationlayer.projectcalico.org/applicationlayer.projectcalico.org_globalwafpolicies.yaml similarity index 100% rename from pkg/imports/crds/enterprise/v3.projectcalico.org/applicationlayer.projectcalico.org_globalwafpolicies.yaml rename to pkg/imports/crds/enterprise/applicationlayer.projectcalico.org/applicationlayer.projectcalico.org_globalwafpolicies.yaml diff --git a/pkg/imports/crds/enterprise/v3.projectcalico.org/applicationlayer.projectcalico.org_globalwafvalidationpolicies.yaml b/pkg/imports/crds/enterprise/applicationlayer.projectcalico.org/applicationlayer.projectcalico.org_globalwafvalidationpolicies.yaml similarity index 100% rename from pkg/imports/crds/enterprise/v3.projectcalico.org/applicationlayer.projectcalico.org_globalwafvalidationpolicies.yaml rename to pkg/imports/crds/enterprise/applicationlayer.projectcalico.org/applicationlayer.projectcalico.org_globalwafvalidationpolicies.yaml diff --git a/pkg/imports/crds/enterprise/v3.projectcalico.org/applicationlayer.projectcalico.org_wafplugins.yaml b/pkg/imports/crds/enterprise/applicationlayer.projectcalico.org/applicationlayer.projectcalico.org_wafplugins.yaml similarity index 100% rename from pkg/imports/crds/enterprise/v3.projectcalico.org/applicationlayer.projectcalico.org_wafplugins.yaml rename to pkg/imports/crds/enterprise/applicationlayer.projectcalico.org/applicationlayer.projectcalico.org_wafplugins.yaml diff --git a/pkg/imports/crds/enterprise/v3.projectcalico.org/applicationlayer.projectcalico.org_wafpolicies.yaml b/pkg/imports/crds/enterprise/applicationlayer.projectcalico.org/applicationlayer.projectcalico.org_wafpolicies.yaml similarity index 100% rename from pkg/imports/crds/enterprise/v3.projectcalico.org/applicationlayer.projectcalico.org_wafpolicies.yaml rename to pkg/imports/crds/enterprise/applicationlayer.projectcalico.org/applicationlayer.projectcalico.org_wafpolicies.yaml diff --git a/pkg/imports/crds/enterprise/v3.projectcalico.org/applicationlayer.projectcalico.org_wafvalidationpolicies.yaml b/pkg/imports/crds/enterprise/applicationlayer.projectcalico.org/applicationlayer.projectcalico.org_wafvalidationpolicies.yaml similarity index 100% rename from pkg/imports/crds/enterprise/v3.projectcalico.org/applicationlayer.projectcalico.org_wafvalidationpolicies.yaml rename to pkg/imports/crds/enterprise/applicationlayer.projectcalico.org/applicationlayer.projectcalico.org_wafvalidationpolicies.yaml