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
81 changes: 42 additions & 39 deletions internal/gatewayapi/envoyextensionpolicy.go
Original file line number Diff line number Diff line change
Expand Up @@ -946,57 +946,60 @@ func (t *Translator) translateEnvoyExtensionPolicyForListeners(
listenerNames.Insert(irListenerName(listener))
}

routesWithDirectResponse := sets.New[string]()
failed := luaError != nil
if wasmError != nil {
failed = failed || !wasmFailOpen
}
if extProcError != nil {
failed = failed || !extProcFailOpen
}
if dynamicModuleError != nil {
failed = true
}

for _, http := range x.HTTP {
if !listenerNames.Has(http.Name) {
continue
}

// A Policy targeting the specific scope(xRoute rule, xRoute, Gateway
// A Policy targeting a more specific scope (xRoute rule, xRoute, Gateway
// listener, ListenerSet listener) wins over a policy targeting a lesser
// specific scope(Gateway/ListenerSet).
for _, r := range http.Routes {
// if already set - there's a specific level policy, so skip
if r.EnvoyExtensions != nil {
continue
}
// specific scope (Gateway/ListenerSet). A non-nil EnvoyExtensions means this
// listener is already owned by a more specific policy.
if http.EnvoyExtensions != nil {
continue
}

failRoute := false
// Lua extension doesn't have a fail open option, so fail the route if there is a lua error
// TODO: we may also add fail open option for Lua extension to align with other extensions
if luaError != nil {
failRoute = true
}
if wasmError != nil {
failRoute = failRoute || !wasmFailOpen
}
if extProcError != nil {
failRoute = failRoute || !extProcFailOpen
}
if dynamicModuleError != nil {
failRoute = true
}
if failRoute {
// Fail closed: a fail-closed error in any extension makes every route under
// this listener return a 500. No extension is attached at listener scope, so
// the filters do not run on those synthetic error responses.
if failed {
for _, r := range http.Routes {
// if already set - there's a specific level policy, so skip
if r.EnvoyExtensions != nil {
continue
}
r.DirectResponse = &ir.CustomResponse{
StatusCode: new(uint32(500)),
}
routesWithDirectResponse.Insert(r.Name)
} else {
r.EnvoyExtensions = &ir.EnvoyExtensionFeatures{
ExtProcs: extProcs,
Wasms: wasms,
Luas: luas,
DynamicModules: dynamicModules,
}
}
continue
}

// All extensions are attached at listener scope and delivered at VirtualHost
// scope by the xDS translator. Routes owned by a more specific policy carry
// their own EnvoyExtensions and fully override this one.
//
// Record the ownership sentinel even when every extension slice is empty
// (e.g. all entries failed validation but were fail-open): this listener is
// still owned by this policy, and leaving EnvoyExtensions nil would let a
// lesser-specific Gateway/ListenerSet policy see it as unowned and attach.
http.EnvoyExtensions = &ir.EnvoyExtensionFeatures{
ExtProcs: extProcs,
Wasms: wasms,
Luas: luas,
DynamicModules: dynamicModules,
}
}
if len(routesWithDirectResponse) > 0 {
t.Logger.Info("setting 500 direct response in routes due to errors in EnvoyExtensionPolicy",
"policy", fmt.Sprintf("%s/%s", policy.Namespace, policy.Name),
"routes", sets.List(routesWithDirectResponse),
"error", errs,
)
}

return errs
Expand Down
3 changes: 3 additions & 0 deletions internal/gatewayapi/globalresources.go
Original file line number Diff line number Diff line change
Expand Up @@ -116,6 +116,9 @@ func containsGlobalRateLimit(httpListeners []*ir.HTTPListener) bool {

func containsWasm(httpListeners []*ir.HTTPListener) bool {
for _, httpListener := range httpListeners {
if httpListener.EnvoyExtensions != nil && len(httpListener.EnvoyExtensions.Wasms) > 0 {
return true
}
for _, route := range httpListener.Routes {
if route.EnvoyExtensions != nil &&
len(route.EnvoyExtensions.Wasms) > 0 {
Expand Down
48 changes: 24 additions & 24 deletions internal/gatewayapi/testdata/custom-filter-order.out.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -257,6 +257,30 @@ xdsIR:
protocol: TCP
http:
- address: 0.0.0.0
envoyExtensions:
wasms:
- config:
parameter1:
key1: value1
key2: value2
parameter2: value3
failOpen: false
httpWasmCode:
originalDownloadingURL: https://www.example.com/wasm-filter-1.wasm
servingURL: https://envoy-gateway.envoy-gateway-system.svc.cluster.local:18002/5c90b9a82642ce00a7753923fabead306b9d9a54a7c0bd2463a1af3efcfb110b.wasm
sha256: 2d89c4c6ab2a1c615c7696ed37ade9e50654ac70384b5d45100eb08e62130ff4
name: envoyextensionpolicy/envoy-gateway/policy-for-gateway/wasm/0
wasmName: wasm-filter-1
- config:
parameter1: value1
parameter2: value2
failOpen: false
httpWasmCode:
originalDownloadingURL: https://www.example.com/wasm-filter-2.wasm
servingURL: https://envoy-gateway.envoy-gateway-system.svc.cluster.local:18002/593e4cc60a7e0fa4d4f86531a5e20e785213a52000f056a7a8b5c5afcb908052.wasm
sha256: 84274ca23246855cc491b3c6a657a89167e0b109a7ae380f1e64df77c910307e
name: envoyextensionpolicy/envoy-gateway/policy-for-gateway/wasm/1
wasmName: wasm-filter-2
externalPort: 80
hostnames:
- '*'
Expand Down Expand Up @@ -290,30 +314,6 @@ xdsIR:
name: httproute/envoy-gateway/httproute-1/rule/0/backend/0
protocol: HTTP
weight: 1
envoyExtensions:
wasms:
- config:
parameter1:
key1: value1
key2: value2
parameter2: value3
failOpen: false
httpWasmCode:
originalDownloadingURL: https://www.example.com/wasm-filter-1.wasm
servingURL: https://envoy-gateway.envoy-gateway-system.svc.cluster.local:18002/5c90b9a82642ce00a7753923fabead306b9d9a54a7c0bd2463a1af3efcfb110b.wasm
sha256: 2d89c4c6ab2a1c615c7696ed37ade9e50654ac70384b5d45100eb08e62130ff4
name: envoyextensionpolicy/envoy-gateway/policy-for-gateway/wasm/0
wasmName: wasm-filter-1
- config:
parameter1: value1
parameter2: value2
failOpen: false
httpWasmCode:
originalDownloadingURL: https://www.example.com/wasm-filter-2.wasm
servingURL: https://envoy-gateway.envoy-gateway-system.svc.cluster.local:18002/593e4cc60a7e0fa4d4f86531a5e20e785213a52000f056a7a8b5c5afcb908052.wasm
sha256: 84274ca23246855cc491b3c6a657a89167e0b109a7ae380f1e64df77c910307e
name: envoyextensionpolicy/envoy-gateway/policy-for-gateway/wasm/1
wasmName: wasm-filter-2
hostname: www.example.com
isHTTP2: false
metadata:
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,97 @@
gateways:
- apiVersion: gateway.networking.k8s.io/v1
kind: Gateway
metadata:
namespace: envoy-gateway
name: gateway-1
spec:
gatewayClassName: envoy-gateway-class
listeners:
- name: listener-1
protocol: HTTP
port: 8081
allowedRoutes:
namespaces:
from: All
- name: listener-2
protocol: HTTP
port: 8082
allowedRoutes:
namespaces:
from: All
httpRoutes:
- apiVersion: gateway.networking.k8s.io/v1
kind: HTTPRoute
metadata:
namespace: default
name: httproute-1 # attached to listener-1, which is owned by an empty fail-open listener policy
spec:
hostnames:
- www.foo.com
parentRefs:
- namespace: envoy-gateway
name: gateway-1
sectionName: listener-1
rules:
- matches:
- path:
value: "/foo"
backendRefs:
- name: service-1
port: 8080
- apiVersion: gateway.networking.k8s.io/v1
kind: HTTPRoute
metadata:
namespace: default
name: httproute-2 # attached to listener-2, which should still receive the Gateway-wide wasm filter
spec:
hostnames:
- www.bar.com
parentRefs:
- namespace: envoy-gateway
name: gateway-1
sectionName: listener-2
rules:
- matches:
- path:
value: "/bar"
backendRefs:
- name: service-1
port: 8080
envoyExtensionPolicies:
- apiVersion: gateway.envoyproxy.io/v1alpha1
kind: EnvoyExtensionPolicy
metadata:
namespace: envoy-gateway
name: policy-for-gateway-1-listener-1
spec:
targetRef:
group: gateway.networking.k8s.io
kind: Gateway
name: gateway-1
sectionName: listener-1
wasm:
- name: wasm-filter-1
code:
type: HTTP
http:
url: https://www.example.com/non-existent.wasm
sha256: 2d89c4c6ab2a1c615c7696ed37ade9e50654ac70384b5d45100eb08e62130ff4
failOpen: true
- apiVersion: gateway.envoyproxy.io/v1alpha1
kind: EnvoyExtensionPolicy
metadata:
namespace: envoy-gateway
name: policy-for-gateway-1
spec:
targetRef:
group: gateway.networking.k8s.io
kind: Gateway
name: gateway-1
wasm:
- name: wasm-filter-1
code:
type: HTTP
http:
url: https://www.example.com/wasm-filter-1.wasm
sha256: 2d89c4c6ab2a1c615c7696ed37ade9e50654ac70384b5d45100eb08e62130ff4
Loading
Loading