Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: gateway http listener isolation #4000

Merged
merged 1 commit into from
Aug 15, 2024
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
1 change: 0 additions & 1 deletion internal/gatewayapi/conformance/suite.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,6 @@ import (
// SkipTests is a list of tests that are skipped in the conformance suite.
var SkipTests = []suite.ConformanceTest{
tests.GatewayStaticAddresses,
tests.GatewayHTTPListenerIsolation, // https://github.com/envoyproxy/gateway/issues/3352
}

func skipTestsShortNames(skipTests []suite.ConformanceTest) []string {
Expand Down
45 changes: 35 additions & 10 deletions internal/gatewayapi/helpers.go
Original file line number Diff line number Diff line change
Expand Up @@ -262,12 +262,12 @@
return servicePort
}

// computeHosts returns a list of the intersecting hostnames between the route
// and the listener.
func computeHosts(routeHostnames []string, listenerHostname *gwapiv1.Hostname) []string {
// computeHosts returns a list of intersecting listener hostnames and route hostnames
// that don't intersect with other listener hostnames.
func computeHosts(routeHostnames []string, listenerContext *ListenerContext) []string {
var listenerHostnameVal string
if listenerHostname != nil {
listenerHostnameVal = string(*listenerHostname)
if listenerContext != nil && listenerContext.Hostname != nil {
listenerHostnameVal = string(*listenerContext.Hostname)
}

// No route hostnames specified: use the listener hostname if specified,
Expand All @@ -280,8 +280,9 @@
return []string{"*"}
}

var hostnames []string
hostnamesSet := map[string]struct{}{}

// Find intersecting hostnames
for i := range routeHostnames {
routeHostname := routeHostnames[i]

Expand All @@ -290,27 +291,51 @@
switch {
// No listener hostname: use the route hostname.
case len(listenerHostnameVal) == 0:
hostnames = append(hostnames, routeHostname)
hostnamesSet[routeHostname] = struct{}{}

// Listener hostname matches the route hostname: use it.
case listenerHostnameVal == routeHostname:
hostnames = append(hostnames, routeHostname)
hostnamesSet[routeHostname] = struct{}{}

// Listener has a wildcard hostname: check if the route hostname matches.
case strings.HasPrefix(listenerHostnameVal, "*"):
if hostnameMatchesWildcardHostname(routeHostname, listenerHostnameVal) {
hostnames = append(hostnames, routeHostname)
hostnamesSet[routeHostname] = struct{}{}
}

// Route has a wildcard hostname: check if the listener hostname matches.
case strings.HasPrefix(routeHostname, "*"):
if hostnameMatchesWildcardHostname(listenerHostnameVal, routeHostname) {
hostnames = append(hostnames, listenerHostnameVal)
hostnamesSet[listenerHostnameVal] = struct{}{}
}

}
}

// Filter out route hostnames that intersect with other listener hostnames
var listeners []*ListenerContext
if listenerContext != nil && listenerContext.gateway != nil {
listeners = listenerContext.gateway.listeners
}

for _, listener := range listeners {
if listenerContext == listener {
continue
}
if listenerContext != nil && listenerContext.Port != listener.Port {
continue

Check warning on line 326 in internal/gatewayapi/helpers.go

View check run for this annotation

Codecov / codecov/patch

internal/gatewayapi/helpers.go#L326

Added line #L326 was not covered by tests
}
if listener.Hostname == nil {
continue
}
delete(hostnamesSet, string(*listener.Hostname))
}

var hostnames []string
for host := range hostnamesSet {
hostnames = append(hostnames, host)
}

return hostnames
}

Expand Down
4 changes: 2 additions & 2 deletions internal/gatewayapi/route.go
Original file line number Diff line number Diff line change
Expand Up @@ -699,7 +699,7 @@ func (t *Translator) processHTTPRouteParentRefListener(route RouteContext, route
var hasHostnameIntersection bool

for _, listener := range parentRef.listeners {
hosts := computeHosts(GetHostnames(route), listener.Hostname)
hosts := computeHosts(GetHostnames(route), listener)
if len(hosts) == 0 {
continue
}
Expand Down Expand Up @@ -867,7 +867,7 @@ func (t *Translator) processTLSRouteParentRefs(tlsRoute *TLSRouteContext, resour

var hasHostnameIntersection bool
for _, listener := range parentRef.listeners {
hosts := computeHosts(GetHostnames(tlsRoute), listener.Hostname)
hosts := computeHosts(GetHostnames(tlsRoute), listener)
if len(hosts) == 0 {
continue
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
gateways:
- apiVersion: gateway.networking.k8s.io/v1
kind: Gateway
metadata:
name: gateway-1
namespace: envoy-gateway
spec:
gatewayClassName: envoy-gateway-class
listeners:
- name: empty-hostname
port: 80
protocol: HTTP
allowedRoutes:
namespaces:
from: All
- name: wildcard-example-com
port: 80
protocol: HTTP
hostname: "*.example.com"
allowedRoutes:
namespaces:
from: All
httpRoutes:
- apiVersion: gateway.networking.k8s.io/v1
kind: HTTPRoute
metadata:
name: httproute-1
namespace: envoy-gateway
spec:
parentRefs:
- name: gateway-1
namespace: envoy-gateway
sectionName: empty-hostname
hostnames:
- "bar.com"
- "*.example.com" # request matching is prevented by the isolation wildcard-example-com listener

Check warning on line 36 in internal/gatewayapi/testdata/gateway-http-listener-with-hostname-intersection.in.yaml

View workflow job for this annotation

GitHub Actions / lint

36:27 [comments] too few spaces before comment

Check warning on line 36 in internal/gatewayapi/testdata/gateway-http-listener-with-hostname-intersection.in.yaml

View workflow job for this annotation

GitHub Actions / lint

36:27 [comments] too few spaces before comment
rules:
- matches:
- path:
type: PathPrefix
value: /empty-hostname
backendRefs:
- name: service-1
port: 8080
- apiVersion: gateway.networking.k8s.io/v1
kind: HTTPRoute
metadata:
name: httproute-2
namespace: envoy-gateway
spec:
parentRefs:
- name: gateway-1
namespace: envoy-gateway
sectionName: wildcard-example-com
hostnames:
- "bar.com" # doesn't match wildcard-example-com listener

Check warning on line 56 in internal/gatewayapi/testdata/gateway-http-listener-with-hostname-intersection.in.yaml

View workflow job for this annotation

GitHub Actions / lint

56:21 [comments] too few spaces before comment

Check warning on line 56 in internal/gatewayapi/testdata/gateway-http-listener-with-hostname-intersection.in.yaml

View workflow job for this annotation

GitHub Actions / lint

56:21 [comments] too few spaces before comment
- "*.example.com"
rules:
- matches:
- path:
type: PathPrefix
value: /wildcard-example-com
backendRefs:
- name: service-1
port: 8080
Loading
Loading