Skip to content
45 changes: 45 additions & 0 deletions api/v1/gatewayapi_types.go
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,51 @@ type GatewayAPISpec struct {
// does not yet have any version of those CRDs.
// +optional
CRDManagement *CRDManagement `json:"crdManagement,omitempty"`

// Extensions enables and configures Tigera-built add-ons that sit on top of the
// Gateway API data plane. Each add-on is opt-in: an unset Extensions, an unset
// add-on field, and an empty add-on object all leave the add-on disabled.
// +optional
Extensions *GatewayAPIExtensions `json:"extensions,omitempty"`
}

// GatewayAPIExtensions enables and configures Tigera-built Gateway API add-ons.
type GatewayAPIExtensions struct {
// WAF enables and configures the Tigera Web Application Firewall (Coraza WASM
// + applicationlayer reconcilers). Default-off semantics: when WAF is nil,
// when WAF.State is nil, and when WAF.State is "Disabled", the operator does
// not render the WAF env vars or RBAC on calico-kube-controllers. Set
// WAF.State = "Enabled" to turn the feature on. See design
// `tigera/designs#25` (PMREQ-384) for the full surface.
// +optional
WAF *WAFExtensionSpec `json:"waf,omitempty"`
}

// WAFExtensionSpec configures the WAF Gateway API add-on.
type WAFExtensionSpec struct {
// State turns the WAF Gateway API add-on on or off. Default (nil or
// "Disabled") means the operator does not render the WAF surface on
// calico-kube-controllers. Set to "Enabled" to opt in.
// +optional
State *WAFExtensionState `json:"state,omitempty"`
}

// WAFExtensionState is the on/off enum for the WAF Gateway API add-on.
// +kubebuilder:validation:Enum=Enabled;Disabled
type WAFExtensionState string

const (
WAFExtensionStateEnabled WAFExtensionState = "Enabled"
WAFExtensionStateDisabled WAFExtensionState = "Disabled"
)

// IsWAFGatewayExtensionEnabled returns true iff spec.extensions.waf.state == Enabled.
// Unset Extensions, unset WAF, unset State, and explicit Disabled all return false.
func (s *GatewayAPISpec) IsWAFGatewayExtensionEnabled() bool {
if s == nil || s.Extensions == nil || s.Extensions.WAF == nil || s.Extensions.WAF.State == nil {
return false
}
return *s.Extensions.WAF.State == WAFExtensionStateEnabled
}

type GatewayClassSpec struct {
Expand Down
61 changes: 45 additions & 16 deletions api/v1/zz_generated.deepcopy.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 4 additions & 0 deletions pkg/common/common.go
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,10 @@ const (
EgressAccessControlFeature = "egress-access-control"
// PolicyRecommendation feature name
PolicyRecommendationFeature = "policy-recommendation"
// GatewayAddonsFeature gates Tigera-built add-ons that layer on top of an
// ingress gateway (currently the WAF v2/v3 admission webhook). The bare
// ingress gateway data path is NOT licensed by this feature.
GatewayAddonsFeature = "ingress-gateway-addons"
// MultipleOwnersLabel used to indicate multiple owner references.
// If the render code places this label on an object, the object mergeState machinery will merge owner
// references with any that already exist on the object rather than replace the owner references. Further
Expand Down
26 changes: 26 additions & 0 deletions pkg/components/enterprise.go
Original file line number Diff line number Diff line change
Expand Up @@ -162,6 +162,30 @@ var (
variant: enterpriseVariant,
}

ComponentCorazaWASM = Component{
Version: "master",
Image: "coraza-wasm",
Registry: "",
imagePath: "",
variant: enterpriseVariant,
}

ComponentQueryServer = Component{
Version: "master",
Image: "queryserver",
Registry: "",
imagePath: "",
variant: enterpriseVariant,
}

ComponentL7AdmissionController = Component{
Version: "master",
Image: "l7-admission-controller",
Registry: "",
imagePath: "",
variant: enterpriseVariant,
}

ComponentCoreOSPrometheus = Component{
Version: "v3.9.1",
variant: enterpriseVariant,
Expand Down Expand Up @@ -283,6 +307,8 @@ var (
ComponentGatewayL7Collector,
ComponentEnvoyProxy,
ComponentDikastes,
ComponentCorazaWASM,
ComponentQueryServer,
ComponentPrometheus,
ComponentPrometheusAlertmanager,
ComponentTigeraNode,
Expand Down
22 changes: 22 additions & 0 deletions pkg/controller/installation/core_controller.go
Original file line number Diff line number Diff line change
Expand Up @@ -213,6 +213,13 @@ func Add(mgr manager.Manager, opts options.ControllerOptions) error {
}

// Watch for changes to KubeControllersConfiguration.
// Watch GatewayAPI: spec.extensions.waf.state gates the WAF v3 surface on
// calico-kube-controllers. See design tigera/designs#25 (PMREQ-384) §Gating.
if err := c.WatchObject(&operatorv1.GatewayAPI{}, &handler.EnqueueRequestForObject{}); err != nil {
log.V(5).Info("Failed to create GatewayAPI watch", "err", err)
return fmt.Errorf("core-controller failed to watch operator GatewayAPI resource: %w", err)
}

err = c.WatchObject(&v3.KubeControllersConfiguration{}, &handler.EnqueueRequestForObject{})
if err != nil {
return fmt.Errorf("tigera-installation-controller failed to watch KubeControllersConfiguration resource: %w", err)
Expand Down Expand Up @@ -1595,6 +1602,20 @@ func (r *ReconcileInstallation) Reconcile(ctx context.Context, request reconcile
}
components = append(components, render.CSI(&csiCfg))

// Read the GatewayAPI CR (if present) to decide whether to render the WAF
// v3 (Gateway API add-on) surface — env vars, RBAC, applicationlayer
// reconciler — on calico-kube-controllers. Default-off: if no GatewayAPI
// CR exists or spec.extensions.waf.state != Enabled, the WAF surface is
// not rendered. See design tigera/designs#25 (PMREQ-384) §Gating.
wafGatewayExtensionEnabled := false
gatewayAPI := &operatorv1.GatewayAPI{}
if err := r.client.Get(ctx, utils.DefaultInstanceKey, gatewayAPI); err == nil {
wafGatewayExtensionEnabled = gatewayAPI.Spec.IsWAFGatewayExtensionEnabled()
} else if !apierrors.IsNotFound(err) {
r.status.SetDegraded(operatorv1.ResourceReadError, "Error reading GatewayAPI", err, reqLogger)
return reconcile.Result{}, err
}

// Build a configuration for rendering calico/kube-controllers.
kubeControllersCfg := kubecontrollers.KubeControllersConfiguration{
K8sServiceEp: k8sapi.Endpoint,
Expand All @@ -1609,6 +1630,7 @@ func (r *ReconcileInstallation) Reconcile(ctx context.Context, request reconcile
TrustedBundle: typhaNodeTLS.TrustedBundle,
Namespace: common.CalicoNamespace,
BindingNamespaces: []string{common.CalicoNamespace},
WAFGatewayExtensionEnabled: wafGatewayExtensionEnabled,
}
components = append(components, kubecontrollers.NewCalicoKubeControllers(&kubeControllersCfg))

Expand Down
26 changes: 26 additions & 0 deletions pkg/imports/crds/operator/operator.tigera.io_gatewayapis.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,32 @@ spec:
- name
- namespace
type: object
extensions:
description: |-
Extensions enables and configures Tigera-built add-ons that sit on top of the
Gateway API data plane. Each add-on is opt-in: an unset Extensions, an unset
add-on field, and an empty add-on object all leave the add-on disabled.
properties:
waf:
description: |-
WAF enables and configures the Tigera Web Application Firewall (Coraza WASM
+ applicationlayer reconcilers). Default-off semantics: when WAF is nil,
when WAF.State is nil, and when WAF.State is "Disabled", the operator does
not render the WAF env vars or RBAC on calico-kube-controllers. Set
WAF.State = "Enabled" to turn the feature on. See design
`tigera/designs#25` (PMREQ-384) for the full surface.
properties:
state:
description: |-
State turns the WAF Gateway API add-on on or off. Default (nil or
"Disabled") means the operator does not render the WAF surface on
calico-kube-controllers. Set to "Enabled" to opt in.
enum:
- Enabled
- Disabled
type: string
type: object
type: object
gatewayCertgenJob:
description: Allows customization of the gateway certgen job.
properties:
Expand Down
Loading
Loading