Skip to content
Merged
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
2 changes: 1 addition & 1 deletion examples/envoy-ext-auth/Dockerfile
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
FROM golang:1.24.3 AS builder
FROM golang:1.24.9 AS builder

ARG GO_LDFLAGS=""

Expand Down
2 changes: 1 addition & 1 deletion examples/envoy-ext-auth/go.mod
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
module github.com/envoyproxy/gateway-grcp-ext-auth

go 1.24.3
go 1.24.9

require (
github.com/envoyproxy/go-control-plane/envoy v1.32.4
Expand Down
2 changes: 1 addition & 1 deletion examples/extension-server/go.mod
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
module github.com/exampleorg/envoygateway-extension

go 1.24.3
go 1.24.9

require (
github.com/envoyproxy/gateway v1.3.1
Expand Down
2 changes: 1 addition & 1 deletion examples/grpc-ext-proc/Dockerfile
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
FROM golang:1.24.3 AS builder
FROM golang:1.24.9 AS builder

ARG GO_LDFLAGS=""

Expand Down
2 changes: 1 addition & 1 deletion examples/grpc-ext-proc/go.mod
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
module github.com/envoyproxy/gateway-grpc-ext-proc

go 1.24.3
go 1.24.9

require (
github.com/envoyproxy/go-control-plane/envoy v1.32.4
Expand Down
2 changes: 1 addition & 1 deletion examples/preserve-case-backend/Dockerfile
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
FROM golang:1.24.3 AS builder
FROM golang:1.24.9 AS builder

ARG GO_LDFLAGS=""

Expand Down
2 changes: 1 addition & 1 deletion examples/preserve-case-backend/go.mod
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
module github.com/envoyproxy/gateway-preserve-case-backend

go 1.24.3
go 1.24.9

require github.com/valyala/fasthttp v1.61.0

Expand Down
2 changes: 1 addition & 1 deletion examples/simple-extension-server/Dockerfile
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
FROM golang:1.24.3 AS builder
FROM golang:1.24.9 AS builder

ARG GO_LDFLAGS=""

Expand Down
2 changes: 1 addition & 1 deletion examples/simple-extension-server/go.mod
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
module github.com/envoyproxy/gateway-simple-extension-server

go 1.24.3
go 1.24.9

require (
github.com/envoyproxy/gateway v1.3.2
Expand Down
2 changes: 1 addition & 1 deletion examples/static-file-server/Dockerfile
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
FROM golang:1.24.3 AS builder
FROM golang:1.24.9 AS builder

ARG GO_LDFLAGS=""

Expand Down
2 changes: 1 addition & 1 deletion examples/static-file-server/go.mod
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
module github.com/envoyproxy/static-file-server

go 1.24.3
go 1.24.9
5 changes: 4 additions & 1 deletion go.mod
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
module github.com/envoyproxy/gateway

go 1.24.3
go 1.24.9

// Replace the otelgrpc version because of k8s.io/client-go v0.33.3
replace go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.61.0 => go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.58.0

require (
fortio.org/fortio v1.69.4
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -189,6 +189,7 @@ xds:
typedConfig:
'@type': type.googleapis.com/envoy.extensions.filters.http.ratelimit.v3.RateLimit
domain: eag-ratelimit
disableXEnvoyRatelimitedHeader: true
failureModeDeny: true
rateLimitService:
grpcService:
Expand Down
30 changes: 21 additions & 9 deletions internal/gatewayapi/filters.go
Original file line number Diff line number Diff line change
Expand Up @@ -932,22 +932,34 @@ func (t *Translator) processRequestMirrorFilter(
return nil
}

// Get the route type from the filter context to determine the correct BackendRef type
routeType := GetRouteType(filterContext.Route)
weight := int32(1)
mirrorBackend := mirrorFilter.BackendRef

// Wrap the filter's BackendObjectReference into a BackendRef so we can use existing tooling to check it
weight := int32(1)
mirrorBackendRef := gwapiv1.HTTPBackendRef{
BackendRef: gwapiv1.BackendRef{
BackendObjectReference: mirrorBackend,
Weight: &weight,
},
// Create the appropriate BackendRef type based on the route type
var mirrorBackendRef BackendRefContext
if routeType == resource.KindGRPCRoute {
mirrorBackendRef = gwapiv1.GRPCBackendRef{
BackendRef: gwapiv1.BackendRef{
BackendObjectReference: mirrorBackend,
Weight: &weight,
},
}
} else {
mirrorBackendRef = gwapiv1.HTTPBackendRef{
BackendRef: gwapiv1.BackendRef{
BackendObjectReference: mirrorBackend,
Weight: &weight,
},
}
}

// This sets the status on the HTTPRoute, should the usage be changed so that the status message reflects that the backendRef is from the filter?
// This sets the status on the Route, should the usage be changed so that the status message reflects that the backendRef is from the filter?
filterNs := filterContext.Route.GetNamespace()
serviceNamespace := NamespaceDerefOr(mirrorBackend.Namespace, filterNs)
err = t.validateBackendRef(mirrorBackendRef, filterContext.Route,
resources, serviceNamespace, resource.KindHTTPRoute)
resources, serviceNamespace, routeType)
if err != nil {
return status.NewRouteStatusError(
fmt.Errorf("failed to validate the RequestMirror filter: %w", err), err.Reason()).WithType(gwapiv1.RouteConditionResolvedRefs)
Expand Down
35 changes: 22 additions & 13 deletions internal/gatewayapi/listener.go
Original file line number Diff line number Diff line change
Expand Up @@ -241,7 +241,7 @@ func checkOverlappingHostnames(httpsListeners []*ListenerContext) {
if httpsListeners[i].Port != httpsListeners[j].Port {
continue
}
if isOverlappingHostname(httpsListeners[i].Hostname, httpsListeners[j].Hostname) {
if areOverlappingHostnames(httpsListeners[i].Hostname, httpsListeners[j].Hostname) {
// Overlapping listeners can be more than two, we only report the first two for simplicity.
overlappingListeners[i] = &overlappingListener{
gateway1: httpsListeners[i].gateway,
Expand Down Expand Up @@ -393,7 +393,7 @@ type overlappingCertificate struct {
func isOverlappingCertificate(cert1DNSNames, cert2DNSNames []string) *overlappingCertificate {
for _, dns1 := range cert1DNSNames {
for _, dns2 := range cert2DNSNames {
if isOverlappingHostname(ptr.To(gwapiv1.Hostname(dns1)), ptr.To(gwapiv1.Hostname(dns2))) {
if areOverlappingHostnames(ptr.To(gwapiv1.Hostname(dns1)), ptr.To(gwapiv1.Hostname(dns2))) {
return &overlappingCertificate{
san1: dns1,
san2: dns2,
Expand All @@ -404,22 +404,31 @@ func isOverlappingCertificate(cert1DNSNames, cert2DNSNames []string) *overlappin
return nil
}

// isOverlappingHostname checks if two hostnames overlap.
func isOverlappingHostname(hostname1, hostname2 *gwapiv1.Hostname) bool {
if hostname1 == nil || hostname2 == nil {
func areOverlappingHostnames(this, other *gwapiv1.Hostname) bool {
if this == nil || other == nil {
return true
}
domain1 := strings.Replace(string(*hostname1), "*.", "", 1)
domain2 := strings.Replace(string(*hostname2), "*.", "", 1)
return isSubdomain(domain1, domain2) || isSubdomain(domain2, domain1)
return hostnameMatchesWithOther(this, other) || hostnameMatchesWithOther(other, this)
}

// isSubdomain checks if subDomain is a sub-domain of domain
func isSubdomain(subDomain, domain string) bool {
if subDomain == domain {
return true
// hostnameMatchesWithOther returns true if this hostname matches other hostname.
// Assumes that hostnames will either be fully qualified or a wildcard hostname prefixed with a single wildcard.
// E.g. "*.*.example.com" is not valid.
func hostnameMatchesWithOther(this, other *gwapiv1.Hostname) bool {
thisString := string(*this)
otherString := string(*other)
if hasWildcardPrefix(other) && !hasWildcardPrefix(this) {
return strings.HasSuffix(thisString, otherString[1:]) &&
!strings.Contains(strings.TrimSuffix(thisString, otherString[1:]), ".") // not a subdomain
}
return thisString == otherString
}

func hasWildcardPrefix(h *gwapiv1.Hostname) bool {
if h == nil {
return false
}
return strings.HasSuffix(subDomain, fmt.Sprintf(".%s", domain))
return len(string(*h)) > 1 && string(*h)[0] == '*'
}

func buildListenerMetadata(listener *ListenerContext, gateway *GatewayContext) *ir.ResourceMetadata {
Expand Down
29 changes: 17 additions & 12 deletions internal/gatewayapi/listener_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -95,7 +95,7 @@ func TestProxySamplingRate(t *testing.T) {
}
}

func TestIsOverlappingHostname(t *testing.T) {
func TestAreOverlappingHostnames(t *testing.T) {
tests := []struct {
name string
hostname1 *gwapiv1.Hostname
Expand All @@ -115,10 +115,10 @@ func TestIsOverlappingHostname(t *testing.T) {
want: true,
},
{
name: "two wildcards matches subdomain",
name: "two wildcards with subdomain does not match",
hostname1: ptr.To(gwapiv1.Hostname("*.example.com")),
hostname2: ptr.To(gwapiv1.Hostname("*.test.example.com")),
want: true,
want: false,
},
{
name: "nil hostname matches all",
Expand All @@ -139,22 +139,22 @@ func TestIsOverlappingHostname(t *testing.T) {
want: true,
},
{
name: "wildcard matches exact",
name: "wildcard matches exactly one level of subdomain",
hostname1: ptr.To(gwapiv1.Hostname("*.example.com")),
hostname2: ptr.To(gwapiv1.Hostname("test.example.com")),
want: true,
},
{
name: "wildcard matches subdomain",
name: "wildcard matches only one level of subdomain",
hostname1: ptr.To(gwapiv1.Hostname("*.example.com")),
hostname2: ptr.To(gwapiv1.Hostname("sub.test.example.com")),
want: true,
want: false,
},
{
name: "wildcard matches empty subdomain",
name: "wildcard does not match empty subdomain",
hostname1: ptr.To(gwapiv1.Hostname("*.example.com")),
hostname2: ptr.To(gwapiv1.Hostname("example.com")),
want: true,
want: false,
},
{
name: "different domains",
Expand All @@ -180,15 +180,21 @@ func TestIsOverlappingHostname(t *testing.T) {
hostname2: ptr.To(gwapiv1.Hostname("testing-api.foo.dev")),
want: false,
},
{
name: "sub domain does not match with parent domain",
hostname1: ptr.To(gwapiv1.Hostname("api.foo.dev")),
hostname2: ptr.To(gwapiv1.Hostname("foo.dev")),
want: false,
},
}

for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
if got := isOverlappingHostname(tt.hostname1, tt.hostname2); got != tt.want {
if got := areOverlappingHostnames(tt.hostname1, tt.hostname2); got != tt.want {
t.Errorf("isOverlappingHostname(%q, %q) = %v, want %v", ptr.Deref(tt.hostname1, ""), ptr.Deref(tt.hostname2, ""), got, tt.want)
}
// Test should be symmetric
if got := isOverlappingHostname(tt.hostname2, tt.hostname1); got != tt.want {
if got := areOverlappingHostnames(tt.hostname2, tt.hostname1); got != tt.want {
t.Errorf("isOverlappingHostname(%q, %q) = %v, want %v", ptr.Deref(tt.hostname2, ""), ptr.Deref(tt.hostname1, ""), got, tt.want)
}
})
Expand Down Expand Up @@ -301,15 +307,14 @@ func TestCheckOverlappingHostnames(t *testing.T) {
Name: "listener-3",
Protocol: gwapiv1.HTTPSProtocolType,
Port: 443,
Hostname: ptr.To(gwapiv1.Hostname("sub.test.example.com")),
Hostname: ptr.To(gwapiv1.Hostname("sub.test.example.com")), // sub domain does not match with parent domain
},
},
},
},
expected: map[int]string{
0: "test.example.com",
1: "*.example.com",
2: "*.example.com",
},
},
{
Expand Down
37 changes: 37 additions & 0 deletions internal/gatewayapi/testdata/grpcroute-with-mirror.in.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
gateways:
- apiVersion: gateway.networking.k8s.io/v1
kind: Gateway
metadata:
namespace: envoy-gateway
name: gateway-1
spec:
gatewayClassName: envoy-gateway-class
listeners:
- name: http
protocol: HTTP
port: 80
allowedRoutes:
namespaces:
from: All
grpcRoutes:
- apiVersion: gateway.networking.k8s.io/v1alpha2
kind: GRPCRoute
metadata:
namespace: default
name: grpcroute-1
spec:
parentRefs:
- namespace: envoy-gateway
name: gateway-1
sectionName: http
rules:
- backendRefs:
- name: service-1
port: 8080
filters:
- type: RequestMirror
requestMirror:
backendRef:
kind: Service
name: service-2
port: 8080
Loading