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
61 changes: 46 additions & 15 deletions internal/gatewayapi/filters.go
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ type HTTPFiltersTranslator interface {
processRedirectFilter(filter v1beta1.HTTPRouteFilter, filterContext *HTTPFiltersContext)
processRequestHeaderModifierFilter(filter v1beta1.HTTPRouteFilter, filterContext *HTTPFiltersContext)
processResponseHeaderModifierFilter(filter v1beta1.HTTPRouteFilter, filterContext *HTTPFiltersContext)
processUnknownHTTPFilter(filter v1beta1.HTTPRouteFilter, filterContext *HTTPFiltersContext)
processExtensionRefHTTPFilter(filter v1beta1.HTTPRouteFilter, filterContext *HTTPFiltersContext, resources *Resources)
processUnsupportedHTTPFilter(filter v1beta1.HTTPRouteFilter, filterContext *HTTPFiltersContext)
}

Expand All @@ -52,19 +52,27 @@ type HTTPFilterChains struct {
}

// ProcessHTTPFilters translate gateway api http filters to IRs.
func (t *Translator) ProcessHTTPFilters(parentRef *RouteParentContext, httpRoute *HTTPRouteContext, filters []v1beta1.HTTPRouteFilter) *HTTPFiltersContext {
func (t *Translator) ProcessHTTPFilters(parentRef *RouteParentContext,
httpRoute *HTTPRouteContext,
filters []v1beta1.HTTPRouteFilter,
resources *Resources) *HTTPFiltersContext {
httpFiltersContext := &HTTPFiltersContext{
ParentRef: parentRef,
HTTPRoute: httpRoute,

HTTPFilterChains: &HTTPFilterChains{},
}

for _, filter := range filters {
for i := range filters {
filter := filters[i]
// If an invalid filter type has been configured then skip processing any more filters
if httpFiltersContext.DirectResponse != nil {
break
}
if err := ValidateHTTPRouteFilter(&filter); err != nil {
t.processInvalidHTTPFilter(filter, httpFiltersContext, err)
break
}

switch filter.Type {
case v1beta1.HTTPRouteFilterURLRewrite:
Expand All @@ -76,7 +84,7 @@ func (t *Translator) ProcessHTTPFilters(parentRef *RouteParentContext, httpRoute
case v1beta1.HTTPRouteFilterResponseHeaderModifier:
t.processResponseHeaderModifierFilter(filter, httpFiltersContext)
case v1beta1.HTTPRouteFilterExtensionRef:
t.processUnknownHTTPFilter(filter, httpFiltersContext)
t.processExtensionRefHTTPFilter(filter, httpFiltersContext, resources)
default:
t.processUnsupportedHTTPFilter(filter, httpFiltersContext)
}
Expand Down Expand Up @@ -599,12 +607,38 @@ func (t *Translator) processResponseHeaderModifierFilter(
}
}

func (t *Translator) processUnknownHTTPFilter(
filter v1beta1.HTTPRouteFilter,
filterContext *HTTPFiltersContext) {
// "If a reference to a custom filter type cannot be resolved, the filter MUST NOT be skipped.
// Instead, requests that would have been processed by that filter MUST receive a HTTP error response."
errMsg := fmt.Sprintf("Unknown custom filter type: %s", filter.Type)
func (t *Translator) processExtensionRefHTTPFilter(filter v1beta1.HTTPRouteFilter, filterContext *HTTPFiltersContext, resources *Resources) {
// If a reference to a custom filter type cannot be resolved, the filter MUST NOT be skipped.
// Instead, requests that would have been processed by that filter MUST receive an HTTP error
// response.
found := false

for _, f := range resources.AuthenFilters {
if f.Namespace == filterContext.HTTPRoute.Namespace && f.Name == string(filter.ExtensionRef.Name) {
found = true
break
}
}

if !found {
errMsg := fmt.Sprintf("Reference not found for filter type: %s", filter.Type)
// Reset the conditions in case the Accepted=True condition exists.
filterContext.ParentRef.ResetConditions(filterContext.HTTPRoute)
filterContext.ParentRef.SetCondition(filterContext.HTTPRoute,
v1beta1.RouteConditionResolvedRefs,
metav1.ConditionFalse,
v1beta1.RouteReasonBackendNotFound,
errMsg,
)
filterContext.DirectResponse = &ir.DirectResponse{
Body: &errMsg,
StatusCode: 500,
}
}
}

func (t *Translator) processUnsupportedHTTPFilter(filter v1beta1.HTTPRouteFilter, filterContext *HTTPFiltersContext) {
errMsg := fmt.Sprintf("Unsupported filter type: %s", filter.Type)
filterContext.ParentRef.SetCondition(filterContext.HTTPRoute,
v1beta1.RouteConditionAccepted,
metav1.ConditionFalse,
Expand All @@ -617,11 +651,8 @@ func (t *Translator) processUnknownHTTPFilter(
}
}

func (t *Translator) processUnsupportedHTTPFilter(
filter v1beta1.HTTPRouteFilter,
filterContext *HTTPFiltersContext) {
// Unsupported filters.
errMsg := fmt.Sprintf("Unsupported filter type: %s", filter.Type)
func (t *Translator) processInvalidHTTPFilter(filter v1beta1.HTTPRouteFilter, filterContext *HTTPFiltersContext, err error) {
errMsg := fmt.Sprintf("Invalid filter %s: %v", filter.Type, err)
filterContext.ParentRef.SetCondition(filterContext.HTTPRoute,
v1beta1.RouteConditionAccepted,
metav1.ConditionFalse,
Expand Down
2 changes: 1 addition & 1 deletion internal/gatewayapi/route.go
Original file line number Diff line number Diff line change
Expand Up @@ -88,7 +88,7 @@ func (t *Translator) processHTTPRouteRules(httpRoute *HTTPRouteContext, parentRe

// compute matches, filters, backends
for ruleIdx, rule := range httpRoute.Spec.Rules {
httpFiltersContext := t.ProcessHTTPFilters(parentRef, httpRoute, rule.Filters)
httpFiltersContext := t.ProcessHTTPFilters(parentRef, httpRoute, rule.Filters, resources)

// A rule is matched if any one of its matches
// is satisfied (i.e. a logical "OR"), so generate
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
gateways:
- apiVersion: gateway.networking.k8s.io/v1beta1
kind: Gateway
metadata:
namespace: envoy-gateway
name: gateway-1
spec:
gatewayClassName: envoy-gateway-class
listeners:
- name: http
protocol: HTTP
port: 80
hostname: "*.envoyproxy.io"
allowedRoutes:
namespaces:
from: All
httpRoutes:
- apiVersion: gateway.networking.k8s.io/v1beta1
kind: HTTPRoute
metadata:
namespace: default
name: httproute-1
spec:
hostnames:
- gateway.envoyproxy.io
parentRefs:
- namespace: envoy-gateway
name: gateway-1
sectionName: http
rules:
- matches:
- path:
value: "/"
backendRefs:
- name: service-1
port: 8080
filters:
- type: ExtensionRef
extensionRef:
group: gateway.envoyproxy.io
kind: AuthenticationFilter
name: test

Original file line number Diff line number Diff line change
@@ -0,0 +1,102 @@
gateways:
- apiVersion: gateway.networking.k8s.io/v1beta1
kind: Gateway
metadata:
namespace: envoy-gateway
name: gateway-1
spec:
gatewayClassName: envoy-gateway-class
listeners:
- name: http
protocol: HTTP
port: 80
hostname: "*.envoyproxy.io"
allowedRoutes:
namespaces:
from: All
status:
listeners:
- name: http
supportedKinds:
- group: gateway.networking.k8s.io
kind: HTTPRoute
attachedRoutes: 1
conditions:
- type: Programmed
status: "True"
reason: Programmed
message: Listener is ready
httpRoutes:
- apiVersion: gateway.networking.k8s.io/v1beta1
kind: HTTPRoute
metadata:
namespace: default
name: httproute-1
spec:
hostnames:
- gateway.envoyproxy.io
parentRefs:
- namespace: envoy-gateway
name: gateway-1
sectionName: http
rules:
- matches:
- path:
value: "/"
backendRefs:
- name: service-1
port: 8080
filters:
- type: ExtensionRef
extensionRef:
group: gateway.envoyproxy.io
kind: AuthenticationFilter
name: test
status:
parents:
- parentRef:
namespace: envoy-gateway
name: gateway-1
sectionName: http
controllerName: gateway.envoyproxy.io/gatewayclass-controller
conditions:
- type: ResolvedRefs
status: "False"
reason: BackendNotFound
message: "Reference not found for filter type: ExtensionRef"
xdsIR:
envoy-gateway-gateway-1:
http:
- name: envoy-gateway-gateway-1-http
address: 0.0.0.0
port: 10080
hostnames:
- "*.envoyproxy.io"
routes:
- name: default-httproute-1-rule-0-match-0-gateway.envoyproxy.io
pathMatch:
prefix: "/"
headerMatches:
- name: ":authority"
exact: gateway.envoyproxy.io
# I believe the correct way to handle an invalid filter should be to allow the HTTPRoute to function
# normally but leave out the filter config and set the status, but this behaviour can be changed.
directResponse:
body: "Reference not found for filter type: ExtensionRef"
statusCode: 500
infraIR:
envoy-gateway-gateway-1:
proxy:
metadata:
labels:
gateway.envoyproxy.io/owning-gateway-namespace: envoy-gateway
gateway.envoyproxy.io/owning-gateway-name: gateway-1
name: envoy-gateway-gateway-1
image: envoyproxy/envoy:translator-tests
listeners:
- address: ""
ports:
- name: http
protocol: "HTTP"
containerPort: 10080
servicePort: 80
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,7 @@ httpRoutes:
- type: Accepted
status: "False"
reason: UnsupportedValue
message: "Unknown custom filter type: ExtensionRef"
message: "Invalid filter ExtensionRef: invalid group; must be gateway.envoyproxy.io"
xdsIR:
envoy-gateway-gateway-1:
http:
Expand All @@ -82,7 +82,7 @@ xdsIR:
# I believe the correct way to handle an invalid filter should be to allow the HTTPRoute to function
# normally but leave out the filter config and set the status, but this behaviour can be changed.
directResponse:
body: "Unknown custom filter type: ExtensionRef"
body: "Invalid filter ExtensionRef: invalid group; must be gateway.envoyproxy.io"
statusCode: 500
infraIR:
envoy-gateway-gateway-1:
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
gateways:
- apiVersion: gateway.networking.k8s.io/v1beta1
kind: Gateway
metadata:
namespace: envoy-gateway
name: gateway-1
spec:
gatewayClassName: envoy-gateway-class
listeners:
- name: http
protocol: HTTP
port: 80
hostname: "*.envoyproxy.io"
allowedRoutes:
namespaces:
from: All
httpRoutes:
- apiVersion: gateway.networking.k8s.io/v1beta1
kind: HTTPRoute
metadata:
namespace: default
name: httproute-1
spec:
hostnames:
- gateway.envoyproxy.io
parentRefs:
- namespace: envoy-gateway
name: gateway-1
sectionName: http
rules:
- matches:
- path:
value: "/"
backendRefs:
- name: service-1
port: 8080
filters:
- type: ExtensionRef
extensionRef:
group: gateway.envoyproxy.io
kind: AuthenticationFilter
name: test
authenFilters:
- apiVersion: gateway.envoyproxy.io/v1alpha1
kind: AuthenticationFilter
metadata:
namespace: default
name: test
spec:
type: JWT
jwtProviders:
- name: test
issuer: https://www.test.local
remoteJWKS:
uri: https://test.local/jwt/public-key/jwks.json
Loading