Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
138 changes: 18 additions & 120 deletions pkg/render/gatewayapi/gateway_api.go
Original file line number Diff line number Diff line change
Expand Up @@ -419,7 +419,6 @@ type gatewayAPIImplementationComponent struct {
envoyGatewayImage string
envoyProxyImage string
envoyRatelimitImage string
wafHTTPFilterImage string
L7LogCollectorImage string

// Pre-rendered helm chart resources.
Expand Down Expand Up @@ -453,10 +452,6 @@ func (pr *gatewayAPIImplementationComponent) ResolveImages(is *operatorv1.ImageS
if err != nil {
return err
}
pr.wafHTTPFilterImage, err = components.GetReference(components.CombinedCalicoImage(pr.cfg.Installation), reg, path, prefix, is)
if err != nil {
return err
}
pr.L7LogCollectorImage, err = components.GetReference(components.ComponentGatewayL7Collector, reg, path, prefix, is)
if err != nil {
return err
Expand Down Expand Up @@ -927,42 +922,14 @@ func (pr *gatewayAPIImplementationComponent) envoyProxyConfig(className, ns stri
}
applyEnvoyProxyServiceOverrides(envoyProxy, classSpec.GatewayService)

// Setup WAF HTTP Filter and l7 Log collector on Enterprise.
// Inject the l7-log-collector init container on Enterprise so envoy access
// logs ship to felix. PMREQ-384 (2026-05-12 PM sign-off) deprecated the
// waf-http-filter ext_proc sidecar that used to live alongside it; the
// CRD-driven WASM data plane is the WAF enforcement path now.
if pr.cfg.Installation.Variant.IsEnterprise() {
// The WAF HTTP filter is not supported when the envoy proxy is deployed as a DaemonSet
// as there is no support for init containers in a DaemonSet.
// L7 log collector relies on init-container support, so DaemonSet
// providers are skipped (no init containers on a DaemonSet).
if envoyProxy.Spec.Provider.Kubernetes.EnvoyDeployment != nil {
// Add or update the Init Container to the deployment
wafHTTPFilter := corev1.Container{
Name: wafFilterName,
Image: pr.wafHTTPFilterImage,
Command: []string{components.CalicoBinaryPath, "component", "waf-http-filter"},
Args: []string{
"--logFileDirectory",
"/var/log/calico/waf",
"--logFileName",
"waf.log",
"--socketPath",
"/var/run/waf-http-filter/extproc.sock",
},
RestartPolicy: ptr.To(corev1.ContainerRestartPolicyAlways),
VolumeMounts: []corev1.VolumeMount{
{
Name: wafFilterName,
MountPath: "/var/run/waf-http-filter",
},
{
Name: "var-log-calico",
MountPath: "/var/log/calico",
},
},
Env: []corev1.EnvVar{
GatewayNameEnvVar,
GatewayNamespaceEnvVar,
},
SecurityContext: securitycontext.NewRootContext(true),
}
// need to make changes to the envoy container to mount the socket
l7LogCollector := corev1.Container{
Name: "l7-log-collector",
Image: pr.L7LogCollectorImage,
Expand Down Expand Up @@ -997,16 +964,8 @@ func (pr *gatewayAPIImplementationComponent) envoyProxyConfig(className, ns stri
SecurityContext: securitycontext.NewRootContext(true),
}

hasWAFHTTPFilter := false
hasL7LogCollector := false
for i, initContainer := range envoyProxy.Spec.Provider.Kubernetes.EnvoyDeployment.InitContainers {
if initContainer.Name == wafHTTPFilter.Name {
hasWAFHTTPFilter = true
// Handle update
if initContainer.Image != wafHTTPFilter.Image {
envoyProxy.Spec.Provider.Kubernetes.EnvoyDeployment.InitContainers[i] = wafHTTPFilter
}
}
if initContainer.Name == l7LogCollector.Name {
hasL7LogCollector = true
// Handle update
Expand All @@ -1019,68 +978,30 @@ func (pr *gatewayAPIImplementationComponent) envoyProxyConfig(className, ns stri
}
}
}
if !hasWAFHTTPFilter {
envoyProxy.Spec.Provider.Kubernetes.EnvoyDeployment.InitContainers = append(envoyProxy.Spec.Provider.Kubernetes.EnvoyDeployment.InitContainers, wafHTTPFilter)
}

if !hasL7LogCollector {
envoyProxy.Spec.Provider.Kubernetes.EnvoyDeployment.InitContainers = append(envoyProxy.Spec.Provider.Kubernetes.EnvoyDeployment.InitContainers, l7LogCollector)
}

accessLogsName := "access-logs"
// Add or update Container volume mount
wafSocketVolumeMount := corev1.VolumeMount{
Name: wafFilterName,
MountPath: "/var/run/waf-http-filter",
}

const accessLogsName = "access-logs"
l7SocketVolumeMount := corev1.VolumeMount{
Name: accessLogsName,
MountPath: "/access_logs",
}

hasWAFFilterSocketVolumeMount := false
hasAccessLogsVolumeMount := false

for i, volumeMount := range envoyProxy.Spec.Provider.Kubernetes.EnvoyDeployment.Container.VolumeMounts {
switch volumeMount.Name {
case wafSocketVolumeMount.Name:
hasWAFFilterSocketVolumeMount = true
if volumeMount.MountPath != wafSocketVolumeMount.MountPath {
envoyProxy.Spec.Provider.Kubernetes.EnvoyDeployment.Container.VolumeMounts[i] = wafSocketVolumeMount
}
case l7SocketVolumeMount.Name:
if volumeMount.Name == l7SocketVolumeMount.Name {
hasAccessLogsVolumeMount = true
if volumeMount.MountPath != l7SocketVolumeMount.MountPath {
envoyProxy.Spec.Provider.Kubernetes.EnvoyDeployment.Container.VolumeMounts[i] = l7SocketVolumeMount
}

}
}
if !hasWAFFilterSocketVolumeMount {
envoyProxy.Spec.Provider.Kubernetes.EnvoyDeployment.Container.VolumeMounts = append(envoyProxy.Spec.Provider.Kubernetes.EnvoyDeployment.Container.VolumeMounts, wafSocketVolumeMount)
}

if !hasAccessLogsVolumeMount {
envoyProxy.Spec.Provider.Kubernetes.EnvoyDeployment.Container.VolumeMounts = append(envoyProxy.Spec.Provider.Kubernetes.EnvoyDeployment.Container.VolumeMounts, l7SocketVolumeMount)
}

// Add or update Pod volumes
logsVolume := corev1.Volume{
VolumeSource: corev1.VolumeSource{
HostPath: &corev1.HostPathVolumeSource{
Path: "/var/log/calico",
Type: ptr.To(corev1.HostPathDirectoryOrCreate),
},
},
Name: "var-log-calico",
}
WAFHttpFilterSocketVolume := corev1.Volume{
VolumeSource: corev1.VolumeSource{
EmptyDir: &corev1.EmptyDirVolumeSource{},
},
Name: wafFilterName,
}
// Add or update Pod volumes.
AccessLogsVolume := []corev1.Volume{
{
VolumeSource: corev1.VolumeSource{
Expand All @@ -1097,23 +1018,8 @@ func (pr *gatewayAPIImplementationComponent) envoyProxyConfig(className, ns stri
Name: "felix-sync",
},
}
hasLogsVolume := false
hasSocketVolume := false
hasAccessLogsVolume := false
for i, volume := range envoyProxy.Spec.Provider.Kubernetes.EnvoyDeployment.Pod.Volumes {
if volume.Name == logsVolume.Name {
hasLogsVolume = true
// Handle update
if volume.HostPath.Path != logsVolume.HostPath.Path || volume.HostPath.Type != logsVolume.HostPath.Type {
envoyProxy.Spec.Provider.Kubernetes.EnvoyDeployment.Pod.Volumes[i] = logsVolume
}
}
if volume.Name == WAFHttpFilterSocketVolume.Name {
hasSocketVolume = true
if volume.EmptyDir != WAFHttpFilterSocketVolume.EmptyDir {
envoyProxy.Spec.Provider.Kubernetes.EnvoyDeployment.Pod.Volumes[i] = WAFHttpFilterSocketVolume
}
}
for _, acVolume := range AccessLogsVolume {
if volume.Name == acVolume.Name {
hasAccessLogsVolume = true
Expand All @@ -1122,20 +1028,16 @@ func (pr *gatewayAPIImplementationComponent) envoyProxyConfig(className, ns stri
}
}
}

}
if !hasLogsVolume {
envoyProxy.Spec.Provider.Kubernetes.EnvoyDeployment.Pod.Volumes = append(envoyProxy.Spec.Provider.Kubernetes.EnvoyDeployment.Pod.Volumes, logsVolume)
}
if !hasSocketVolume {
envoyProxy.Spec.Provider.Kubernetes.EnvoyDeployment.Pod.Volumes = append(envoyProxy.Spec.Provider.Kubernetes.EnvoyDeployment.Pod.Volumes, WAFHttpFilterSocketVolume)
}
if !hasAccessLogsVolume {
envoyProxy.Spec.Provider.Kubernetes.EnvoyDeployment.Pod.Volumes = append(envoyProxy.Spec.Provider.Kubernetes.EnvoyDeployment.Pod.Volumes, AccessLogsVolume...)
}

// Configure service account for WAF HTTP Filter license client
// Use EnvoyProxy patch mechanism to set serviceAccountName and automountServiceAccountToken
// Pin the proxy pod's identity to the per-namespace SA created in
// Objects() so l7-log-collector can read Gateway-API resources via
// the namespaced RoleBinding. Token-based license enforcement
// (previously done by the waf-http-filter sidecar) moved to the
// reconciler before EEP generation.
serviceAccountPatch := map[string]interface{}{
"spec": map[string]interface{}{
"template": map[string]interface{}{
Expand All @@ -1147,7 +1049,6 @@ func (pr *gatewayAPIImplementationComponent) envoyProxyConfig(className, ns stri
},
}

// Convert patch to JSON
patchBytes, err := json.Marshal(serviceAccountPatch)
if err == nil {
if envoyProxy.Spec.Provider.Kubernetes.EnvoyDeployment.Patch == nil {
Expand Down Expand Up @@ -1283,8 +1184,10 @@ const (
wafFilterGatewayResourcesRoleName = wafFilterName + "-gateway-resources"
)

// wafHttpFilterClusterScopedRole creates the ClusterRole granting access to cluster-scoped
// resources (license keys, token reviews) needed by every WAF HTTP Filter / L7 Log Collector.
// wafHttpFilterClusterScopedRole creates the ClusterRole granting access to
// cluster-scoped resources needed by the L7 Log Collector. The tokenreviews
// rule was dropped when the waf-http-filter sidecar was deprecated; license
// enforcement now happens at the reconciler before EEP generation.
func (pr *gatewayAPIImplementationComponent) wafHttpFilterClusterScopedRole() *rbacv1.ClusterRole {
return &rbacv1.ClusterRole{
TypeMeta: metav1.TypeMeta{Kind: "ClusterRole", APIVersion: "rbac.authorization.k8s.io/v1"},
Expand All @@ -1297,11 +1200,6 @@ func (pr *gatewayAPIImplementationComponent) wafHttpFilterClusterScopedRole() *r
Resources: []string{"licensekeys"},
Verbs: []string{"get", "watch"},
},
{
APIGroups: []string{"authentication.k8s.io"},
Resources: []string{"tokenreviews"},
Verbs: []string{"create"},
},
},
}
}
Expand Down
Loading