diff --git a/internal/gatewayapi/envoyextensionpolicy.go b/internal/gatewayapi/envoyextensionpolicy.go index 723dd57c3e..a89a661db5 100644 --- a/internal/gatewayapi/envoyextensionpolicy.go +++ b/internal/gatewayapi/envoyextensionpolicy.go @@ -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 diff --git a/internal/gatewayapi/globalresources.go b/internal/gatewayapi/globalresources.go index 1000890724..71a8cc9262 100644 --- a/internal/gatewayapi/globalresources.go +++ b/internal/gatewayapi/globalresources.go @@ -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 { diff --git a/internal/gatewayapi/testdata/custom-filter-order.out.yaml b/internal/gatewayapi/testdata/custom-filter-order.out.yaml index 358921f346..ee3cb2cc0b 100644 --- a/internal/gatewayapi/testdata/custom-filter-order.out.yaml +++ b/internal/gatewayapi/testdata/custom-filter-order.out.yaml @@ -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: - '*' @@ -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: diff --git a/internal/gatewayapi/testdata/envoyextensionpolicy-listener-failopen-ownership.in.yaml b/internal/gatewayapi/testdata/envoyextensionpolicy-listener-failopen-ownership.in.yaml new file mode 100644 index 0000000000..1f0e53ef93 --- /dev/null +++ b/internal/gatewayapi/testdata/envoyextensionpolicy-listener-failopen-ownership.in.yaml @@ -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 diff --git a/internal/gatewayapi/testdata/envoyextensionpolicy-listener-failopen-ownership.out.yaml b/internal/gatewayapi/testdata/envoyextensionpolicy-listener-failopen-ownership.out.yaml new file mode 100644 index 0000000000..373c44c1ca --- /dev/null +++ b/internal/gatewayapi/testdata/envoyextensionpolicy-listener-failopen-ownership.out.yaml @@ -0,0 +1,390 @@ +envoyExtensionPolicies: +- apiVersion: gateway.envoyproxy.io/v1alpha1 + kind: EnvoyExtensionPolicy + metadata: + name: policy-for-gateway-1-listener-1 + namespace: envoy-gateway + spec: + targetRef: + group: gateway.networking.k8s.io + kind: Gateway + name: gateway-1 + sectionName: listener-1 + wasm: + - code: + http: + sha256: 2d89c4c6ab2a1c615c7696ed37ade9e50654ac70384b5d45100eb08e62130ff4 + url: https://www.example.com/non-existent.wasm + type: HTTP + failOpen: true + name: wasm-filter-1 + status: + ancestors: + - ancestorRef: + group: gateway.networking.k8s.io + kind: Gateway + name: gateway-1 + namespace: envoy-gateway + sectionName: listener-1 + conditions: + - lastTransitionTime: null + message: 'Wasm: module downloaded from https://www.example.com/non-existent.wasm + has checksum 36ed359d2ddef6346c48c9c63ab424db2df51bb19d532e8744bfbbbd6ef0f45a, + which does not match: 2d89c4c6ab2a1c615c7696ed37ade9e50654ac70384b5d45100eb08e62130ff4.' + reason: Invalid + status: "False" + type: Accepted + - lastTransitionTime: null + message: spec.targetRef is deprecated, use spec.targetRefs instead + reason: DeprecatedField + status: "True" + type: Warning + controllerName: gateway.envoyproxy.io/gatewayclass-controller +- apiVersion: gateway.envoyproxy.io/v1alpha1 + kind: EnvoyExtensionPolicy + metadata: + name: policy-for-gateway-1 + namespace: envoy-gateway + spec: + targetRef: + group: gateway.networking.k8s.io + kind: Gateway + name: gateway-1 + wasm: + - code: + http: + sha256: 2d89c4c6ab2a1c615c7696ed37ade9e50654ac70384b5d45100eb08e62130ff4 + url: https://www.example.com/wasm-filter-1.wasm + type: HTTP + name: wasm-filter-1 + status: + ancestors: + - ancestorRef: + group: gateway.networking.k8s.io + kind: Gateway + name: gateway-1 + namespace: envoy-gateway + conditions: + - lastTransitionTime: null + message: Policy has been accepted. + reason: Accepted + status: "True" + type: Accepted + - lastTransitionTime: null + message: spec.targetRef is deprecated, use spec.targetRefs instead + reason: DeprecatedField + status: "True" + type: Warning + - lastTransitionTime: null + message: 'This policy is being overridden by other envoyExtensionPolicies + for these gateway listeners: [envoy-gateway/gateway-1/listener-1]' + reason: Overridden + status: "True" + type: Overridden + controllerName: gateway.envoyproxy.io/gatewayclass-controller +gateways: +- apiVersion: gateway.networking.k8s.io/v1 + kind: Gateway + metadata: + name: gateway-1 + namespace: envoy-gateway + spec: + gatewayClassName: envoy-gateway-class + listeners: + - allowedRoutes: + namespaces: + from: All + name: listener-1 + port: 8081 + protocol: HTTP + - allowedRoutes: + namespaces: + from: All + name: listener-2 + port: 8082 + protocol: HTTP + status: + listeners: + - attachedRoutes: 1 + conditions: + - lastTransitionTime: null + message: Sending translated listener configuration to the data plane + reason: Programmed + status: "True" + type: Programmed + - lastTransitionTime: null + message: Listener has been successfully translated + reason: Accepted + status: "True" + type: Accepted + - lastTransitionTime: null + message: Listener references have been resolved + reason: ResolvedRefs + status: "True" + type: ResolvedRefs + name: listener-1 + supportedKinds: + - group: gateway.networking.k8s.io + kind: HTTPRoute + - group: gateway.networking.k8s.io + kind: GRPCRoute + - attachedRoutes: 1 + conditions: + - lastTransitionTime: null + message: Sending translated listener configuration to the data plane + reason: Programmed + status: "True" + type: Programmed + - lastTransitionTime: null + message: Listener has been successfully translated + reason: Accepted + status: "True" + type: Accepted + - lastTransitionTime: null + message: Listener references have been resolved + reason: ResolvedRefs + status: "True" + type: ResolvedRefs + name: listener-2 + supportedKinds: + - group: gateway.networking.k8s.io + kind: HTTPRoute + - group: gateway.networking.k8s.io + kind: GRPCRoute +httpRoutes: +- apiVersion: gateway.networking.k8s.io/v1 + kind: HTTPRoute + metadata: + name: httproute-1 + namespace: default + spec: + hostnames: + - www.foo.com + parentRefs: + - name: gateway-1 + namespace: envoy-gateway + sectionName: listener-1 + rules: + - backendRefs: + - name: service-1 + port: 8080 + matches: + - path: + value: /foo + status: + parents: + - conditions: + - lastTransitionTime: null + message: Route is accepted + reason: Accepted + status: "True" + type: Accepted + - lastTransitionTime: null + message: Resolved all the Object references for the Route + reason: ResolvedRefs + status: "True" + type: ResolvedRefs + controllerName: gateway.envoyproxy.io/gatewayclass-controller + parentRef: + name: gateway-1 + namespace: envoy-gateway + sectionName: listener-1 +- apiVersion: gateway.networking.k8s.io/v1 + kind: HTTPRoute + metadata: + name: httproute-2 + namespace: default + spec: + hostnames: + - www.bar.com + parentRefs: + - name: gateway-1 + namespace: envoy-gateway + sectionName: listener-2 + rules: + - backendRefs: + - name: service-1 + port: 8080 + matches: + - path: + value: /bar + status: + parents: + - conditions: + - lastTransitionTime: null + message: Route is accepted + reason: Accepted + status: "True" + type: Accepted + - lastTransitionTime: null + message: Resolved all the Object references for the Route + reason: ResolvedRefs + status: "True" + type: ResolvedRefs + controllerName: gateway.envoyproxy.io/gatewayclass-controller + parentRef: + name: gateway-1 + namespace: envoy-gateway + sectionName: listener-2 +infraIR: + envoy-gateway/gateway-1: + proxy: + listeners: + - name: envoy-gateway/gateway-1/listener-1 + ports: + - containerPort: 8081 + name: http-8081 + protocol: HTTP + servicePort: 8081 + - name: envoy-gateway/gateway-1/listener-2 + ports: + - containerPort: 8082 + name: http-8082 + protocol: HTTP + servicePort: 8082 + metadata: + labels: + gateway.envoyproxy.io/owning-gateway-name: gateway-1 + gateway.envoyproxy.io/owning-gateway-namespace: envoy-gateway + ownerReference: + kind: GatewayClass + name: envoy-gateway-class + name: envoy-gateway/gateway-1 + namespace: envoy-gateway-system +xdsIR: + envoy-gateway/gateway-1: + accessLog: + json: + - path: /dev/stdout + globalResources: + envoyClientCertificate: + certificate: LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUREVENDQWZXZ0F3SUJBZ0lVRUZNaFA5ZUo5WEFCV3NRNVptNmJSazJjTE5Rd0RRWUpLb1pJaHZjTkFRRUwKQlFBd0ZqRVVNQklHQTFVRUF3d0xabTl2TG1KaGNpNWpiMjB3SGhjTk1qUXdNakk1TURrek1ERXdXaGNOTXpRdwpNakkyTURrek1ERXdXakFXTVJRd0VnWURWUVFEREF0bWIyOHVZbUZ5TG1OdmJUQ0NBU0l3RFFZSktvWklodmNOCkFRRUJCUUFEZ2dFUEFEQ0NBUW9DZ2dFQkFKbEk2WXhFOVprQ1BzNnBDUXhickNtZWl4OVA1RGZ4OVJ1NUxENFQKSm1kVzdJS2R0UVYvd2ZMbXRzdTc2QithVGRDaldlMEJUZmVPT1JCYlIzY1BBRzZFbFFMaWNsUVVydW4zcStncwpKcEsrSTdjSStqNXc4STY4WEg1V1E3clZVdGJ3SHBxYncrY1ZuQnFJVU9MaUlhdGpJZjdLWDUxTTF1RjljZkVICkU0RG5jSDZyYnI1OS9SRlpCc2toeHM1T3p3Sklmb2hreXZGd2V1VHd4Sy9WcGpJKzdPYzQ4QUJDWHBOTzlEL3EKRWgrck9hdWpBTWNYZ0hRSVRrQ2lpVVRjVW82TFNIOXZMWlB0YXFmem9acTZuaE1xcFc2NUUxcEF3RjNqeVRUeAphNUk4SmNmU0Zqa2llWjIwTFVRTW43TThVNHhIamFvL2d2SDBDQWZkQjdSTFUyc0NBd0VBQWFOVE1GRXdIUVlEClZSME9CQllFRk9SQ0U4dS8xRERXN2loWnA3Y3g5dFNtUG02T01COEdBMVVkSXdRWU1CYUFGT1JDRTh1LzFERFcKN2loWnA3Y3g5dFNtUG02T01BOEdBMVVkRXdFQi93UUZNQU1CQWY4d0RRWUpLb1pJaHZjTkFRRUxCUUFEZ2dFQgpBRnQ1M3pqc3FUYUg1YThFMmNodm1XQWdDcnhSSzhiVkxNeGl3TkdqYm1FUFJ6K3c2TngrazBBOEtFY0lEc0tjClNYY2k1OHU0b1didFZKQmx6YS9adWpIUjZQMUJuT3BsK2FveTc4NGJiZDRQMzl3VExvWGZNZmJCQ20xdmV2aDkKQUpLbncyWnRxcjRta2JMY3hFcWxxM3NCTEZBUzlzUUxuS05DZTJjR0xkVHAyYm9HK3FjZ3lRZ0NJTTZmOEVNdgpXUGlmQ01NR3V6Sy9HUkY0YlBPL1lGNDhld0R1M1VlaWgwWFhkVUFPRTlDdFVhOE5JaGMxVVBhT3pQcnRZVnFyClpPR2t2L0t1K0I3OGg4U0VzTzlYclFjdXdiT25KeDZLdFIrYWV5a3ZBcFhDUTNmWkMvYllLQUFSK1A4QUpvUVoKYndJVW1YaTRnajVtK2JLUGhlK2lyK0U9Ci0tLS0tRU5EIENFUlRJRklDQVRFLS0tLS0= + name: envoy-gateway-system/envoy + privateKey: '[redacted]' + proxyServiceCluster: + metadata: + kind: Service + name: envoy-envoy-gateway-gateway-1-196ae069 + namespace: envoy-gateway-system + sectionName: "8080" + name: envoy-gateway/gateway-1 + settings: + - addressType: IP + endpoints: + - host: 7.6.5.4 + port: 8080 + zone: zone1 + metadata: + kind: Service + name: envoy-envoy-gateway-gateway-1-196ae069 + namespace: envoy-gateway-system + sectionName: "8080" + name: envoy-gateway/gateway-1 + protocol: TCP + http: + - address: 0.0.0.0 + envoyExtensions: {} + externalPort: 8081 + hostnames: + - '*' + metadata: + kind: Gateway + name: gateway-1 + namespace: envoy-gateway + sectionName: listener-1 + name: envoy-gateway/gateway-1/listener-1 + path: + escapedSlashesAction: UnescapeAndRedirect + mergeSlashes: true + port: 8081 + routes: + - destination: + metadata: + kind: HTTPRoute + name: httproute-1 + namespace: default + name: httproute/default/httproute-1/rule/0 + settings: + - addressType: IP + endpoints: + - host: 7.7.7.7 + port: 8080 + metadata: + kind: Service + name: service-1 + namespace: default + sectionName: "8080" + name: httproute/default/httproute-1/rule/0/backend/0 + protocol: HTTP + weight: 1 + hostname: www.foo.com + isHTTP2: false + metadata: + kind: HTTPRoute + name: httproute-1 + namespace: default + name: httproute/default/httproute-1/rule/0/match/0/www_foo_com + pathMatch: + distinct: false + name: "" + prefix: /foo + - address: 0.0.0.0 + envoyExtensions: + wasms: + - config: null + 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-1/wasm/0 + wasmName: wasm-filter-1 + externalPort: 8082 + hostnames: + - '*' + metadata: + kind: Gateway + name: gateway-1 + namespace: envoy-gateway + sectionName: listener-2 + name: envoy-gateway/gateway-1/listener-2 + path: + escapedSlashesAction: UnescapeAndRedirect + mergeSlashes: true + port: 8082 + routes: + - destination: + metadata: + kind: HTTPRoute + name: httproute-2 + namespace: default + name: httproute/default/httproute-2/rule/0 + settings: + - addressType: IP + endpoints: + - host: 7.7.7.7 + port: 8080 + metadata: + kind: Service + name: service-1 + namespace: default + sectionName: "8080" + name: httproute/default/httproute-2/rule/0/backend/0 + protocol: HTTP + weight: 1 + hostname: www.bar.com + isHTTP2: false + metadata: + kind: HTTPRoute + name: httproute-2 + namespace: default + name: httproute/default/httproute-2/rule/0/match/0/www_bar_com + pathMatch: + distinct: false + name: "" + prefix: /bar + readyListener: + address: 0.0.0.0 + ipFamily: IPv4 + path: /ready + port: 19003 diff --git a/internal/gatewayapi/testdata/envoyextensionpolicy-listenerset-invalid.out.yaml b/internal/gatewayapi/testdata/envoyextensionpolicy-listenerset-invalid.out.yaml index 67fff3b192..a37e2668b9 100644 --- a/internal/gatewayapi/testdata/envoyextensionpolicy-listenerset-invalid.out.yaml +++ b/internal/gatewayapi/testdata/envoyextensionpolicy-listenerset-invalid.out.yaml @@ -331,6 +331,13 @@ xdsIR: mergeSlashes: true port: 10080 - address: 0.0.0.0 + envoyExtensions: + luas: + - code: | + function envoy_on_request(request_handle) + request_handle:logInfo("listenerset-section") + end + name: envoyextensionpolicy/envoy-gateway/target-listenerset-section/lua/0 externalPort: 8081 hostnames: - '*' diff --git a/internal/gatewayapi/testdata/envoyextensionpolicy-listenerset-same-name-listeners.out.yaml b/internal/gatewayapi/testdata/envoyextensionpolicy-listenerset-same-name-listeners.out.yaml index e20142ef28..526e406cce 100644 --- a/internal/gatewayapi/testdata/envoyextensionpolicy-listenerset-same-name-listeners.out.yaml +++ b/internal/gatewayapi/testdata/envoyextensionpolicy-listenerset-same-name-listeners.out.yaml @@ -423,6 +423,13 @@ xdsIR: protocol: TCP http: - address: 0.0.0.0 + envoyExtensions: + luas: + - code: | + function envoy_on_request(request_handle) + request_handle:logInfo("gateway-shared") + end + name: envoyextensionpolicy/envoy-gateway/target-gateway-shared/lua/0 externalPort: 80 hostnames: - '*' @@ -456,14 +463,6 @@ xdsIR: name: httproute/default/route-on-gateway/rule/0/backend/0 protocol: HTTP weight: 1 - envoyExtensions: - luas: - - Code: | - function envoy_on_request(request_handle) - request_handle:logInfo("gateway-shared") - end - FilterContext: null - Name: envoyextensionpolicy/envoy-gateway/target-gateway-shared/lua/0 hostname: '*' isHTTP2: false metadata: @@ -476,6 +475,13 @@ xdsIR: name: "" prefix: / - address: 0.0.0.0 + envoyExtensions: + luas: + - code: | + function envoy_on_request(request_handle) + request_handle:logInfo("listenerset-shared") + end + name: envoyextensionpolicy/envoy-gateway/target-listenerset-shared/lua/0 externalPort: 8081 hostnames: - '*' @@ -509,14 +515,6 @@ xdsIR: name: httproute/default/route-on-listenerset/rule/0/backend/0 protocol: HTTP weight: 1 - envoyExtensions: - luas: - - Code: | - function envoy_on_request(request_handle) - request_handle:logInfo("listenerset-shared") - end - FilterContext: null - Name: envoyextensionpolicy/envoy-gateway/target-listenerset-shared/lua/0 hostname: '*' isHTTP2: false metadata: @@ -529,6 +527,13 @@ xdsIR: name: "" prefix: / - address: 0.0.0.0 + envoyExtensions: + luas: + - code: | + function envoy_on_request(request_handle) + request_handle:logInfo("other-listenerset-shared") + end + name: envoyextensionpolicy/envoy-gateway/target-other-listenerset-shared/lua/0 externalPort: 8082 hostnames: - '*' @@ -562,14 +567,6 @@ xdsIR: name: httproute/default/route-on-other-listenerset/rule/0/backend/0 protocol: HTTP weight: 1 - envoyExtensions: - luas: - - Code: | - function envoy_on_request(request_handle) - request_handle:logInfo("other-listenerset-shared") - end - FilterContext: null - Name: envoyextensionpolicy/envoy-gateway/target-other-listenerset-shared/lua/0 hostname: '*' isHTTP2: false metadata: diff --git a/internal/gatewayapi/testdata/envoyextensionpolicy-listenerset.out.yaml b/internal/gatewayapi/testdata/envoyextensionpolicy-listenerset.out.yaml index 3ec3c1f5b9..e652817f5b 100644 --- a/internal/gatewayapi/testdata/envoyextensionpolicy-listenerset.out.yaml +++ b/internal/gatewayapi/testdata/envoyextensionpolicy-listenerset.out.yaml @@ -441,6 +441,13 @@ xdsIR: protocol: TCP http: - address: 0.0.0.0 + envoyExtensions: + luas: + - code: | + function envoy_on_request(request_handle) + request_handle:logInfo("gateway") + end + name: envoyextensionpolicy/envoy-gateway/target-gw/lua/0 externalPort: 80 hostnames: - '*' @@ -474,14 +481,6 @@ xdsIR: name: httproute/default/route-on-gw/rule/0/backend/0 protocol: HTTP weight: 1 - envoyExtensions: - luas: - - Code: | - function envoy_on_request(request_handle) - request_handle:logInfo("gateway") - end - FilterContext: null - Name: envoyextensionpolicy/envoy-gateway/target-gw/lua/0 hostname: '*' isHTTP2: false metadata: @@ -494,6 +493,13 @@ xdsIR: name: "" prefix: / - address: 0.0.0.0 + envoyExtensions: + luas: + - code: | + function envoy_on_request(request_handle) + request_handle:logInfo("gateway-section") + end + name: envoyextensionpolicy/envoy-gateway/target-gw-section/lua/0 externalPort: 8080 hostnames: - '*' @@ -527,14 +533,6 @@ xdsIR: name: httproute/default/route-on-gw/rule/0/backend/0 protocol: HTTP weight: 1 - envoyExtensions: - luas: - - Code: | - function envoy_on_request(request_handle) - request_handle:logInfo("gateway-section") - end - FilterContext: null - Name: envoyextensionpolicy/envoy-gateway/target-gw-section/lua/0 hostname: '*' isHTTP2: false metadata: @@ -547,6 +545,13 @@ xdsIR: name: "" prefix: / - address: 0.0.0.0 + envoyExtensions: + luas: + - code: | + function envoy_on_request(request_handle) + request_handle:logInfo("listenerset-section") + end + name: envoyextensionpolicy/envoy-gateway/target-listenerset-section/lua/0 externalPort: 8081 hostnames: - '*' @@ -580,14 +585,6 @@ xdsIR: name: httproute/default/route-on-ls/rule/0/backend/0 protocol: HTTP weight: 1 - envoyExtensions: - luas: - - Code: | - function envoy_on_request(request_handle) - request_handle:logInfo("listenerset-section") - end - FilterContext: null - Name: envoyextensionpolicy/envoy-gateway/target-listenerset-section/lua/0 hostname: '*' isHTTP2: false metadata: @@ -600,6 +597,13 @@ xdsIR: name: "" prefix: / - address: 0.0.0.0 + envoyExtensions: + luas: + - code: | + function envoy_on_request(request_handle) + request_handle:logInfo("listenerset") + end + name: envoyextensionpolicy/envoy-gateway/target-listenerset/lua/0 externalPort: 8082 hostnames: - '*' @@ -633,14 +637,6 @@ xdsIR: name: httproute/default/route-on-ls/rule/0/backend/0 protocol: HTTP weight: 1 - envoyExtensions: - luas: - - Code: | - function envoy_on_request(request_handle) - request_handle:logInfo("listenerset") - end - FilterContext: null - Name: envoyextensionpolicy/envoy-gateway/target-listenerset/lua/0 hostname: '*' isHTTP2: false metadata: diff --git a/internal/gatewayapi/testdata/envoyextensionpolicy-override-replace.out.yaml b/internal/gatewayapi/testdata/envoyextensionpolicy-override-replace.out.yaml index 1a5c92bfdf..ea24901c3a 100644 --- a/internal/gatewayapi/testdata/envoyextensionpolicy-override-replace.out.yaml +++ b/internal/gatewayapi/testdata/envoyextensionpolicy-override-replace.out.yaml @@ -301,6 +301,29 @@ xdsIR: protocol: TCP http: - address: 0.0.0.0 + envoyExtensions: + extProcs: + - authority: grpc-backend.envoy-gateway:9000 + destination: + metadata: + kind: EnvoyExtensionPolicy + name: policy-for-gateway-1 + namespace: envoy-gateway + name: envoyextensionpolicy/envoy-gateway/policy-for-gateway-1/extproc/0 + settings: + - addressType: IP + endpoints: + - host: 7.7.7.1 + port: 9000 + metadata: + kind: Service + name: grpc-backend + namespace: envoy-gateway + sectionName: "9000" + name: envoyextensionpolicy/envoy-gateway/policy-for-gateway-1/extproc/0/backend/0 + protocol: GRPC + weight: 1 + name: envoyextensionpolicy/envoy-gateway/policy-for-gateway-1/extproc/0 externalPort: 80 hostnames: - '*' @@ -387,29 +410,6 @@ xdsIR: name: httproute/default/httproute-2/rule/0/backend/0 protocol: HTTP weight: 1 - envoyExtensions: - extProcs: - - authority: grpc-backend.envoy-gateway:9000 - destination: - metadata: - kind: EnvoyExtensionPolicy - name: policy-for-gateway-1 - namespace: envoy-gateway - name: envoyextensionpolicy/envoy-gateway/policy-for-gateway-1/extproc/0 - settings: - - addressType: IP - endpoints: - - host: 7.7.7.1 - port: 9000 - metadata: - kind: Service - name: grpc-backend - namespace: envoy-gateway - sectionName: "9000" - name: envoyextensionpolicy/envoy-gateway/policy-for-gateway-1/extproc/0/backend/0 - protocol: GRPC - weight: 1 - name: envoyextensionpolicy/envoy-gateway/policy-for-gateway-1/extproc/0 hostname: gateway.envoyproxy.io isHTTP2: false metadata: diff --git a/internal/gatewayapi/testdata/envoyextensionpolicy-route-listenerset.out.yaml b/internal/gatewayapi/testdata/envoyextensionpolicy-route-listenerset.out.yaml index 376026565e..a67c1e45db 100644 --- a/internal/gatewayapi/testdata/envoyextensionpolicy-route-listenerset.out.yaml +++ b/internal/gatewayapi/testdata/envoyextensionpolicy-route-listenerset.out.yaml @@ -478,6 +478,13 @@ xdsIR: protocol: TCP http: - address: 0.0.0.0 + envoyExtensions: + luas: + - code: | + function envoy_on_request(request_handle) + request_handle:logInfo("gateway") + end + name: envoyextensionpolicy/envoy-gateway/target-gw/lua/0 externalPort: 80 hostnames: - '*' @@ -511,14 +518,6 @@ xdsIR: name: httproute/default/route-on-gw/rule/0/backend/0 protocol: HTTP weight: 1 - envoyExtensions: - luas: - - Code: | - function envoy_on_request(request_handle) - request_handle:logInfo("gateway") - end - FilterContext: null - Name: envoyextensionpolicy/envoy-gateway/target-gw/lua/0 hostname: '*' isHTTP2: false metadata: @@ -531,6 +530,13 @@ xdsIR: name: "" prefix: / - address: 0.0.0.0 + envoyExtensions: + luas: + - code: | + function envoy_on_request(request_handle) + request_handle:logInfo("gateway-section") + end + name: envoyextensionpolicy/envoy-gateway/target-gw-section/lua/0 externalPort: 8080 hostnames: - '*' @@ -564,14 +570,6 @@ xdsIR: name: httproute/default/route-on-gw/rule/0/backend/0 protocol: HTTP weight: 1 - envoyExtensions: - luas: - - Code: | - function envoy_on_request(request_handle) - request_handle:logInfo("gateway-section") - end - FilterContext: null - Name: envoyextensionpolicy/envoy-gateway/target-gw-section/lua/0 hostname: '*' isHTTP2: false metadata: @@ -584,6 +582,13 @@ xdsIR: name: "" prefix: / - address: 0.0.0.0 + envoyExtensions: + luas: + - code: | + function envoy_on_request(request_handle) + request_handle:logInfo("listenerset-section") + end + name: envoyextensionpolicy/envoy-gateway/target-listenerset-section/lua/0 externalPort: 8081 hostnames: - '*' @@ -619,12 +624,11 @@ xdsIR: weight: 1 envoyExtensions: luas: - - Code: | + - code: | function envoy_on_request(request_handle) request_handle:logInfo("route") end - FilterContext: null - Name: envoyextensionpolicy/default/target-route/lua/0 + name: envoyextensionpolicy/default/target-route/lua/0 hostname: '*' isHTTP2: false metadata: @@ -637,6 +641,13 @@ xdsIR: name: "" prefix: / - address: 0.0.0.0 + envoyExtensions: + luas: + - code: | + function envoy_on_request(request_handle) + request_handle:logInfo("listenerset") + end + name: envoyextensionpolicy/envoy-gateway/target-listenerset/lua/0 externalPort: 8082 hostnames: - '*' @@ -672,12 +683,11 @@ xdsIR: weight: 1 envoyExtensions: luas: - - Code: | + - code: | function envoy_on_request(request_handle) request_handle:logInfo("route") end - FilterContext: null - Name: envoyextensionpolicy/default/target-route/lua/0 + name: envoyextensionpolicy/default/target-route/lua/0 hostname: '*' isHTTP2: false metadata: diff --git a/internal/gatewayapi/testdata/envoyextensionpolicy-section-name-override.out.yaml b/internal/gatewayapi/testdata/envoyextensionpolicy-section-name-override.out.yaml index 4fca32d00b..dbccf89487 100644 --- a/internal/gatewayapi/testdata/envoyextensionpolicy-section-name-override.out.yaml +++ b/internal/gatewayapi/testdata/envoyextensionpolicy-section-name-override.out.yaml @@ -359,6 +359,29 @@ xdsIR: protocol: TCP http: - address: 0.0.0.0 + envoyExtensions: + extProcs: + - authority: grpc-backend-2.envoy-gateway:8002 + destination: + metadata: + kind: EnvoyExtensionPolicy + name: policy-for-gateway-1-listener-1 + namespace: envoy-gateway + name: envoyextensionpolicy/envoy-gateway/policy-for-gateway-1-listener-1/extproc/0 + settings: + - addressType: IP + endpoints: + - host: 7.7.7.2 + port: 8002 + metadata: + kind: Service + name: grpc-backend-2 + namespace: envoy-gateway + sectionName: "8002" + name: envoyextensionpolicy/envoy-gateway/policy-for-gateway-1-listener-1/extproc/0/backend/0 + protocol: GRPC + weight: 1 + name: envoyextensionpolicy/envoy-gateway/policy-for-gateway-1-listener-1/extproc/0 externalPort: 8081 hostnames: - '*' @@ -503,29 +526,6 @@ xdsIR: name: httproute/default/httproute-2/rule/0/backend/0 protocol: HTTP weight: 1 - envoyExtensions: - extProcs: - - authority: grpc-backend-2.envoy-gateway:8002 - destination: - metadata: - kind: EnvoyExtensionPolicy - name: policy-for-gateway-1-listener-1 - namespace: envoy-gateway - name: envoyextensionpolicy/envoy-gateway/policy-for-gateway-1-listener-1/extproc/0 - settings: - - addressType: IP - endpoints: - - host: 7.7.7.2 - port: 8002 - metadata: - kind: Service - name: grpc-backend-2 - namespace: envoy-gateway - sectionName: "8002" - name: envoyextensionpolicy/envoy-gateway/policy-for-gateway-1-listener-1/extproc/0/backend/0 - protocol: GRPC - weight: 1 - name: envoyextensionpolicy/envoy-gateway/policy-for-gateway-1-listener-1/extproc/0 hostname: gateway.envoyproxy.io isHTTP2: false metadata: @@ -539,6 +539,29 @@ xdsIR: name: "" prefix: /foo - address: 0.0.0.0 + envoyExtensions: + extProcs: + - authority: grpc-backend-1.envoy-gateway:8001 + destination: + metadata: + kind: EnvoyExtensionPolicy + name: policy-for-gateway-1 + namespace: envoy-gateway + name: envoyextensionpolicy/envoy-gateway/policy-for-gateway-1/extproc/0 + settings: + - addressType: IP + endpoints: + - host: 7.7.7.1 + port: 8001 + metadata: + kind: Service + name: grpc-backend-1 + namespace: envoy-gateway + sectionName: "8001" + name: envoyextensionpolicy/envoy-gateway/policy-for-gateway-1/extproc/0/backend/0 + protocol: GRPC + weight: 1 + name: envoyextensionpolicy/envoy-gateway/policy-for-gateway-1/extproc/0 externalPort: 8082 hostnames: - '*' @@ -573,29 +596,6 @@ xdsIR: name: httproute/default/httproute-2/rule/0/backend/0 protocol: HTTP weight: 1 - envoyExtensions: - extProcs: - - authority: grpc-backend-1.envoy-gateway:8001 - destination: - metadata: - kind: EnvoyExtensionPolicy - name: policy-for-gateway-1 - namespace: envoy-gateway - name: envoyextensionpolicy/envoy-gateway/policy-for-gateway-1/extproc/0 - settings: - - addressType: IP - endpoints: - - host: 7.7.7.1 - port: 8001 - metadata: - kind: Service - name: grpc-backend-1 - namespace: envoy-gateway - sectionName: "8001" - name: envoyextensionpolicy/envoy-gateway/policy-for-gateway-1/extproc/0/backend/0 - protocol: GRPC - weight: 1 - name: envoyextensionpolicy/envoy-gateway/policy-for-gateway-1/extproc/0 hostname: gateway.envoyproxy.io isHTTP2: false metadata: diff --git a/internal/gatewayapi/testdata/envoyextensionpolicy-status-conditions-truncated.out.yaml b/internal/gatewayapi/testdata/envoyextensionpolicy-status-conditions-truncated.out.yaml index 9090e02d1e..97051b52bf 100644 --- a/internal/gatewayapi/testdata/envoyextensionpolicy-status-conditions-truncated.out.yaml +++ b/internal/gatewayapi/testdata/envoyextensionpolicy-status-conditions-truncated.out.yaml @@ -3058,6 +3058,7 @@ xdsIR: protocol: TCP http: - address: 0.0.0.0 + envoyExtensions: {} externalPort: 80 hostnames: - '*' diff --git a/internal/gatewayapi/testdata/envoyextensionpolicy-status-conditions.out.yaml b/internal/gatewayapi/testdata/envoyextensionpolicy-status-conditions.out.yaml index 9508ec8d51..dc064680ac 100644 --- a/internal/gatewayapi/testdata/envoyextensionpolicy-status-conditions.out.yaml +++ b/internal/gatewayapi/testdata/envoyextensionpolicy-status-conditions.out.yaml @@ -596,6 +596,7 @@ xdsIR: protocol: TCP http: - address: 0.0.0.0 + envoyExtensions: {} externalPort: 80 hostnames: - '*' diff --git a/internal/gatewayapi/testdata/envoyextensionpolicy-with-dynamicmodule.out.yaml b/internal/gatewayapi/testdata/envoyextensionpolicy-with-dynamicmodule.out.yaml index 1eede11cad..d4c20c6bc4 100644 --- a/internal/gatewayapi/testdata/envoyextensionpolicy-with-dynamicmodule.out.yaml +++ b/internal/gatewayapi/testdata/envoyextensionpolicy-with-dynamicmodule.out.yaml @@ -335,6 +335,26 @@ xdsIR: protocol: TCP http: - address: 0.0.0.0 + envoyExtensions: + dynamicModules: + - config: + authEndpoint: https://auth.example.com + doNotClose: false + filterName: auth-check + loadGlobally: false + name: envoyextensionpolicy/envoy-gateway/policy-for-gateway/dynamic-module/0 + path: /usr/lib/envoy/modules/my_auth.so + terminalFilter: false + - config: + authEndpoint: https://remote-auth.example.com + doNotClose: false + filterName: remote-auth-check + loadGlobally: false + name: envoyextensionpolicy/envoy-gateway/policy-for-gateway/dynamic-module/1 + remote: + sha256: abcdef0123456789abcdef0123456789abcdef0123456789abcdef0123456789 + url: https://modules.example.com/libremote_auth.so + terminalFilter: false externalPort: 80 hostnames: - '*' @@ -414,26 +434,6 @@ xdsIR: name: httproute/default/httproute-2/rule/0/backend/0 protocol: HTTP weight: 1 - envoyExtensions: - dynamicModules: - - config: - authEndpoint: https://auth.example.com - doNotClose: false - filterName: auth-check - loadGlobally: false - name: envoyextensionpolicy/envoy-gateway/policy-for-gateway/dynamic-module/0 - path: /usr/lib/envoy/modules/my_auth.so - terminalFilter: false - - config: - authEndpoint: https://remote-auth.example.com - doNotClose: false - filterName: remote-auth-check - loadGlobally: false - name: envoyextensionpolicy/envoy-gateway/policy-for-gateway/dynamic-module/1 - remote: - sha256: abcdef0123456789abcdef0123456789abcdef0123456789abcdef0123456789 - url: https://modules.example.com/libremote_auth.so - terminalFilter: false hostname: www.example.com isHTTP2: false metadata: diff --git a/internal/gatewayapi/testdata/envoyextensionpolicy-with-extproc-with-backendtlspolicy-per-resource-secret.out.yaml b/internal/gatewayapi/testdata/envoyextensionpolicy-with-extproc-with-backendtlspolicy-per-resource-secret.out.yaml index 8f5c6ead3a..d404fd6e65 100644 --- a/internal/gatewayapi/testdata/envoyextensionpolicy-with-extproc-with-backendtlspolicy-per-resource-secret.out.yaml +++ b/internal/gatewayapi/testdata/envoyextensionpolicy-with-extproc-with-backendtlspolicy-per-resource-secret.out.yaml @@ -369,6 +369,84 @@ xdsIR: protocol: TCP http: - address: 0.0.0.0 + envoyExtensions: + extProcs: + - allowModeOverride: true + authority: grpc-backend.envoy-gateway:8000 + destination: + metadata: + kind: EnvoyExtensionPolicy + name: policy-for-gateway + namespace: default + name: envoyextensionpolicy/default/policy-for-gateway/extproc/0 + settings: + - addressType: IP + endpoints: + - host: 7.7.7.7 + port: 8000 + metadata: + kind: Service + name: grpc-backend + namespace: envoy-gateway + sectionName: "8000" + name: envoyextensionpolicy/default/policy-for-gateway/extproc/0/backend/0 + protocol: GRPC + tls: + alpnProtocols: null + caCertificate: + certificate: LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSURKekNDQWcrZ0F3SUJBZ0lVQWw2VUtJdUttenRlODFjbGx6NVBmZE4ySWxJd0RRWUpLb1pJaHZjTkFRRUwKQlFBd0l6RVFNQTRHQTFVRUF3d0hiWGxqYVdWdWRERVBNQTBHQTFVRUNnd0dhM1ZpWldSaU1CNFhEVEl6TVRBdwpNakExTkRFMU4xb1hEVEkwTVRBd01UQTFOREUxTjFvd0l6RVFNQTRHQTFVRUF3d0hiWGxqYVdWdWRERVBNQTBHCkExVUVDZ3dHYTNWaVpXUmlNSUlCSWpBTkJna3Foa2lHOXcwQkFRRUZBQU9DQVE4QU1JSUJDZ0tDQVFFQXdTVGMKMXlqOEhXNjJueW5rRmJYbzRWWEt2MmpDMFBNN2RQVmt5ODdGd2VaY1RLTG9XUVZQUUUycDJrTERLNk9Fc3ptTQp5eXIreHhXdHlpdmVyZW1yV3FuS2tOVFloTGZZUGhnUWtjemliN2VVYWxtRmpVYmhXZEx2SGFrYkVnQ29kbjNiCmt6NTdtSW5YMlZwaURPS2c0a3lIZml1WFdwaUJxckN4MEtOTHB4bzNERVFjRmNzUVRlVEh6aDQ3NTJHVjA0UlUKVGkvR0VXeXpJc2w0Umc3dEd0QXdtY0lQZ1VOVWZZMlEzOTBGR3FkSDRhaG4rbXcvNmFGYlczMVc2M2Q5WUpWcQppb3lPVmNhTUlwTTVCL2M3UWM4U3VoQ0kxWUdoVXlnNGNSSExFdzVWdGlraW95RTNYMDRrbmEzalFBajU0WWJSCmJwRWhjMzVhcEtMQjIxSE9VUUlEQVFBQm8xTXdVVEFkQmdOVkhRNEVGZ1FVeXZsMFZJNXZKVlN1WUZYdTdCNDgKNlBiTUVBb3dId1lEVlIwakJCZ3dGb0FVeXZsMFZJNXZKVlN1WUZYdTdCNDg2UGJNRUFvd0R3WURWUjBUQVFILwpCQVV3QXdFQi96QU5CZ2txaGtpRzl3MEJBUXNGQUFPQ0FRRUFNTHhyZ0ZWTXVOUnEyd0F3Y0J0N1NuTlI1Q2Z6CjJNdlhxNUVVbXVhd0lVaTlrYVlqd2RWaURSRUdTams3SlcxN3ZsNTc2SGpEa2RmUndpNEUyOFN5ZFJJblpmNkoKaThIWmNaN2NhSDZEeFIzMzVmZ0hWekxpNU5pVGNlL09qTkJRelEyTUpYVkRkOERCbUc1ZnlhdEppT0pRNGJXRQpBN0ZsUDBSZFAzQ08zR1dFME01aVhPQjJtMXFXa0UyZXlPNFVIdndUcU5RTGRyZEFYZ0RRbGJhbTllNEJHM0dnCmQvNnRoQWtXRGJ0L1FOVCtFSkhEQ3ZoRFJLaDFSdUdIeWcrWSsvbmViVFdXckZXc2t0UnJiT29IQ1ppQ3BYSTEKM2VYRTZudDBZa2d0RHhHMjJLcW5ocEFnOWdVU3MyaGxob3h5dmt6eUYwbXU2TmhQbHdBZ25xNysvUT09Ci0tLS0tRU5EIENFUlRJRklDQVRFLS0tLS0K + name: policy-btls-grpc/envoy-gateway-ca + maxVersion: "1.3" + minVersion: "1.2" + sni: grpc-backend + weight: 1 + failOpen: true + forwardingMetadataNamespaces: + - envoy.filters.http.ext_authz + messageTimeout: 5s + name: envoyextensionpolicy/default/policy-for-gateway/extproc/0 + receivingMetadataNamespaces: + - envoy.filters.http.my_custom + requestAttributes: + - request.path + requestBodyProcessingMode: Buffered + requestHeaderProcessing: true + responseAttributes: + - xds.route_metadata + - connection.requested_server_name + responseBodyProcessingMode: Streamed + responseHeaderProcessing: true + - authority: grpc-backend-system-ca.default:9001 + destination: + metadata: + kind: EnvoyExtensionPolicy + name: policy-for-gateway + namespace: default + name: envoyextensionpolicy/default/policy-for-gateway/extproc/1 + settings: + - addressType: IP + endpoints: + - host: 9.9.9.9 + port: 9001 + metadata: + kind: Service + name: grpc-backend-system-ca + namespace: default + sectionName: "9001" + name: envoyextensionpolicy/default/policy-for-gateway/extproc/1/backend/0 + protocol: GRPC + tls: + alpnProtocols: null + caCertificate: + name: policy-btls-grpc-system-ca/default-ca + maxVersion: "1.3" + minVersion: "1.2" + sni: grpc-backend-system-ca + useSystemTrustStore: true + weight: 1 + name: envoyextensionpolicy/default/policy-for-gateway/extproc/1 + requestHeaderProcessing: true + responseHeaderProcessing: true externalPort: 80 hostnames: - '*' @@ -404,84 +482,6 @@ xdsIR: weight: 1 directResponse: statusCode: 500 - envoyExtensions: - extProcs: - - allowModeOverride: true - authority: grpc-backend.envoy-gateway:8000 - destination: - metadata: - kind: EnvoyExtensionPolicy - name: policy-for-gateway - namespace: default - name: envoyextensionpolicy/default/policy-for-gateway/extproc/0 - settings: - - addressType: IP - endpoints: - - host: 7.7.7.7 - port: 8000 - metadata: - kind: Service - name: grpc-backend - namespace: envoy-gateway - sectionName: "8000" - name: envoyextensionpolicy/default/policy-for-gateway/extproc/0/backend/0 - protocol: GRPC - tls: - alpnProtocols: null - caCertificate: - certificate: LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSURKekNDQWcrZ0F3SUJBZ0lVQWw2VUtJdUttenRlODFjbGx6NVBmZE4ySWxJd0RRWUpLb1pJaHZjTkFRRUwKQlFBd0l6RVFNQTRHQTFVRUF3d0hiWGxqYVdWdWRERVBNQTBHQTFVRUNnd0dhM1ZpWldSaU1CNFhEVEl6TVRBdwpNakExTkRFMU4xb1hEVEkwTVRBd01UQTFOREUxTjFvd0l6RVFNQTRHQTFVRUF3d0hiWGxqYVdWdWRERVBNQTBHCkExVUVDZ3dHYTNWaVpXUmlNSUlCSWpBTkJna3Foa2lHOXcwQkFRRUZBQU9DQVE4QU1JSUJDZ0tDQVFFQXdTVGMKMXlqOEhXNjJueW5rRmJYbzRWWEt2MmpDMFBNN2RQVmt5ODdGd2VaY1RLTG9XUVZQUUUycDJrTERLNk9Fc3ptTQp5eXIreHhXdHlpdmVyZW1yV3FuS2tOVFloTGZZUGhnUWtjemliN2VVYWxtRmpVYmhXZEx2SGFrYkVnQ29kbjNiCmt6NTdtSW5YMlZwaURPS2c0a3lIZml1WFdwaUJxckN4MEtOTHB4bzNERVFjRmNzUVRlVEh6aDQ3NTJHVjA0UlUKVGkvR0VXeXpJc2w0Umc3dEd0QXdtY0lQZ1VOVWZZMlEzOTBGR3FkSDRhaG4rbXcvNmFGYlczMVc2M2Q5WUpWcQppb3lPVmNhTUlwTTVCL2M3UWM4U3VoQ0kxWUdoVXlnNGNSSExFdzVWdGlraW95RTNYMDRrbmEzalFBajU0WWJSCmJwRWhjMzVhcEtMQjIxSE9VUUlEQVFBQm8xTXdVVEFkQmdOVkhRNEVGZ1FVeXZsMFZJNXZKVlN1WUZYdTdCNDgKNlBiTUVBb3dId1lEVlIwakJCZ3dGb0FVeXZsMFZJNXZKVlN1WUZYdTdCNDg2UGJNRUFvd0R3WURWUjBUQVFILwpCQVV3QXdFQi96QU5CZ2txaGtpRzl3MEJBUXNGQUFPQ0FRRUFNTHhyZ0ZWTXVOUnEyd0F3Y0J0N1NuTlI1Q2Z6CjJNdlhxNUVVbXVhd0lVaTlrYVlqd2RWaURSRUdTams3SlcxN3ZsNTc2SGpEa2RmUndpNEUyOFN5ZFJJblpmNkoKaThIWmNaN2NhSDZEeFIzMzVmZ0hWekxpNU5pVGNlL09qTkJRelEyTUpYVkRkOERCbUc1ZnlhdEppT0pRNGJXRQpBN0ZsUDBSZFAzQ08zR1dFME01aVhPQjJtMXFXa0UyZXlPNFVIdndUcU5RTGRyZEFYZ0RRbGJhbTllNEJHM0dnCmQvNnRoQWtXRGJ0L1FOVCtFSkhEQ3ZoRFJLaDFSdUdIeWcrWSsvbmViVFdXckZXc2t0UnJiT29IQ1ppQ3BYSTEKM2VYRTZudDBZa2d0RHhHMjJLcW5ocEFnOWdVU3MyaGxob3h5dmt6eUYwbXU2TmhQbHdBZ25xNysvUT09Ci0tLS0tRU5EIENFUlRJRklDQVRFLS0tLS0K - name: policy-btls-grpc/envoy-gateway-ca - maxVersion: "1.3" - minVersion: "1.2" - sni: grpc-backend - weight: 1 - failOpen: true - forwardingMetadataNamespaces: - - envoy.filters.http.ext_authz - messageTimeout: 5s - name: envoyextensionpolicy/default/policy-for-gateway/extproc/0 - receivingMetadataNamespaces: - - envoy.filters.http.my_custom - requestAttributes: - - request.path - requestBodyProcessingMode: Buffered - requestHeaderProcessing: true - responseAttributes: - - xds.route_metadata - - connection.requested_server_name - responseBodyProcessingMode: Streamed - responseHeaderProcessing: true - - authority: grpc-backend-system-ca.default:9001 - destination: - metadata: - kind: EnvoyExtensionPolicy - name: policy-for-gateway - namespace: default - name: envoyextensionpolicy/default/policy-for-gateway/extproc/1 - settings: - - addressType: IP - endpoints: - - host: 9.9.9.9 - port: 9001 - metadata: - kind: Service - name: grpc-backend-system-ca - namespace: default - sectionName: "9001" - name: envoyextensionpolicy/default/policy-for-gateway/extproc/1/backend/0 - protocol: GRPC - tls: - alpnProtocols: null - caCertificate: - name: policy-btls-grpc-system-ca/default-ca - maxVersion: "1.3" - minVersion: "1.2" - sni: grpc-backend-system-ca - useSystemTrustStore: true - weight: 1 - name: envoyextensionpolicy/default/policy-for-gateway/extproc/1 - requestHeaderProcessing: true - responseHeaderProcessing: true hostname: www.foo.com isHTTP2: false metadata: @@ -512,84 +512,6 @@ xdsIR: name: httproute/default/httproute-2/rule/0/backend/0 protocol: HTTP weight: 1 - envoyExtensions: - extProcs: - - allowModeOverride: true - authority: grpc-backend.envoy-gateway:8000 - destination: - metadata: - kind: EnvoyExtensionPolicy - name: policy-for-gateway - namespace: default - name: envoyextensionpolicy/default/policy-for-gateway/extproc/0 - settings: - - addressType: IP - endpoints: - - host: 7.7.7.7 - port: 8000 - metadata: - kind: Service - name: grpc-backend - namespace: envoy-gateway - sectionName: "8000" - name: envoyextensionpolicy/default/policy-for-gateway/extproc/0/backend/0 - protocol: GRPC - tls: - alpnProtocols: null - caCertificate: - certificate: LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSURKekNDQWcrZ0F3SUJBZ0lVQWw2VUtJdUttenRlODFjbGx6NVBmZE4ySWxJd0RRWUpLb1pJaHZjTkFRRUwKQlFBd0l6RVFNQTRHQTFVRUF3d0hiWGxqYVdWdWRERVBNQTBHQTFVRUNnd0dhM1ZpWldSaU1CNFhEVEl6TVRBdwpNakExTkRFMU4xb1hEVEkwTVRBd01UQTFOREUxTjFvd0l6RVFNQTRHQTFVRUF3d0hiWGxqYVdWdWRERVBNQTBHCkExVUVDZ3dHYTNWaVpXUmlNSUlCSWpBTkJna3Foa2lHOXcwQkFRRUZBQU9DQVE4QU1JSUJDZ0tDQVFFQXdTVGMKMXlqOEhXNjJueW5rRmJYbzRWWEt2MmpDMFBNN2RQVmt5ODdGd2VaY1RLTG9XUVZQUUUycDJrTERLNk9Fc3ptTQp5eXIreHhXdHlpdmVyZW1yV3FuS2tOVFloTGZZUGhnUWtjemliN2VVYWxtRmpVYmhXZEx2SGFrYkVnQ29kbjNiCmt6NTdtSW5YMlZwaURPS2c0a3lIZml1WFdwaUJxckN4MEtOTHB4bzNERVFjRmNzUVRlVEh6aDQ3NTJHVjA0UlUKVGkvR0VXeXpJc2w0Umc3dEd0QXdtY0lQZ1VOVWZZMlEzOTBGR3FkSDRhaG4rbXcvNmFGYlczMVc2M2Q5WUpWcQppb3lPVmNhTUlwTTVCL2M3UWM4U3VoQ0kxWUdoVXlnNGNSSExFdzVWdGlraW95RTNYMDRrbmEzalFBajU0WWJSCmJwRWhjMzVhcEtMQjIxSE9VUUlEQVFBQm8xTXdVVEFkQmdOVkhRNEVGZ1FVeXZsMFZJNXZKVlN1WUZYdTdCNDgKNlBiTUVBb3dId1lEVlIwakJCZ3dGb0FVeXZsMFZJNXZKVlN1WUZYdTdCNDg2UGJNRUFvd0R3WURWUjBUQVFILwpCQVV3QXdFQi96QU5CZ2txaGtpRzl3MEJBUXNGQUFPQ0FRRUFNTHhyZ0ZWTXVOUnEyd0F3Y0J0N1NuTlI1Q2Z6CjJNdlhxNUVVbXVhd0lVaTlrYVlqd2RWaURSRUdTams3SlcxN3ZsNTc2SGpEa2RmUndpNEUyOFN5ZFJJblpmNkoKaThIWmNaN2NhSDZEeFIzMzVmZ0hWekxpNU5pVGNlL09qTkJRelEyTUpYVkRkOERCbUc1ZnlhdEppT0pRNGJXRQpBN0ZsUDBSZFAzQ08zR1dFME01aVhPQjJtMXFXa0UyZXlPNFVIdndUcU5RTGRyZEFYZ0RRbGJhbTllNEJHM0dnCmQvNnRoQWtXRGJ0L1FOVCtFSkhEQ3ZoRFJLaDFSdUdIeWcrWSsvbmViVFdXckZXc2t0UnJiT29IQ1ppQ3BYSTEKM2VYRTZudDBZa2d0RHhHMjJLcW5ocEFnOWdVU3MyaGxob3h5dmt6eUYwbXU2TmhQbHdBZ25xNysvUT09Ci0tLS0tRU5EIENFUlRJRklDQVRFLS0tLS0K - name: policy-btls-grpc/envoy-gateway-ca - maxVersion: "1.3" - minVersion: "1.2" - sni: grpc-backend - weight: 1 - failOpen: true - forwardingMetadataNamespaces: - - envoy.filters.http.ext_authz - messageTimeout: 5s - name: envoyextensionpolicy/default/policy-for-gateway/extproc/0 - receivingMetadataNamespaces: - - envoy.filters.http.my_custom - requestAttributes: - - request.path - requestBodyProcessingMode: Buffered - requestHeaderProcessing: true - responseAttributes: - - xds.route_metadata - - connection.requested_server_name - responseBodyProcessingMode: Streamed - responseHeaderProcessing: true - - authority: grpc-backend-system-ca.default:9001 - destination: - metadata: - kind: EnvoyExtensionPolicy - name: policy-for-gateway - namespace: default - name: envoyextensionpolicy/default/policy-for-gateway/extproc/1 - settings: - - addressType: IP - endpoints: - - host: 9.9.9.9 - port: 9001 - metadata: - kind: Service - name: grpc-backend-system-ca - namespace: default - sectionName: "9001" - name: envoyextensionpolicy/default/policy-for-gateway/extproc/1/backend/0 - protocol: GRPC - tls: - alpnProtocols: null - caCertificate: - name: policy-btls-grpc-system-ca/default-ca - maxVersion: "1.3" - minVersion: "1.2" - sni: grpc-backend-system-ca - useSystemTrustStore: true - weight: 1 - name: envoyextensionpolicy/default/policy-for-gateway/extproc/1 - requestHeaderProcessing: true - responseHeaderProcessing: true hostname: www.bar.com isHTTP2: false metadata: diff --git a/internal/gatewayapi/testdata/envoyextensionpolicy-with-extproc-with-backendtlspolicy-shared-secret.out.yaml b/internal/gatewayapi/testdata/envoyextensionpolicy-with-extproc-with-backendtlspolicy-shared-secret.out.yaml index e7507cf3d9..a01b2c5856 100644 --- a/internal/gatewayapi/testdata/envoyextensionpolicy-with-extproc-with-backendtlspolicy-shared-secret.out.yaml +++ b/internal/gatewayapi/testdata/envoyextensionpolicy-with-extproc-with-backendtlspolicy-shared-secret.out.yaml @@ -369,6 +369,84 @@ xdsIR: protocol: TCP http: - address: 0.0.0.0 + envoyExtensions: + extProcs: + - allowModeOverride: true + authority: grpc-backend.envoy-gateway:8000 + destination: + metadata: + kind: EnvoyExtensionPolicy + name: policy-for-gateway + namespace: default + name: envoyextensionpolicy/default/policy-for-gateway/extproc/0 + settings: + - addressType: IP + endpoints: + - host: 7.7.7.7 + port: 8000 + metadata: + kind: Service + name: grpc-backend + namespace: envoy-gateway + sectionName: "8000" + name: envoyextensionpolicy/default/policy-for-gateway/extproc/0/backend/0 + protocol: GRPC + tls: + alpnProtocols: null + caCertificate: + certificate: LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSURKekNDQWcrZ0F3SUJBZ0lVQWw2VUtJdUttenRlODFjbGx6NVBmZE4ySWxJd0RRWUpLb1pJaHZjTkFRRUwKQlFBd0l6RVFNQTRHQTFVRUF3d0hiWGxqYVdWdWRERVBNQTBHQTFVRUNnd0dhM1ZpWldSaU1CNFhEVEl6TVRBdwpNakExTkRFMU4xb1hEVEkwTVRBd01UQTFOREUxTjFvd0l6RVFNQTRHQTFVRUF3d0hiWGxqYVdWdWRERVBNQTBHCkExVUVDZ3dHYTNWaVpXUmlNSUlCSWpBTkJna3Foa2lHOXcwQkFRRUZBQU9DQVE4QU1JSUJDZ0tDQVFFQXdTVGMKMXlqOEhXNjJueW5rRmJYbzRWWEt2MmpDMFBNN2RQVmt5ODdGd2VaY1RLTG9XUVZQUUUycDJrTERLNk9Fc3ptTQp5eXIreHhXdHlpdmVyZW1yV3FuS2tOVFloTGZZUGhnUWtjemliN2VVYWxtRmpVYmhXZEx2SGFrYkVnQ29kbjNiCmt6NTdtSW5YMlZwaURPS2c0a3lIZml1WFdwaUJxckN4MEtOTHB4bzNERVFjRmNzUVRlVEh6aDQ3NTJHVjA0UlUKVGkvR0VXeXpJc2w0Umc3dEd0QXdtY0lQZ1VOVWZZMlEzOTBGR3FkSDRhaG4rbXcvNmFGYlczMVc2M2Q5WUpWcQppb3lPVmNhTUlwTTVCL2M3UWM4U3VoQ0kxWUdoVXlnNGNSSExFdzVWdGlraW95RTNYMDRrbmEzalFBajU0WWJSCmJwRWhjMzVhcEtMQjIxSE9VUUlEQVFBQm8xTXdVVEFkQmdOVkhRNEVGZ1FVeXZsMFZJNXZKVlN1WUZYdTdCNDgKNlBiTUVBb3dId1lEVlIwakJCZ3dGb0FVeXZsMFZJNXZKVlN1WUZYdTdCNDg2UGJNRUFvd0R3WURWUjBUQVFILwpCQVV3QXdFQi96QU5CZ2txaGtpRzl3MEJBUXNGQUFPQ0FRRUFNTHhyZ0ZWTXVOUnEyd0F3Y0J0N1NuTlI1Q2Z6CjJNdlhxNUVVbXVhd0lVaTlrYVlqd2RWaURSRUdTams3SlcxN3ZsNTc2SGpEa2RmUndpNEUyOFN5ZFJJblpmNkoKaThIWmNaN2NhSDZEeFIzMzVmZ0hWekxpNU5pVGNlL09qTkJRelEyTUpYVkRkOERCbUc1ZnlhdEppT0pRNGJXRQpBN0ZsUDBSZFAzQ08zR1dFME01aVhPQjJtMXFXa0UyZXlPNFVIdndUcU5RTGRyZEFYZ0RRbGJhbTllNEJHM0dnCmQvNnRoQWtXRGJ0L1FOVCtFSkhEQ3ZoRFJLaDFSdUdIeWcrWSsvbmViVFdXckZXc2t0UnJiT29IQ1ppQ3BYSTEKM2VYRTZudDBZa2d0RHhHMjJLcW5ocEFnOWdVU3MyaGxob3h5dmt6eUYwbXU2TmhQbHdBZ25xNysvUT09Ci0tLS0tRU5EIENFUlRJRklDQVRFLS0tLS0K + name: policy-btls-grpc/envoy-gateway-ca + maxVersion: "1.3" + minVersion: "1.2" + sni: grpc-backend + weight: 1 + failOpen: true + forwardingMetadataNamespaces: + - envoy.filters.http.ext_authz + messageTimeout: 5s + name: envoyextensionpolicy/default/policy-for-gateway/extproc/0 + receivingMetadataNamespaces: + - envoy.filters.http.my_custom + requestAttributes: + - request.path + requestBodyProcessingMode: Buffered + requestHeaderProcessing: true + responseAttributes: + - xds.route_metadata + - connection.requested_server_name + responseBodyProcessingMode: Streamed + responseHeaderProcessing: true + - authority: grpc-backend-system-ca.default:9001 + destination: + metadata: + kind: EnvoyExtensionPolicy + name: policy-for-gateway + namespace: default + name: envoyextensionpolicy/default/policy-for-gateway/extproc/1 + settings: + - addressType: IP + endpoints: + - host: 9.9.9.9 + port: 9001 + metadata: + kind: Service + name: grpc-backend-system-ca + namespace: default + sectionName: "9001" + name: envoyextensionpolicy/default/policy-for-gateway/extproc/1/backend/0 + protocol: GRPC + tls: + alpnProtocols: null + caCertificate: + name: system_ca_certificates + maxVersion: "1.3" + minVersion: "1.2" + sni: grpc-backend-system-ca + useSystemTrustStore: true + weight: 1 + name: envoyextensionpolicy/default/policy-for-gateway/extproc/1 + requestHeaderProcessing: true + responseHeaderProcessing: true externalPort: 80 hostnames: - '*' @@ -404,84 +482,6 @@ xdsIR: weight: 1 directResponse: statusCode: 500 - envoyExtensions: - extProcs: - - allowModeOverride: true - authority: grpc-backend.envoy-gateway:8000 - destination: - metadata: - kind: EnvoyExtensionPolicy - name: policy-for-gateway - namespace: default - name: envoyextensionpolicy/default/policy-for-gateway/extproc/0 - settings: - - addressType: IP - endpoints: - - host: 7.7.7.7 - port: 8000 - metadata: - kind: Service - name: grpc-backend - namespace: envoy-gateway - sectionName: "8000" - name: envoyextensionpolicy/default/policy-for-gateway/extproc/0/backend/0 - protocol: GRPC - tls: - alpnProtocols: null - caCertificate: - certificate: LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSURKekNDQWcrZ0F3SUJBZ0lVQWw2VUtJdUttenRlODFjbGx6NVBmZE4ySWxJd0RRWUpLb1pJaHZjTkFRRUwKQlFBd0l6RVFNQTRHQTFVRUF3d0hiWGxqYVdWdWRERVBNQTBHQTFVRUNnd0dhM1ZpWldSaU1CNFhEVEl6TVRBdwpNakExTkRFMU4xb1hEVEkwTVRBd01UQTFOREUxTjFvd0l6RVFNQTRHQTFVRUF3d0hiWGxqYVdWdWRERVBNQTBHCkExVUVDZ3dHYTNWaVpXUmlNSUlCSWpBTkJna3Foa2lHOXcwQkFRRUZBQU9DQVE4QU1JSUJDZ0tDQVFFQXdTVGMKMXlqOEhXNjJueW5rRmJYbzRWWEt2MmpDMFBNN2RQVmt5ODdGd2VaY1RLTG9XUVZQUUUycDJrTERLNk9Fc3ptTQp5eXIreHhXdHlpdmVyZW1yV3FuS2tOVFloTGZZUGhnUWtjemliN2VVYWxtRmpVYmhXZEx2SGFrYkVnQ29kbjNiCmt6NTdtSW5YMlZwaURPS2c0a3lIZml1WFdwaUJxckN4MEtOTHB4bzNERVFjRmNzUVRlVEh6aDQ3NTJHVjA0UlUKVGkvR0VXeXpJc2w0Umc3dEd0QXdtY0lQZ1VOVWZZMlEzOTBGR3FkSDRhaG4rbXcvNmFGYlczMVc2M2Q5WUpWcQppb3lPVmNhTUlwTTVCL2M3UWM4U3VoQ0kxWUdoVXlnNGNSSExFdzVWdGlraW95RTNYMDRrbmEzalFBajU0WWJSCmJwRWhjMzVhcEtMQjIxSE9VUUlEQVFBQm8xTXdVVEFkQmdOVkhRNEVGZ1FVeXZsMFZJNXZKVlN1WUZYdTdCNDgKNlBiTUVBb3dId1lEVlIwakJCZ3dGb0FVeXZsMFZJNXZKVlN1WUZYdTdCNDg2UGJNRUFvd0R3WURWUjBUQVFILwpCQVV3QXdFQi96QU5CZ2txaGtpRzl3MEJBUXNGQUFPQ0FRRUFNTHhyZ0ZWTXVOUnEyd0F3Y0J0N1NuTlI1Q2Z6CjJNdlhxNUVVbXVhd0lVaTlrYVlqd2RWaURSRUdTams3SlcxN3ZsNTc2SGpEa2RmUndpNEUyOFN5ZFJJblpmNkoKaThIWmNaN2NhSDZEeFIzMzVmZ0hWekxpNU5pVGNlL09qTkJRelEyTUpYVkRkOERCbUc1ZnlhdEppT0pRNGJXRQpBN0ZsUDBSZFAzQ08zR1dFME01aVhPQjJtMXFXa0UyZXlPNFVIdndUcU5RTGRyZEFYZ0RRbGJhbTllNEJHM0dnCmQvNnRoQWtXRGJ0L1FOVCtFSkhEQ3ZoRFJLaDFSdUdIeWcrWSsvbmViVFdXckZXc2t0UnJiT29IQ1ppQ3BYSTEKM2VYRTZudDBZa2d0RHhHMjJLcW5ocEFnOWdVU3MyaGxob3h5dmt6eUYwbXU2TmhQbHdBZ25xNysvUT09Ci0tLS0tRU5EIENFUlRJRklDQVRFLS0tLS0K - name: policy-btls-grpc/envoy-gateway-ca - maxVersion: "1.3" - minVersion: "1.2" - sni: grpc-backend - weight: 1 - failOpen: true - forwardingMetadataNamespaces: - - envoy.filters.http.ext_authz - messageTimeout: 5s - name: envoyextensionpolicy/default/policy-for-gateway/extproc/0 - receivingMetadataNamespaces: - - envoy.filters.http.my_custom - requestAttributes: - - request.path - requestBodyProcessingMode: Buffered - requestHeaderProcessing: true - responseAttributes: - - xds.route_metadata - - connection.requested_server_name - responseBodyProcessingMode: Streamed - responseHeaderProcessing: true - - authority: grpc-backend-system-ca.default:9001 - destination: - metadata: - kind: EnvoyExtensionPolicy - name: policy-for-gateway - namespace: default - name: envoyextensionpolicy/default/policy-for-gateway/extproc/1 - settings: - - addressType: IP - endpoints: - - host: 9.9.9.9 - port: 9001 - metadata: - kind: Service - name: grpc-backend-system-ca - namespace: default - sectionName: "9001" - name: envoyextensionpolicy/default/policy-for-gateway/extproc/1/backend/0 - protocol: GRPC - tls: - alpnProtocols: null - caCertificate: - name: system_ca_certificates - maxVersion: "1.3" - minVersion: "1.2" - sni: grpc-backend-system-ca - useSystemTrustStore: true - weight: 1 - name: envoyextensionpolicy/default/policy-for-gateway/extproc/1 - requestHeaderProcessing: true - responseHeaderProcessing: true hostname: www.foo.com isHTTP2: false metadata: @@ -512,84 +512,6 @@ xdsIR: name: httproute/default/httproute-2/rule/0/backend/0 protocol: HTTP weight: 1 - envoyExtensions: - extProcs: - - allowModeOverride: true - authority: grpc-backend.envoy-gateway:8000 - destination: - metadata: - kind: EnvoyExtensionPolicy - name: policy-for-gateway - namespace: default - name: envoyextensionpolicy/default/policy-for-gateway/extproc/0 - settings: - - addressType: IP - endpoints: - - host: 7.7.7.7 - port: 8000 - metadata: - kind: Service - name: grpc-backend - namespace: envoy-gateway - sectionName: "8000" - name: envoyextensionpolicy/default/policy-for-gateway/extproc/0/backend/0 - protocol: GRPC - tls: - alpnProtocols: null - caCertificate: - certificate: LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSURKekNDQWcrZ0F3SUJBZ0lVQWw2VUtJdUttenRlODFjbGx6NVBmZE4ySWxJd0RRWUpLb1pJaHZjTkFRRUwKQlFBd0l6RVFNQTRHQTFVRUF3d0hiWGxqYVdWdWRERVBNQTBHQTFVRUNnd0dhM1ZpWldSaU1CNFhEVEl6TVRBdwpNakExTkRFMU4xb1hEVEkwTVRBd01UQTFOREUxTjFvd0l6RVFNQTRHQTFVRUF3d0hiWGxqYVdWdWRERVBNQTBHCkExVUVDZ3dHYTNWaVpXUmlNSUlCSWpBTkJna3Foa2lHOXcwQkFRRUZBQU9DQVE4QU1JSUJDZ0tDQVFFQXdTVGMKMXlqOEhXNjJueW5rRmJYbzRWWEt2MmpDMFBNN2RQVmt5ODdGd2VaY1RLTG9XUVZQUUUycDJrTERLNk9Fc3ptTQp5eXIreHhXdHlpdmVyZW1yV3FuS2tOVFloTGZZUGhnUWtjemliN2VVYWxtRmpVYmhXZEx2SGFrYkVnQ29kbjNiCmt6NTdtSW5YMlZwaURPS2c0a3lIZml1WFdwaUJxckN4MEtOTHB4bzNERVFjRmNzUVRlVEh6aDQ3NTJHVjA0UlUKVGkvR0VXeXpJc2w0Umc3dEd0QXdtY0lQZ1VOVWZZMlEzOTBGR3FkSDRhaG4rbXcvNmFGYlczMVc2M2Q5WUpWcQppb3lPVmNhTUlwTTVCL2M3UWM4U3VoQ0kxWUdoVXlnNGNSSExFdzVWdGlraW95RTNYMDRrbmEzalFBajU0WWJSCmJwRWhjMzVhcEtMQjIxSE9VUUlEQVFBQm8xTXdVVEFkQmdOVkhRNEVGZ1FVeXZsMFZJNXZKVlN1WUZYdTdCNDgKNlBiTUVBb3dId1lEVlIwakJCZ3dGb0FVeXZsMFZJNXZKVlN1WUZYdTdCNDg2UGJNRUFvd0R3WURWUjBUQVFILwpCQVV3QXdFQi96QU5CZ2txaGtpRzl3MEJBUXNGQUFPQ0FRRUFNTHhyZ0ZWTXVOUnEyd0F3Y0J0N1NuTlI1Q2Z6CjJNdlhxNUVVbXVhd0lVaTlrYVlqd2RWaURSRUdTams3SlcxN3ZsNTc2SGpEa2RmUndpNEUyOFN5ZFJJblpmNkoKaThIWmNaN2NhSDZEeFIzMzVmZ0hWekxpNU5pVGNlL09qTkJRelEyTUpYVkRkOERCbUc1ZnlhdEppT0pRNGJXRQpBN0ZsUDBSZFAzQ08zR1dFME01aVhPQjJtMXFXa0UyZXlPNFVIdndUcU5RTGRyZEFYZ0RRbGJhbTllNEJHM0dnCmQvNnRoQWtXRGJ0L1FOVCtFSkhEQ3ZoRFJLaDFSdUdIeWcrWSsvbmViVFdXckZXc2t0UnJiT29IQ1ppQ3BYSTEKM2VYRTZudDBZa2d0RHhHMjJLcW5ocEFnOWdVU3MyaGxob3h5dmt6eUYwbXU2TmhQbHdBZ25xNysvUT09Ci0tLS0tRU5EIENFUlRJRklDQVRFLS0tLS0K - name: policy-btls-grpc/envoy-gateway-ca - maxVersion: "1.3" - minVersion: "1.2" - sni: grpc-backend - weight: 1 - failOpen: true - forwardingMetadataNamespaces: - - envoy.filters.http.ext_authz - messageTimeout: 5s - name: envoyextensionpolicy/default/policy-for-gateway/extproc/0 - receivingMetadataNamespaces: - - envoy.filters.http.my_custom - requestAttributes: - - request.path - requestBodyProcessingMode: Buffered - requestHeaderProcessing: true - responseAttributes: - - xds.route_metadata - - connection.requested_server_name - responseBodyProcessingMode: Streamed - responseHeaderProcessing: true - - authority: grpc-backend-system-ca.default:9001 - destination: - metadata: - kind: EnvoyExtensionPolicy - name: policy-for-gateway - namespace: default - name: envoyextensionpolicy/default/policy-for-gateway/extproc/1 - settings: - - addressType: IP - endpoints: - - host: 9.9.9.9 - port: 9001 - metadata: - kind: Service - name: grpc-backend-system-ca - namespace: default - sectionName: "9001" - name: envoyextensionpolicy/default/policy-for-gateway/extproc/1/backend/0 - protocol: GRPC - tls: - alpnProtocols: null - caCertificate: - name: system_ca_certificates - maxVersion: "1.3" - minVersion: "1.2" - sni: grpc-backend-system-ca - useSystemTrustStore: true - weight: 1 - name: envoyextensionpolicy/default/policy-for-gateway/extproc/1 - requestHeaderProcessing: true - responseHeaderProcessing: true hostname: www.bar.com isHTTP2: false metadata: diff --git a/internal/gatewayapi/testdata/envoyextensionpolicy-with-extproc-with-backendtlspolicy.out.yaml b/internal/gatewayapi/testdata/envoyextensionpolicy-with-extproc-with-backendtlspolicy.out.yaml index e638a63610..cbe3971b52 100644 --- a/internal/gatewayapi/testdata/envoyextensionpolicy-with-extproc-with-backendtlspolicy.out.yaml +++ b/internal/gatewayapi/testdata/envoyextensionpolicy-with-extproc-with-backendtlspolicy.out.yaml @@ -330,6 +330,54 @@ xdsIR: protocol: TCP http: - address: 0.0.0.0 + envoyExtensions: + extProcs: + - allowModeOverride: true + authority: grpc-backend.envoy-gateway:8000 + destination: + metadata: + kind: EnvoyExtensionPolicy + name: policy-for-gateway + namespace: default + name: envoyextensionpolicy/default/policy-for-gateway/extproc/0 + settings: + - addressType: IP + endpoints: + - host: 7.7.7.7 + port: 8000 + metadata: + kind: Service + name: grpc-backend + namespace: envoy-gateway + sectionName: "8000" + name: envoyextensionpolicy/default/policy-for-gateway/extproc/0/backend/0 + protocol: GRPC + tls: + alpnProtocols: null + caCertificate: + certificate: LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSURKekNDQWcrZ0F3SUJBZ0lVQWw2VUtJdUttenRlODFjbGx6NVBmZE4ySWxJd0RRWUpLb1pJaHZjTkFRRUwKQlFBd0l6RVFNQTRHQTFVRUF3d0hiWGxqYVdWdWRERVBNQTBHQTFVRUNnd0dhM1ZpWldSaU1CNFhEVEl6TVRBdwpNakExTkRFMU4xb1hEVEkwTVRBd01UQTFOREUxTjFvd0l6RVFNQTRHQTFVRUF3d0hiWGxqYVdWdWRERVBNQTBHCkExVUVDZ3dHYTNWaVpXUmlNSUlCSWpBTkJna3Foa2lHOXcwQkFRRUZBQU9DQVE4QU1JSUJDZ0tDQVFFQXdTVGMKMXlqOEhXNjJueW5rRmJYbzRWWEt2MmpDMFBNN2RQVmt5ODdGd2VaY1RLTG9XUVZQUUUycDJrTERLNk9Fc3ptTQp5eXIreHhXdHlpdmVyZW1yV3FuS2tOVFloTGZZUGhnUWtjemliN2VVYWxtRmpVYmhXZEx2SGFrYkVnQ29kbjNiCmt6NTdtSW5YMlZwaURPS2c0a3lIZml1WFdwaUJxckN4MEtOTHB4bzNERVFjRmNzUVRlVEh6aDQ3NTJHVjA0UlUKVGkvR0VXeXpJc2w0Umc3dEd0QXdtY0lQZ1VOVWZZMlEzOTBGR3FkSDRhaG4rbXcvNmFGYlczMVc2M2Q5WUpWcQppb3lPVmNhTUlwTTVCL2M3UWM4U3VoQ0kxWUdoVXlnNGNSSExFdzVWdGlraW95RTNYMDRrbmEzalFBajU0WWJSCmJwRWhjMzVhcEtMQjIxSE9VUUlEQVFBQm8xTXdVVEFkQmdOVkhRNEVGZ1FVeXZsMFZJNXZKVlN1WUZYdTdCNDgKNlBiTUVBb3dId1lEVlIwakJCZ3dGb0FVeXZsMFZJNXZKVlN1WUZYdTdCNDg2UGJNRUFvd0R3WURWUjBUQVFILwpCQVV3QXdFQi96QU5CZ2txaGtpRzl3MEJBUXNGQUFPQ0FRRUFNTHhyZ0ZWTXVOUnEyd0F3Y0J0N1NuTlI1Q2Z6CjJNdlhxNUVVbXVhd0lVaTlrYVlqd2RWaURSRUdTams3SlcxN3ZsNTc2SGpEa2RmUndpNEUyOFN5ZFJJblpmNkoKaThIWmNaN2NhSDZEeFIzMzVmZ0hWekxpNU5pVGNlL09qTkJRelEyTUpYVkRkOERCbUc1ZnlhdEppT0pRNGJXRQpBN0ZsUDBSZFAzQ08zR1dFME01aVhPQjJtMXFXa0UyZXlPNFVIdndUcU5RTGRyZEFYZ0RRbGJhbTllNEJHM0dnCmQvNnRoQWtXRGJ0L1FOVCtFSkhEQ3ZoRFJLaDFSdUdIeWcrWSsvbmViVFdXckZXc2t0UnJiT29IQ1ppQ3BYSTEKM2VYRTZudDBZa2d0RHhHMjJLcW5ocEFnOWdVU3MyaGxob3h5dmt6eUYwbXU2TmhQbHdBZ25xNysvUT09Ci0tLS0tRU5EIENFUlRJRklDQVRFLS0tLS0K + name: policy-btls-grpc/envoy-gateway-ca + maxVersion: "1.3" + minVersion: "1.2" + sni: grpc-backend + weight: 1 + failOpen: true + forwardingMetadataNamespaces: + - envoy.filters.http.ext_authz + messageTimeout: 5s + name: envoyextensionpolicy/default/policy-for-gateway/extproc/0 + receivingMetadataNamespaces: + - envoy.filters.http.my_custom + requestAttributes: + - request.path + requestBodyProcessingMode: Buffered + requestHeaderProcessing: true + responseAttributes: + - xds.route_metadata + - connection.requested_server_name + responseBodyProcessingMode: Streamed + responseHeaderProcessing: true + statusOnError: 503 externalPort: 80 hostnames: - '*' @@ -365,54 +413,6 @@ xdsIR: weight: 1 directResponse: statusCode: 500 - envoyExtensions: - extProcs: - - allowModeOverride: true - authority: grpc-backend.envoy-gateway:8000 - destination: - metadata: - kind: EnvoyExtensionPolicy - name: policy-for-gateway - namespace: default - name: envoyextensionpolicy/default/policy-for-gateway/extproc/0 - settings: - - addressType: IP - endpoints: - - host: 7.7.7.7 - port: 8000 - metadata: - kind: Service - name: grpc-backend - namespace: envoy-gateway - sectionName: "8000" - name: envoyextensionpolicy/default/policy-for-gateway/extproc/0/backend/0 - protocol: GRPC - tls: - alpnProtocols: null - caCertificate: - certificate: LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSURKekNDQWcrZ0F3SUJBZ0lVQWw2VUtJdUttenRlODFjbGx6NVBmZE4ySWxJd0RRWUpLb1pJaHZjTkFRRUwKQlFBd0l6RVFNQTRHQTFVRUF3d0hiWGxqYVdWdWRERVBNQTBHQTFVRUNnd0dhM1ZpWldSaU1CNFhEVEl6TVRBdwpNakExTkRFMU4xb1hEVEkwTVRBd01UQTFOREUxTjFvd0l6RVFNQTRHQTFVRUF3d0hiWGxqYVdWdWRERVBNQTBHCkExVUVDZ3dHYTNWaVpXUmlNSUlCSWpBTkJna3Foa2lHOXcwQkFRRUZBQU9DQVE4QU1JSUJDZ0tDQVFFQXdTVGMKMXlqOEhXNjJueW5rRmJYbzRWWEt2MmpDMFBNN2RQVmt5ODdGd2VaY1RLTG9XUVZQUUUycDJrTERLNk9Fc3ptTQp5eXIreHhXdHlpdmVyZW1yV3FuS2tOVFloTGZZUGhnUWtjemliN2VVYWxtRmpVYmhXZEx2SGFrYkVnQ29kbjNiCmt6NTdtSW5YMlZwaURPS2c0a3lIZml1WFdwaUJxckN4MEtOTHB4bzNERVFjRmNzUVRlVEh6aDQ3NTJHVjA0UlUKVGkvR0VXeXpJc2w0Umc3dEd0QXdtY0lQZ1VOVWZZMlEzOTBGR3FkSDRhaG4rbXcvNmFGYlczMVc2M2Q5WUpWcQppb3lPVmNhTUlwTTVCL2M3UWM4U3VoQ0kxWUdoVXlnNGNSSExFdzVWdGlraW95RTNYMDRrbmEzalFBajU0WWJSCmJwRWhjMzVhcEtMQjIxSE9VUUlEQVFBQm8xTXdVVEFkQmdOVkhRNEVGZ1FVeXZsMFZJNXZKVlN1WUZYdTdCNDgKNlBiTUVBb3dId1lEVlIwakJCZ3dGb0FVeXZsMFZJNXZKVlN1WUZYdTdCNDg2UGJNRUFvd0R3WURWUjBUQVFILwpCQVV3QXdFQi96QU5CZ2txaGtpRzl3MEJBUXNGQUFPQ0FRRUFNTHhyZ0ZWTXVOUnEyd0F3Y0J0N1NuTlI1Q2Z6CjJNdlhxNUVVbXVhd0lVaTlrYVlqd2RWaURSRUdTams3SlcxN3ZsNTc2SGpEa2RmUndpNEUyOFN5ZFJJblpmNkoKaThIWmNaN2NhSDZEeFIzMzVmZ0hWekxpNU5pVGNlL09qTkJRelEyTUpYVkRkOERCbUc1ZnlhdEppT0pRNGJXRQpBN0ZsUDBSZFAzQ08zR1dFME01aVhPQjJtMXFXa0UyZXlPNFVIdndUcU5RTGRyZEFYZ0RRbGJhbTllNEJHM0dnCmQvNnRoQWtXRGJ0L1FOVCtFSkhEQ3ZoRFJLaDFSdUdIeWcrWSsvbmViVFdXckZXc2t0UnJiT29IQ1ppQ3BYSTEKM2VYRTZudDBZa2d0RHhHMjJLcW5ocEFnOWdVU3MyaGxob3h5dmt6eUYwbXU2TmhQbHdBZ25xNysvUT09Ci0tLS0tRU5EIENFUlRJRklDQVRFLS0tLS0K - name: policy-btls-grpc/envoy-gateway-ca - maxVersion: "1.3" - minVersion: "1.2" - sni: grpc-backend - weight: 1 - failOpen: true - forwardingMetadataNamespaces: - - envoy.filters.http.ext_authz - messageTimeout: 5s - name: envoyextensionpolicy/default/policy-for-gateway/extproc/0 - receivingMetadataNamespaces: - - envoy.filters.http.my_custom - requestAttributes: - - request.path - requestBodyProcessingMode: Buffered - requestHeaderProcessing: true - responseAttributes: - - xds.route_metadata - - connection.requested_server_name - responseBodyProcessingMode: Streamed - responseHeaderProcessing: true - statusOnError: 503 hostname: www.foo.com isHTTP2: false metadata: @@ -443,54 +443,6 @@ xdsIR: name: httproute/default/httproute-2/rule/0/backend/0 protocol: HTTP weight: 1 - envoyExtensions: - extProcs: - - allowModeOverride: true - authority: grpc-backend.envoy-gateway:8000 - destination: - metadata: - kind: EnvoyExtensionPolicy - name: policy-for-gateway - namespace: default - name: envoyextensionpolicy/default/policy-for-gateway/extproc/0 - settings: - - addressType: IP - endpoints: - - host: 7.7.7.7 - port: 8000 - metadata: - kind: Service - name: grpc-backend - namespace: envoy-gateway - sectionName: "8000" - name: envoyextensionpolicy/default/policy-for-gateway/extproc/0/backend/0 - protocol: GRPC - tls: - alpnProtocols: null - caCertificate: - certificate: LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSURKekNDQWcrZ0F3SUJBZ0lVQWw2VUtJdUttenRlODFjbGx6NVBmZE4ySWxJd0RRWUpLb1pJaHZjTkFRRUwKQlFBd0l6RVFNQTRHQTFVRUF3d0hiWGxqYVdWdWRERVBNQTBHQTFVRUNnd0dhM1ZpWldSaU1CNFhEVEl6TVRBdwpNakExTkRFMU4xb1hEVEkwTVRBd01UQTFOREUxTjFvd0l6RVFNQTRHQTFVRUF3d0hiWGxqYVdWdWRERVBNQTBHCkExVUVDZ3dHYTNWaVpXUmlNSUlCSWpBTkJna3Foa2lHOXcwQkFRRUZBQU9DQVE4QU1JSUJDZ0tDQVFFQXdTVGMKMXlqOEhXNjJueW5rRmJYbzRWWEt2MmpDMFBNN2RQVmt5ODdGd2VaY1RLTG9XUVZQUUUycDJrTERLNk9Fc3ptTQp5eXIreHhXdHlpdmVyZW1yV3FuS2tOVFloTGZZUGhnUWtjemliN2VVYWxtRmpVYmhXZEx2SGFrYkVnQ29kbjNiCmt6NTdtSW5YMlZwaURPS2c0a3lIZml1WFdwaUJxckN4MEtOTHB4bzNERVFjRmNzUVRlVEh6aDQ3NTJHVjA0UlUKVGkvR0VXeXpJc2w0Umc3dEd0QXdtY0lQZ1VOVWZZMlEzOTBGR3FkSDRhaG4rbXcvNmFGYlczMVc2M2Q5WUpWcQppb3lPVmNhTUlwTTVCL2M3UWM4U3VoQ0kxWUdoVXlnNGNSSExFdzVWdGlraW95RTNYMDRrbmEzalFBajU0WWJSCmJwRWhjMzVhcEtMQjIxSE9VUUlEQVFBQm8xTXdVVEFkQmdOVkhRNEVGZ1FVeXZsMFZJNXZKVlN1WUZYdTdCNDgKNlBiTUVBb3dId1lEVlIwakJCZ3dGb0FVeXZsMFZJNXZKVlN1WUZYdTdCNDg2UGJNRUFvd0R3WURWUjBUQVFILwpCQVV3QXdFQi96QU5CZ2txaGtpRzl3MEJBUXNGQUFPQ0FRRUFNTHhyZ0ZWTXVOUnEyd0F3Y0J0N1NuTlI1Q2Z6CjJNdlhxNUVVbXVhd0lVaTlrYVlqd2RWaURSRUdTams3SlcxN3ZsNTc2SGpEa2RmUndpNEUyOFN5ZFJJblpmNkoKaThIWmNaN2NhSDZEeFIzMzVmZ0hWekxpNU5pVGNlL09qTkJRelEyTUpYVkRkOERCbUc1ZnlhdEppT0pRNGJXRQpBN0ZsUDBSZFAzQ08zR1dFME01aVhPQjJtMXFXa0UyZXlPNFVIdndUcU5RTGRyZEFYZ0RRbGJhbTllNEJHM0dnCmQvNnRoQWtXRGJ0L1FOVCtFSkhEQ3ZoRFJLaDFSdUdIeWcrWSsvbmViVFdXckZXc2t0UnJiT29IQ1ppQ3BYSTEKM2VYRTZudDBZa2d0RHhHMjJLcW5ocEFnOWdVU3MyaGxob3h5dmt6eUYwbXU2TmhQbHdBZ25xNysvUT09Ci0tLS0tRU5EIENFUlRJRklDQVRFLS0tLS0K - name: policy-btls-grpc/envoy-gateway-ca - maxVersion: "1.3" - minVersion: "1.2" - sni: grpc-backend - weight: 1 - failOpen: true - forwardingMetadataNamespaces: - - envoy.filters.http.ext_authz - messageTimeout: 5s - name: envoyextensionpolicy/default/policy-for-gateway/extproc/0 - receivingMetadataNamespaces: - - envoy.filters.http.my_custom - requestAttributes: - - request.path - requestBodyProcessingMode: Buffered - requestHeaderProcessing: true - responseAttributes: - - xds.route_metadata - - connection.requested_server_name - responseBodyProcessingMode: Streamed - responseHeaderProcessing: true - statusOnError: 503 hostname: www.bar.com isHTTP2: false metadata: diff --git a/internal/gatewayapi/testdata/envoyextensionpolicy-with-invalid-lua-validation-disabled.out.yaml b/internal/gatewayapi/testdata/envoyextensionpolicy-with-invalid-lua-validation-disabled.out.yaml index 68b4e397ba..0c418ae76a 100644 --- a/internal/gatewayapi/testdata/envoyextensionpolicy-with-invalid-lua-validation-disabled.out.yaml +++ b/internal/gatewayapi/testdata/envoyextensionpolicy-with-invalid-lua-validation-disabled.out.yaml @@ -208,15 +208,14 @@ xdsIR: weight: 1 envoyExtensions: luas: - - Code: | + - code: | function envoy_on_response(response_handle) local value = 10 if value > 5 print("Value is greater than 5") end end - FilterContext: null - Name: envoyextensionpolicy/default/policy-for-http-route/lua/0 + name: envoyextensionpolicy/default/policy-for-http-route/lua/0 hostname: www.example.com isHTTP2: false metadata: diff --git a/internal/gatewayapi/testdata/envoyextensionpolicy-with-invalid-lua-validation-syntax.out.yaml b/internal/gatewayapi/testdata/envoyextensionpolicy-with-invalid-lua-validation-syntax.out.yaml index b79ae5ac67..577c10e453 100644 --- a/internal/gatewayapi/testdata/envoyextensionpolicy-with-invalid-lua-validation-syntax.out.yaml +++ b/internal/gatewayapi/testdata/envoyextensionpolicy-with-invalid-lua-validation-syntax.out.yaml @@ -298,7 +298,7 @@ xdsIR: weight: 1 envoyExtensions: luas: - - Code: | + - code: | local json = require("json") function envoy_on_response(response_handle) local content_type = response_handle:headers():get("content-type") @@ -317,8 +317,7 @@ xdsIR: end return envoy.lua.ResponseStatus.Continue end - FilterContext: null - Name: envoyextensionpolicy/default/policy-for-http-route/lua/0 + name: envoyextensionpolicy/default/policy-for-http-route/lua/0 hostname: www.example.com isHTTP2: false metadata: diff --git a/internal/gatewayapi/testdata/envoyextensionpolicy-with-invalid-lua.out.yaml b/internal/gatewayapi/testdata/envoyextensionpolicy-with-invalid-lua.out.yaml index 8c9e4d42ab..e8a0f6b7ab 100644 --- a/internal/gatewayapi/testdata/envoyextensionpolicy-with-invalid-lua.out.yaml +++ b/internal/gatewayapi/testdata/envoyextensionpolicy-with-invalid-lua.out.yaml @@ -253,6 +253,11 @@ xdsIR: protocol: TCP http: - address: 0.0.0.0 + envoyExtensions: + luas: + - code: function envoy_on_request(request_handle) request_handle:logInfo('Goodbye.') + end + name: envoyextensionpolicy/envoy-gateway/policy-for-gateway/lua/0 externalPort: 80 hostnames: - '*' @@ -288,12 +293,6 @@ xdsIR: weight: 1 directResponse: statusCode: 500 - envoyExtensions: - luas: - - Code: function envoy_on_request(request_handle) request_handle:logInfo('Goodbye.') - end - FilterContext: null - Name: envoyextensionpolicy/envoy-gateway/policy-for-gateway/lua/0 hostname: www.example.com isHTTP2: false metadata: @@ -324,12 +323,6 @@ xdsIR: name: httproute/default/httproute-2/rule/0/backend/0 protocol: HTTP weight: 1 - envoyExtensions: - luas: - - Code: function envoy_on_request(request_handle) request_handle:logInfo('Goodbye.') - end - FilterContext: null - Name: envoyextensionpolicy/envoy-gateway/policy-for-gateway/lua/0 hostname: www.example.com isHTTP2: false metadata: diff --git a/internal/gatewayapi/testdata/envoyextensionpolicy-with-lua-configmap.out.yaml b/internal/gatewayapi/testdata/envoyextensionpolicy-with-lua-configmap.out.yaml index df57f5706f..dc6adc46bf 100644 --- a/internal/gatewayapi/testdata/envoyextensionpolicy-with-lua-configmap.out.yaml +++ b/internal/gatewayapi/testdata/envoyextensionpolicy-with-lua-configmap.out.yaml @@ -425,6 +425,13 @@ xdsIR: protocol: TCP http: - address: 0.0.0.0 + envoyExtensions: + luas: + - code: | + function envoy_on_request(request_handle) + request_handle:logInfo('Goodbye.') + end + name: envoyextensionpolicy/envoy-gateway/policy-for-gateway/lua/0 externalPort: 80 hostnames: - '*' @@ -460,14 +467,6 @@ xdsIR: weight: 1 directResponse: statusCode: 500 - envoyExtensions: - luas: - - Code: | - function envoy_on_request(request_handle) - request_handle:logInfo('Goodbye.') - end - FilterContext: null - Name: envoyextensionpolicy/envoy-gateway/policy-for-gateway/lua/0 hostname: www.example.com isHTTP2: false metadata: @@ -500,14 +499,6 @@ xdsIR: weight: 1 directResponse: statusCode: 500 - envoyExtensions: - luas: - - Code: | - function envoy_on_request(request_handle) - request_handle:logInfo('Goodbye.') - end - FilterContext: null - Name: envoyextensionpolicy/envoy-gateway/policy-for-gateway/lua/0 hostname: www.example.com isHTTP2: false metadata: @@ -540,14 +531,6 @@ xdsIR: weight: 1 directResponse: statusCode: 500 - envoyExtensions: - luas: - - Code: | - function envoy_on_request(request_handle) - request_handle:logInfo('Goodbye.') - end - FilterContext: null - Name: envoyextensionpolicy/envoy-gateway/policy-for-gateway/lua/0 hostname: www.example.com isHTTP2: false metadata: @@ -580,13 +563,13 @@ xdsIR: weight: 1 envoyExtensions: luas: - - Code: | + - code: | function envoy_on_response(response_handle) response_handle:logWarn('Goodbye.') end - FilterContext: + filterContext: token_header: x-session-token - Name: envoyextensionpolicy/default/policy-for-http-route/lua/0 + name: envoyextensionpolicy/default/policy-for-http-route/lua/0 hostname: www.example.com isHTTP2: false metadata: @@ -617,14 +600,6 @@ xdsIR: name: httproute/default/httproute-2/rule/0/backend/0 protocol: HTTP weight: 1 - envoyExtensions: - luas: - - Code: | - function envoy_on_request(request_handle) - request_handle:logInfo('Goodbye.') - end - FilterContext: null - Name: envoyextensionpolicy/envoy-gateway/policy-for-gateway/lua/0 hostname: www.example.com isHTTP2: false metadata: diff --git a/internal/gatewayapi/testdata/envoyextensionpolicy-with-lua.in.yaml b/internal/gatewayapi/testdata/envoyextensionpolicy-with-lua.in.yaml index 763e770bfb..ece399e09d 100644 --- a/internal/gatewayapi/testdata/envoyextensionpolicy-with-lua.in.yaml +++ b/internal/gatewayapi/testdata/envoyextensionpolicy-with-lua.in.yaml @@ -13,6 +13,47 @@ gateways: allowedRoutes: namespaces: from: All +# two listeners on the same port, each with a distinct Lua policy. +- apiVersion: gateway.networking.k8s.io/v1 + kind: Gateway + metadata: + namespace: envoy-gateway + name: gateway-2 + spec: + gatewayClassName: envoy-gateway-class + listeners: + - name: http-a + protocol: HTTP + port: 80 + hostname: "app-a.example.com" + allowedRoutes: + namespaces: + from: All + - name: http-b + protocol: HTTP + port: 80 + hostname: "app-b.example.com" + allowedRoutes: + namespaces: + from: All +# A listener with a listener-scoped policy that carries only a route-level extension (Wasm, +# no Lua), plus a Gateway-wide policy with Lua. The Gateway-wide Lua must not leak onto this +# listener since it's already fully governed by the more-specific listener policy. +- apiVersion: gateway.networking.k8s.io/v1 + kind: Gateway + metadata: + namespace: envoy-gateway + name: gateway-3 + spec: + gatewayClassName: envoy-gateway-class + listeners: + - name: http + protocol: HTTP + port: 80 + hostname: "gw3.example.com" + allowedRoutes: + namespaces: + from: All httpRoutes: - apiVersion: gateway.networking.k8s.io/v1 kind: HTTPRoute @@ -52,6 +93,66 @@ httpRoutes: backendRefs: - name: service-1 port: 8080 +- apiVersion: gateway.networking.k8s.io/v1 + kind: HTTPRoute + metadata: + namespace: default + name: httproute-a + spec: + hostnames: + - app-a.example.com + parentRefs: + - namespace: envoy-gateway + name: gateway-2 + sectionName: http-a + rules: + - matches: + - path: + type: PathPrefix + value: "/" + backendRefs: + - name: service-1 + port: 8080 +- apiVersion: gateway.networking.k8s.io/v1 + kind: HTTPRoute + metadata: + namespace: default + name: httproute-b + spec: + hostnames: + - app-b.example.com + parentRefs: + - namespace: envoy-gateway + name: gateway-2 + sectionName: http-b + rules: + - matches: + - path: + type: PathPrefix + value: "/" + backendRefs: + - name: service-1 + port: 8080 +- apiVersion: gateway.networking.k8s.io/v1 + kind: HTTPRoute + metadata: + namespace: default + name: httproute-gw3 + spec: + hostnames: + - gw3.example.com + parentRefs: + - namespace: envoy-gateway + name: gateway-3 + sectionName: http + rules: + - matches: + - path: + type: PathPrefix + value: "/" + backendRefs: + - name: service-1 + port: 8080 envoyextensionpolicies: - apiVersion: gateway.envoyproxy.io/v1alpha1 kind: EnvoyExtensionPolicy @@ -88,3 +189,71 @@ envoyextensionpolicies: filterContext: token_header: x-api-key mode: strict +- apiVersion: gateway.envoyproxy.io/v1alpha1 + kind: EnvoyExtensionPolicy + metadata: + namespace: envoy-gateway + name: policy-for-gateway-a + generation: 30 + spec: + targetRef: + group: gateway.networking.k8s.io + kind: Gateway + name: gateway-2 + sectionName: http-a + lua: + - type: Inline + inline: "function envoy_on_request(request_handle) + request_handle:logInfo('tenant-A script.') + end" +- apiVersion: gateway.envoyproxy.io/v1alpha1 + kind: EnvoyExtensionPolicy + metadata: + namespace: envoy-gateway + name: policy-for-gateway-b + generation: 30 + spec: + targetRef: + group: gateway.networking.k8s.io + kind: Gateway + name: gateway-2 + sectionName: http-b + lua: + - type: Inline + inline: "function envoy_on_request(request_handle) + request_handle:logInfo('tenant-B script.') + end" +- apiVersion: gateway.envoyproxy.io/v1alpha1 + kind: EnvoyExtensionPolicy + metadata: + namespace: envoy-gateway + name: policy-for-listener-wasm # listener-scoped, Wasm only, no Lua + generation: 40 + spec: + targetRef: + group: gateway.networking.k8s.io + kind: Gateway + name: gateway-3 + sectionName: http + wasm: + - name: wasm-filter-gw3 + code: + type: HTTP + http: + url: https://www.example.com/wasm-filter-gw3.wasm +- apiVersion: gateway.envoyproxy.io/v1alpha1 + kind: EnvoyExtensionPolicy + metadata: + namespace: envoy-gateway + name: policy-for-gateway-3 # Gateway-wide, must not leak Lua onto gateway-3/http + generation: 40 + spec: + targetRef: + group: gateway.networking.k8s.io + kind: Gateway + name: gateway-3 + lua: + - type: Inline + inline: "function envoy_on_request(request_handle) + request_handle:logInfo('should not run on gateway-3 listener.') + end" diff --git a/internal/gatewayapi/testdata/envoyextensionpolicy-with-lua.out.yaml b/internal/gatewayapi/testdata/envoyextensionpolicy-with-lua.out.yaml index 29bfd408e5..c744c980a8 100644 --- a/internal/gatewayapi/testdata/envoyextensionpolicy-with-lua.out.yaml +++ b/internal/gatewayapi/testdata/envoyextensionpolicy-with-lua.out.yaml @@ -39,6 +39,123 @@ envoyExtensionPolicies: status: "True" type: Warning controllerName: gateway.envoyproxy.io/gatewayclass-controller +- apiVersion: gateway.envoyproxy.io/v1alpha1 + kind: EnvoyExtensionPolicy + metadata: + generation: 30 + name: policy-for-gateway-a + namespace: envoy-gateway + spec: + lua: + - inline: function envoy_on_request(request_handle) request_handle:logInfo('tenant-A + script.') end + type: Inline + targetRef: + group: gateway.networking.k8s.io + kind: Gateway + name: gateway-2 + sectionName: http-a + status: + ancestors: + - ancestorRef: + group: gateway.networking.k8s.io + kind: Gateway + name: gateway-2 + namespace: envoy-gateway + sectionName: http-a + conditions: + - lastTransitionTime: null + message: Policy has been accepted. + observedGeneration: 30 + reason: Accepted + status: "True" + type: Accepted + - lastTransitionTime: null + message: spec.targetRef is deprecated, use spec.targetRefs instead + observedGeneration: 30 + reason: DeprecatedField + status: "True" + type: Warning + controllerName: gateway.envoyproxy.io/gatewayclass-controller +- apiVersion: gateway.envoyproxy.io/v1alpha1 + kind: EnvoyExtensionPolicy + metadata: + generation: 30 + name: policy-for-gateway-b + namespace: envoy-gateway + spec: + lua: + - inline: function envoy_on_request(request_handle) request_handle:logInfo('tenant-B + script.') end + type: Inline + targetRef: + group: gateway.networking.k8s.io + kind: Gateway + name: gateway-2 + sectionName: http-b + status: + ancestors: + - ancestorRef: + group: gateway.networking.k8s.io + kind: Gateway + name: gateway-2 + namespace: envoy-gateway + sectionName: http-b + conditions: + - lastTransitionTime: null + message: Policy has been accepted. + observedGeneration: 30 + reason: Accepted + status: "True" + type: Accepted + - lastTransitionTime: null + message: spec.targetRef is deprecated, use spec.targetRefs instead + observedGeneration: 30 + reason: DeprecatedField + status: "True" + type: Warning + controllerName: gateway.envoyproxy.io/gatewayclass-controller +- apiVersion: gateway.envoyproxy.io/v1alpha1 + kind: EnvoyExtensionPolicy + metadata: + generation: 40 + name: policy-for-listener-wasm + namespace: envoy-gateway + spec: + targetRef: + group: gateway.networking.k8s.io + kind: Gateway + name: gateway-3 + sectionName: http + wasm: + - code: + http: + sha256: null + url: https://www.example.com/wasm-filter-gw3.wasm + type: HTTP + name: wasm-filter-gw3 + status: + ancestors: + - ancestorRef: + group: gateway.networking.k8s.io + kind: Gateway + name: gateway-3 + namespace: envoy-gateway + sectionName: http + conditions: + - lastTransitionTime: null + message: Policy has been accepted. + observedGeneration: 40 + reason: Accepted + status: "True" + type: Accepted + - lastTransitionTime: null + message: spec.targetRef is deprecated, use spec.targetRefs instead + observedGeneration: 40 + reason: DeprecatedField + status: "True" + type: Warning + controllerName: gateway.envoyproxy.io/gatewayclass-controller - apiVersion: gateway.envoyproxy.io/v1alpha1 kind: EnvoyExtensionPolicy metadata: @@ -82,6 +199,49 @@ envoyExtensionPolicies: status: "True" type: Overridden controllerName: gateway.envoyproxy.io/gatewayclass-controller +- apiVersion: gateway.envoyproxy.io/v1alpha1 + kind: EnvoyExtensionPolicy + metadata: + generation: 40 + name: policy-for-gateway-3 + namespace: envoy-gateway + spec: + lua: + - inline: function envoy_on_request(request_handle) request_handle:logInfo('should + not run on gateway-3 listener.') end + type: Inline + targetRef: + group: gateway.networking.k8s.io + kind: Gateway + name: gateway-3 + status: + ancestors: + - ancestorRef: + group: gateway.networking.k8s.io + kind: Gateway + name: gateway-3 + namespace: envoy-gateway + conditions: + - lastTransitionTime: null + message: Policy has been accepted. + observedGeneration: 40 + reason: Accepted + status: "True" + type: Accepted + - lastTransitionTime: null + message: spec.targetRef is deprecated, use spec.targetRefs instead + observedGeneration: 40 + reason: DeprecatedField + status: "True" + type: Warning + - lastTransitionTime: null + message: 'This policy is being overridden by other envoyExtensionPolicies + for these gateway listeners: [envoy-gateway/gateway-3/http]' + observedGeneration: 40 + reason: Overridden + status: "True" + type: Overridden + controllerName: gateway.envoyproxy.io/gatewayclass-controller gateways: - apiVersion: gateway.networking.k8s.io/v1 kind: Gateway @@ -122,6 +282,116 @@ gateways: kind: HTTPRoute - group: gateway.networking.k8s.io kind: GRPCRoute +- apiVersion: gateway.networking.k8s.io/v1 + kind: Gateway + metadata: + name: gateway-2 + namespace: envoy-gateway + spec: + gatewayClassName: envoy-gateway-class + listeners: + - allowedRoutes: + namespaces: + from: All + hostname: app-a.example.com + name: http-a + port: 80 + protocol: HTTP + - allowedRoutes: + namespaces: + from: All + hostname: app-b.example.com + name: http-b + port: 80 + protocol: HTTP + status: + listeners: + - attachedRoutes: 1 + conditions: + - lastTransitionTime: null + message: Sending translated listener configuration to the data plane + reason: Programmed + status: "True" + type: Programmed + - lastTransitionTime: null + message: Listener has been successfully translated + reason: Accepted + status: "True" + type: Accepted + - lastTransitionTime: null + message: Listener references have been resolved + reason: ResolvedRefs + status: "True" + type: ResolvedRefs + name: http-a + supportedKinds: + - group: gateway.networking.k8s.io + kind: HTTPRoute + - group: gateway.networking.k8s.io + kind: GRPCRoute + - attachedRoutes: 1 + conditions: + - lastTransitionTime: null + message: Sending translated listener configuration to the data plane + reason: Programmed + status: "True" + type: Programmed + - lastTransitionTime: null + message: Listener has been successfully translated + reason: Accepted + status: "True" + type: Accepted + - lastTransitionTime: null + message: Listener references have been resolved + reason: ResolvedRefs + status: "True" + type: ResolvedRefs + name: http-b + supportedKinds: + - group: gateway.networking.k8s.io + kind: HTTPRoute + - group: gateway.networking.k8s.io + kind: GRPCRoute +- apiVersion: gateway.networking.k8s.io/v1 + kind: Gateway + metadata: + name: gateway-3 + namespace: envoy-gateway + spec: + gatewayClassName: envoy-gateway-class + listeners: + - allowedRoutes: + namespaces: + from: All + hostname: gw3.example.com + name: http + port: 80 + protocol: HTTP + status: + listeners: + - attachedRoutes: 1 + conditions: + - lastTransitionTime: null + message: Sending translated listener configuration to the data plane + reason: Programmed + status: "True" + type: Programmed + - lastTransitionTime: null + message: Listener has been successfully translated + reason: Accepted + status: "True" + type: Accepted + - lastTransitionTime: null + message: Listener references have been resolved + reason: ResolvedRefs + status: "True" + type: ResolvedRefs + name: http + supportedKinds: + - group: gateway.networking.k8s.io + kind: HTTPRoute + - group: gateway.networking.k8s.io + kind: GRPCRoute httpRoutes: - apiVersion: gateway.networking.k8s.io/v1 kind: HTTPRoute @@ -197,6 +467,120 @@ httpRoutes: name: gateway-1 namespace: envoy-gateway sectionName: http +- apiVersion: gateway.networking.k8s.io/v1 + kind: HTTPRoute + metadata: + name: httproute-a + namespace: default + spec: + hostnames: + - app-a.example.com + parentRefs: + - name: gateway-2 + namespace: envoy-gateway + sectionName: http-a + rules: + - backendRefs: + - name: service-1 + port: 8080 + matches: + - path: + type: PathPrefix + value: / + status: + parents: + - conditions: + - lastTransitionTime: null + message: Route is accepted + reason: Accepted + status: "True" + type: Accepted + - lastTransitionTime: null + message: Resolved all the Object references for the Route + reason: ResolvedRefs + status: "True" + type: ResolvedRefs + controllerName: gateway.envoyproxy.io/gatewayclass-controller + parentRef: + name: gateway-2 + namespace: envoy-gateway + sectionName: http-a +- apiVersion: gateway.networking.k8s.io/v1 + kind: HTTPRoute + metadata: + name: httproute-b + namespace: default + spec: + hostnames: + - app-b.example.com + parentRefs: + - name: gateway-2 + namespace: envoy-gateway + sectionName: http-b + rules: + - backendRefs: + - name: service-1 + port: 8080 + matches: + - path: + type: PathPrefix + value: / + status: + parents: + - conditions: + - lastTransitionTime: null + message: Route is accepted + reason: Accepted + status: "True" + type: Accepted + - lastTransitionTime: null + message: Resolved all the Object references for the Route + reason: ResolvedRefs + status: "True" + type: ResolvedRefs + controllerName: gateway.envoyproxy.io/gatewayclass-controller + parentRef: + name: gateway-2 + namespace: envoy-gateway + sectionName: http-b +- apiVersion: gateway.networking.k8s.io/v1 + kind: HTTPRoute + metadata: + name: httproute-gw3 + namespace: default + spec: + hostnames: + - gw3.example.com + parentRefs: + - name: gateway-3 + namespace: envoy-gateway + sectionName: http + rules: + - backendRefs: + - name: service-1 + port: 8080 + matches: + - path: + type: PathPrefix + value: / + status: + parents: + - conditions: + - lastTransitionTime: null + message: Route is accepted + reason: Accepted + status: "True" + type: Accepted + - lastTransitionTime: null + message: Resolved all the Object references for the Route + reason: ResolvedRefs + status: "True" + type: ResolvedRefs + controllerName: gateway.envoyproxy.io/gatewayclass-controller + parentRef: + name: gateway-3 + namespace: envoy-gateway + sectionName: http infraIR: envoy-gateway/gateway-1: proxy: @@ -216,6 +600,42 @@ infraIR: name: envoy-gateway-class name: envoy-gateway/gateway-1 namespace: envoy-gateway-system + envoy-gateway/gateway-2: + proxy: + listeners: + - name: envoy-gateway/gateway-2/http-a + ports: + - containerPort: 10080 + name: http-80 + protocol: HTTP + servicePort: 80 + metadata: + labels: + gateway.envoyproxy.io/owning-gateway-name: gateway-2 + gateway.envoyproxy.io/owning-gateway-namespace: envoy-gateway + ownerReference: + kind: GatewayClass + name: envoy-gateway-class + name: envoy-gateway/gateway-2 + namespace: envoy-gateway-system + envoy-gateway/gateway-3: + proxy: + listeners: + - name: envoy-gateway/gateway-3/http + ports: + - containerPort: 10080 + name: http-80 + protocol: HTTP + servicePort: 80 + metadata: + labels: + gateway.envoyproxy.io/owning-gateway-name: gateway-3 + gateway.envoyproxy.io/owning-gateway-namespace: envoy-gateway + ownerReference: + kind: GatewayClass + name: envoy-gateway-class + name: envoy-gateway/gateway-3 + namespace: envoy-gateway-system xdsIR: envoy-gateway/gateway-1: accessLog: @@ -244,6 +664,11 @@ xdsIR: protocol: TCP http: - address: 0.0.0.0 + envoyExtensions: + luas: + - code: function envoy_on_request(request_handle) request_handle:logInfo('Goodbye.') + end + name: envoyextensionpolicy/envoy-gateway/policy-for-gateway/lua/0 externalPort: 80 hostnames: - '*' @@ -279,12 +704,12 @@ xdsIR: weight: 1 envoyExtensions: luas: - - Code: function envoy_on_response(response_handle) response_handle:logWarn('Goodbye.') + - code: function envoy_on_response(response_handle) response_handle:logWarn('Goodbye.') end - FilterContext: + filterContext: mode: strict token_header: x-api-key - Name: envoyextensionpolicy/default/policy-for-http-route/lua/0 + name: envoyextensionpolicy/default/policy-for-http-route/lua/0 hostname: www.example.com isHTTP2: false metadata: @@ -315,12 +740,6 @@ xdsIR: name: httproute/default/httproute-2/rule/0/backend/0 protocol: HTTP weight: 1 - envoyExtensions: - luas: - - Code: function envoy_on_request(request_handle) request_handle:logInfo('Goodbye.') - end - FilterContext: null - Name: envoyextensionpolicy/envoy-gateway/policy-for-gateway/lua/0 hostname: www.example.com isHTTP2: false metadata: @@ -337,3 +756,224 @@ xdsIR: ipFamily: IPv4 path: /ready port: 19003 + envoy-gateway/gateway-2: + accessLog: + json: + - path: /dev/stdout + globalResources: + proxyServiceCluster: + metadata: + kind: Service + name: envoy-envoy-gateway-gateway-2-4a0e4eb9 + namespace: envoy-gateway-system + sectionName: "8080" + name: envoy-gateway/gateway-2 + settings: + - addressType: IP + endpoints: + - host: 7.6.5.4 + port: 8080 + zone: zone1 + metadata: + kind: Service + name: envoy-envoy-gateway-gateway-2-4a0e4eb9 + namespace: envoy-gateway-system + sectionName: "8080" + name: envoy-gateway/gateway-2 + protocol: TCP + http: + - address: 0.0.0.0 + envoyExtensions: + luas: + - code: function envoy_on_request(request_handle) request_handle:logInfo('tenant-A + script.') end + name: envoyextensionpolicy/envoy-gateway/policy-for-gateway-a/lua/0 + externalPort: 80 + hostnames: + - app-a.example.com + metadata: + kind: Gateway + name: gateway-2 + namespace: envoy-gateway + sectionName: http-a + name: envoy-gateway/gateway-2/http-a + path: + escapedSlashesAction: UnescapeAndRedirect + mergeSlashes: true + port: 10080 + routes: + - destination: + metadata: + kind: HTTPRoute + name: httproute-a + namespace: default + name: httproute/default/httproute-a/rule/0 + settings: + - addressType: IP + endpoints: + - host: 7.7.7.7 + port: 8080 + metadata: + kind: Service + name: service-1 + namespace: default + sectionName: "8080" + name: httproute/default/httproute-a/rule/0/backend/0 + protocol: HTTP + weight: 1 + hostname: app-a.example.com + isHTTP2: false + metadata: + kind: HTTPRoute + name: httproute-a + namespace: default + name: httproute/default/httproute-a/rule/0/match/0/app-a_example_com + pathMatch: + distinct: false + name: "" + prefix: / + - address: 0.0.0.0 + envoyExtensions: + luas: + - code: function envoy_on_request(request_handle) request_handle:logInfo('tenant-B + script.') end + name: envoyextensionpolicy/envoy-gateway/policy-for-gateway-b/lua/0 + externalPort: 80 + hostnames: + - app-b.example.com + metadata: + kind: Gateway + name: gateway-2 + namespace: envoy-gateway + sectionName: http-b + name: envoy-gateway/gateway-2/http-b + path: + escapedSlashesAction: UnescapeAndRedirect + mergeSlashes: true + port: 10080 + routes: + - destination: + metadata: + kind: HTTPRoute + name: httproute-b + namespace: default + name: httproute/default/httproute-b/rule/0 + settings: + - addressType: IP + endpoints: + - host: 7.7.7.7 + port: 8080 + metadata: + kind: Service + name: service-1 + namespace: default + sectionName: "8080" + name: httproute/default/httproute-b/rule/0/backend/0 + protocol: HTTP + weight: 1 + hostname: app-b.example.com + isHTTP2: false + metadata: + kind: HTTPRoute + name: httproute-b + namespace: default + name: httproute/default/httproute-b/rule/0/match/0/app-b_example_com + pathMatch: + distinct: false + name: "" + prefix: / + readyListener: + address: 0.0.0.0 + ipFamily: IPv4 + path: /ready + port: 19003 + envoy-gateway/gateway-3: + accessLog: + json: + - path: /dev/stdout + globalResources: + envoyClientCertificate: + certificate: LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUREVENDQWZXZ0F3SUJBZ0lVRUZNaFA5ZUo5WEFCV3NRNVptNmJSazJjTE5Rd0RRWUpLb1pJaHZjTkFRRUwKQlFBd0ZqRVVNQklHQTFVRUF3d0xabTl2TG1KaGNpNWpiMjB3SGhjTk1qUXdNakk1TURrek1ERXdXaGNOTXpRdwpNakkyTURrek1ERXdXakFXTVJRd0VnWURWUVFEREF0bWIyOHVZbUZ5TG1OdmJUQ0NBU0l3RFFZSktvWklodmNOCkFRRUJCUUFEZ2dFUEFEQ0NBUW9DZ2dFQkFKbEk2WXhFOVprQ1BzNnBDUXhickNtZWl4OVA1RGZ4OVJ1NUxENFQKSm1kVzdJS2R0UVYvd2ZMbXRzdTc2QithVGRDaldlMEJUZmVPT1JCYlIzY1BBRzZFbFFMaWNsUVVydW4zcStncwpKcEsrSTdjSStqNXc4STY4WEg1V1E3clZVdGJ3SHBxYncrY1ZuQnFJVU9MaUlhdGpJZjdLWDUxTTF1RjljZkVICkU0RG5jSDZyYnI1OS9SRlpCc2toeHM1T3p3Sklmb2hreXZGd2V1VHd4Sy9WcGpJKzdPYzQ4QUJDWHBOTzlEL3EKRWgrck9hdWpBTWNYZ0hRSVRrQ2lpVVRjVW82TFNIOXZMWlB0YXFmem9acTZuaE1xcFc2NUUxcEF3RjNqeVRUeAphNUk4SmNmU0Zqa2llWjIwTFVRTW43TThVNHhIamFvL2d2SDBDQWZkQjdSTFUyc0NBd0VBQWFOVE1GRXdIUVlEClZSME9CQllFRk9SQ0U4dS8xRERXN2loWnA3Y3g5dFNtUG02T01COEdBMVVkSXdRWU1CYUFGT1JDRTh1LzFERFcKN2loWnA3Y3g5dFNtUG02T01BOEdBMVVkRXdFQi93UUZNQU1CQWY4d0RRWUpLb1pJaHZjTkFRRUxCUUFEZ2dFQgpBRnQ1M3pqc3FUYUg1YThFMmNodm1XQWdDcnhSSzhiVkxNeGl3TkdqYm1FUFJ6K3c2TngrazBBOEtFY0lEc0tjClNYY2k1OHU0b1didFZKQmx6YS9adWpIUjZQMUJuT3BsK2FveTc4NGJiZDRQMzl3VExvWGZNZmJCQ20xdmV2aDkKQUpLbncyWnRxcjRta2JMY3hFcWxxM3NCTEZBUzlzUUxuS05DZTJjR0xkVHAyYm9HK3FjZ3lRZ0NJTTZmOEVNdgpXUGlmQ01NR3V6Sy9HUkY0YlBPL1lGNDhld0R1M1VlaWgwWFhkVUFPRTlDdFVhOE5JaGMxVVBhT3pQcnRZVnFyClpPR2t2L0t1K0I3OGg4U0VzTzlYclFjdXdiT25KeDZLdFIrYWV5a3ZBcFhDUTNmWkMvYllLQUFSK1A4QUpvUVoKYndJVW1YaTRnajVtK2JLUGhlK2lyK0U9Ci0tLS0tRU5EIENFUlRJRklDQVRFLS0tLS0= + name: envoy-gateway-system/envoy + privateKey: '[redacted]' + proxyServiceCluster: + metadata: + kind: Service + name: envoy-envoy-gateway-gateway-3-32e857a6 + namespace: envoy-gateway-system + sectionName: "8080" + name: envoy-gateway/gateway-3 + settings: + - addressType: IP + endpoints: + - host: 7.6.5.4 + port: 8080 + zone: zone1 + metadata: + kind: Service + name: envoy-envoy-gateway-gateway-3-32e857a6 + namespace: envoy-gateway-system + sectionName: "8080" + name: envoy-gateway/gateway-3 + protocol: TCP + http: + - address: 0.0.0.0 + envoyExtensions: + wasms: + - config: null + failOpen: false + httpWasmCode: + originalDownloadingURL: https://www.example.com/wasm-filter-gw3.wasm + servingURL: https://envoy-gateway.envoy-gateway-system.svc.cluster.local:18002/6f443df69aab42a606fc6b8d18ce47bc6ed642c929cb2ed90adbaf509acf60f7.wasm + sha256: c377a55221a8fb8aacbac301b3e9f0cc0cb766a3442aebb32f39f38b72694027 + name: envoyextensionpolicy/envoy-gateway/policy-for-listener-wasm/wasm/0 + wasmName: wasm-filter-gw3 + externalPort: 80 + hostnames: + - gw3.example.com + metadata: + kind: Gateway + name: gateway-3 + namespace: envoy-gateway + sectionName: http + name: envoy-gateway/gateway-3/http + path: + escapedSlashesAction: UnescapeAndRedirect + mergeSlashes: true + port: 10080 + routes: + - destination: + metadata: + kind: HTTPRoute + name: httproute-gw3 + namespace: default + name: httproute/default/httproute-gw3/rule/0 + settings: + - addressType: IP + endpoints: + - host: 7.7.7.7 + port: 8080 + metadata: + kind: Service + name: service-1 + namespace: default + sectionName: "8080" + name: httproute/default/httproute-gw3/rule/0/backend/0 + protocol: HTTP + weight: 1 + hostname: gw3.example.com + isHTTP2: false + metadata: + kind: HTTPRoute + name: httproute-gw3 + namespace: default + name: httproute/default/httproute-gw3/rule/0/match/0/gw3_example_com + pathMatch: + distinct: false + name: "" + prefix: / + readyListener: + address: 0.0.0.0 + ipFamily: IPv4 + path: /ready + port: 19003 diff --git a/internal/gatewayapi/testdata/envoyextensionpolicy-with-wasm-env-vars.out.yaml b/internal/gatewayapi/testdata/envoyextensionpolicy-with-wasm-env-vars.out.yaml index 73f2f7e136..0a0c0906e7 100644 --- a/internal/gatewayapi/testdata/envoyextensionpolicy-with-wasm-env-vars.out.yaml +++ b/internal/gatewayapi/testdata/envoyextensionpolicy-with-wasm-env-vars.out.yaml @@ -271,6 +271,39 @@ xdsIR: protocol: TCP http: - address: 0.0.0.0 + envoyExtensions: + wasms: + - config: null + failOpen: false + hostKeys: + - SOME_KEY + - ANOTHER_KEY + 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: null + failOpen: false + hostKeys: + - SOME_KEY + - ANOTHER_KEY + httpWasmCode: + originalDownloadingURL: oci://www.example.com/wasm-filter-2:v1.0.0 + servingURL: https://envoy-gateway.envoy-gateway-system.svc.cluster.local:18002/7abf116e5cd5a20389604a5ba0f3bd04fdf76f92181fe67506b42c2ee596d3fd.wasm + sha256: 314100af781b98a8ca175d5bf90a8bf76576e20a2f397a88223404edc6ebfd46 + name: envoyextensionpolicy/envoy-gateway/policy-for-gateway/wasm/1 + rootID: my-root-id + wasmName: wasm-filter-2 + - config: null + failOpen: false + httpWasmCode: + originalDownloadingURL: oci://www.example.com:8080/wasm-filter-3:latest + servingURL: https://envoy-gateway.envoy-gateway-system.svc.cluster.local:18002/42d30b4a4cc631415e6e48c02d244700da327201eb273f752cacf745715b31d9.wasm + sha256: 2a19e4f337e5223d7287e7fccd933fb01905deaff804292e5257f8c681b82bee + name: envoyextensionpolicy/envoy-gateway/policy-for-gateway/wasm/2 + wasmName: envoyextensionpolicy/envoy-gateway/policy-for-gateway/wasm/2 externalPort: 80 hostnames: - '*' @@ -347,39 +380,6 @@ xdsIR: name: httproute/default/httproute-2/rule/0/backend/0 protocol: HTTP weight: 1 - envoyExtensions: - wasms: - - config: null - failOpen: false - hostKeys: - - SOME_KEY - - ANOTHER_KEY - 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: null - failOpen: false - hostKeys: - - SOME_KEY - - ANOTHER_KEY - httpWasmCode: - originalDownloadingURL: oci://www.example.com/wasm-filter-2:v1.0.0 - servingURL: https://envoy-gateway.envoy-gateway-system.svc.cluster.local:18002/7abf116e5cd5a20389604a5ba0f3bd04fdf76f92181fe67506b42c2ee596d3fd.wasm - sha256: 314100af781b98a8ca175d5bf90a8bf76576e20a2f397a88223404edc6ebfd46 - name: envoyextensionpolicy/envoy-gateway/policy-for-gateway/wasm/1 - rootID: my-root-id - wasmName: wasm-filter-2 - - config: null - failOpen: false - httpWasmCode: - originalDownloadingURL: oci://www.example.com:8080/wasm-filter-3:latest - servingURL: https://envoy-gateway.envoy-gateway-system.svc.cluster.local:18002/42d30b4a4cc631415e6e48c02d244700da327201eb273f752cacf745715b31d9.wasm - sha256: 2a19e4f337e5223d7287e7fccd933fb01905deaff804292e5257f8c681b82bee - name: envoyextensionpolicy/envoy-gateway/policy-for-gateway/wasm/2 - wasmName: envoyextensionpolicy/envoy-gateway/policy-for-gateway/wasm/2 hostname: www.example.com isHTTP2: false metadata: diff --git a/internal/gatewayapi/testdata/envoyextensionpolicy-with-wasm-invalid-configuration.in.yaml b/internal/gatewayapi/testdata/envoyextensionpolicy-with-wasm-invalid-configuration.in.yaml index 11f01273bc..3fdf7e8033 100644 --- a/internal/gatewayapi/testdata/envoyextensionpolicy-with-wasm-invalid-configuration.in.yaml +++ b/internal/gatewayapi/testdata/envoyextensionpolicy-with-wasm-invalid-configuration.in.yaml @@ -316,3 +316,6 @@ envoyExtensionPolicies: pullSecretRef: name: my-pull-secret-1 sha256: 314100af781b98a8ca175d5bf90a8bf76576e20a2f397a88223404edc6ebfd46 + lua: + - type: Inline + inline: "function envoy_on_request(request_handle) end" diff --git a/internal/gatewayapi/testdata/envoyextensionpolicy-with-wasm-invalid-configuration.out.yaml b/internal/gatewayapi/testdata/envoyextensionpolicy-with-wasm-invalid-configuration.out.yaml index dcfca230a6..cc013e51da 100644 --- a/internal/gatewayapi/testdata/envoyextensionpolicy-with-wasm-invalid-configuration.out.yaml +++ b/internal/gatewayapi/testdata/envoyextensionpolicy-with-wasm-invalid-configuration.out.yaml @@ -228,6 +228,9 @@ envoyExtensionPolicies: name: policy-for-gateway-3 namespace: default spec: + lua: + - inline: function envoy_on_request(request_handle) end + type: Inline targetRef: group: gateway.networking.k8s.io kind: Gateway @@ -895,6 +898,7 @@ xdsIR: protocol: TCP http: - address: 0.0.0.0 + envoyExtensions: {} externalPort: 80 hostnames: - '*' @@ -928,7 +932,6 @@ xdsIR: name: httproute/default/httproute-5/rule/0/backend/0 protocol: HTTP weight: 1 - envoyExtensions: {} hostname: www.foo.com isHTTP2: false metadata: @@ -959,7 +962,6 @@ xdsIR: name: httproute/default/httproute-6/rule/0/backend/0 protocol: HTTP weight: 1 - envoyExtensions: {} hostname: www.bar.com isHTTP2: false metadata: diff --git a/internal/gatewayapi/testdata/envoyextensionpolicy-with-wasm-targetrefs.out.yaml b/internal/gatewayapi/testdata/envoyextensionpolicy-with-wasm-targetrefs.out.yaml index 3c9077b3a7..1ec50b0166 100644 --- a/internal/gatewayapi/testdata/envoyextensionpolicy-with-wasm-targetrefs.out.yaml +++ b/internal/gatewayapi/testdata/envoyextensionpolicy-with-wasm-targetrefs.out.yaml @@ -232,6 +232,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: - '*' @@ -319,30 +343,6 @@ xdsIR: name: httproute/envoy-gateway/httproute-2/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: diff --git a/internal/gatewayapi/testdata/envoyextensionpolicy-with-wasm.out.yaml b/internal/gatewayapi/testdata/envoyextensionpolicy-with-wasm.out.yaml index cf73e95f12..bd354da86a 100644 --- a/internal/gatewayapi/testdata/envoyextensionpolicy-with-wasm.out.yaml +++ b/internal/gatewayapi/testdata/envoyextensionpolicy-with-wasm.out.yaml @@ -273,6 +273,39 @@ 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: oci://www.example.com/wasm-filter-2:v1.0.0 + servingURL: https://envoy-gateway.envoy-gateway-system.svc.cluster.local:18002/7abf116e5cd5a20389604a5ba0f3bd04fdf76f92181fe67506b42c2ee596d3fd.wasm + sha256: 314100af781b98a8ca175d5bf90a8bf76576e20a2f397a88223404edc6ebfd46 + name: envoyextensionpolicy/envoy-gateway/policy-for-gateway/wasm/1 + rootID: my-root-id + wasmName: wasm-filter-2 + - config: null + failOpen: false + httpWasmCode: + originalDownloadingURL: oci://www.example.com:8080/wasm-filter-3:latest + servingURL: https://envoy-gateway.envoy-gateway-system.svc.cluster.local:18002/42d30b4a4cc631415e6e48c02d244700da327201eb273f752cacf745715b31d9.wasm + sha256: 2a19e4f337e5223d7287e7fccd933fb01905deaff804292e5257f8c681b82bee + name: envoyextensionpolicy/envoy-gateway/policy-for-gateway/wasm/2 + wasmName: envoyextensionpolicy/envoy-gateway/policy-for-gateway/wasm/2 externalPort: 80 hostnames: - '*' @@ -351,39 +384,6 @@ xdsIR: name: httproute/default/httproute-2/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: oci://www.example.com/wasm-filter-2:v1.0.0 - servingURL: https://envoy-gateway.envoy-gateway-system.svc.cluster.local:18002/7abf116e5cd5a20389604a5ba0f3bd04fdf76f92181fe67506b42c2ee596d3fd.wasm - sha256: 314100af781b98a8ca175d5bf90a8bf76576e20a2f397a88223404edc6ebfd46 - name: envoyextensionpolicy/envoy-gateway/policy-for-gateway/wasm/1 - rootID: my-root-id - wasmName: wasm-filter-2 - - config: null - failOpen: false - httpWasmCode: - originalDownloadingURL: oci://www.example.com:8080/wasm-filter-3:latest - servingURL: https://envoy-gateway.envoy-gateway-system.svc.cluster.local:18002/42d30b4a4cc631415e6e48c02d244700da327201eb273f752cacf745715b31d9.wasm - sha256: 2a19e4f337e5223d7287e7fccd933fb01905deaff804292e5257f8c681b82bee - name: envoyextensionpolicy/envoy-gateway/policy-for-gateway/wasm/2 - wasmName: envoyextensionpolicy/envoy-gateway/policy-for-gateway/wasm/2 hostname: www.example.com isHTTP2: false metadata: diff --git a/internal/ir/xds.go b/internal/ir/xds.go index 0cf1778775..1d4a258a84 100644 --- a/internal/ir/xds.go +++ b/internal/ir/xds.go @@ -401,6 +401,8 @@ type HTTPListener struct { MatchBackendScheme bool `json:"matchBackendScheme,omitempty" yaml:"matchBackendScheme,omitempty"` // RequestID defines configuration for the UUID request ID extension. RequestID *RequestIDExtensionAction `json:"requestID,omitempty" yaml:"requestID,omitempty"` + // EnvoyExtension holds the features associated with EnvoyExtensionPolicy + EnvoyExtensions *EnvoyExtensionFeatures `json:"envoyExtensions,omitempty" yaml:"envoyExtensions,omitempty"` } // Validate the fields within the HTTPListener structure @@ -3923,12 +3925,12 @@ type ExtProc struct { type Lua struct { // Name is a unique name for the LUa configuration. // The xds translator only generates one Lua filter for each unique name - Name string + Name string `json:"name" yaml:"name"` // Code is the Lua source code - Code *string + Code *string `json:"code,omitempty" yaml:"code,omitempty"` // FilterContext is the filter context configuration for the Lua script. // This is a JSON object passed to the Lua script via request_handle:filterContext(). - FilterContext *apiextensionsv1.JSON + FilterContext *apiextensionsv1.JSON `json:"filterContext,omitempty" yaml:"filterContext,omitempty"` } // Wasm holds the information associated with the Wasm extensions. diff --git a/internal/ir/zz_generated.deepcopy.go b/internal/ir/zz_generated.deepcopy.go index f71396097a..f04ae5abcb 100644 --- a/internal/ir/zz_generated.deepcopy.go +++ b/internal/ir/zz_generated.deepcopy.go @@ -2483,6 +2483,11 @@ func (in *HTTPListener) DeepCopyInto(out *HTTPListener) { *out = new(RequestIDExtensionAction) **out = **in } + if in.EnvoyExtensions != nil { + in, out := &in.EnvoyExtensions, &out.EnvoyExtensions + *out = new(EnvoyExtensionFeatures) + (*in).DeepCopyInto(*out) + } } // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new HTTPListener. diff --git a/internal/xds/translator/api_key_auth.go b/internal/xds/translator/api_key_auth.go index cfbaf29152..f491dcf40f 100644 --- a/internal/xds/translator/api_key_auth.go +++ b/internal/xds/translator/api_key_auth.go @@ -84,7 +84,7 @@ func buildHCMAPIKeyAuthFilter(apiKeyAuth *ir.APIKeyAuth) (*hcmv3.HttpFilter, err }, nil } -func (*apiKeyAuth) patchResources(*types.ResourceVersionTable, []*ir.HTTPRoute) error { +func (*apiKeyAuth) patchResources(*types.ResourceVersionTable, *ir.HTTPListener, []*ir.HTTPRoute) error { return nil } @@ -176,3 +176,7 @@ func buildAPIKeyAuthFilterPerRouteConfig(apiKeyAuth *ir.APIKeyAuth) *apikeyauthv Forwarding: apiKeyAuthProto.Forwarding, } } + +func (*apiKeyAuth) patchVirtualHost(_ *routev3.VirtualHost, _ *ir.HTTPListener) error { + return nil +} diff --git a/internal/xds/translator/authorization.go b/internal/xds/translator/authorization.go index d90257b090..fea8945546 100644 --- a/internal/xds/translator/authorization.go +++ b/internal/xds/translator/authorization.go @@ -693,7 +693,7 @@ func buildJWTPredicate(jwt egv1a1.JWTPrincipal) ([]*matcherv3.Matcher_MatcherLis return jwtPredicate, nil } -func (c *rbac) patchResources(*types.ResourceVersionTable, []*ir.HTTPRoute) error { +func (c *rbac) patchResources(*types.ResourceVersionTable, *ir.HTTPListener, []*ir.HTTPRoute) error { return nil } @@ -940,3 +940,7 @@ func wrapPredicateWithNot(predicate *matcherv3.Matcher_MatcherList_Predicate, in }, } } + +func (*rbac) patchVirtualHost(_ *routev3.VirtualHost, _ *ir.HTTPListener) error { + return nil +} diff --git a/internal/xds/translator/bandwidth_limit.go b/internal/xds/translator/bandwidth_limit.go index 02e5d63bf8..c17982e438 100644 --- a/internal/xds/translator/bandwidth_limit.go +++ b/internal/xds/translator/bandwidth_limit.go @@ -106,7 +106,7 @@ func listenerContainsBandwidthLimitResponse(irListener *ir.HTTPListener) bool { return false } -func (*bandwidthLimit) patchResources(*types.ResourceVersionTable, []*ir.HTTPRoute) error { +func (*bandwidthLimit) patchResources(*types.ResourceVersionTable, *ir.HTTPListener, []*ir.HTTPRoute) error { return nil } @@ -182,3 +182,7 @@ func buildBandwidthLimitResponseProto(cfg *ir.BandwidthLimitConfig) *bwlimitv3.B } return proto } + +func (*bandwidthLimit) patchVirtualHost(_ *routev3.VirtualHost, _ *ir.HTTPListener) error { + return nil +} diff --git a/internal/xds/translator/basicauth.go b/internal/xds/translator/basicauth.go index bbf4b3f511..da4560b7f8 100644 --- a/internal/xds/translator/basicauth.go +++ b/internal/xds/translator/basicauth.go @@ -109,7 +109,7 @@ func basicAuthFilterName(basicAuth *ir.BasicAuth) string { return perRouteFilterName(egv1a1.EnvoyFilterBasicAuth, basicAuth.Name) } -func (*basicAuth) patchResources(*types.ResourceVersionTable, []*ir.HTTPRoute) error { +func (*basicAuth) patchResources(*types.ResourceVersionTable, *ir.HTTPListener, []*ir.HTTPRoute) error { return nil } @@ -163,3 +163,7 @@ func basicAuthPerRouteConfig(basicAuth *ir.BasicAuth) *basicauthv3.BasicAuthPerR }, } } + +func (*basicAuth) patchVirtualHost(_ *routev3.VirtualHost, _ *ir.HTTPListener) error { + return nil +} diff --git a/internal/xds/translator/compressor.go b/internal/xds/translator/compressor.go index ddc35d6d6a..39dc0f20f3 100644 --- a/internal/xds/translator/compressor.go +++ b/internal/xds/translator/compressor.go @@ -131,7 +131,7 @@ func buildCompressorFilter(compression *ir.Compression) (*hcmv3.HttpFilter, erro }, nil } -func (*compressor) patchResources(*types.ResourceVersionTable, []*ir.HTTPRoute) error { +func (*compressor) patchResources(*types.ResourceVersionTable, *ir.HTTPListener, []*ir.HTTPRoute) error { return nil } @@ -195,3 +195,7 @@ func compressorPerRouteConfig() *compressorv3.CompressorPerRoute { }, } } + +func (*compressor) patchVirtualHost(_ *routev3.VirtualHost, _ *ir.HTTPListener) error { + return nil +} diff --git a/internal/xds/translator/cors.go b/internal/xds/translator/cors.go index 5aff0a80e9..78bd8fa254 100644 --- a/internal/xds/translator/cors.go +++ b/internal/xds/translator/cors.go @@ -199,6 +199,10 @@ func hasWildcard(array []string) bool { return false } -func (c *cors) patchResources(*types.ResourceVersionTable, []*ir.HTTPRoute) error { +func (c *cors) patchResources(*types.ResourceVersionTable, *ir.HTTPListener, []*ir.HTTPRoute) error { + return nil +} + +func (*cors) patchVirtualHost(_ *routev3.VirtualHost, _ *ir.HTTPListener) error { return nil } diff --git a/internal/xds/translator/credentialInjector.go b/internal/xds/translator/credentialInjector.go index d647e7f1a4..2096952a1d 100644 --- a/internal/xds/translator/credentialInjector.go +++ b/internal/xds/translator/credentialInjector.go @@ -110,7 +110,7 @@ func credentialSecretName(credentialInjection *ir.CredentialInjection) string { return fmt.Sprintf("credential_injector/credential/%s", credentialInjection.Name) } -func (*credentialInjector) patchResources(resource *types.ResourceVersionTable, routes []*ir.HTTPRoute) error { +func (*credentialInjector) patchResources(resource *types.ResourceVersionTable, _ *ir.HTTPListener, routes []*ir.HTTPRoute) error { var errs error for _, route := range routes { @@ -160,3 +160,7 @@ func (*credentialInjector) patchRoute(route *routev3.Route, irRoute *ir.HTTPRout } return nil } + +func (*credentialInjector) patchVirtualHost(_ *routev3.VirtualHost, _ *ir.HTTPListener) error { + return nil +} diff --git a/internal/xds/translator/csrf.go b/internal/xds/translator/csrf.go index 6e21ea4073..be610c788e 100644 --- a/internal/xds/translator/csrf.go +++ b/internal/xds/translator/csrf.go @@ -138,7 +138,11 @@ func (*csrf) patchRoute(route *routev3.Route, irRoute *ir.HTTPRoute, _ *ir.HTTPL return nil } -func (*csrf) patchResources(*types.ResourceVersionTable, []*ir.HTTPRoute) error { +func (*csrf) patchResources(*types.ResourceVersionTable, *ir.HTTPListener, []*ir.HTTPRoute) error { + return nil +} + +func (*csrf) patchVirtualHost(_ *routev3.VirtualHost, _ *ir.HTTPListener) error { return nil } diff --git a/internal/xds/translator/custom_response.go b/internal/xds/translator/custom_response.go index 65977b6791..af56e97ca6 100644 --- a/internal/xds/translator/custom_response.go +++ b/internal/xds/translator/custom_response.go @@ -500,7 +500,7 @@ func (c *customResponse) routeContainsResponseOverride(irRoute *ir.HTTPRoute) bo return false } -func (c *customResponse) patchResources(_ *types.ResourceVersionTable, _ []*ir.HTTPRoute) error { +func (c *customResponse) patchResources(_ *types.ResourceVersionTable, _ *ir.HTTPListener, _ []*ir.HTTPRoute) error { return nil } @@ -524,3 +524,7 @@ func (c *customResponse) patchRoute(route *routev3.Route, irRoute *ir.HTTPRoute, } return nil } + +func (*customResponse) patchVirtualHost(_ *routev3.VirtualHost, _ *ir.HTTPListener) error { + return nil +} diff --git a/internal/xds/translator/dynamic_forward_proxy.go b/internal/xds/translator/dynamic_forward_proxy.go index fe598d19b3..e4589c0b9c 100644 --- a/internal/xds/translator/dynamic_forward_proxy.go +++ b/internal/xds/translator/dynamic_forward_proxy.go @@ -91,7 +91,7 @@ func (*dynamicForwardProxy) patchRoute(route *routev3.Route, irRoute *ir.HTTPRou return nil } -func (*dynamicForwardProxy) patchResources(_ *types.ResourceVersionTable, _ []*ir.HTTPRoute) error { +func (*dynamicForwardProxy) patchResources(_ *types.ResourceVersionTable, _ *ir.HTTPListener, _ []*ir.HTTPRoute) error { return nil } @@ -234,3 +234,7 @@ func buildDFPLoopbackRBACPerRoute(irRoute *ir.HTTPRoute) (*rbacv3.RBACPerRoute, }, }, nil } + +func (*dynamicForwardProxy) patchVirtualHost(_ *routev3.VirtualHost, _ *ir.HTTPListener) error { + return nil +} diff --git a/internal/xds/translator/dynamicmodule.go b/internal/xds/translator/dynamicmodule.go index c117d29054..653d28b3f1 100644 --- a/internal/xds/translator/dynamicmodule.go +++ b/internal/xds/translator/dynamicmodule.go @@ -7,6 +7,9 @@ package translator import ( "errors" + "fmt" + "slices" + "strconv" corev3 "github.com/envoyproxy/go-control-plane/envoy/config/core/v3" routev3 "github.com/envoyproxy/go-control-plane/envoy/config/route/v3" @@ -30,13 +33,22 @@ type dynamicModule struct{} var _ httpFilter = &dynamicModule{} -// patchHCM builds and appends the dynamic module filters to the HTTP Connection Manager -// if applicable, and they do not already exist. -// Note: this method creates a filter for each route that contains a dynamic module config. -// The filter is disabled by default and enabled on the route level. +// patchHCM adds disabled envoy.filters.http.filter_chain placeholder filters to the HTTP +// Connection Manager: one for per-listener (per-connection) DynamicModule and one for per-route +// DynamicModule. +// +// Both placeholders are added together as soon as either scope has a DynamicModule policy +// anywhere on this listener, even if the other scope currently has none. This keeps the HCM's +// filter set stable across that kind of policy churn too: e.g. adding a per-listener +// DynamicModule policy later to a listener that already has per-route DynamicModule only changes +// route/virtual host TypedPerFilterConfig (an RDS update), never the listener's filter list +// (which would require an LDS update and a connection drain). +// +// DynamicModule has no native per-route override at all, while EG's EnvoyExtensionPolicy API +// allows an ordered list of DynamicModule filters per listener/route. The filter_chain filter +// wraps an ordered, named sub-chain of DynamicModule filters that is supplied separately (per +// virtual host for listener-scoped DynamicModule, per route for route-scoped DynamicModule). func (*dynamicModule) patchHCM(mgr *hcmv3.HttpConnectionManager, irListener *ir.HTTPListener) error { - var errs error - if mgr == nil { return errors.New("hcm is nil") } @@ -44,51 +56,40 @@ func (*dynamicModule) patchHCM(mgr *hcmv3.HttpConnectionManager, irListener *ir. return errors.New("ir listener is nil") } - for _, route := range irListener.Routes { - if !routeContainsDynamicModule(route) { + hasListenerDynamicModule := listenerContainsDynamicModule(irListener) + hasRouteDynamicModule := slices.ContainsFunc(irListener.Routes, routeContainsDynamicModule) + if !hasListenerDynamicModule && !hasRouteDynamicModule { + return nil + } + + for _, filterName := range []string{eepListenerFCFilterName(), eepFCFilterName()} { + if hcmContainsFilter(mgr, filterName) { continue } - for _, dm := range route.EnvoyExtensions.DynamicModules { - if hcmContainsFilter(mgr, dynamicModuleFilterName(&dm)) { - continue - } - filter, err := buildHCMDynamicModuleFilter(&dm) - if err != nil { - errs = errors.Join(errs, err) - continue - } - mgr.HttpFilters = append(mgr.HttpFilters, filter) + filter, err := buildHCMFilterChainFilter(filterName) + if err != nil { + return err } + mgr.HttpFilters = append(mgr.HttpFilters, filter) } - return errs + return nil } -// buildHCMDynamicModuleFilter returns a dynamic module HTTP filter from the provided IR DynamicModule. -func buildHCMDynamicModuleFilter(dm *ir.DynamicModule) (*hcmv3.HttpFilter, error) { - dmProto, err := dynamicModuleConfig(dm) - if err != nil { - return nil, err - } - - dmAny, err := anypb.New(dmProto) - if err != nil { - return nil, err - } - - // All dynamic module filters for all Routes are aggregated on HCM and disabled by default. - // Per-route config is used to enable the relevant filters on appropriate routes. - return &hcmv3.HttpFilter{ - Name: dynamicModuleFilterName(dm), - Disabled: true, - ConfigType: &hcmv3.HttpFilter_TypedConfig{ - TypedConfig: dmAny, - }, - }, nil +// dynamicModuleSubFilterName returns the stable top-level filter name for the per-route +// DynamicModule slot index. The index is the execution slot within the ordered +// EnvoyExtensionPolicy DynamicModule list, so route 0th modules always bind to the same +// listener-level filter. +func dynamicModuleSubFilterName(idx int) string { + return perRouteFilterName(egv1a1.EnvoyFilterDynamicModules, strconv.Itoa(idx)) } -func dynamicModuleFilterName(dm *ir.DynamicModule) string { - return perRouteFilterName(egv1a1.EnvoyFilterDynamicModules, dm.Name) +// dynamicModuleListenerSubFilterName returns the stable HCM-level filter name for a +// listener-level DynamicModule slot. Using the envoy.filters.http.dynamic_modules prefix +// (instead of the raw policy name) ensures sortHTTPFilters assigns it the correct order +// relative to route-level slots. +func dynamicModuleListenerSubFilterName(idx int) string { + return fmt.Sprintf("%s/listener/%d", egv1a1.EnvoyFilterDynamicModules, idx) } func dynamicModuleConfig(dm *ir.DynamicModule) (*dmfilterv3.DynamicModuleFilter, error) { @@ -162,33 +163,51 @@ func routeContainsDynamicModule(irRoute *ir.HTTPRoute) bool { return irRoute.EnvoyExtensions != nil && len(irRoute.EnvoyExtensions.DynamicModules) > 0 } +// listenerContainsDynamicModule returns true if DynamicModules exist at listener scope. +func listenerContainsDynamicModule(irListener *ir.HTTPListener) bool { + return irListener != nil && irListener.EnvoyExtensions != nil && len(irListener.EnvoyExtensions.DynamicModules) > 0 +} + // patchResources creates clusters for remote dynamic module sources. -func (*dynamicModule) patchResources(tCtx *types.ResourceVersionTable, routes []*ir.HTTPRoute) error { +func (*dynamicModule) patchResources(tCtx *types.ResourceVersionTable, irListener *ir.HTTPListener, routes []*ir.HTTPRoute) error { if tCtx == nil || tCtx.XdsResources == nil { return errors.New("xds resource table is nil") } var errs error - for _, route := range routes { - if !routeContainsDynamicModule(route) { - continue - } - - for _, dm := range route.EnvoyExtensions.DynamicModules { + addClusters := func(dms []ir.DynamicModule) { + for _, dm := range dms { if dm.Remote == nil { continue } - if err := addClusterFromURL(dm.Remote.URL, nil, tCtx); err != nil { errs = errors.Join(errs, err) } } } + if listenerContainsDynamicModule(irListener) { + addClusters(irListener.EnvoyExtensions.DynamicModules) + } + for _, route := range routes { + if !routeContainsDynamicModule(route) { + continue + } + addClusters(route.EnvoyExtensions.DynamicModules) + } + return errs } // patchRoute enables the corresponding dynamic module filter for the provided route. +// +// A nil EnvoyExtensions means no route-scoped policy owns this route: it keeps inheriting the +// listener-scoped DynamicModules delivered at VirtualHost scope by patchVirtualHost. +// +// A non-nil EnvoyExtensions means a more specific (xRoute or route rule) policy owns this route +// and fully replaces — never merges with — the listener-scoped policy. The extension count is +// intentionally not checked: an empty result (e.g. fail-open invalid Wasm) still represents a +// more specific policy that owns this route and must suppress the lower-scope DynamicModules. func (*dynamicModule) patchRoute(route *routev3.Route, irRoute *ir.HTTPRoute, _ *ir.HTTPListener) error { if route == nil { return errors.New("xds route is nil") @@ -200,13 +219,87 @@ func (*dynamicModule) patchRoute(route *routev3.Route, irRoute *ir.HTTPRoute, _ return nil } - for _, dm := range irRoute.EnvoyExtensions.DynamicModules { - filterName := dynamicModuleFilterName(&dm) - if err := enableFilterOnRoute(route, filterName, &routev3.FilterConfig{ - Config: &anypb.Any{}, - }); err != nil { + // A non-nil EnvoyExtensions means a more specific route policy owns this route and fully + // replaces the listener-scoped policy. The extension count is intentionally not checked + // here: an empty result (e.g. fail-open invalid Wasm) still represents a more specific + // policy that owns this route and must suppress the lower-scope DynamicModule. + if err := disableFilterOnRouteOnce(route, eepListenerFCFilterName()); err != nil { + return err + } + + var newFilters []*corev3.TypedExtensionConfig + for idx := range irRoute.EnvoyExtensions.DynamicModules { + cfg, err := dynamicModuleConfig(&irRoute.EnvoyExtensions.DynamicModules[idx]) + if err != nil { return err } + cfgAny, err := anypb.New(cfg) + if err != nil { + return err + } + newFilters = append(newFilters, &corev3.TypedExtensionConfig{ + Name: dynamicModuleSubFilterName(idx), + TypedConfig: cfgAny, + }) + } + + if len(newFilters) == 0 { + return nil + } + + merged, err := mergeFilterChainConfigPerRoute(route.GetTypedPerFilterConfig()[eepFCFilterName()], newFilters) + if err != nil { + return err + } + if route.TypedPerFilterConfig == nil { + route.TypedPerFilterConfig = make(map[string]*anypb.Any) + } + route.TypedPerFilterConfig[eepFCFilterName()] = merged + return nil +} + +// patchVirtualHost enables the listener-scoped DynamicModule filters at VirtualHost scope so a +// listener's policy does not bleed into virtual hosts belonging to a different listener that +// shares the same RouteConfiguration. Delivery via VirtualHost TypedPerFilterConfig goes through +// RDS, so policy changes do not trigger listener drains. +func (*dynamicModule) patchVirtualHost(vh *routev3.VirtualHost, httpListener *ir.HTTPListener) error { + if !listenerContainsDynamicModule(httpListener) { + return nil + } + + filterName := eepListenerFCFilterName() + existing := vh.GetTypedPerFilterConfig()[filterName] + alreadyDelivered, err := filterChainAlreadyHasType(existing, egv1a1.EnvoyFilterDynamicModules) + if err != nil { + return err + } + if alreadyDelivered { + return nil + } + + var newFilters []*corev3.TypedExtensionConfig + for idx := range httpListener.EnvoyExtensions.DynamicModules { + cfg, err := dynamicModuleConfig(&httpListener.EnvoyExtensions.DynamicModules[idx]) + if err != nil { + return err + } + cfgAny, err := anypb.New(cfg) + if err != nil { + return err + } + newFilters = append(newFilters, &corev3.TypedExtensionConfig{ + Name: dynamicModuleListenerSubFilterName(idx), + TypedConfig: cfgAny, + }) + } + + merged, err := mergeFilterChainConfigPerRoute(existing, newFilters) + if err != nil { + return err + } + if vh.TypedPerFilterConfig == nil { + vh.TypedPerFilterConfig = make(map[string]*anypb.Any) } + vh.TypedPerFilterConfig[filterName] = merged return nil } diff --git a/internal/xds/translator/extauth.go b/internal/xds/translator/extauth.go index 2405ba505b..0625607f34 100644 --- a/internal/xds/translator/extauth.go +++ b/internal/xds/translator/extauth.go @@ -253,7 +253,7 @@ func routeContainsExtAuth(irRoute *ir.HTTPRoute) bool { // patchResources patches the cluster resources for the external auth services. func (*extAuth) patchResources(tCtx *types.ResourceVersionTable, - routes []*ir.HTTPRoute, + _ *ir.HTTPListener, routes []*ir.HTTPRoute, ) error { if tCtx == nil || tCtx.XdsResources == nil { return errors.New("xds resource table is nil") @@ -329,3 +329,7 @@ func convertContextExtensions(irCtxExts []*ir.ContextExtention) map[string]strin return ctxExts } + +func (*extAuth) patchVirtualHost(_ *routev3.VirtualHost, _ *ir.HTTPListener) error { + return nil +} diff --git a/internal/xds/translator/extproc.go b/internal/xds/translator/extproc.go index 846796d76b..6b37c5c88f 100644 --- a/internal/xds/translator/extproc.go +++ b/internal/xds/translator/extproc.go @@ -9,6 +9,7 @@ import ( "errors" "fmt" "slices" + "strconv" corev3 "github.com/envoyproxy/go-control-plane/envoy/config/core/v3" routev3 "github.com/envoyproxy/go-control-plane/envoy/config/route/v3" @@ -31,69 +32,61 @@ type extProc struct{} var _ httpFilter = &extProc{} -// patchHCM builds and appends the ext_proc Filters to the HTTP Connection Manager -// if applicable, and it does not already exist. -// Note: this method creates an ext_proc filter for each route that contains an ExtAuthz config. -// The filter is disabled by default. It is enabled on the route level. +// patchHCM adds disabled envoy.filters.http.filter_chain placeholder filters to the HTTP +// Connection Manager: one for per-listener (per-connection) ExtProc and one for per-route +// ExtProc. +// +// Both placeholders are added together as soon as either scope has an ExtProc policy anywhere on +// this listener, even if the other scope currently has none. This keeps the HCM's filter set +// stable across that kind of policy churn too: e.g. adding a per-listener ExtProc policy later to +// a listener that already has per-route ExtProc only changes route/virtual host +// TypedPerFilterConfig (an RDS update), never the listener's filter list (which would require +// an LDS update and a connection drain). +// +// Envoy's ExtProcPerRoute API can only override one processor for one filter instance, while EG's +// EnvoyExtensionPolicy API allows an ordered list of ExtProc filters per listener/route. The +// filter_chain filter wraps an ordered, named sub-chain of ExtProc filters that is supplied +// separately (per virtual host for listener-scoped ExtProc, per route for route-scoped ExtProc). func (*extProc) patchHCM(mgr *hcmv3.HttpConnectionManager, irListener *ir.HTTPListener) error { - var errs error - if mgr == nil { return errors.New("hcm is nil") } - if irListener == nil { return errors.New("ir listener is nil") } - for _, route := range irListener.Routes { - if !routeContainsExtProc(route) { + hasListenerExtProc := listenerContainsExtProc(irListener) + hasRouteExtProc := slices.ContainsFunc(irListener.Routes, routeContainsExtProc) + if !hasListenerExtProc && !hasRouteExtProc { + return nil + } + + for _, filterName := range []string{eepListenerFCFilterName(), eepFCFilterName()} { + if hcmContainsFilter(mgr, filterName) { continue } - - for i := range route.EnvoyExtensions.ExtProcs { - ep := &route.EnvoyExtensions.ExtProcs[i] - if hcmContainsFilter(mgr, extProcFilterName(ep)) { - continue - } - - filter, err := buildHCMExtProcFilter(ep) - if err != nil { - errs = errors.Join(errs, err) - continue - } - - mgr.HttpFilters = append(mgr.HttpFilters, filter) + filter, err := buildHCMFilterChainFilter(filterName) + if err != nil { + return err } + mgr.HttpFilters = append(mgr.HttpFilters, filter) } - return errs + return nil } -// buildHCMExtProcFilter returns an ext_proc HTTP filter from the provided IR HTTPRoute. -func buildHCMExtProcFilter(extProc *ir.ExtProc) (*hcmv3.HttpFilter, error) { - extAuthProto, err := extProcConfig(extProc) - if err != nil { - return nil, err - } - extAuthAny, err := anypb.New(extAuthProto) - if err != nil { - return nil, err - } - - // All extproc filters for all Routes are aggregated on HCM and disabled by default - // Per-route config is used to enable the relevant filters on appropriate routes - return &hcmv3.HttpFilter{ - Name: extProcFilterName(extProc), - Disabled: true, - ConfigType: &hcmv3.HttpFilter_TypedConfig{ - TypedConfig: extAuthAny, - }, - }, nil +// extProcSubFilterName returns the stable top-level filter name for the per-route ExtProc slot +// index. The index is the execution slot within the ordered EnvoyExtensionPolicy ExtProc list, so +// route 0th processors always bind to the same listener-level filter. +func extProcSubFilterName(idx int) string { + return perRouteFilterName(egv1a1.EnvoyFilterExtProc, strconv.Itoa(idx)) } -func extProcFilterName(extProc *ir.ExtProc) string { - return perRouteFilterName(egv1a1.EnvoyFilterExtProc, extProc.Name) +// extProcListenerSubFilterName returns the stable HCM-level filter name for a listener-level +// ExtProc slot. Using the envoy.filters.http.ext_proc prefix (instead of the raw policy name) +// ensures sortHTTPFilters assigns it the correct order relative to route-level slots. +func extProcListenerSubFilterName(idx int) string { + return fmt.Sprintf("%s/listener/%d", egv1a1.EnvoyFilterExtProc, idx) } func extProcConfig(extProc *ir.ExtProc) (*extprocv3.ExternalProcessor, error) { @@ -177,34 +170,51 @@ func routeContainsExtProc(irRoute *ir.HTTPRoute) bool { return irRoute.EnvoyExtensions != nil && len(irRoute.EnvoyExtensions.ExtProcs) > 0 } +// listenerContainsExtProc returns true if ExtProcs exist at listener scope. +func listenerContainsExtProc(irListener *ir.HTTPListener) bool { + return irListener != nil && irListener.EnvoyExtensions != nil && len(irListener.EnvoyExtensions.ExtProcs) > 0 +} + // patchResources patches the cluster resources for the external services. func (*extProc) patchResources(tCtx *types.ResourceVersionTable, - routes []*ir.HTTPRoute, + irListener *ir.HTTPListener, routes []*ir.HTTPRoute, ) error { if tCtx == nil || tCtx.XdsResources == nil { return errors.New("xds resource table is nil") } var errs error + addClusters := func(extProcs []ir.ExtProc) { + for i := range extProcs { + ep := extProcs[i] + if err := createExtServiceXDSCluster(&ep.Destination, ep.Traffic, tCtx); err != nil { + errs = errors.Join(errs, err) + } + } + } + + if listenerContainsExtProc(irListener) { + addClusters(irListener.EnvoyExtensions.ExtProcs) + } for _, route := range routes { if !routeContainsExtProc(route) { continue } - - for i := range route.EnvoyExtensions.ExtProcs { - ep := route.EnvoyExtensions.ExtProcs[i] - if err := createExtServiceXDSCluster( - &ep.Destination, ep.Traffic, tCtx); err != nil { - errs = errors.Join(errs, err) - } - } + addClusters(route.EnvoyExtensions.ExtProcs) } return errs } // patchRoute patches the provided route with the extProc config if applicable. -// Note: this method enables the corresponding extProc filter for the provided route. +// +// A nil EnvoyExtensions means no route-scoped policy owns this route: it keeps inheriting the +// listener-scoped ExtProcs delivered at VirtualHost scope by patchVirtualHost. +// +// A non-nil EnvoyExtensions means a more specific (xRoute or route rule) policy owns this route +// and fully replaces — never merges with — the listener-scoped policy. The extension count is +// intentionally not checked: an empty result (e.g. fail-open invalid Wasm) still represents a +// more specific policy that owns this route and must suppress the lower-scope ExtProcs. func (*extProc) patchRoute(route *routev3.Route, irRoute *ir.HTTPRoute, _ *ir.HTTPListener) error { if route == nil { return errors.New("xds route is nil") @@ -216,15 +226,42 @@ func (*extProc) patchRoute(route *routev3.Route, irRoute *ir.HTTPRoute, _ *ir.HT return nil } - for i := range irRoute.EnvoyExtensions.ExtProcs { - ep := &irRoute.EnvoyExtensions.ExtProcs[i] - filterName := extProcFilterName(ep) - if err := enableFilterOnRoute(route, filterName, &routev3.FilterConfig{ - Config: &anypb.Any{}, - }); err != nil { + // A non-nil EnvoyExtensions means a more specific route policy owns this route and fully + // replaces the listener-scoped policy. The extension count is intentionally not checked + // here: an empty result (e.g. fail-open invalid Wasm) still represents a more specific + // policy that owns this route and must suppress the lower-scope ExtProc. + if err := disableFilterOnRouteOnce(route, eepListenerFCFilterName()); err != nil { + return err + } + + var newFilters []*corev3.TypedExtensionConfig + for idx := range irRoute.EnvoyExtensions.ExtProcs { + cfg, err := extProcConfig(&irRoute.EnvoyExtensions.ExtProcs[idx]) + if err != nil { return err } + cfgAny, err := anypb.New(cfg) + if err != nil { + return err + } + newFilters = append(newFilters, &corev3.TypedExtensionConfig{ + Name: extProcSubFilterName(idx), + TypedConfig: cfgAny, + }) + } + + if len(newFilters) == 0 { + return nil } + + merged, err := mergeFilterChainConfigPerRoute(route.GetTypedPerFilterConfig()[eepFCFilterName()], newFilters) + if err != nil { + return err + } + if route.TypedPerFilterConfig == nil { + route.TypedPerFilterConfig = make(map[string]*anypb.Any) + } + route.TypedPerFilterConfig[eepFCFilterName()] = merged return nil } @@ -276,3 +313,49 @@ func translateExtProcBodyProcessingMode(mode *ir.ExtProcBodyProcessingMode) extp } return extprocv3.ProcessingMode_NONE } + +// patchVirtualHost enables the listener-scoped ExtProc filters at VirtualHost scope so a +// listener's policy does not bleed into virtual hosts belonging to a different listener that +// shares the same RouteConfiguration. Delivery via VirtualHost TypedPerFilterConfig goes through +// RDS, so policy changes do not trigger listener drains. +func (*extProc) patchVirtualHost(vh *routev3.VirtualHost, httpListener *ir.HTTPListener) error { + if !listenerContainsExtProc(httpListener) { + return nil + } + + filterName := eepListenerFCFilterName() + existing := vh.GetTypedPerFilterConfig()[filterName] + alreadyDelivered, err := filterChainAlreadyHasType(existing, egv1a1.EnvoyFilterExtProc) + if err != nil { + return err + } + if alreadyDelivered { + return nil + } + + var newFilters []*corev3.TypedExtensionConfig + for idx := range httpListener.EnvoyExtensions.ExtProcs { + cfg, err := extProcConfig(&httpListener.EnvoyExtensions.ExtProcs[idx]) + if err != nil { + return err + } + cfgAny, err := anypb.New(cfg) + if err != nil { + return err + } + newFilters = append(newFilters, &corev3.TypedExtensionConfig{ + Name: extProcListenerSubFilterName(idx), + TypedConfig: cfgAny, + }) + } + + merged, err := mergeFilterChainConfigPerRoute(existing, newFilters) + if err != nil { + return err + } + if vh.TypedPerFilterConfig == nil { + vh.TypedPerFilterConfig = make(map[string]*anypb.Any) + } + vh.TypedPerFilterConfig[filterName] = merged + return nil +} diff --git a/internal/xds/translator/fault.go b/internal/xds/translator/fault.go index 142fd58ea1..f1c281a577 100644 --- a/internal/xds/translator/fault.go +++ b/internal/xds/translator/fault.go @@ -100,7 +100,7 @@ func routeContainsFault(irRoute *ir.HTTPRoute) bool { return false } -func (*fault) patchResources(*types.ResourceVersionTable, []*ir.HTTPRoute) error { +func (*fault) patchResources(*types.ResourceVersionTable, *ir.HTTPListener, []*ir.HTTPRoute) error { return nil } @@ -174,3 +174,7 @@ func (*fault) patchRoute(route *routev3.Route, irRoute *ir.HTTPRoute, _ *ir.HTTP return nil } + +func (*fault) patchVirtualHost(_ *routev3.VirtualHost, _ *ir.HTTPListener) error { + return nil +} diff --git a/internal/xds/translator/geoip.go b/internal/xds/translator/geoip.go index b70c98bf99..255796ae05 100644 --- a/internal/xds/translator/geoip.go +++ b/internal/xds/translator/geoip.go @@ -296,6 +296,10 @@ func (*geoip) patchRoute(*routev3.Route, *ir.HTTPRoute, *ir.HTTPListener) error return nil } -func (*geoip) patchResources(*types.ResourceVersionTable, []*ir.HTTPRoute) error { +func (*geoip) patchResources(*types.ResourceVersionTable, *ir.HTTPListener, []*ir.HTTPRoute) error { + return nil +} + +func (*geoip) patchVirtualHost(_ *routev3.VirtualHost, _ *ir.HTTPListener) error { return nil } diff --git a/internal/xds/translator/globalresources.go b/internal/xds/translator/globalresources.go index 2fa12a4fb3..088adc9930 100644 --- a/internal/xds/translator/globalresources.go +++ b/internal/xds/translator/globalresources.go @@ -222,6 +222,9 @@ func buildEnvoyClientTLSSocket(envoyClientCertificate *ir.TLSCertificate) (*core 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 { diff --git a/internal/xds/translator/header_mutation.go b/internal/xds/translator/header_mutation.go index 7281c3f645..8ef463794e 100644 --- a/internal/xds/translator/header_mutation.go +++ b/internal/xds/translator/header_mutation.go @@ -53,7 +53,7 @@ func (*headerMutation) patchHCM(mgr *hcmv3.HttpConnectionManager, irListener *ir return nil } -func (*headerMutation) patchResources(*types.ResourceVersionTable, []*ir.HTTPRoute) error { +func (*headerMutation) patchResources(*types.ResourceVersionTable, *ir.HTTPListener, []*ir.HTTPRoute) error { return nil } @@ -162,3 +162,7 @@ func buildHeaderMutationRules(addHeaders []ir.AddHeader, removeHeaders []string, return mutationRules } + +func (*headerMutation) patchVirtualHost(_ *routev3.VirtualHost, _ *ir.HTTPListener) error { + return nil +} diff --git a/internal/xds/translator/healthcheck.go b/internal/xds/translator/healthcheck.go index 6551aa61fa..7e7d18d3e8 100644 --- a/internal/xds/translator/healthcheck.go +++ b/internal/xds/translator/healthcheck.go @@ -94,10 +94,14 @@ func buildHealthCheckFilter(healthCheck *ir.HealthCheckSettings) (*hcmv3.HttpFil }, nil } -func (*healthCheck) patchResources(*types.ResourceVersionTable, []*ir.HTTPRoute) error { +func (*healthCheck) patchResources(*types.ResourceVersionTable, *ir.HTTPListener, []*ir.HTTPRoute) error { return nil } func (*healthCheck) patchRoute(_ *routev3.Route, _ *ir.HTTPRoute, _ *ir.HTTPListener) error { return nil } + +func (*healthCheck) patchVirtualHost(_ *routev3.VirtualHost, _ *ir.HTTPListener) error { + return nil +} diff --git a/internal/xds/translator/httpfilters.go b/internal/xds/translator/httpfilters.go index d95e52541a..3b297b7d0d 100644 --- a/internal/xds/translator/httpfilters.go +++ b/internal/xds/translator/httpfilters.go @@ -7,9 +7,7 @@ package translator import ( "container/list" - "fmt" "sort" - "strconv" "strings" routev3 "github.com/envoyproxy/go-control-plane/envoy/config/route/v3" @@ -58,13 +56,18 @@ type httpFilter interface { // patchRoute patches the provide Route with a filter's Route level configuration. patchRoute(route *routev3.Route, irRoute *ir.HTTPRoute, httpListener *ir.HTTPListener) error + // patchVirtualHost patches the provided VirtualHost with a filter's VirtualHost level configuration. + // Note: this method may be called multiple times for the same VirtualHost when multiple IR listeners + // share the same RouteConfiguration (cleartext listeners on the same port). + patchVirtualHost(vh *routev3.VirtualHost, httpListener *ir.HTTPListener) error + // patchResources adds all the other needed resources referenced by this // filter to the resource version table. // for example: // - a jwt filter needs to add the cluster for the jwks. // - an oidc filter needs to add the cluster for token endpoint and the secret // for the oauth2 client secret and the hmac secret. - patchResources(tCtx *types.ResourceVersionTable, routes []*ir.HTTPRoute) error + patchResources(tCtx *types.ResourceVersionTable, irListener *ir.HTTPListener, routes []*ir.HTTPRoute) error } type OrderedHTTPFilter struct { @@ -128,14 +131,12 @@ func newOrderedHTTPFilter(filter *hcmv3.HttpFilter) *OrderedHTTPFilter { order = 11 case isFilterType(filter, egv1a1.EnvoyFilterBuffer): order = 12 - case isFilterType(filter, egv1a1.EnvoyFilterLua): - order = 13 + mustGetFilterIndex(filter.Name) - case isFilterType(filter, egv1a1.EnvoyFilterExtProc): - order = 100 + mustGetFilterIndex(filter.Name) - case isFilterType(filter, egv1a1.EnvoyFilterWasm): - order = 200 + mustGetFilterIndex(filter.Name) - case isFilterType(filter, egv1a1.EnvoyFilterDynamicModules): - order = 250 + mustGetFilterIndex(filter.Name) + case filter.Name == eepListenerFCFilterName(): + // Lua, ExtProc, Wasm, and DynamicModule all share this one placeholder for their + // listener-scoped instances, and it runs before the shared route-scoped placeholder. + order = 13 + case filter.Name == eepFCFilterName(): + order = 63 case isFilterType(filter, egv1a1.EnvoyFilterGeoIP): order = 300 case isFilterType(filter, egv1a1.EnvoyFilterRBAC): @@ -344,22 +345,34 @@ func patchRouteWithPerRouteConfig(route *routev3.Route, irRoute *ir.HTTPRoute, h return nil } +// patchVirtualHost calls each filter's patchVirtualHost to apply VirtualHost-level configuration. +func patchVirtualHost(vh *routev3.VirtualHost, httpListener *ir.HTTPListener) error { + for _, filter := range httpFilters { + if err := filter.patchVirtualHost(vh, httpListener); err != nil { + return err + } + } + return nil +} + // isFilterType returns true if the filter is the provided filter type. func isFilterType(filter *hcmv3.HttpFilter, filterType egv1a1.EnvoyFilter) bool { // Multiple filters of the same types are added to the HCM filter chain, one for each // route. The filter name is prefixed with the filter type, for example: // "envoy.filters.http.oauth2_first-route". - return strings.HasPrefix(filter.Name, string(filterType)) -} - -// mustGetFilterIndex returns the index of the filter in its filter type. -func mustGetFilterIndex(filterName string) int { - a := strings.Split(filterName, "/") - index, err := strconv.Atoi(a[len(a)-1]) - if err != nil { - panic(fmt.Errorf("cannot get filter index from %s :%w", filterName, err)) + if strings.HasPrefix(filter.Name, string(filterType)) { + return true + } + // Lua, ExtProc, Wasm, and DynamicModules are all delivered via the same two shared + // envoy.filters.http.filter_chain placeholder filters rather than under their own + // filter-type prefix, so FilterOrder entries that reference any of these types need to + // match those placeholder names too. Because the placeholder is shared, moving one of + // these types in a custom FilterOrder moves all of them together. + switch filterType { + case egv1a1.EnvoyFilterLua, egv1a1.EnvoyFilterExtProc, egv1a1.EnvoyFilterWasm, egv1a1.EnvoyFilterDynamicModules: + return filter.Name == eepFCFilterName() || filter.Name == eepListenerFCFilterName() } - return index + return false } // patchResources adds all the other needed resources referenced by this @@ -367,9 +380,9 @@ func mustGetFilterIndex(filterName string) int { // for example: // - a jwt filter needs to add the cluster for the jwks. // - an oidc filter needs to add the secret for the oauth2 client secret. -func patchResources(tCtx *types.ResourceVersionTable, routes []*ir.HTTPRoute) error { +func patchResources(tCtx *types.ResourceVersionTable, irListener *ir.HTTPListener, routes []*ir.HTTPRoute) error { for _, filter := range httpFilters { - if err := filter.patchResources(tCtx, routes); err != nil { + if err := filter.patchResources(tCtx, irListener, routes); err != nil { return err } } diff --git a/internal/xds/translator/httpfilters_test.go b/internal/xds/translator/httpfilters_test.go index 7e988be4c7..a85c21204e 100644 --- a/internal/xds/translator/httpfilters_test.go +++ b/internal/xds/translator/httpfilters_test.go @@ -427,6 +427,27 @@ func Test_sortHTTPFilters(t *testing.T) { httpFilterForTest(egv1a1.EnvoyFilterRouter), }, }, + { + name: "custom filter order-eep-filter-chain-placeholder", + filters: []*hcmv3.HttpFilter{ + httpFilterForTest(egv1a1.EnvoyFilterRouter), + httpFilterForTest(egv1a1.EnvoyFilterOAuth2 + "/securitypolicy/default/policy-for-http-route-1"), + httpFilterForTest(egv1a1.EnvoyFilter(eepFCFilterName())), + httpFilterForTest(egv1a1.EnvoyFilter(eepListenerFCFilterName())), + }, + filterOrder: []egv1a1.FilterPosition{ + { + Name: egv1a1.EnvoyFilterLua, + After: new(egv1a1.EnvoyFilterOAuth2), + }, + }, + want: []*hcmv3.HttpFilter{ + httpFilterForTest(egv1a1.EnvoyFilterOAuth2 + "/securitypolicy/default/policy-for-http-route-1"), + httpFilterForTest(egv1a1.EnvoyFilter(eepListenerFCFilterName())), + httpFilterForTest(egv1a1.EnvoyFilter(eepFCFilterName())), + httpFilterForTest(egv1a1.EnvoyFilterRouter), + }, + }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { diff --git a/internal/xds/translator/jwt.go b/internal/xds/translator/jwt.go index 1fe48a4944..f40ef3be12 100644 --- a/internal/xds/translator/jwt.go +++ b/internal/xds/translator/jwt.go @@ -426,7 +426,7 @@ func (*jwt) patchRoute(route *routev3.Route, irRoute *ir.HTTPRoute, _ *ir.HTTPLi } // patchResources creates JWKS clusters from the provided routes, if needed. -func (*jwt) patchResources(tCtx *types.ResourceVersionTable, routes []*ir.HTTPRoute) error { +func (*jwt) patchResources(tCtx *types.ResourceVersionTable, _ *ir.HTTPListener, routes []*ir.HTTPRoute) error { if tCtx == nil || tCtx.XdsResources == nil { return errors.New("xds resource table is nil") } @@ -508,3 +508,7 @@ func buildJwtFromHeaders(headers []egv1a1.JWTHeaderExtractor) []*jwtauthnv3.JwtH return jwtHeaders } + +func (*jwt) patchVirtualHost(_ *routev3.VirtualHost, _ *ir.HTTPListener) error { + return nil +} diff --git a/internal/xds/translator/local_ratelimit.go b/internal/xds/translator/local_ratelimit.go index f527740123..ca99cdc9e4 100644 --- a/internal/xds/translator/local_ratelimit.go +++ b/internal/xds/translator/local_ratelimit.go @@ -111,7 +111,7 @@ func routeContainsLocalRateLimit(irRoute *ir.HTTPRoute) bool { } func (*localRateLimit) patchResources(*types.ResourceVersionTable, - []*ir.HTTPRoute, + *ir.HTTPListener, []*ir.HTTPRoute, ) error { return nil } @@ -483,3 +483,7 @@ func buildQueryParamMatchLocalRateLimitActions( *descriptorEntries = append(*descriptorEntries, entry) } } + +func (*localRateLimit) patchVirtualHost(_ *routev3.VirtualHost, _ *ir.HTTPListener) error { + return nil +} diff --git a/internal/xds/translator/lua.go b/internal/xds/translator/lua.go index 3186afdb46..f73f7b4afa 100644 --- a/internal/xds/translator/lua.go +++ b/internal/xds/translator/lua.go @@ -7,13 +7,15 @@ package translator import ( "errors" + "fmt" + "slices" + "strconv" corev3 "github.com/envoyproxy/go-control-plane/envoy/config/core/v3" routev3 "github.com/envoyproxy/go-control-plane/envoy/config/route/v3" luafilterv3 "github.com/envoyproxy/go-control-plane/envoy/extensions/filters/http/lua/v3" hcmv3 "github.com/envoyproxy/go-control-plane/envoy/extensions/filters/network/http_connection_manager/v3" "google.golang.org/protobuf/encoding/protojson" - "google.golang.org/protobuf/proto" "google.golang.org/protobuf/types/known/anypb" "google.golang.org/protobuf/types/known/structpb" @@ -30,8 +32,24 @@ type lua struct{} var _ httpFilter = &lua{} -// patchHCM builds and appends the lua Filters to the HTTP Connection Manager -// Lua filters are created in disabled mode. +// patchHCM adds disabled envoy.filters.http.filter_chain placeholder filters to the HTTP +// Connection Manager: one shared placeholder for per-listener (per-connection) EnvoyExtensionPolicy +// extensions and one shared placeholder for per-route extensions. Lua, ExtProc, Wasm, and +// DynamicModule all deliver their instances through these same two placeholders instead of each +// type getting its own, so the HCM's filter list never grows or reorders as extensions of any +// type are added, removed, or renamed. +// +// Both placeholders are added together as soon as either scope has a Lua policy anywhere on +// this listener, even if the other scope currently has none. This keeps the HCM's filter set +// stable across that kind of policy churn too: e.g. adding a per-listener Lua policy later to +// a listener that already has per-route Lua only changes route/virtual host +// TypedPerFilterConfig (an RDS update), never the listener's filter list (which would require +// an LDS update and a connection drain). +// +// Envoy's LuaPerRoute API can only override one script for one filter instance, while EG's +// EnvoyExtensionPolicy API allows an ordered list of Lua filters per listener/route. The +// filter_chain filter wraps an ordered, named sub-chain of Lua filters that is supplied +// separately (per virtual host for listener-scoped Lua, per route for route-scoped Lua). func (*lua) patchHCM(mgr *hcmv3.HttpConnectionManager, irListener *ir.HTTPListener) error { if mgr == nil { return errors.New("hcm is nil") @@ -40,76 +58,57 @@ func (*lua) patchHCM(mgr *hcmv3.HttpConnectionManager, irListener *ir.HTTPListen return errors.New("ir listener is nil") } - var errs error - for _, route := range irListener.Routes { - if !routeContainsLua(route) { + hasListenerLua := irListener.EnvoyExtensions != nil && len(irListener.EnvoyExtensions.Luas) > 0 + hasRouteLua := slices.ContainsFunc(irListener.Routes, routeContainsLua) + if !hasListenerLua && !hasRouteLua { + return nil + } + + for _, filterName := range []string{eepListenerFCFilterName(), eepFCFilterName()} { + if hcmContainsFilter(mgr, filterName) { continue } - for _, ep := range route.EnvoyExtensions.Luas { - if hcmContainsFilter(mgr, luaFilterName(ep)) { - continue - } - filter, err := buildHCMLuaFilter(ep) - if err != nil { - errs = errors.Join(errs, err) - continue - } - mgr.HttpFilters = append(mgr.HttpFilters, filter) + filter, err := buildHCMFilterChainFilter(filterName) + if err != nil { + return err } + mgr.HttpFilters = append(mgr.HttpFilters, filter) } - return errs + return nil } -// buildHCMLuaFilter returns a Lua filter for HCM. -func buildHCMLuaFilter(lua ir.Lua) (*hcmv3.HttpFilter, error) { - var ( - luaProto *luafilterv3.Lua - luaAny *anypb.Any - err error - ) - luaProto = &luafilterv3.Lua{ - DefaultSourceCode: &corev3.DataSource{ - Specifier: &corev3.DataSource_InlineString{ - InlineString: *lua.Code, - }, - }, - } - if err = luaProto.ValidateAll(); err != nil { - return nil, err - } - if luaAny, err = anypb.New(luaProto); err != nil { - return nil, err - } - - return &hcmv3.HttpFilter{ - Name: luaFilterName(lua), - Disabled: true, - ConfigType: &hcmv3.HttpFilter_TypedConfig{ - TypedConfig: luaAny, - }, - }, nil +// luaFilterName returns the stable top-level filter name for the per-route Lua slot index. +// The index is the execution slot within the ordered EnvoyExtensionPolicy Lua +// list, so route 0th scripts always bind to the same listener-level filter. +func luaFilterName(idx int) string { + return perRouteFilterName(egv1a1.EnvoyFilterLua, strconv.Itoa(idx)) } -func luaFilterName(lua ir.Lua) string { - return perRouteFilterName(egv1a1.EnvoyFilterLua, lua.Name) +// luaListenerFilterName returns the stable HCM-level filter name for a listener-level +// Lua slot. Using the envoy.filters.http.lua prefix (instead of the raw policy name) +// ensures sortHTTPFilters assigns it the correct order relative to route-level slots. +func luaListenerFilterName(idx int) string { + return fmt.Sprintf("%s/listener/%d", egv1a1.EnvoyFilterLua, idx) } -// routeContainsLua returns true if Luas exists for the provided route. +// routeContainsLua returns true if the route has any Lua extensions. func routeContainsLua(irRoute *ir.HTTPRoute) bool { if irRoute == nil { return false } - return irRoute.EnvoyExtensions != nil && len(irRoute.EnvoyExtensions.Luas) > 0 } // patchResources patches the cluster resources for the http lua code source. -func (*lua) patchResources(_ *types.ResourceVersionTable, _ []*ir.HTTPRoute) error { +func (*lua) patchResources(_ *types.ResourceVersionTable, _ *ir.HTTPListener, _ []*ir.HTTPRoute) error { return nil } -// patchRoute patches the provided route so Lua filters are enabled if applicable. +// patchRoute patches the provided route with LuaPerRoute so the Lua filter runs with the route's script. +// Routes with no Lua entries fall back to the listener-level Lua inherited from the virtual host. +// Only routes with their own Lua entries disable the inherited listener-level Lua and install +// their own scripts in its place. func (*lua) patchRoute(route *routev3.Route, irRoute *ir.HTTPRoute, _ *ir.HTTPListener) error { if route == nil { return errors.New("xds route is nil") @@ -121,32 +120,131 @@ func (*lua) patchRoute(route *routev3.Route, irRoute *ir.HTTPRoute, _ *ir.HTTPLi return nil } - for _, ep := range irRoute.EnvoyExtensions.Luas { - filterName := luaFilterName(ep) - routeCfg, err := buildLuaRouteFilterConfig(ep) - if err != nil { - return err + // A non-nil EnvoyExtensions means a more specific route policy owns this route and fully + // replaces the listener-scoped policy. The extension count is intentionally not checked + // here: an empty result (e.g. fail-open invalid Wasm) still represents a more specific + // policy that owns this route and must suppress the lower-scope Lua. + if err := disableFilterOnRouteOnce(route, eepListenerFCFilterName()); err != nil { + return err + } + + var newFilters []*corev3.TypedExtensionConfig + for idx, ep := range irRoute.EnvoyExtensions.Luas { + filterName := luaFilterName(idx) + luaOnFCFilter := &luafilterv3.Lua{ + DefaultSourceCode: &corev3.DataSource{ + Specifier: &corev3.DataSource_InlineString{ + InlineString: *ep.Code, + }, + }, + } + + // TODO: support filterContext in Lua filter make this simpler + if ep.FilterContext != nil && ep.FilterContext.Raw != nil { + luaPerRoute := &luafilterv3.LuaPerRoute{} + filterCtx := &structpb.Struct{} + if err := protojson.Unmarshal(ep.FilterContext.Raw, filterCtx); err != nil { + return err + } + luaPerRoute.FilterContext = filterCtx + luaPerRouteAny, err := anypb.New(luaPerRoute) + if err != nil { + return err + } + if route.TypedPerFilterConfig == nil { + route.TypedPerFilterConfig = make(map[string]*anypb.Any) + } + route.TypedPerFilterConfig[filterName] = luaPerRouteAny } - if err := enableFilterOnRoute(route, filterName, routeCfg); err != nil { + luaOnFCFilterAny, err := anypb.New(luaOnFCFilter) + if err != nil { return err } + newFilters = append(newFilters, &corev3.TypedExtensionConfig{ + Name: filterName, + TypedConfig: luaOnFCFilterAny, + }) + } + + if len(newFilters) == 0 { + return nil + } + + merged, err := mergeFilterChainConfigPerRoute(route.GetTypedPerFilterConfig()[eepFCFilterName()], newFilters) + if err != nil { + return err + } + if route.TypedPerFilterConfig == nil { + route.TypedPerFilterConfig = make(map[string]*anypb.Any) } + route.TypedPerFilterConfig[eepFCFilterName()] = merged return nil } -func buildLuaRouteFilterConfig(lua ir.Lua) (proto.Message, error) { - if lua.FilterContext == nil || lua.FilterContext.Raw == nil { - return &routev3.FilterConfig{ - Config: &anypb.Any{}, - }, nil +// patchVirtualHost delivers listener-level Lua source at VirtualHost scope so that a listener's +// Lua policy does not bleed into virtual hosts belonging to a different listener that shares the +// same RouteConfiguration (cleartext listeners on the same port). Delivery via VirtualHost +// TypedPerFilterConfig still goes through RDS, so Lua script changes do not trigger listener drains. +func (*lua) patchVirtualHost(vh *routev3.VirtualHost, httpListener *ir.HTTPListener) error { + if httpListener.EnvoyExtensions == nil || len(httpListener.EnvoyExtensions.Luas) == 0 { + return nil + } + + filterName := eepListenerFCFilterName() + existing := vh.GetTypedPerFilterConfig()[filterName] + alreadyDelivered, err := filterChainAlreadyHasType(existing, egv1a1.EnvoyFilterLua) + if err != nil { + return err + } + if alreadyDelivered { + // Already delivered for this VirtualHost, e.g. because patchVirtualHost was called + // again for a different IR listener sharing the same RouteConfiguration. + return nil + } + + if vh.TypedPerFilterConfig == nil { + vh.TypedPerFilterConfig = map[string]*anypb.Any{} } - filterCtx := &structpb.Struct{} - if err := protojson.Unmarshal(lua.FilterContext.Raw, filterCtx); err != nil { - return nil, err + var newFilters []*corev3.TypedExtensionConfig + for i, ep := range httpListener.EnvoyExtensions.Luas { + subFilterName := luaListenerFilterName(i) + luaOnFCFilter := &luafilterv3.Lua{ + DefaultSourceCode: &corev3.DataSource{ + Specifier: &corev3.DataSource_InlineString{ + InlineString: *ep.Code, + }, + }, + } + + // TODO: support filterContext in Lua filter make this simpler + if ep.FilterContext != nil && ep.FilterContext.Raw != nil { + luaPerRoute := &luafilterv3.LuaPerRoute{} + filterCtx := &structpb.Struct{} + if err := protojson.Unmarshal(ep.FilterContext.Raw, filterCtx); err != nil { + return err + } + luaPerRoute.FilterContext = filterCtx + luaPerRouteAny, err := anypb.New(luaPerRoute) + if err != nil { + return err + } + vh.TypedPerFilterConfig[subFilterName] = luaPerRouteAny + } + luaOnFCFilterAny, err := anypb.New(luaOnFCFilter) + if err != nil { + return err + } + newFilters = append(newFilters, &corev3.TypedExtensionConfig{ + Name: subFilterName, + TypedConfig: luaOnFCFilterAny, + }) } - return &luafilterv3.LuaPerRoute{ - FilterContext: filterCtx, - }, nil + merged, err := mergeFilterChainConfigPerRoute(existing, newFilters) + if err != nil { + return err + } + vh.TypedPerFilterConfig[filterName] = merged + return nil } diff --git a/internal/xds/translator/oidc.go b/internal/xds/translator/oidc.go index fba5f7da53..f498249003 100644 --- a/internal/xds/translator/oidc.go +++ b/internal/xds/translator/oidc.go @@ -403,7 +403,7 @@ func routeContainsOIDC(irRoute *ir.HTTPRoute) bool { } func (*oidc) patchResources(tCtx *types.ResourceVersionTable, - routes []*ir.HTTPRoute, + _ *ir.HTTPListener, routes []*ir.HTTPRoute, ) error { if err := createOAuthServerClusters(tCtx, routes); err != nil { return err @@ -600,3 +600,7 @@ func (*oidc) patchRoute(route *routev3.Route, irRoute *ir.HTTPRoute, _ *ir.HTTPL route.TypedPerFilterConfig[string(egv1a1.EnvoyFilterOAuth2)] = oauth2Any return nil } + +func (*oidc) patchVirtualHost(_ *routev3.VirtualHost, _ *ir.HTTPListener) error { + return nil +} diff --git a/internal/xds/translator/request_buffer.go b/internal/xds/translator/request_buffer.go index 231506e34b..6fef1db011 100644 --- a/internal/xds/translator/request_buffer.go +++ b/internal/xds/translator/request_buffer.go @@ -96,7 +96,7 @@ func buildHCMRequestBufferFilter(spec *ir.RequestBuffer) (*hcmv3.HttpFilter, err }, nil } -func (r *requestBuffer) patchResources(_ *types.ResourceVersionTable, _ []*ir.HTTPRoute) error { +func (r *requestBuffer) patchResources(_ *types.ResourceVersionTable, _ *ir.HTTPListener, _ []*ir.HTTPRoute) error { return nil } @@ -145,3 +145,7 @@ func buildRequestBufferPerRouteProto(spec *ir.RequestBuffer) (*anypb.Any, error) func routeContainsRequestBuffer(route *ir.HTTPRoute) bool { return route.Traffic != nil && route.Traffic.RequestBuffer != nil } + +func (*requestBuffer) patchVirtualHost(_ *routev3.VirtualHost, _ *ir.HTTPListener) error { + return nil +} diff --git a/internal/xds/translator/session_persistence.go b/internal/xds/translator/session_persistence.go index 114672a7cd..e2966268d3 100644 --- a/internal/xds/translator/session_persistence.go +++ b/internal/xds/translator/session_persistence.go @@ -229,6 +229,10 @@ func (s *sessionPersistence) patchRoute(route *routev3.Route, irRoute *ir.HTTPRo // patchResources adds all the other needed resources referenced by this // filter to the resource version table. -func (s *sessionPersistence) patchResources(_ *types.ResourceVersionTable, _ []*ir.HTTPRoute) error { +func (s *sessionPersistence) patchResources(_ *types.ResourceVersionTable, _ *ir.HTTPListener, _ []*ir.HTTPRoute) error { + return nil +} + +func (*sessionPersistence) patchVirtualHost(_ *routev3.VirtualHost, _ *ir.HTTPListener) error { return nil } diff --git a/internal/xds/translator/testdata/in/xds-ir/dynamicmodule.yaml b/internal/xds/translator/testdata/in/xds-ir/dynamicmodule.yaml index 7764636556..45473d2fb8 100644 --- a/internal/xds/translator/testdata/in/xds-ir/dynamicmodule.yaml +++ b/internal/xds/translator/testdata/in/xds-ir/dynamicmodule.yaml @@ -122,3 +122,98 @@ http: path: /opt/modules/my_module.so name: envoyextensionpolicy/default/policy-path/dynamic-module/0 terminalFilter: false +# Listener-scoped DynamicModule (attached at Gateway/Listener scope, with a remote source to +# exercise cluster creation) with three routes: +# - httproute-5: no route-scoped policy, inherits the listener-scoped module via VirtualHost. +# - httproute-6: route-scoped policy with a different module, fully replacing the listener one. +# - httproute-7: route-scoped policy that targets the SAME module as the listener (a policy can +# target both a Gateway and one of its HTTPRoutes via separate targetRefs), so the filter name +# collides across scopes and must not be disabled then re-enabled. +- address: 0.0.0.0 + hostnames: + - '*' + name: envoy-gateway/gateway-1/http-listener-scope + envoyExtensions: + dynamicModules: + - doNotClose: false + filterName: listener-filter + loadGlobally: false + name: envoyextensionpolicy/envoy-gateway/policy-for-gateway-listener/dynamic-module/0 + remote: + url: https://listener-modules.example.com/liblistener.so + sha256: 0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef + terminalFilter: false + path: + escapedSlashesAction: UnescapeAndRedirect + mergeSlashes: true + port: 10081 + routes: + - destination: + name: httproute/default/httproute-5/rule/0 + settings: + - addressType: IP + endpoints: + - host: 7.7.7.7 + port: 8080 + protocol: HTTP + weight: 1 + name: httproute/default/httproute-5/rule/0/backend/0 + hostname: listener-scope.example.com + isHTTP2: false + name: httproute/default/httproute-5/rule/0/match/0/listener_scope_example_com + pathMatch: + distinct: false + name: "" + prefix: /inherit + - destination: + name: httproute/default/httproute-6/rule/0 + settings: + - addressType: IP + endpoints: + - host: 7.7.7.7 + port: 8080 + protocol: HTTP + weight: 1 + name: httproute/default/httproute-6/rule/0/backend/0 + envoyExtensions: + dynamicModules: + - doNotClose: false + filterName: route-override-filter + loadGlobally: false + path: /usr/lib/envoy/modules/route_override.so + name: envoyextensionpolicy/default/policy-for-route-6/dynamic-module/0 + terminalFilter: false + hostname: listener-scope.example.com + isHTTP2: false + name: httproute/default/httproute-6/rule/0/match/0/listener_scope_example_com + pathMatch: + distinct: false + name: "" + prefix: /override + - destination: + name: httproute/default/httproute-7/rule/0 + settings: + - addressType: IP + endpoints: + - host: 7.7.7.7 + port: 8080 + protocol: HTTP + weight: 1 + name: httproute/default/httproute-7/rule/0/backend/0 + envoyExtensions: + dynamicModules: + - doNotClose: false + filterName: listener-filter + loadGlobally: false + name: envoyextensionpolicy/envoy-gateway/policy-for-gateway-listener/dynamic-module/0 + remote: + url: https://listener-modules.example.com/liblistener.so + sha256: 0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef + terminalFilter: false + hostname: listener-scope.example.com + isHTTP2: false + name: httproute/default/httproute-7/rule/0/match/0/listener_scope_example_com + pathMatch: + distinct: false + name: "" + prefix: /same-name diff --git a/internal/xds/translator/testdata/in/xds-ir/ext-proc.yaml b/internal/xds/translator/testdata/in/xds-ir/ext-proc.yaml index 915bc8fc6a..166792a530 100644 --- a/internal/xds/translator/testdata/in/xds-ir/ext-proc.yaml +++ b/internal/xds/translator/testdata/in/xds-ir/ext-proc.yaml @@ -132,3 +132,99 @@ http: distinct: false name: "" prefix: /bar + # Listener-scoped ExtProc (attached at Gateway/Listener scope) with three routes: + # - httproute-4: no route-scoped policy, inherits the listener-scoped ExtProc via VirtualHost. + # - httproute-5: route-scoped policy with a different ExtProc, fully replacing the listener one. + # - httproute-6: route-scoped policy that targets the SAME ExtProc as the listener (a policy can + # target both a Gateway and one of its HTTPRoutes via separate targetRefs), so the filter name + # collides across scopes and must not be disabled then re-enabled. + - address: 0.0.0.0 + hostnames: + - '*' + name: envoy-gateway/gateway-1/http-listener-scope + envoyExtensions: + extProcs: + - name: envoyextensionpolicy/envoy-gateway/policy-for-gateway-listener/extproc/0 + authority: grpc-backend-listener.envoy-gateway:9000 + destination: + name: envoyextensionpolicy/envoy-gateway/policy-for-gateway-listener/0/grpc-backend-listener + settings: + - protocol: GRPC + weight: 1 + name: envoyextensionpolicy/envoy-gateway/policy-for-gateway-listener/0/grpc-backend-listener/backend/0 + path: + escapedSlashesAction: UnescapeAndRedirect + mergeSlashes: true + port: 10081 + routes: + - destination: + name: httproute/default/httproute-4/rule/0 + settings: + - addressType: IP + endpoints: + - host: 7.7.7.7 + port: 8080 + protocol: HTTP + weight: 1 + name: httproute/default/httproute-4/rule/0/backend/0 + hostname: listener-scope.envoyproxy.io + isHTTP2: false + name: httproute/default/httproute-4/rule/0/match/0/listener_scope_envoyproxy_io + pathMatch: + distinct: false + name: "" + prefix: /inherit + - destination: + name: httproute/default/httproute-5/rule/0 + settings: + - addressType: IP + endpoints: + - host: 7.7.7.7 + port: 8080 + protocol: HTTP + weight: 1 + name: httproute/default/httproute-5/rule/0/backend/0 + envoyExtensions: + extProcs: + - name: envoyextensionpolicy/default/policy-for-route-5/extproc/0 + authority: grpc-backend-5.default:9500 + destination: + name: envoyextensionpolicy/default/policy-for-route-5/0/grpc-backend-5 + settings: + - protocol: GRPC + weight: 1 + name: envoyextensionpolicy/default/policy-for-route-5/0/grpc-backend-5/backend/0 + hostname: listener-scope.envoyproxy.io + isHTTP2: false + name: httproute/default/httproute-5/rule/0/match/0/listener_scope_envoyproxy_io + pathMatch: + distinct: false + name: "" + prefix: /override + - destination: + name: httproute/default/httproute-6/rule/0 + settings: + - addressType: IP + endpoints: + - host: 7.7.7.7 + port: 8080 + protocol: HTTP + weight: 1 + name: httproute/default/httproute-6/rule/0/backend/0 + envoyExtensions: + extProcs: + - name: envoyextensionpolicy/envoy-gateway/policy-for-gateway-listener/extproc/0 + authority: grpc-backend-listener.envoy-gateway:9000 + destination: + name: envoyextensionpolicy/envoy-gateway/policy-for-gateway-listener/0/grpc-backend-listener + settings: + - protocol: GRPC + weight: 1 + name: envoyextensionpolicy/envoy-gateway/policy-for-gateway-listener/0/grpc-backend-listener/backend/0 + hostname: listener-scope.envoyproxy.io + isHTTP2: false + name: httproute/default/httproute-6/rule/0/match/0/listener_scope_envoyproxy_io + pathMatch: + distinct: false + name: "" + prefix: /same-name diff --git a/internal/xds/translator/testdata/in/xds-ir/lua.yaml b/internal/xds/translator/testdata/in/xds-ir/lua.yaml index fddfa9a4a7..24854f98a0 100644 --- a/internal/xds/translator/testdata/in/xds-ir/lua.yaml +++ b/internal/xds/translator/testdata/in/xds-ir/lua.yaml @@ -1,4 +1,5 @@ http: +# Lua filter per route only - address: 0.0.0.0 hostnames: - '*' @@ -61,3 +62,296 @@ http: response_handle:logError('Hello.') end name: envoyextensionpolicy/envoy-gateway/policy-for-gateway/lua/1 +# Lua filter per route +- address: 0.0.0.0 + hostnames: + - '*' + name: envoy-gateway/gateway-1/http-2 + envoyExtensions: + luas: + - code: function envoy_on_request(request_handle) + request_handle:logInfo('Goodbye from gateway.') + end + name: envoyextensionpolicy/default/policy-for-gateway/lua/0 + filterContext: + token_header: x-api-key + mode: strict + path: + escapedSlashesAction: UnescapeAndRedirect + mergeSlashes: true + port: 10081 + routes: + - destination: + name: httproute/default/httproute-2/rule/0 + settings: + - addressType: IP + endpoints: + - host: 7.7.7.7 + port: 8080 + protocol: HTTP + weight: 1 + name: httproute/default/httproute-3/rule/0/backend/0 + hostname: www.example.com + isHTTP2: false + name: httproute/default/httproute-3/rule/0/match/0/www_example_com + pathMatch: + distinct: false + name: "" + prefix: /foo + envoyExtensions: + luas: + - code: function envoy_on_request(request_handle) + request_handle:logInfo('Goodbye.') + end + name: envoyextensionpolicy/default/policy-for-http-route/lua/0 + filterContext: + token_header: x-api-key + mode: strict +# Lua filter per listener +- address: 0.0.0.0 + hostnames: + - '*' + name: envoy-gateway/gateway-1/http-3 + envoyExtensions: + luas: + - code: function envoy_on_request(request_handle) + request_handle:logInfo('Goodbye from gateway.') + end + name: envoyextensionpolicy/default/policy-for-gateway/lua/0 + filterContext: + token_header: x-api-key + mode: strict + path: + escapedSlashesAction: UnescapeAndRedirect + mergeSlashes: true + port: 10082 + routes: + - destination: + name: httproute/default/httproute-3/rule/0 + settings: + - addressType: IP + endpoints: + - host: 7.7.7.7 + port: 8080 + protocol: HTTP + weight: 1 + name: httproute/default/httproute-3/rule/0/backend/0 + hostname: www.example.com + isHTTP2: false + name: httproute/default/httproute-3/rule/0/match/0/www_example_com + pathMatch: + distinct: false + name: "" + prefix: /foo +# Listener Lua with an ExtProc-only route override (EnvoyExtensions non-nil, Luas empty). +# The ExtProc route must disable the inherited listener Lua even though it has no route-level Lua. +- address: 0.0.0.0 + hostnames: + - '*' + name: envoy-gateway/gateway-1/http-4 + envoyExtensions: + luas: + - code: function envoy_on_request(request_handle) + request_handle:logInfo('Goodbye from gateway.') + end + name: envoyextensionpolicy/default/policy-for-gateway/lua/0 + path: + escapedSlashesAction: UnescapeAndRedirect + mergeSlashes: true + port: 10083 + routes: + # This route has an ExtProc-only EnvoyExtensionPolicy (Luas is empty). + # Inherited listener Lua must be disabled so the more-specific policy fully governs this route. + - destination: + name: httproute/default/httproute-4/rule/0 + settings: + - addressType: IP + endpoints: + - host: 7.7.7.7 + port: 8080 + protocol: HTTP + weight: 1 + name: httproute/default/httproute-4/rule/0/backend/0 + hostname: www.example.com + isHTTP2: false + name: httproute/default/httproute-4/rule/0/match/0/www_example_com + pathMatch: + distinct: false + name: "" + prefix: /foo + envoyExtensions: + extProcs: + - name: envoyextensionpolicy/default/policy-for-http-route/extproc/0 + authority: grpc-backend.default:8000 + destination: + name: envoyextensionpolicy/default/policy-for-http-route/0/grpc-backend + settings: + - protocol: GRPC + weight: 1 + name: envoyextensionpolicy/default/policy-for-http-route/0/grpc-backend/backend/0 + # This route has no EnvoyExtensionPolicy — it inherits the listener Lua normally. + - destination: + name: httproute/default/httproute-5/rule/0 + settings: + - addressType: IP + endpoints: + - host: 7.7.7.7 + port: 8080 + protocol: HTTP + weight: 1 + name: httproute/default/httproute-5/rule/0/backend/0 + hostname: www.example.com + isHTTP2: false + name: httproute/default/httproute-5/rule/0/match/0/www_example_com + pathMatch: + distinct: false + name: "" + prefix: /bar +# Two cleartext listeners sharing the same port — shared RouteConfiguration. +# Each listener's Lua script must be scoped to its own virtual hosts only. +# Listener A +- address: 0.0.0.0 + hostnames: + - 'app-a.example.com' + name: envoy-gateway/gateway-1/http-5 + envoyExtensions: + luas: + - code: function envoy_on_request(request_handle) + request_handle:logInfo('tenant-A script.') + end + name: envoyextensionpolicy/default/policy-for-gateway-a/lua/0 + path: + escapedSlashesAction: UnescapeAndRedirect + mergeSlashes: true + port: 10084 + routes: + - destination: + name: httproute/default/httproute-6/rule/0 + settings: + - addressType: IP + endpoints: + - host: 7.7.7.7 + port: 8080 + protocol: HTTP + weight: 1 + name: httproute/default/httproute-6/rule/0/backend/0 + hostname: app-a.example.com + isHTTP2: false + name: httproute/default/httproute-6/rule/0/match/0/app-a_example_com + pathMatch: + distinct: false + name: "" + prefix: / +# Listener B — same port 10084, different hostname +- address: 0.0.0.0 + hostnames: + - 'app-b.example.com' + name: envoy-gateway/gateway-1/http-6 + envoyExtensions: + luas: + - code: function envoy_on_request(request_handle) + request_handle:logInfo('tenant-B script.') + end + name: envoyextensionpolicy/default/policy-for-gateway-b/lua/0 + path: + escapedSlashesAction: UnescapeAndRedirect + mergeSlashes: true + port: 10084 + routes: + - destination: + name: httproute/default/httproute-7/rule/0 + settings: + - addressType: IP + endpoints: + - host: 8.8.8.8 + port: 8080 + protocol: HTTP + weight: 1 + name: httproute/default/httproute-7/rule/0/backend/0 + hostname: app-b.example.com + isHTTP2: false + name: httproute/default/httproute-7/rule/0/match/0/app-b_example_com + pathMatch: + distinct: false + name: "" + prefix: / +# Gateway policy with Lua and ExtProc, both attached at listener scope from the same policy. +# No route under this listener has its own policy, so both stay listener-scoped and the +# listener Lua must NOT be disabled for httproute-8. +- address: 0.0.0.0 + hostnames: + - '*' + name: envoy-gateway/gateway-1/http-7 + envoyExtensions: + luas: + - code: function envoy_on_request(request_handle) + request_handle:logInfo('Gateway Lua.') + end + name: envoyextensionpolicy/default/policy-for-gateway/lua/0 + extProcs: + - name: envoyextensionpolicy/default/policy-for-gateway/extproc/0 + authority: grpc-backend.default:8000 + destination: + name: envoyextensionpolicy/default/policy-for-gateway/0/grpc-backend + settings: + - protocol: GRPC + weight: 1 + name: envoyextensionpolicy/default/policy-for-gateway/0/grpc-backend/backend/0 + path: + escapedSlashesAction: UnescapeAndRedirect + mergeSlashes: true + port: 10085 + routes: + - destination: + name: httproute/default/httproute-8/rule/0 + settings: + - addressType: IP + endpoints: + - host: 7.7.7.7 + port: 8080 + protocol: HTTP + weight: 1 + name: httproute/default/httproute-8/rule/0/backend/0 + hostname: www.example.com + isHTTP2: false + name: httproute/default/httproute-8/rule/0/match/0/www_example_com + pathMatch: + distinct: false + name: "" + prefix: /foo +# Listener Lua with a route that has a fail-open empty policy (EnvoyExtensions non-nil but all +# extension slices empty). The listener Lua must still be disabled because the more-specific +# route policy owns this route regardless of producing no extensions. +- address: 0.0.0.0 + hostnames: + - '*' + name: envoy-gateway/gateway-1/http-8 + envoyExtensions: + luas: + - code: function envoy_on_request(request_handle) + request_handle:logInfo('Gateway Lua.') + end + name: envoyextensionpolicy/default/policy-for-gateway/lua/0 + path: + escapedSlashesAction: UnescapeAndRedirect + mergeSlashes: true + port: 10086 + routes: + - destination: + name: httproute/default/httproute-9/rule/0 + settings: + - addressType: IP + endpoints: + - host: 7.7.7.7 + port: 8080 + protocol: HTTP + weight: 1 + name: httproute/default/httproute-9/rule/0/backend/0 + hostname: www.example.com + isHTTP2: false + name: httproute/default/httproute-9/rule/0/match/0/www_example_com + pathMatch: + distinct: false + name: "" + prefix: /foo + envoyExtensions: {} diff --git a/internal/xds/translator/testdata/in/xds-ir/wasm.yaml b/internal/xds/translator/testdata/in/xds-ir/wasm.yaml index de8897fadf..c1083d7948 100644 --- a/internal/xds/translator/testdata/in/xds-ir/wasm.yaml +++ b/internal/xds/translator/testdata/in/xds-ir/wasm.yaml @@ -98,3 +98,99 @@ http: hostKeys: - SOME_KEY - ANOTHER_KEY +# Listener-scoped Wasm (attached at Gateway/Listener scope) with three routes: +# - httproute-3: no route-scoped policy, inherits the listener-scoped Wasm via VirtualHost. +# - httproute-4: route-scoped policy with a different Wasm, fully replacing the listener one. +# - httproute-5: route-scoped policy that targets the SAME Wasm as the listener (a policy can +# target both a Gateway and one of its HTTPRoutes via separate targetRefs), so the filter name +# collides across scopes and must not be disabled then re-enabled. +- address: 0.0.0.0 + hostnames: + - '*' + name: envoy-gateway/gateway-1/http-listener-scope + envoyExtensions: + wasms: + - config: null + failOpen: false + httpWasmCode: + servingURL: https://envoy-gateway.envoy-gateway-system.svc.cluster.local:18002/8c1f1a2b3c4d5e6f7a8b9c0d1e2f3a4b5c6d7e8f9a0b1c2d3e4f5a6b7c8d9e0f.wasm + originalDownloadingURL: https://www.example.com/wasm-filter-listener.wasm + sha256: 8c1f1a2b3c4d5e6f7a8b9c0d1e2f3a4b5c6d7e8f9a0b1c2d3e4f5a6b7c8d9e0f + name: envoyextensionpolicy/envoy-gateway/policy-for-gateway-listener/wasm/0 + wasmName: wasm-filter-listener + path: + escapedSlashesAction: UnescapeAndRedirect + mergeSlashes: true + port: 10081 + routes: + - destination: + name: httproute/default/httproute-3/rule/0 + settings: + - addressType: IP + endpoints: + - host: 7.7.7.7 + port: 8080 + protocol: HTTP + weight: 1 + name: httproute/default/httproute-3/rule/0/backend/0 + hostname: listener-scope.example.com + isHTTP2: false + name: httproute/default/httproute-3/rule/0/match/0/listener_scope_example_com + pathMatch: + distinct: false + name: "" + prefix: /inherit + - destination: + name: httproute/default/httproute-4/rule/0 + settings: + - addressType: IP + endpoints: + - host: 7.7.7.7 + port: 8080 + protocol: HTTP + weight: 1 + name: httproute/default/httproute-4/rule/0/backend/0 + envoyExtensions: + wasms: + - config: null + failOpen: false + httpWasmCode: + servingURL: https://envoy-gateway.envoy-gateway-system.svc.cluster.local:18002/9d2e2b3c4d5e6f7a8b9c0d1e2f3a4b5c6d7e8f9a0b1c2d3e4f5a6b7c8d9e0f1a.wasm + originalDownloadingURL: https://www.example.com/wasm-filter-route-override.wasm + sha256: 9d2e2b3c4d5e6f7a8b9c0d1e2f3a4b5c6d7e8f9a0b1c2d3e4f5a6b7c8d9e0f1a + name: envoyextensionpolicy/default/policy-for-route-4/wasm/0 + wasmName: wasm-filter-route-override + hostname: listener-scope.example.com + isHTTP2: false + name: httproute/default/httproute-4/rule/0/match/0/listener_scope_example_com + pathMatch: + distinct: false + name: "" + prefix: /override + - destination: + name: httproute/default/httproute-5/rule/0 + settings: + - addressType: IP + endpoints: + - host: 7.7.7.7 + port: 8080 + protocol: HTTP + weight: 1 + name: httproute/default/httproute-5/rule/0/backend/0 + envoyExtensions: + wasms: + - config: null + failOpen: false + httpWasmCode: + servingURL: https://envoy-gateway.envoy-gateway-system.svc.cluster.local:18002/8c1f1a2b3c4d5e6f7a8b9c0d1e2f3a4b5c6d7e8f9a0b1c2d3e4f5a6b7c8d9e0f.wasm + originalDownloadingURL: https://www.example.com/wasm-filter-listener.wasm + sha256: 8c1f1a2b3c4d5e6f7a8b9c0d1e2f3a4b5c6d7e8f9a0b1c2d3e4f5a6b7c8d9e0f + name: envoyextensionpolicy/envoy-gateway/policy-for-gateway-listener/wasm/0 + wasmName: wasm-filter-listener + hostname: listener-scope.example.com + isHTTP2: false + name: httproute/default/httproute-5/rule/0/match/0/listener_scope_example_com + pathMatch: + distinct: false + name: "" + prefix: /same-name diff --git a/internal/xds/translator/testdata/out/xds-ir/backend-priority.listeners.yaml b/internal/xds/translator/testdata/out/xds-ir/backend-priority.listeners.yaml index 7fdc101e34..ee8223e5a0 100644 --- a/internal/xds/translator/testdata/out/xds-ir/backend-priority.listeners.yaml +++ b/internal/xds/translator/testdata/out/xds-ir/backend-priority.listeners.yaml @@ -15,19 +15,13 @@ maxConcurrentStreams: 100 httpFilters: - disabled: true - name: envoy.filters.http.ext_proc/envoyextensionpolicy/default/policy-for-http-route/extproc/0 + name: envoy.filters.http.filter_chain.eep.listener typedConfig: - '@type': type.googleapis.com/envoy.extensions.filters.http.ext_proc.v3.ExternalProcessor - grpcService: - envoyGrpc: - authority: grpc-backend.envoy-gateway:8000 - clusterName: envoyextensionpolicy/default/policy-for-http-route/0 - timeout: 10s - processingMode: - requestHeaderMode: SKIP - requestTrailerMode: SKIP - responseHeaderMode: SKIP - responseTrailerMode: SKIP + '@type': type.googleapis.com/envoy.extensions.filters.http.filter_chain.v3.FilterChainConfig + - disabled: true + name: envoy.filters.http.filter_chain.eep.route + typedConfig: + '@type': type.googleapis.com/envoy.extensions.filters.http.filter_chain.v3.FilterChainConfig - name: envoy.filters.http.router typedConfig: '@type': type.googleapis.com/envoy.extensions.filters.http.router.v3.Router diff --git a/internal/xds/translator/testdata/out/xds-ir/backend-priority.routes.yaml b/internal/xds/translator/testdata/out/xds-ir/backend-priority.routes.yaml index e5e50ccde2..3bcb015933 100644 --- a/internal/xds/translator/testdata/out/xds-ir/backend-priority.routes.yaml +++ b/internal/xds/translator/testdata/out/xds-ir/backend-priority.routes.yaml @@ -28,9 +28,26 @@ upgradeConfigs: - upgradeType: websocket typedPerFilterConfig: - envoy.filters.http.ext_proc/envoyextensionpolicy/default/policy-for-http-route/extproc/0: + envoy.filters.http.filter_chain.eep.listener: '@type': type.googleapis.com/envoy.config.route.v3.FilterConfig - config: {} + disabled: true + envoy.filters.http.filter_chain.eep.route: + '@type': type.googleapis.com/envoy.extensions.filters.http.filter_chain.v3.FilterChainConfigPerRoute + filterChain: + filters: + - name: envoy.filters.http.ext_proc/0 + typedConfig: + '@type': type.googleapis.com/envoy.extensions.filters.http.ext_proc.v3.ExternalProcessor + grpcService: + envoyGrpc: + authority: grpc-backend.envoy-gateway:8000 + clusterName: envoyextensionpolicy/default/policy-for-http-route/0 + timeout: 10s + processingMode: + requestHeaderMode: SKIP + requestTrailerMode: SKIP + responseHeaderMode: SKIP + responseTrailerMode: SKIP - domains: - www.bar.com metadata: diff --git a/internal/xds/translator/testdata/out/xds-ir/custom-filter-order.listeners.yaml b/internal/xds/translator/testdata/out/xds-ir/custom-filter-order.listeners.yaml index 60c140c9ad..c18d64d64e 100644 --- a/internal/xds/translator/testdata/out/xds-ir/custom-filter-order.listeners.yaml +++ b/internal/xds/translator/testdata/out/xds-ir/custom-filter-order.listeners.yaml @@ -24,53 +24,13 @@ typedConfig: '@type': type.googleapis.com/envoy.extensions.filters.http.cors.v3.Cors - disabled: true - name: envoy.filters.http.wasm/envoyextensionpolicy/envoy-gateway/policy-for-gateway/0 + name: envoy.filters.http.filter_chain.eep.listener typedConfig: - '@type': type.googleapis.com/envoy.extensions.filters.http.wasm.v3.Wasm - config: - configuration: - '@type': type.googleapis.com/google.protobuf.StringValue - value: '{"parameter1":{"key1":"value1","key2":"value2"},"parameter2":"value3"}' - name: wasm-filter-1 - vmConfig: - code: - remote: - httpUri: - cluster: wasm_cluster - timeout: 10s - uri: https://envoy-gateway:18002/42d30b4a4cc631415e6e48c02d244700da327201eb273f752cacf745715b31d9.wasm - retryPolicy: - numRetries: 10 - retryBackOff: - baseInterval: 1s - maxInterval: 30s - sha256: 746df05c8f3a0b07a46c0967cfbc5cbe5b9d48d0f79b6177eeedf8be6c8b34b5 - runtime: envoy.wasm.runtime.v8 - vmId: envoyextensionpolicy/envoy-gateway/policy-for-gateway/0 + '@type': type.googleapis.com/envoy.extensions.filters.http.filter_chain.v3.FilterChainConfig - disabled: true - name: envoy.filters.http.wasm/envoyextensionpolicy/envoy-gateway/policy-for-gateway/1 + name: envoy.filters.http.filter_chain.eep.route typedConfig: - '@type': type.googleapis.com/envoy.extensions.filters.http.wasm.v3.Wasm - config: - configuration: - '@type': type.googleapis.com/google.protobuf.StringValue - value: '{"parameter1":"value1","parameter2":"value2"}' - name: wasm-filter-2 - vmConfig: - code: - remote: - httpUri: - cluster: wasm_cluster - timeout: 10s - uri: https://envoy-gateway:18002/7abf116e5cd5a20389604a5ba0f3bd04fdf76f92181fe67506b42c2ee596d3fd.wasm - retryPolicy: - numRetries: 10 - retryBackOff: - baseInterval: 1s - maxInterval: 30s - sha256: a1efca12ea51069abb123bf9c77889fcc2a31cc5483fc14d115e44fdf07c7980 - runtime: envoy.wasm.runtime.v8 - vmId: envoyextensionpolicy/envoy-gateway/policy-for-gateway/1 + '@type': type.googleapis.com/envoy.extensions.filters.http.filter_chain.v3.FilterChainConfig - name: envoy.filters.http.jwt_authn typedConfig: '@type': type.googleapis.com/envoy.extensions.filters.http.jwt_authn.v3.JwtAuthentication diff --git a/internal/xds/translator/testdata/out/xds-ir/custom-filter-order.routes.yaml b/internal/xds/translator/testdata/out/xds-ir/custom-filter-order.routes.yaml index bae1ee1b81..7a190cca3c 100644 --- a/internal/xds/translator/testdata/out/xds-ir/custom-filter-order.routes.yaml +++ b/internal/xds/translator/testdata/out/xds-ir/custom-filter-order.routes.yaml @@ -24,12 +24,59 @@ regex: https://.*\.test\.com:8080 - exact: https://www.test.org:8080 forwardNotMatchingPreflights: false + envoy.filters.http.filter_chain.eep.listener: + '@type': type.googleapis.com/envoy.config.route.v3.FilterConfig + disabled: true + envoy.filters.http.filter_chain.eep.route: + '@type': type.googleapis.com/envoy.extensions.filters.http.filter_chain.v3.FilterChainConfigPerRoute + filterChain: + filters: + - name: envoy.filters.http.wasm/0 + typedConfig: + '@type': type.googleapis.com/envoy.extensions.filters.http.wasm.v3.Wasm + config: + configuration: + '@type': type.googleapis.com/google.protobuf.StringValue + value: '{"parameter1":{"key1":"value1","key2":"value2"},"parameter2":"value3"}' + name: wasm-filter-1 + vmConfig: + code: + remote: + httpUri: + cluster: wasm_cluster + timeout: 10s + uri: https://envoy-gateway:18002/42d30b4a4cc631415e6e48c02d244700da327201eb273f752cacf745715b31d9.wasm + retryPolicy: + numRetries: 10 + retryBackOff: + baseInterval: 1s + maxInterval: 30s + sha256: 746df05c8f3a0b07a46c0967cfbc5cbe5b9d48d0f79b6177eeedf8be6c8b34b5 + runtime: envoy.wasm.runtime.v8 + vmId: envoyextensionpolicy/envoy-gateway/policy-for-gateway/0 + - name: envoy.filters.http.wasm/1 + typedConfig: + '@type': type.googleapis.com/envoy.extensions.filters.http.wasm.v3.Wasm + config: + configuration: + '@type': type.googleapis.com/google.protobuf.StringValue + value: '{"parameter1":"value1","parameter2":"value2"}' + name: wasm-filter-2 + vmConfig: + code: + remote: + httpUri: + cluster: wasm_cluster + timeout: 10s + uri: https://envoy-gateway:18002/7abf116e5cd5a20389604a5ba0f3bd04fdf76f92181fe67506b42c2ee596d3fd.wasm + retryPolicy: + numRetries: 10 + retryBackOff: + baseInterval: 1s + maxInterval: 30s + sha256: a1efca12ea51069abb123bf9c77889fcc2a31cc5483fc14d115e44fdf07c7980 + runtime: envoy.wasm.runtime.v8 + vmId: envoyextensionpolicy/envoy-gateway/policy-for-gateway/1 envoy.filters.http.jwt_authn: '@type': type.googleapis.com/envoy.extensions.filters.http.jwt_authn.v3.PerRouteConfig requirementName: example1-or-example2_73a070ef6c8ee8ea - envoy.filters.http.wasm/envoyextensionpolicy/envoy-gateway/policy-for-gateway/0: - '@type': type.googleapis.com/envoy.config.route.v3.FilterConfig - config: {} - envoy.filters.http.wasm/envoyextensionpolicy/envoy-gateway/policy-for-gateway/1: - '@type': type.googleapis.com/envoy.config.route.v3.FilterConfig - config: {} diff --git a/internal/xds/translator/testdata/out/xds-ir/dns-lookup-family.listeners.yaml b/internal/xds/translator/testdata/out/xds-ir/dns-lookup-family.listeners.yaml index 95b918703a..e992c56d39 100644 --- a/internal/xds/translator/testdata/out/xds-ir/dns-lookup-family.listeners.yaml +++ b/internal/xds/translator/testdata/out/xds-ir/dns-lookup-family.listeners.yaml @@ -139,19 +139,13 @@ withRequestBody: maxRequestBytes: 8192 - disabled: true - name: envoy.filters.http.ext_proc/envoyextensionpolicy/default/policy-for-httproute/extproc/0 + name: envoy.filters.http.filter_chain.eep.listener typedConfig: - '@type': type.googleapis.com/envoy.extensions.filters.http.ext_proc.v3.ExternalProcessor - grpcService: - envoyGrpc: - authority: backend-fqdn2.default:9090 - clusterName: envoyextensionpolicy/default/policy-for-httproute/extproc/0 - timeout: 10s - processingMode: - requestHeaderMode: SKIP - requestTrailerMode: SKIP - responseHeaderMode: SKIP - responseTrailerMode: SKIP + '@type': type.googleapis.com/envoy.extensions.filters.http.filter_chain.v3.FilterChainConfig + - disabled: true + name: envoy.filters.http.filter_chain.eep.route + typedConfig: + '@type': type.googleapis.com/envoy.extensions.filters.http.filter_chain.v3.FilterChainConfig - name: envoy.filters.http.grpc_web typedConfig: '@type': type.googleapis.com/envoy.extensions.filters.http.grpc_web.v3.GrpcWeb diff --git a/internal/xds/translator/testdata/out/xds-ir/dns-lookup-family.routes.yaml b/internal/xds/translator/testdata/out/xds-ir/dns-lookup-family.routes.yaml index 22a2d4c21c..874f787fa4 100644 --- a/internal/xds/translator/testdata/out/xds-ir/dns-lookup-family.routes.yaml +++ b/internal/xds/translator/testdata/out/xds-ir/dns-lookup-family.routes.yaml @@ -31,9 +31,26 @@ envoy.filters.http.ext_authz/securitypolicy/envoy-gateway/policy-for-gateway-1: '@type': type.googleapis.com/envoy.extensions.filters.http.ext_authz.v3.ExtAuthzPerRoute checkSettings: {} - envoy.filters.http.ext_proc/envoyextensionpolicy/default/policy-for-httproute/extproc/0: + envoy.filters.http.filter_chain.eep.listener: '@type': type.googleapis.com/envoy.config.route.v3.FilterConfig - config: {} + disabled: true + envoy.filters.http.filter_chain.eep.route: + '@type': type.googleapis.com/envoy.extensions.filters.http.filter_chain.v3.FilterChainConfigPerRoute + filterChain: + filters: + - name: envoy.filters.http.ext_proc/0 + typedConfig: + '@type': type.googleapis.com/envoy.extensions.filters.http.ext_proc.v3.ExternalProcessor + grpcService: + envoyGrpc: + authority: backend-fqdn2.default:9090 + clusterName: envoyextensionpolicy/default/policy-for-httproute/extproc/0 + timeout: 10s + processingMode: + requestHeaderMode: SKIP + requestTrailerMode: SKIP + responseHeaderMode: SKIP + responseTrailerMode: SKIP - domains: - '*' metadata: diff --git a/internal/xds/translator/testdata/out/xds-ir/dynamicmodule.clusters.yaml b/internal/xds/translator/testdata/out/xds-ir/dynamicmodule.clusters.yaml index d74bab929b..bb37df695a 100644 --- a/internal/xds/translator/testdata/out/xds-ir/dynamicmodule.clusters.yaml +++ b/internal/xds/translator/testdata/out/xds-ir/dynamicmodule.clusters.yaml @@ -138,3 +138,120 @@ trustedCa: filename: /etc/ssl/certs/ca-certificates.crt sni: modules.example.com +- circuitBreakers: + thresholds: + - maxRetries: 1024 + commonLbConfig: {} + connectTimeout: 10s + dnsLookupFamily: V4_PREFERRED + edsClusterConfig: + edsConfig: + ads: {} + resourceApiVersion: V3 + serviceName: httproute/default/httproute-5/rule/0 + ignoreHealthOnHostRemoval: true + loadBalancingPolicy: + policies: + - typedExtensionConfig: + name: envoy.load_balancing_policies.least_request + typedConfig: + '@type': type.googleapis.com/envoy.extensions.load_balancing_policies.least_request.v3.LeastRequest + localityLbConfig: + localityWeightedLbConfig: {} + name: httproute/default/httproute-5/rule/0 + perConnectionBufferLimitBytes: 32768 + type: EDS +- circuitBreakers: + thresholds: + - maxRetries: 1024 + commonLbConfig: {} + connectTimeout: 10s + dnsLookupFamily: V4_PREFERRED + edsClusterConfig: + edsConfig: + ads: {} + resourceApiVersion: V3 + serviceName: httproute/default/httproute-6/rule/0 + ignoreHealthOnHostRemoval: true + loadBalancingPolicy: + policies: + - typedExtensionConfig: + name: envoy.load_balancing_policies.least_request + typedConfig: + '@type': type.googleapis.com/envoy.extensions.load_balancing_policies.least_request.v3.LeastRequest + localityLbConfig: + localityWeightedLbConfig: {} + name: httproute/default/httproute-6/rule/0 + perConnectionBufferLimitBytes: 32768 + type: EDS +- circuitBreakers: + thresholds: + - maxRetries: 1024 + commonLbConfig: {} + connectTimeout: 10s + dnsLookupFamily: V4_PREFERRED + edsClusterConfig: + edsConfig: + ads: {} + resourceApiVersion: V3 + serviceName: httproute/default/httproute-7/rule/0 + ignoreHealthOnHostRemoval: true + loadBalancingPolicy: + policies: + - typedExtensionConfig: + name: envoy.load_balancing_policies.least_request + typedConfig: + '@type': type.googleapis.com/envoy.extensions.load_balancing_policies.least_request.v3.LeastRequest + localityLbConfig: + localityWeightedLbConfig: {} + name: httproute/default/httproute-7/rule/0 + perConnectionBufferLimitBytes: 32768 + type: EDS +- circuitBreakers: + thresholds: + - maxRetries: 1024 + clusterType: + name: envoy.cluster.dns + typedConfig: + '@type': type.googleapis.com/envoy.extensions.clusters.dns.v3.DnsCluster + dnsLookupFamily: V4_PREFERRED + dnsRefreshRate: 30s + respectDnsTtl: true + commonLbConfig: {} + connectTimeout: 10s + dnsLookupFamily: V4_PREFERRED + ignoreHealthOnHostRemoval: true + loadAssignment: + clusterName: listener-modules_example_com_443 + endpoints: + - lbEndpoints: + - endpoint: + address: + socketAddress: + address: listener-modules.example.com + portValue: 443 + loadBalancingWeight: 1 + loadBalancingWeight: 1 + locality: + region: listener-modules_example_com_443/backend/-1 + loadBalancingPolicy: + policies: + - typedExtensionConfig: + name: envoy.load_balancing_policies.least_request + typedConfig: + '@type': type.googleapis.com/envoy.extensions.load_balancing_policies.least_request.v3.LeastRequest + localityLbConfig: + localityWeightedLbConfig: {} + name: listener-modules_example_com_443 + perConnectionBufferLimitBytes: 32768 + transportSocket: + name: envoy.transport_sockets.tls + typedConfig: + '@type': type.googleapis.com/envoy.extensions.transport_sockets.tls.v3.UpstreamTlsContext + commonTlsContext: + tlsParams: + tlsMaximumProtocolVersion: TLSv1_3 + validationContext: + trustedCa: + filename: /etc/ssl/certs/ca-certificates.crt + sni: listener-modules.example.com diff --git a/internal/xds/translator/testdata/out/xds-ir/dynamicmodule.endpoints.yaml b/internal/xds/translator/testdata/out/xds-ir/dynamicmodule.endpoints.yaml index e4cbf3f4ea..1440168674 100644 --- a/internal/xds/translator/testdata/out/xds-ir/dynamicmodule.endpoints.yaml +++ b/internal/xds/translator/testdata/out/xds-ir/dynamicmodule.endpoints.yaml @@ -46,3 +46,39 @@ loadBalancingWeight: 1 locality: region: httproute/default/httproute-4/rule/0/backend/0 +- clusterName: httproute/default/httproute-5/rule/0 + endpoints: + - lbEndpoints: + - endpoint: + address: + socketAddress: + address: 7.7.7.7 + portValue: 8080 + loadBalancingWeight: 1 + loadBalancingWeight: 1 + locality: + region: httproute/default/httproute-5/rule/0/backend/0 +- clusterName: httproute/default/httproute-6/rule/0 + endpoints: + - lbEndpoints: + - endpoint: + address: + socketAddress: + address: 7.7.7.7 + portValue: 8080 + loadBalancingWeight: 1 + loadBalancingWeight: 1 + locality: + region: httproute/default/httproute-6/rule/0/backend/0 +- clusterName: httproute/default/httproute-7/rule/0 + endpoints: + - lbEndpoints: + - endpoint: + address: + socketAddress: + address: 7.7.7.7 + portValue: 8080 + loadBalancingWeight: 1 + loadBalancingWeight: 1 + locality: + region: httproute/default/httproute-7/rule/0/backend/0 diff --git a/internal/xds/translator/testdata/out/xds-ir/dynamicmodule.listeners.yaml b/internal/xds/translator/testdata/out/xds-ir/dynamicmodule.listeners.yaml index a954ff20b0..e960ad6855 100644 --- a/internal/xds/translator/testdata/out/xds-ir/dynamicmodule.listeners.yaml +++ b/internal/xds/translator/testdata/out/xds-ir/dynamicmodule.listeners.yaml @@ -15,66 +15,57 @@ maxConcurrentStreams: 100 httpFilters: - disabled: true - name: envoy.filters.http.dynamic_modules/envoyextensionpolicy/default/policy-for-http-route/dynamic-module/0 + name: envoy.filters.http.filter_chain.eep.listener typedConfig: - '@type': type.googleapis.com/envoy.extensions.filters.http.dynamic_modules.v3.DynamicModuleFilter - dynamicModuleConfig: - doNotClose: true - loadGlobally: true - module: - local: - filename: /usr/lib/envoy/modules/ai_gateway.so - filterConfig: - '@type': type.googleapis.com/google.protobuf.StringValue - value: '{"maxTokensPerMinute":10000}' - filterName: token-ratelimit + '@type': type.googleapis.com/envoy.extensions.filters.http.filter_chain.v3.FilterChainConfig - disabled: true - name: envoy.filters.http.dynamic_modules/envoyextensionpolicy/default/policy-path/dynamic-module/0 + name: envoy.filters.http.filter_chain.eep.route typedConfig: - '@type': type.googleapis.com/envoy.extensions.filters.http.dynamic_modules.v3.DynamicModuleFilter - dynamicModuleConfig: - module: - local: - filename: /opt/modules/my_module.so - filterName: path-filter - - disabled: true - name: envoy.filters.http.dynamic_modules/envoyextensionpolicy/default/policy-terminal/dynamic-module/0 + '@type': type.googleapis.com/envoy.extensions.filters.http.filter_chain.v3.FilterChainConfig + - name: envoy.filters.http.router typedConfig: - '@type': type.googleapis.com/envoy.extensions.filters.http.dynamic_modules.v3.DynamicModuleFilter - dynamicModuleConfig: - module: - local: - filename: /usr/lib/envoy/modules/my_handler.so - filterName: handler - terminalFilter: true + '@type': type.googleapis.com/envoy.extensions.filters.http.router.v3.Router + suppressEnvoyHeaders: true + mergeSlashes: true + normalizePath: true + pathWithEscapedSlashesAction: UNESCAPE_AND_REDIRECT + rds: + configSource: + ads: {} + initialFetchTimeout: 0s + resourceApiVersion: V3 + routeConfigName: envoy-gateway/gateway-1/http + serverHeaderTransformation: PASS_THROUGH + statPrefix: http-10080 + useRemoteAddress: true + name: envoy-gateway/gateway-1/http + maxConnectionsToAcceptPerSocketEvent: 1 + name: envoy-gateway/gateway-1/http + perConnectionBufferLimitBytes: 32768 +- address: + socketAddress: + address: 0.0.0.0 + portValue: 10081 + defaultFilterChain: + filters: + - name: envoy.filters.network.http_connection_manager + typedConfig: + '@type': type.googleapis.com/envoy.extensions.filters.network.http_connection_manager.v3.HttpConnectionManager + commonHttpProtocolOptions: + headersWithUnderscoresAction: REJECT_REQUEST + http2ProtocolOptions: + initialConnectionWindowSize: 1048576 + initialStreamWindowSize: 65536 + maxConcurrentStreams: 100 + httpFilters: - disabled: true - name: envoy.filters.http.dynamic_modules/envoyextensionpolicy/envoy-gateway/policy-for-gateway/dynamic-module/0 + name: envoy.filters.http.filter_chain.eep.listener typedConfig: - '@type': type.googleapis.com/envoy.extensions.filters.http.dynamic_modules.v3.DynamicModuleFilter - dynamicModuleConfig: - module: - local: - filename: /usr/lib/envoy/modules/my_auth.so - filterConfig: - '@type': type.googleapis.com/google.protobuf.StringValue - value: '{"authEndpoint":"https://auth.example.com"}' - filterName: auth-check + '@type': type.googleapis.com/envoy.extensions.filters.http.filter_chain.v3.FilterChainConfig - disabled: true - name: envoy.filters.http.dynamic_modules/envoyextensionpolicy/envoy-gateway/policy-for-gateway/dynamic-module/1 + name: envoy.filters.http.filter_chain.eep.route typedConfig: - '@type': type.googleapis.com/envoy.extensions.filters.http.dynamic_modules.v3.DynamicModuleFilter - dynamicModuleConfig: - module: - remote: - httpUri: - cluster: modules_example_com_443 - timeout: 10s - uri: https://modules.example.com/libremote_auth.so - sha256: abcdef0123456789abcdef0123456789abcdef0123456789abcdef0123456789 - filterConfig: - '@type': type.googleapis.com/google.protobuf.StringValue - value: '{"authEndpoint":"https://remote-auth.example.com"}' - filterName: remote-auth-check + '@type': type.googleapis.com/envoy.extensions.filters.http.filter_chain.v3.FilterChainConfig - name: envoy.filters.http.router typedConfig: '@type': type.googleapis.com/envoy.extensions.filters.http.router.v3.Router @@ -87,11 +78,11 @@ ads: {} initialFetchTimeout: 0s resourceApiVersion: V3 - routeConfigName: envoy-gateway/gateway-1/http + routeConfigName: envoy-gateway/gateway-1/http-listener-scope serverHeaderTransformation: PASS_THROUGH - statPrefix: http-10080 + statPrefix: http-10081 useRemoteAddress: true - name: envoy-gateway/gateway-1/http + name: envoy-gateway/gateway-1/http-listener-scope maxConnectionsToAcceptPerSocketEvent: 1 - name: envoy-gateway/gateway-1/http + name: envoy-gateway/gateway-1/http-listener-scope perConnectionBufferLimitBytes: 32768 diff --git a/internal/xds/translator/testdata/out/xds-ir/dynamicmodule.routes.yaml b/internal/xds/translator/testdata/out/xds-ir/dynamicmodule.routes.yaml index 237c6abf7e..9924217d1a 100644 --- a/internal/xds/translator/testdata/out/xds-ir/dynamicmodule.routes.yaml +++ b/internal/xds/translator/testdata/out/xds-ir/dynamicmodule.routes.yaml @@ -13,9 +13,26 @@ upgradeConfigs: - upgradeType: websocket typedPerFilterConfig: - envoy.filters.http.dynamic_modules/envoyextensionpolicy/default/policy-for-http-route/dynamic-module/0: + envoy.filters.http.filter_chain.eep.listener: '@type': type.googleapis.com/envoy.config.route.v3.FilterConfig - config: {} + disabled: true + envoy.filters.http.filter_chain.eep.route: + '@type': type.googleapis.com/envoy.extensions.filters.http.filter_chain.v3.FilterChainConfigPerRoute + filterChain: + filters: + - name: envoy.filters.http.dynamic_modules/0 + typedConfig: + '@type': type.googleapis.com/envoy.extensions.filters.http.dynamic_modules.v3.DynamicModuleFilter + dynamicModuleConfig: + doNotClose: true + loadGlobally: true + module: + local: + filename: /usr/lib/envoy/modules/ai_gateway.so + filterConfig: + '@type': type.googleapis.com/google.protobuf.StringValue + value: '{"maxTokensPerMinute":10000}' + filterName: token-ratelimit - match: pathSeparatedPrefix: /bar name: httproute/default/httproute-2/rule/0/match/0/www_example_com @@ -24,12 +41,39 @@ upgradeConfigs: - upgradeType: websocket typedPerFilterConfig: - envoy.filters.http.dynamic_modules/envoyextensionpolicy/envoy-gateway/policy-for-gateway/dynamic-module/0: + envoy.filters.http.filter_chain.eep.listener: '@type': type.googleapis.com/envoy.config.route.v3.FilterConfig - config: {} - envoy.filters.http.dynamic_modules/envoyextensionpolicy/envoy-gateway/policy-for-gateway/dynamic-module/1: - '@type': type.googleapis.com/envoy.config.route.v3.FilterConfig - config: {} + disabled: true + envoy.filters.http.filter_chain.eep.route: + '@type': type.googleapis.com/envoy.extensions.filters.http.filter_chain.v3.FilterChainConfigPerRoute + filterChain: + filters: + - name: envoy.filters.http.dynamic_modules/0 + typedConfig: + '@type': type.googleapis.com/envoy.extensions.filters.http.dynamic_modules.v3.DynamicModuleFilter + dynamicModuleConfig: + module: + local: + filename: /usr/lib/envoy/modules/my_auth.so + filterConfig: + '@type': type.googleapis.com/google.protobuf.StringValue + value: '{"authEndpoint":"https://auth.example.com"}' + filterName: auth-check + - name: envoy.filters.http.dynamic_modules/1 + typedConfig: + '@type': type.googleapis.com/envoy.extensions.filters.http.dynamic_modules.v3.DynamicModuleFilter + dynamicModuleConfig: + module: + remote: + httpUri: + cluster: modules_example_com_443 + timeout: 10s + uri: https://modules.example.com/libremote_auth.so + sha256: abcdef0123456789abcdef0123456789abcdef0123456789abcdef0123456789 + filterConfig: + '@type': type.googleapis.com/google.protobuf.StringValue + value: '{"authEndpoint":"https://remote-auth.example.com"}' + filterName: remote-auth-check - match: pathSeparatedPrefix: /terminal name: httproute/default/httproute-3/rule/0/match/0/www_example_com @@ -38,9 +82,22 @@ upgradeConfigs: - upgradeType: websocket typedPerFilterConfig: - envoy.filters.http.dynamic_modules/envoyextensionpolicy/default/policy-terminal/dynamic-module/0: + envoy.filters.http.filter_chain.eep.listener: '@type': type.googleapis.com/envoy.config.route.v3.FilterConfig - config: {} + disabled: true + envoy.filters.http.filter_chain.eep.route: + '@type': type.googleapis.com/envoy.extensions.filters.http.filter_chain.v3.FilterChainConfigPerRoute + filterChain: + filters: + - name: envoy.filters.http.dynamic_modules/0 + typedConfig: + '@type': type.googleapis.com/envoy.extensions.filters.http.dynamic_modules.v3.DynamicModuleFilter + dynamicModuleConfig: + module: + local: + filename: /usr/lib/envoy/modules/my_handler.so + filterName: handler + terminalFilter: true - match: pathSeparatedPrefix: /path-loaded name: httproute/default/httproute-4/rule/0/match/0/www_example_com @@ -49,6 +106,99 @@ upgradeConfigs: - upgradeType: websocket typedPerFilterConfig: - envoy.filters.http.dynamic_modules/envoyextensionpolicy/default/policy-path/dynamic-module/0: + envoy.filters.http.filter_chain.eep.listener: + '@type': type.googleapis.com/envoy.config.route.v3.FilterConfig + disabled: true + envoy.filters.http.filter_chain.eep.route: + '@type': type.googleapis.com/envoy.extensions.filters.http.filter_chain.v3.FilterChainConfigPerRoute + filterChain: + filters: + - name: envoy.filters.http.dynamic_modules/0 + typedConfig: + '@type': type.googleapis.com/envoy.extensions.filters.http.dynamic_modules.v3.DynamicModuleFilter + dynamicModuleConfig: + module: + local: + filename: /opt/modules/my_module.so + filterName: path-filter +- ignorePortInHostMatching: true + name: envoy-gateway/gateway-1/http-listener-scope + virtualHosts: + - domains: + - listener-scope.example.com + name: envoy-gateway/gateway-1/http-listener-scope/listener-scope_example_com + routes: + - match: + pathSeparatedPrefix: /inherit + name: httproute/default/httproute-5/rule/0/match/0/listener_scope_example_com + route: + cluster: httproute/default/httproute-5/rule/0 + upgradeConfigs: + - upgradeType: websocket + - match: + pathSeparatedPrefix: /override + name: httproute/default/httproute-6/rule/0/match/0/listener_scope_example_com + route: + cluster: httproute/default/httproute-6/rule/0 + upgradeConfigs: + - upgradeType: websocket + typedPerFilterConfig: + envoy.filters.http.filter_chain.eep.listener: + '@type': type.googleapis.com/envoy.config.route.v3.FilterConfig + disabled: true + envoy.filters.http.filter_chain.eep.route: + '@type': type.googleapis.com/envoy.extensions.filters.http.filter_chain.v3.FilterChainConfigPerRoute + filterChain: + filters: + - name: envoy.filters.http.dynamic_modules/0 + typedConfig: + '@type': type.googleapis.com/envoy.extensions.filters.http.dynamic_modules.v3.DynamicModuleFilter + dynamicModuleConfig: + module: + local: + filename: /usr/lib/envoy/modules/route_override.so + filterName: route-override-filter + - match: + pathSeparatedPrefix: /same-name + name: httproute/default/httproute-7/rule/0/match/0/listener_scope_example_com + route: + cluster: httproute/default/httproute-7/rule/0 + upgradeConfigs: + - upgradeType: websocket + typedPerFilterConfig: + envoy.filters.http.filter_chain.eep.listener: '@type': type.googleapis.com/envoy.config.route.v3.FilterConfig - config: {} + disabled: true + envoy.filters.http.filter_chain.eep.route: + '@type': type.googleapis.com/envoy.extensions.filters.http.filter_chain.v3.FilterChainConfigPerRoute + filterChain: + filters: + - name: envoy.filters.http.dynamic_modules/0 + typedConfig: + '@type': type.googleapis.com/envoy.extensions.filters.http.dynamic_modules.v3.DynamicModuleFilter + dynamicModuleConfig: + module: + remote: + httpUri: + cluster: listener-modules_example_com_443 + timeout: 10s + uri: https://listener-modules.example.com/liblistener.so + sha256: 0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef + filterName: listener-filter + typedPerFilterConfig: + envoy.filters.http.filter_chain.eep.listener: + '@type': type.googleapis.com/envoy.extensions.filters.http.filter_chain.v3.FilterChainConfigPerRoute + filterChain: + filters: + - name: envoy.filters.http.dynamic_modules/listener/0 + typedConfig: + '@type': type.googleapis.com/envoy.extensions.filters.http.dynamic_modules.v3.DynamicModuleFilter + dynamicModuleConfig: + module: + remote: + httpUri: + cluster: listener-modules_example_com_443 + timeout: 10s + uri: https://listener-modules.example.com/liblistener.so + sha256: 0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef + filterName: listener-filter diff --git a/internal/xds/translator/testdata/out/xds-ir/ext-proc-with-retries.listeners.yaml b/internal/xds/translator/testdata/out/xds-ir/ext-proc-with-retries.listeners.yaml index 02a1a32b15..ee8223e5a0 100644 --- a/internal/xds/translator/testdata/out/xds-ir/ext-proc-with-retries.listeners.yaml +++ b/internal/xds/translator/testdata/out/xds-ir/ext-proc-with-retries.listeners.yaml @@ -15,25 +15,13 @@ maxConcurrentStreams: 100 httpFilters: - disabled: true - name: envoy.filters.http.ext_proc/envoyextensionpolicy/default/policy-for-http-route/extproc/0 + name: envoy.filters.http.filter_chain.eep.listener typedConfig: - '@type': type.googleapis.com/envoy.extensions.filters.http.ext_proc.v3.ExternalProcessor - grpcService: - envoyGrpc: - authority: grpc-backend.envoy-gateway:8000 - clusterName: envoyextensionpolicy/default/policy-for-http-route/0 - retryPolicy: - numRetries: 2 - retryBackOff: - baseInterval: 0.200s - maxInterval: 3s - retryOn: 5xx,deadline-exceeded,internal,unavailable - timeout: 10s - processingMode: - requestHeaderMode: SKIP - requestTrailerMode: SKIP - responseHeaderMode: SKIP - responseTrailerMode: SKIP + '@type': type.googleapis.com/envoy.extensions.filters.http.filter_chain.v3.FilterChainConfig + - disabled: true + name: envoy.filters.http.filter_chain.eep.route + typedConfig: + '@type': type.googleapis.com/envoy.extensions.filters.http.filter_chain.v3.FilterChainConfig - name: envoy.filters.http.router typedConfig: '@type': type.googleapis.com/envoy.extensions.filters.http.router.v3.Router diff --git a/internal/xds/translator/testdata/out/xds-ir/ext-proc-with-retries.routes.yaml b/internal/xds/translator/testdata/out/xds-ir/ext-proc-with-retries.routes.yaml index e5e50ccde2..50073ae41d 100644 --- a/internal/xds/translator/testdata/out/xds-ir/ext-proc-with-retries.routes.yaml +++ b/internal/xds/translator/testdata/out/xds-ir/ext-proc-with-retries.routes.yaml @@ -28,9 +28,32 @@ upgradeConfigs: - upgradeType: websocket typedPerFilterConfig: - envoy.filters.http.ext_proc/envoyextensionpolicy/default/policy-for-http-route/extproc/0: + envoy.filters.http.filter_chain.eep.listener: '@type': type.googleapis.com/envoy.config.route.v3.FilterConfig - config: {} + disabled: true + envoy.filters.http.filter_chain.eep.route: + '@type': type.googleapis.com/envoy.extensions.filters.http.filter_chain.v3.FilterChainConfigPerRoute + filterChain: + filters: + - name: envoy.filters.http.ext_proc/0 + typedConfig: + '@type': type.googleapis.com/envoy.extensions.filters.http.ext_proc.v3.ExternalProcessor + grpcService: + envoyGrpc: + authority: grpc-backend.envoy-gateway:8000 + clusterName: envoyextensionpolicy/default/policy-for-http-route/0 + retryPolicy: + numRetries: 2 + retryBackOff: + baseInterval: 0.200s + maxInterval: 3s + retryOn: 5xx,deadline-exceeded,internal,unavailable + timeout: 10s + processingMode: + requestHeaderMode: SKIP + requestTrailerMode: SKIP + responseHeaderMode: SKIP + responseTrailerMode: SKIP - domains: - www.bar.com metadata: diff --git a/internal/xds/translator/testdata/out/xds-ir/ext-proc-with-traffic-settings.listeners.yaml b/internal/xds/translator/testdata/out/xds-ir/ext-proc-with-traffic-settings.listeners.yaml index 7fdc101e34..ee8223e5a0 100644 --- a/internal/xds/translator/testdata/out/xds-ir/ext-proc-with-traffic-settings.listeners.yaml +++ b/internal/xds/translator/testdata/out/xds-ir/ext-proc-with-traffic-settings.listeners.yaml @@ -15,19 +15,13 @@ maxConcurrentStreams: 100 httpFilters: - disabled: true - name: envoy.filters.http.ext_proc/envoyextensionpolicy/default/policy-for-http-route/extproc/0 + name: envoy.filters.http.filter_chain.eep.listener typedConfig: - '@type': type.googleapis.com/envoy.extensions.filters.http.ext_proc.v3.ExternalProcessor - grpcService: - envoyGrpc: - authority: grpc-backend.envoy-gateway:8000 - clusterName: envoyextensionpolicy/default/policy-for-http-route/0 - timeout: 10s - processingMode: - requestHeaderMode: SKIP - requestTrailerMode: SKIP - responseHeaderMode: SKIP - responseTrailerMode: SKIP + '@type': type.googleapis.com/envoy.extensions.filters.http.filter_chain.v3.FilterChainConfig + - disabled: true + name: envoy.filters.http.filter_chain.eep.route + typedConfig: + '@type': type.googleapis.com/envoy.extensions.filters.http.filter_chain.v3.FilterChainConfig - name: envoy.filters.http.router typedConfig: '@type': type.googleapis.com/envoy.extensions.filters.http.router.v3.Router diff --git a/internal/xds/translator/testdata/out/xds-ir/ext-proc-with-traffic-settings.routes.yaml b/internal/xds/translator/testdata/out/xds-ir/ext-proc-with-traffic-settings.routes.yaml index e5e50ccde2..3bcb015933 100644 --- a/internal/xds/translator/testdata/out/xds-ir/ext-proc-with-traffic-settings.routes.yaml +++ b/internal/xds/translator/testdata/out/xds-ir/ext-proc-with-traffic-settings.routes.yaml @@ -28,9 +28,26 @@ upgradeConfigs: - upgradeType: websocket typedPerFilterConfig: - envoy.filters.http.ext_proc/envoyextensionpolicy/default/policy-for-http-route/extproc/0: + envoy.filters.http.filter_chain.eep.listener: '@type': type.googleapis.com/envoy.config.route.v3.FilterConfig - config: {} + disabled: true + envoy.filters.http.filter_chain.eep.route: + '@type': type.googleapis.com/envoy.extensions.filters.http.filter_chain.v3.FilterChainConfigPerRoute + filterChain: + filters: + - name: envoy.filters.http.ext_proc/0 + typedConfig: + '@type': type.googleapis.com/envoy.extensions.filters.http.ext_proc.v3.ExternalProcessor + grpcService: + envoyGrpc: + authority: grpc-backend.envoy-gateway:8000 + clusterName: envoyextensionpolicy/default/policy-for-http-route/0 + timeout: 10s + processingMode: + requestHeaderMode: SKIP + requestTrailerMode: SKIP + responseHeaderMode: SKIP + responseTrailerMode: SKIP - domains: - www.bar.com metadata: diff --git a/internal/xds/translator/testdata/out/xds-ir/ext-proc.clusters.yaml b/internal/xds/translator/testdata/out/xds-ir/ext-proc.clusters.yaml index 890439caa2..0f2d4e1c9f 100644 --- a/internal/xds/translator/testdata/out/xds-ir/ext-proc.clusters.yaml +++ b/internal/xds/translator/testdata/out/xds-ir/ext-proc.clusters.yaml @@ -217,3 +217,132 @@ http2ProtocolOptions: initialConnectionWindowSize: 1048576 initialStreamWindowSize: 65536 +- circuitBreakers: + thresholds: + - maxRetries: 1024 + commonLbConfig: {} + connectTimeout: 10s + dnsLookupFamily: V4_PREFERRED + edsClusterConfig: + edsConfig: + ads: {} + resourceApiVersion: V3 + serviceName: httproute/default/httproute-4/rule/0 + ignoreHealthOnHostRemoval: true + loadBalancingPolicy: + policies: + - typedExtensionConfig: + name: envoy.load_balancing_policies.least_request + typedConfig: + '@type': type.googleapis.com/envoy.extensions.load_balancing_policies.least_request.v3.LeastRequest + localityLbConfig: + localityWeightedLbConfig: {} + name: httproute/default/httproute-4/rule/0 + perConnectionBufferLimitBytes: 32768 + type: EDS +- circuitBreakers: + thresholds: + - maxRetries: 1024 + commonLbConfig: {} + connectTimeout: 10s + dnsLookupFamily: V4_PREFERRED + edsClusterConfig: + edsConfig: + ads: {} + resourceApiVersion: V3 + serviceName: httproute/default/httproute-5/rule/0 + ignoreHealthOnHostRemoval: true + loadBalancingPolicy: + policies: + - typedExtensionConfig: + name: envoy.load_balancing_policies.least_request + typedConfig: + '@type': type.googleapis.com/envoy.extensions.load_balancing_policies.least_request.v3.LeastRequest + localityLbConfig: + localityWeightedLbConfig: {} + name: httproute/default/httproute-5/rule/0 + perConnectionBufferLimitBytes: 32768 + type: EDS +- circuitBreakers: + thresholds: + - maxRetries: 1024 + commonLbConfig: {} + connectTimeout: 10s + dnsLookupFamily: V4_PREFERRED + edsClusterConfig: + edsConfig: + ads: {} + resourceApiVersion: V3 + serviceName: httproute/default/httproute-6/rule/0 + ignoreHealthOnHostRemoval: true + loadBalancingPolicy: + policies: + - typedExtensionConfig: + name: envoy.load_balancing_policies.least_request + typedConfig: + '@type': type.googleapis.com/envoy.extensions.load_balancing_policies.least_request.v3.LeastRequest + localityLbConfig: + localityWeightedLbConfig: {} + name: httproute/default/httproute-6/rule/0 + perConnectionBufferLimitBytes: 32768 + type: EDS +- circuitBreakers: + thresholds: + - maxRetries: 1024 + commonLbConfig: {} + connectTimeout: 10s + dnsLookupFamily: V4_PREFERRED + edsClusterConfig: + edsConfig: + ads: {} + resourceApiVersion: V3 + serviceName: envoyextensionpolicy/envoy-gateway/policy-for-gateway-listener/0/grpc-backend-listener + ignoreHealthOnHostRemoval: true + loadBalancingPolicy: + policies: + - typedExtensionConfig: + name: envoy.load_balancing_policies.least_request + typedConfig: + '@type': type.googleapis.com/envoy.extensions.load_balancing_policies.least_request.v3.LeastRequest + localityLbConfig: + localityWeightedLbConfig: {} + name: envoyextensionpolicy/envoy-gateway/policy-for-gateway-listener/0/grpc-backend-listener + perConnectionBufferLimitBytes: 32768 + type: EDS + typedExtensionProtocolOptions: + envoy.extensions.upstreams.http.v3.HttpProtocolOptions: + '@type': type.googleapis.com/envoy.extensions.upstreams.http.v3.HttpProtocolOptions + explicitHttpConfig: + http2ProtocolOptions: + initialConnectionWindowSize: 1048576 + initialStreamWindowSize: 65536 +- circuitBreakers: + thresholds: + - maxRetries: 1024 + commonLbConfig: {} + connectTimeout: 10s + dnsLookupFamily: V4_PREFERRED + edsClusterConfig: + edsConfig: + ads: {} + resourceApiVersion: V3 + serviceName: envoyextensionpolicy/default/policy-for-route-5/0/grpc-backend-5 + ignoreHealthOnHostRemoval: true + loadBalancingPolicy: + policies: + - typedExtensionConfig: + name: envoy.load_balancing_policies.least_request + typedConfig: + '@type': type.googleapis.com/envoy.extensions.load_balancing_policies.least_request.v3.LeastRequest + localityLbConfig: + localityWeightedLbConfig: {} + name: envoyextensionpolicy/default/policy-for-route-5/0/grpc-backend-5 + perConnectionBufferLimitBytes: 32768 + type: EDS + typedExtensionProtocolOptions: + envoy.extensions.upstreams.http.v3.HttpProtocolOptions: + '@type': type.googleapis.com/envoy.extensions.upstreams.http.v3.HttpProtocolOptions + explicitHttpConfig: + http2ProtocolOptions: + initialConnectionWindowSize: 1048576 + initialStreamWindowSize: 65536 diff --git a/internal/xds/translator/testdata/out/xds-ir/ext-proc.endpoints.yaml b/internal/xds/translator/testdata/out/xds-ir/ext-proc.endpoints.yaml index b6f8426798..b1b6197eef 100644 --- a/internal/xds/translator/testdata/out/xds-ir/ext-proc.endpoints.yaml +++ b/internal/xds/translator/testdata/out/xds-ir/ext-proc.endpoints.yaml @@ -59,3 +59,49 @@ - loadBalancingWeight: 1 locality: region: envoyextensionpolicy/envoy-gateway/policy-for-route-3/0/grpc-backend-3/backend/0 +- clusterName: httproute/default/httproute-4/rule/0 + endpoints: + - lbEndpoints: + - endpoint: + address: + socketAddress: + address: 7.7.7.7 + portValue: 8080 + loadBalancingWeight: 1 + loadBalancingWeight: 1 + locality: + region: httproute/default/httproute-4/rule/0/backend/0 +- clusterName: httproute/default/httproute-5/rule/0 + endpoints: + - lbEndpoints: + - endpoint: + address: + socketAddress: + address: 7.7.7.7 + portValue: 8080 + loadBalancingWeight: 1 + loadBalancingWeight: 1 + locality: + region: httproute/default/httproute-5/rule/0/backend/0 +- clusterName: httproute/default/httproute-6/rule/0 + endpoints: + - lbEndpoints: + - endpoint: + address: + socketAddress: + address: 7.7.7.7 + portValue: 8080 + loadBalancingWeight: 1 + loadBalancingWeight: 1 + locality: + region: httproute/default/httproute-6/rule/0/backend/0 +- clusterName: envoyextensionpolicy/envoy-gateway/policy-for-gateway-listener/0/grpc-backend-listener + endpoints: + - loadBalancingWeight: 1 + locality: + region: envoyextensionpolicy/envoy-gateway/policy-for-gateway-listener/0/grpc-backend-listener/backend/0 +- clusterName: envoyextensionpolicy/default/policy-for-route-5/0/grpc-backend-5 + endpoints: + - loadBalancingWeight: 1 + locality: + region: envoyextensionpolicy/default/policy-for-route-5/0/grpc-backend-5/backend/0 diff --git a/internal/xds/translator/testdata/out/xds-ir/ext-proc.listeners.yaml b/internal/xds/translator/testdata/out/xds-ir/ext-proc.listeners.yaml index bf74735897..e960ad6855 100644 --- a/internal/xds/translator/testdata/out/xds-ir/ext-proc.listeners.yaml +++ b/internal/xds/translator/testdata/out/xds-ir/ext-proc.listeners.yaml @@ -15,113 +15,57 @@ maxConcurrentStreams: 100 httpFilters: - disabled: true - name: envoy.filters.http.ext_proc/envoyextensionpolicy/default/policy-for-route-1/extproc/0 + name: envoy.filters.http.filter_chain.eep.listener typedConfig: - '@type': type.googleapis.com/envoy.extensions.filters.http.ext_proc.v3.ExternalProcessor - failureModeAllow: true - grpcService: - envoyGrpc: - authority: grpc-backend-2.default:8000 - clusterName: envoyextensionpolicy/default/policy-for-route-1/0/grpc-backend-2 - timeout: 10s - messageTimeout: 5s - processingMode: - requestBodyMode: BUFFERED_PARTIAL - requestHeaderMode: SKIP - requestTrailerMode: SKIP - responseHeaderMode: SEND - responseTrailerMode: SKIP + '@type': type.googleapis.com/envoy.extensions.filters.http.filter_chain.v3.FilterChainConfig - disabled: true - name: envoy.filters.http.ext_proc/envoyextensionpolicy/default/policy-for-route-2/extproc/0 + name: envoy.filters.http.filter_chain.eep.route typedConfig: - '@type': type.googleapis.com/envoy.extensions.filters.http.ext_proc.v3.ExternalProcessor - allowModeOverride: true - failureModeAllow: true - grpcService: - envoyGrpc: - authority: grpc-backend-4.default:4000 - clusterName: envoyextensionpolicy/default/policy-for-route-2/0/grpc-backend-4 - timeout: 10s - messageTimeout: 5s - metadataOptions: - forwardingNamespaces: - untyped: - - envoy.filters.http.ext_authz - receivingNamespaces: - untyped: - - envoy.filters.http.my_custom - processingMode: - requestBodyMode: BUFFERED - requestHeaderMode: SEND - requestTrailerMode: SKIP - responseBodyMode: STREAMED - responseHeaderMode: SKIP - responseTrailerMode: SKIP - requestAttributes: - - xds.route_metadata - - connection.requested_server_name - responseAttributes: - - request.path - - disabled: true - name: envoy.filters.http.ext_proc/envoyextensionpolicy/envoy-gateway/policy-for-gateway-1/extproc/0 + '@type': type.googleapis.com/envoy.extensions.filters.http.filter_chain.v3.FilterChainConfig + - name: envoy.filters.http.router typedConfig: - '@type': type.googleapis.com/envoy.extensions.filters.http.ext_proc.v3.ExternalProcessor - grpcService: - envoyGrpc: - authority: grpc-backend.envoy-gateway:9000 - clusterName: envoyextensionpolicy/envoy-gateway/policy-for-gateway-1/0/grpc-backend - timeout: 10s - messageTimeout: 15s - metadataOptions: - forwardingNamespaces: - untyped: - - envoy.filters.http.ext_proc - receivingNamespaces: - untyped: - - envoy.filters.http.prc_ext - observabilityMode: true - processingMode: - requestHeaderMode: SKIP - requestTrailerMode: SKIP - responseHeaderMode: SKIP - responseTrailerMode: SKIP - requestAttributes: - - xds.route_metadata - - connection.requested_server_name - responseAttributes: - - request.path - statusOnError: - code: ServiceUnavailable + '@type': type.googleapis.com/envoy.extensions.filters.http.router.v3.Router + suppressEnvoyHeaders: true + mergeSlashes: true + normalizePath: true + pathWithEscapedSlashesAction: UNESCAPE_AND_REDIRECT + rds: + configSource: + ads: {} + initialFetchTimeout: 0s + resourceApiVersion: V3 + routeConfigName: envoy-gateway/gateway-1/http + serverHeaderTransformation: PASS_THROUGH + statPrefix: http-10080 + useRemoteAddress: true + name: envoy-gateway/gateway-1/http + maxConnectionsToAcceptPerSocketEvent: 1 + name: envoy-gateway/gateway-1/http + perConnectionBufferLimitBytes: 32768 +- address: + socketAddress: + address: 0.0.0.0 + portValue: 10081 + defaultFilterChain: + filters: + - name: envoy.filters.network.http_connection_manager + typedConfig: + '@type': type.googleapis.com/envoy.extensions.filters.network.http_connection_manager.v3.HttpConnectionManager + commonHttpProtocolOptions: + headersWithUnderscoresAction: REJECT_REQUEST + http2ProtocolOptions: + initialConnectionWindowSize: 1048576 + initialStreamWindowSize: 65536 + maxConcurrentStreams: 100 + httpFilters: - disabled: true - name: envoy.filters.http.ext_proc/envoyextensionpolicy/envoy-gateway/policy-for-gateway-2/extproc/0 + name: envoy.filters.http.filter_chain.eep.listener typedConfig: - '@type': type.googleapis.com/envoy.extensions.filters.http.ext_proc.v3.ExternalProcessor - grpcService: - envoyGrpc: - authority: grpc-backend-3.envoy-gateway:3000 - clusterName: envoyextensionpolicy/envoy-gateway/policy-for-gateway-2/0/grpc-backend-3 - timeout: 10s - processingMode: - requestHeaderMode: SKIP - requestTrailerMode: SKIP - responseHeaderMode: SKIP - responseTrailerMode: SKIP + '@type': type.googleapis.com/envoy.extensions.filters.http.filter_chain.v3.FilterChainConfig - disabled: true - name: envoy.filters.http.ext_proc/envoyextensionpolicy/envoy-gateway/policy-for-route-3/extproc/0 + name: envoy.filters.http.filter_chain.eep.route typedConfig: - '@type': type.googleapis.com/envoy.extensions.filters.http.ext_proc.v3.ExternalProcessor - grpcService: - envoyGrpc: - authority: grpc-backend-3.envoy-gateway:3000 - clusterName: envoyextensionpolicy/envoy-gateway/policy-for-route-3/0/grpc-backend-3 - timeout: 10s - processingMode: - requestBodyMode: FULL_DUPLEX_STREAMED - requestHeaderMode: SKIP - requestTrailerMode: SEND - responseBodyMode: FULL_DUPLEX_STREAMED - responseHeaderMode: SKIP - responseTrailerMode: SEND + '@type': type.googleapis.com/envoy.extensions.filters.http.filter_chain.v3.FilterChainConfig - name: envoy.filters.http.router typedConfig: '@type': type.googleapis.com/envoy.extensions.filters.http.router.v3.Router @@ -134,11 +78,11 @@ ads: {} initialFetchTimeout: 0s resourceApiVersion: V3 - routeConfigName: envoy-gateway/gateway-1/http + routeConfigName: envoy-gateway/gateway-1/http-listener-scope serverHeaderTransformation: PASS_THROUGH - statPrefix: http-10080 + statPrefix: http-10081 useRemoteAddress: true - name: envoy-gateway/gateway-1/http + name: envoy-gateway/gateway-1/http-listener-scope maxConnectionsToAcceptPerSocketEvent: 1 - name: envoy-gateway/gateway-1/http + name: envoy-gateway/gateway-1/http-listener-scope perConnectionBufferLimitBytes: 32768 diff --git a/internal/xds/translator/testdata/out/xds-ir/ext-proc.routes.yaml b/internal/xds/translator/testdata/out/xds-ir/ext-proc.routes.yaml index 8cef38ab6a..89dc137e53 100644 --- a/internal/xds/translator/testdata/out/xds-ir/ext-proc.routes.yaml +++ b/internal/xds/translator/testdata/out/xds-ir/ext-proc.routes.yaml @@ -13,12 +13,59 @@ upgradeConfigs: - upgradeType: websocket typedPerFilterConfig: - envoy.filters.http.ext_proc/envoyextensionpolicy/default/policy-for-route-1/extproc/0: + envoy.filters.http.filter_chain.eep.listener: '@type': type.googleapis.com/envoy.config.route.v3.FilterConfig - config: {} - envoy.filters.http.ext_proc/envoyextensionpolicy/default/policy-for-route-2/extproc/0: - '@type': type.googleapis.com/envoy.config.route.v3.FilterConfig - config: {} + disabled: true + envoy.filters.http.filter_chain.eep.route: + '@type': type.googleapis.com/envoy.extensions.filters.http.filter_chain.v3.FilterChainConfigPerRoute + filterChain: + filters: + - name: envoy.filters.http.ext_proc/0 + typedConfig: + '@type': type.googleapis.com/envoy.extensions.filters.http.ext_proc.v3.ExternalProcessor + allowModeOverride: true + failureModeAllow: true + grpcService: + envoyGrpc: + authority: grpc-backend-4.default:4000 + clusterName: envoyextensionpolicy/default/policy-for-route-2/0/grpc-backend-4 + timeout: 10s + messageTimeout: 5s + metadataOptions: + forwardingNamespaces: + untyped: + - envoy.filters.http.ext_authz + receivingNamespaces: + untyped: + - envoy.filters.http.my_custom + processingMode: + requestBodyMode: BUFFERED + requestHeaderMode: SEND + requestTrailerMode: SKIP + responseBodyMode: STREAMED + responseHeaderMode: SKIP + responseTrailerMode: SKIP + requestAttributes: + - xds.route_metadata + - connection.requested_server_name + responseAttributes: + - request.path + - name: envoy.filters.http.ext_proc/1 + typedConfig: + '@type': type.googleapis.com/envoy.extensions.filters.http.ext_proc.v3.ExternalProcessor + failureModeAllow: true + grpcService: + envoyGrpc: + authority: grpc-backend-2.default:8000 + clusterName: envoyextensionpolicy/default/policy-for-route-1/0/grpc-backend-2 + timeout: 10s + messageTimeout: 5s + processingMode: + requestBodyMode: BUFFERED_PARTIAL + requestHeaderMode: SKIP + requestTrailerMode: SKIP + responseHeaderMode: SEND + responseTrailerMode: SKIP - match: pathSeparatedPrefix: /bar name: httproute/default/httproute-2/rule/0/match/0/gateway_envoyproxy_io @@ -27,9 +74,28 @@ upgradeConfigs: - upgradeType: websocket typedPerFilterConfig: - envoy.filters.http.ext_proc/envoyextensionpolicy/envoy-gateway/policy-for-route-3/extproc/0: + envoy.filters.http.filter_chain.eep.listener: '@type': type.googleapis.com/envoy.config.route.v3.FilterConfig - config: {} + disabled: true + envoy.filters.http.filter_chain.eep.route: + '@type': type.googleapis.com/envoy.extensions.filters.http.filter_chain.v3.FilterChainConfigPerRoute + filterChain: + filters: + - name: envoy.filters.http.ext_proc/0 + typedConfig: + '@type': type.googleapis.com/envoy.extensions.filters.http.ext_proc.v3.ExternalProcessor + grpcService: + envoyGrpc: + authority: grpc-backend-3.envoy-gateway:3000 + clusterName: envoyextensionpolicy/envoy-gateway/policy-for-route-3/0/grpc-backend-3 + timeout: 10s + processingMode: + requestBodyMode: FULL_DUPLEX_STREAMED + requestHeaderMode: SKIP + requestTrailerMode: SEND + responseBodyMode: FULL_DUPLEX_STREAMED + responseHeaderMode: SKIP + responseTrailerMode: SEND - domains: - "" name: envoy-gateway/gateway-1/http/ @@ -41,9 +107,140 @@ upgradeConfigs: - upgradeType: websocket typedPerFilterConfig: - envoy.filters.http.ext_proc/envoyextensionpolicy/envoy-gateway/policy-for-gateway-1/extproc/0: + envoy.filters.http.filter_chain.eep.listener: + '@type': type.googleapis.com/envoy.config.route.v3.FilterConfig + disabled: true + envoy.filters.http.filter_chain.eep.route: + '@type': type.googleapis.com/envoy.extensions.filters.http.filter_chain.v3.FilterChainConfigPerRoute + filterChain: + filters: + - name: envoy.filters.http.ext_proc/0 + typedConfig: + '@type': type.googleapis.com/envoy.extensions.filters.http.ext_proc.v3.ExternalProcessor + grpcService: + envoyGrpc: + authority: grpc-backend-3.envoy-gateway:3000 + clusterName: envoyextensionpolicy/envoy-gateway/policy-for-gateway-2/0/grpc-backend-3 + timeout: 10s + processingMode: + requestHeaderMode: SKIP + requestTrailerMode: SKIP + responseHeaderMode: SKIP + responseTrailerMode: SKIP + - name: envoy.filters.http.ext_proc/1 + typedConfig: + '@type': type.googleapis.com/envoy.extensions.filters.http.ext_proc.v3.ExternalProcessor + grpcService: + envoyGrpc: + authority: grpc-backend.envoy-gateway:9000 + clusterName: envoyextensionpolicy/envoy-gateway/policy-for-gateway-1/0/grpc-backend + timeout: 10s + messageTimeout: 15s + metadataOptions: + forwardingNamespaces: + untyped: + - envoy.filters.http.ext_proc + receivingNamespaces: + untyped: + - envoy.filters.http.prc_ext + observabilityMode: true + processingMode: + requestHeaderMode: SKIP + requestTrailerMode: SKIP + responseHeaderMode: SKIP + responseTrailerMode: SKIP + requestAttributes: + - xds.route_metadata + - connection.requested_server_name + responseAttributes: + - request.path + statusOnError: + code: ServiceUnavailable +- ignorePortInHostMatching: true + name: envoy-gateway/gateway-1/http-listener-scope + virtualHosts: + - domains: + - listener-scope.envoyproxy.io + name: envoy-gateway/gateway-1/http-listener-scope/listener-scope_envoyproxy_io + routes: + - match: + pathSeparatedPrefix: /inherit + name: httproute/default/httproute-4/rule/0/match/0/listener_scope_envoyproxy_io + route: + cluster: httproute/default/httproute-4/rule/0 + upgradeConfigs: + - upgradeType: websocket + - match: + pathSeparatedPrefix: /override + name: httproute/default/httproute-5/rule/0/match/0/listener_scope_envoyproxy_io + route: + cluster: httproute/default/httproute-5/rule/0 + upgradeConfigs: + - upgradeType: websocket + typedPerFilterConfig: + envoy.filters.http.filter_chain.eep.listener: '@type': type.googleapis.com/envoy.config.route.v3.FilterConfig - config: {} - envoy.filters.http.ext_proc/envoyextensionpolicy/envoy-gateway/policy-for-gateway-2/extproc/0: + disabled: true + envoy.filters.http.filter_chain.eep.route: + '@type': type.googleapis.com/envoy.extensions.filters.http.filter_chain.v3.FilterChainConfigPerRoute + filterChain: + filters: + - name: envoy.filters.http.ext_proc/0 + typedConfig: + '@type': type.googleapis.com/envoy.extensions.filters.http.ext_proc.v3.ExternalProcessor + grpcService: + envoyGrpc: + authority: grpc-backend-5.default:9500 + clusterName: envoyextensionpolicy/default/policy-for-route-5/0/grpc-backend-5 + timeout: 10s + processingMode: + requestHeaderMode: SKIP + requestTrailerMode: SKIP + responseHeaderMode: SKIP + responseTrailerMode: SKIP + - match: + pathSeparatedPrefix: /same-name + name: httproute/default/httproute-6/rule/0/match/0/listener_scope_envoyproxy_io + route: + cluster: httproute/default/httproute-6/rule/0 + upgradeConfigs: + - upgradeType: websocket + typedPerFilterConfig: + envoy.filters.http.filter_chain.eep.listener: '@type': type.googleapis.com/envoy.config.route.v3.FilterConfig - config: {} + disabled: true + envoy.filters.http.filter_chain.eep.route: + '@type': type.googleapis.com/envoy.extensions.filters.http.filter_chain.v3.FilterChainConfigPerRoute + filterChain: + filters: + - name: envoy.filters.http.ext_proc/0 + typedConfig: + '@type': type.googleapis.com/envoy.extensions.filters.http.ext_proc.v3.ExternalProcessor + grpcService: + envoyGrpc: + authority: grpc-backend-listener.envoy-gateway:9000 + clusterName: envoyextensionpolicy/envoy-gateway/policy-for-gateway-listener/0/grpc-backend-listener + timeout: 10s + processingMode: + requestHeaderMode: SKIP + requestTrailerMode: SKIP + responseHeaderMode: SKIP + responseTrailerMode: SKIP + typedPerFilterConfig: + envoy.filters.http.filter_chain.eep.listener: + '@type': type.googleapis.com/envoy.extensions.filters.http.filter_chain.v3.FilterChainConfigPerRoute + filterChain: + filters: + - name: envoy.filters.http.ext_proc/listener/0 + typedConfig: + '@type': type.googleapis.com/envoy.extensions.filters.http.ext_proc.v3.ExternalProcessor + grpcService: + envoyGrpc: + authority: grpc-backend-listener.envoy-gateway:9000 + clusterName: envoyextensionpolicy/envoy-gateway/policy-for-gateway-listener/0/grpc-backend-listener + timeout: 10s + processingMode: + requestHeaderMode: SKIP + requestTrailerMode: SKIP + responseHeaderMode: SKIP + responseTrailerMode: SKIP diff --git a/internal/xds/translator/testdata/out/xds-ir/jsonpatch-with-jsonpath.listeners.yaml b/internal/xds/translator/testdata/out/xds-ir/jsonpatch-with-jsonpath.listeners.yaml index bf7ee8d044..fec8e6709c 100644 --- a/internal/xds/translator/testdata/out/xds-ir/jsonpatch-with-jsonpath.listeners.yaml +++ b/internal/xds/translator/testdata/out/xds-ir/jsonpatch-with-jsonpath.listeners.yaml @@ -84,30 +84,13 @@ maxConcurrentStreams: 100 httpFilters: - disabled: true - name: envoy.filters.http.wasm/envoyextensionpolicy/default/policy-for-http-route/wasm/0 + name: envoy.filters.http.filter_chain.eep.listener typedConfig: - '@type': type.googleapis.com/envoy.extensions.filters.http.wasm.v3.Wasm - config: - configuration: - '@type': type.googleapis.com/google.protobuf.StringValue - value: '{"parameter1":{"key1":"value1"},"parameter2":{"key2":{"key3":"value3"}}}' - failOpen: true - name: wasm-filter-4 - vmConfig: - code: - remote: - httpUri: - cluster: wasm_cluster - timeout: 10s - uri: https://envoy-gateway:18002/fe571e7b1ef5dc626ceb2c2c86782a134a92989a2643485238951696ae4334c3.wasm - retryPolicy: - numRetries: 10 - retryBackOff: - baseInterval: 1s - maxInterval: 30s - sha256: a1f0b78b8c1320690327800e3a5de10e7dbba7b6c752e702193a395a52c727b6 - runtime: envoy.wasm.runtime.v8 - vmId: envoyextensionpolicy/default/policy-for-http-route/wasm/0 + '@type': type.googleapis.com/envoy.extensions.filters.http.filter_chain.v3.FilterChainConfig + - disabled: true + name: envoy.filters.http.filter_chain.eep.route + typedConfig: + '@type': type.googleapis.com/envoy.extensions.filters.http.filter_chain.v3.FilterChainConfig - name: envoy.filters.http.router typedConfig: '@type': type.googleapis.com/envoy.extensions.filters.http.router.v3.Router diff --git a/internal/xds/translator/testdata/out/xds-ir/jsonpatch-with-jsonpath.routes.yaml b/internal/xds/translator/testdata/out/xds-ir/jsonpatch-with-jsonpath.routes.yaml index e874e015b2..d8ea76c06e 100644 --- a/internal/xds/translator/testdata/out/xds-ir/jsonpatch-with-jsonpath.routes.yaml +++ b/internal/xds/translator/testdata/out/xds-ir/jsonpatch-with-jsonpath.routes.yaml @@ -52,9 +52,37 @@ another-filter-per-filter-config: '@type': type.googleapis.com/envoy.config.route.v3.FilterConfig config: {} - envoy.filters.http.wasm/envoyextensionpolicy/default/policy-for-http-route/wasm/0: + envoy.filters.http.filter_chain.eep.listener: '@type': type.googleapis.com/envoy.config.route.v3.FilterConfig - config: {} + disabled: true + envoy.filters.http.filter_chain.eep.route: + '@type': type.googleapis.com/envoy.extensions.filters.http.filter_chain.v3.FilterChainConfigPerRoute + filterChain: + filters: + - name: envoy.filters.http.wasm/0 + typedConfig: + '@type': type.googleapis.com/envoy.extensions.filters.http.wasm.v3.Wasm + config: + configuration: + '@type': type.googleapis.com/google.protobuf.StringValue + value: '{"parameter1":{"key1":"value1"},"parameter2":{"key2":{"key3":"value3"}}}' + failOpen: true + name: wasm-filter-4 + vmConfig: + code: + remote: + httpUri: + cluster: wasm_cluster + timeout: 10s + uri: https://envoy-gateway:18002/fe571e7b1ef5dc626ceb2c2c86782a134a92989a2643485238951696ae4334c3.wasm + retryPolicy: + numRetries: 10 + retryBackOff: + baseInterval: 1s + maxInterval: 30s + sha256: a1f0b78b8c1320690327800e3a5de10e7dbba7b6c752e702193a395a52c727b6 + runtime: envoy.wasm.runtime.v8 + vmId: envoyextensionpolicy/default/policy-for-http-route/wasm/0 - match: prefix: / name: httproute/default/httproute-1/rule/1/match/0/www_example_com diff --git a/internal/xds/translator/testdata/out/xds-ir/lua.clusters.yaml b/internal/xds/translator/testdata/out/xds-ir/lua.clusters.yaml index d1b786402b..376d420242 100644 --- a/internal/xds/translator/testdata/out/xds-ir/lua.clusters.yaml +++ b/internal/xds/translator/testdata/out/xds-ir/lua.clusters.yaml @@ -44,3 +44,224 @@ name: httproute/default/httproute-2/rule/0 perConnectionBufferLimitBytes: 32768 type: EDS +- circuitBreakers: + thresholds: + - maxRetries: 1024 + commonLbConfig: {} + connectTimeout: 10s + dnsLookupFamily: V4_PREFERRED + edsClusterConfig: + edsConfig: + ads: {} + resourceApiVersion: V3 + serviceName: httproute/default/httproute-3/rule/0 + ignoreHealthOnHostRemoval: true + loadBalancingPolicy: + policies: + - typedExtensionConfig: + name: envoy.load_balancing_policies.least_request + typedConfig: + '@type': type.googleapis.com/envoy.extensions.load_balancing_policies.least_request.v3.LeastRequest + localityLbConfig: + localityWeightedLbConfig: {} + name: httproute/default/httproute-3/rule/0 + perConnectionBufferLimitBytes: 32768 + type: EDS +- circuitBreakers: + thresholds: + - maxRetries: 1024 + commonLbConfig: {} + connectTimeout: 10s + dnsLookupFamily: V4_PREFERRED + edsClusterConfig: + edsConfig: + ads: {} + resourceApiVersion: V3 + serviceName: httproute/default/httproute-4/rule/0 + ignoreHealthOnHostRemoval: true + loadBalancingPolicy: + policies: + - typedExtensionConfig: + name: envoy.load_balancing_policies.least_request + typedConfig: + '@type': type.googleapis.com/envoy.extensions.load_balancing_policies.least_request.v3.LeastRequest + localityLbConfig: + localityWeightedLbConfig: {} + name: httproute/default/httproute-4/rule/0 + perConnectionBufferLimitBytes: 32768 + type: EDS +- circuitBreakers: + thresholds: + - maxRetries: 1024 + commonLbConfig: {} + connectTimeout: 10s + dnsLookupFamily: V4_PREFERRED + edsClusterConfig: + edsConfig: + ads: {} + resourceApiVersion: V3 + serviceName: httproute/default/httproute-5/rule/0 + ignoreHealthOnHostRemoval: true + loadBalancingPolicy: + policies: + - typedExtensionConfig: + name: envoy.load_balancing_policies.least_request + typedConfig: + '@type': type.googleapis.com/envoy.extensions.load_balancing_policies.least_request.v3.LeastRequest + localityLbConfig: + localityWeightedLbConfig: {} + name: httproute/default/httproute-5/rule/0 + perConnectionBufferLimitBytes: 32768 + type: EDS +- circuitBreakers: + thresholds: + - maxRetries: 1024 + commonLbConfig: {} + connectTimeout: 10s + dnsLookupFamily: V4_PREFERRED + edsClusterConfig: + edsConfig: + ads: {} + resourceApiVersion: V3 + serviceName: envoyextensionpolicy/default/policy-for-http-route/0/grpc-backend + ignoreHealthOnHostRemoval: true + loadBalancingPolicy: + policies: + - typedExtensionConfig: + name: envoy.load_balancing_policies.least_request + typedConfig: + '@type': type.googleapis.com/envoy.extensions.load_balancing_policies.least_request.v3.LeastRequest + localityLbConfig: + localityWeightedLbConfig: {} + name: envoyextensionpolicy/default/policy-for-http-route/0/grpc-backend + perConnectionBufferLimitBytes: 32768 + type: EDS + typedExtensionProtocolOptions: + envoy.extensions.upstreams.http.v3.HttpProtocolOptions: + '@type': type.googleapis.com/envoy.extensions.upstreams.http.v3.HttpProtocolOptions + explicitHttpConfig: + http2ProtocolOptions: + initialConnectionWindowSize: 1048576 + initialStreamWindowSize: 65536 +- circuitBreakers: + thresholds: + - maxRetries: 1024 + commonLbConfig: {} + connectTimeout: 10s + dnsLookupFamily: V4_PREFERRED + edsClusterConfig: + edsConfig: + ads: {} + resourceApiVersion: V3 + serviceName: httproute/default/httproute-6/rule/0 + ignoreHealthOnHostRemoval: true + loadBalancingPolicy: + policies: + - typedExtensionConfig: + name: envoy.load_balancing_policies.least_request + typedConfig: + '@type': type.googleapis.com/envoy.extensions.load_balancing_policies.least_request.v3.LeastRequest + localityLbConfig: + localityWeightedLbConfig: {} + name: httproute/default/httproute-6/rule/0 + perConnectionBufferLimitBytes: 32768 + type: EDS +- circuitBreakers: + thresholds: + - maxRetries: 1024 + commonLbConfig: {} + connectTimeout: 10s + dnsLookupFamily: V4_PREFERRED + edsClusterConfig: + edsConfig: + ads: {} + resourceApiVersion: V3 + serviceName: httproute/default/httproute-7/rule/0 + ignoreHealthOnHostRemoval: true + loadBalancingPolicy: + policies: + - typedExtensionConfig: + name: envoy.load_balancing_policies.least_request + typedConfig: + '@type': type.googleapis.com/envoy.extensions.load_balancing_policies.least_request.v3.LeastRequest + localityLbConfig: + localityWeightedLbConfig: {} + name: httproute/default/httproute-7/rule/0 + perConnectionBufferLimitBytes: 32768 + type: EDS +- circuitBreakers: + thresholds: + - maxRetries: 1024 + commonLbConfig: {} + connectTimeout: 10s + dnsLookupFamily: V4_PREFERRED + edsClusterConfig: + edsConfig: + ads: {} + resourceApiVersion: V3 + serviceName: httproute/default/httproute-8/rule/0 + ignoreHealthOnHostRemoval: true + loadBalancingPolicy: + policies: + - typedExtensionConfig: + name: envoy.load_balancing_policies.least_request + typedConfig: + '@type': type.googleapis.com/envoy.extensions.load_balancing_policies.least_request.v3.LeastRequest + localityLbConfig: + localityWeightedLbConfig: {} + name: httproute/default/httproute-8/rule/0 + perConnectionBufferLimitBytes: 32768 + type: EDS +- circuitBreakers: + thresholds: + - maxRetries: 1024 + commonLbConfig: {} + connectTimeout: 10s + dnsLookupFamily: V4_PREFERRED + edsClusterConfig: + edsConfig: + ads: {} + resourceApiVersion: V3 + serviceName: envoyextensionpolicy/default/policy-for-gateway/0/grpc-backend + ignoreHealthOnHostRemoval: true + loadBalancingPolicy: + policies: + - typedExtensionConfig: + name: envoy.load_balancing_policies.least_request + typedConfig: + '@type': type.googleapis.com/envoy.extensions.load_balancing_policies.least_request.v3.LeastRequest + localityLbConfig: + localityWeightedLbConfig: {} + name: envoyextensionpolicy/default/policy-for-gateway/0/grpc-backend + perConnectionBufferLimitBytes: 32768 + type: EDS + typedExtensionProtocolOptions: + envoy.extensions.upstreams.http.v3.HttpProtocolOptions: + '@type': type.googleapis.com/envoy.extensions.upstreams.http.v3.HttpProtocolOptions + explicitHttpConfig: + http2ProtocolOptions: + initialConnectionWindowSize: 1048576 + initialStreamWindowSize: 65536 +- circuitBreakers: + thresholds: + - maxRetries: 1024 + commonLbConfig: {} + connectTimeout: 10s + dnsLookupFamily: V4_PREFERRED + edsClusterConfig: + edsConfig: + ads: {} + resourceApiVersion: V3 + serviceName: httproute/default/httproute-9/rule/0 + ignoreHealthOnHostRemoval: true + loadBalancingPolicy: + policies: + - typedExtensionConfig: + name: envoy.load_balancing_policies.least_request + typedConfig: + '@type': type.googleapis.com/envoy.extensions.load_balancing_policies.least_request.v3.LeastRequest + localityLbConfig: + localityWeightedLbConfig: {} + name: httproute/default/httproute-9/rule/0 + perConnectionBufferLimitBytes: 32768 + type: EDS diff --git a/internal/xds/translator/testdata/out/xds-ir/lua.endpoints.yaml b/internal/xds/translator/testdata/out/xds-ir/lua.endpoints.yaml index 05442a9a15..11449dbc2a 100644 --- a/internal/xds/translator/testdata/out/xds-ir/lua.endpoints.yaml +++ b/internal/xds/translator/testdata/out/xds-ir/lua.endpoints.yaml @@ -22,3 +22,97 @@ loadBalancingWeight: 1 locality: region: httproute/default/httproute-2/rule/0/backend/0 +- clusterName: httproute/default/httproute-3/rule/0 + endpoints: + - lbEndpoints: + - endpoint: + address: + socketAddress: + address: 7.7.7.7 + portValue: 8080 + loadBalancingWeight: 1 + loadBalancingWeight: 1 + locality: + region: httproute/default/httproute-3/rule/0/backend/0 +- clusterName: httproute/default/httproute-4/rule/0 + endpoints: + - lbEndpoints: + - endpoint: + address: + socketAddress: + address: 7.7.7.7 + portValue: 8080 + loadBalancingWeight: 1 + loadBalancingWeight: 1 + locality: + region: httproute/default/httproute-4/rule/0/backend/0 +- clusterName: httproute/default/httproute-5/rule/0 + endpoints: + - lbEndpoints: + - endpoint: + address: + socketAddress: + address: 7.7.7.7 + portValue: 8080 + loadBalancingWeight: 1 + loadBalancingWeight: 1 + locality: + region: httproute/default/httproute-5/rule/0/backend/0 +- clusterName: envoyextensionpolicy/default/policy-for-http-route/0/grpc-backend + endpoints: + - loadBalancingWeight: 1 + locality: + region: envoyextensionpolicy/default/policy-for-http-route/0/grpc-backend/backend/0 +- clusterName: httproute/default/httproute-6/rule/0 + endpoints: + - lbEndpoints: + - endpoint: + address: + socketAddress: + address: 7.7.7.7 + portValue: 8080 + loadBalancingWeight: 1 + loadBalancingWeight: 1 + locality: + region: httproute/default/httproute-6/rule/0/backend/0 +- clusterName: httproute/default/httproute-7/rule/0 + endpoints: + - lbEndpoints: + - endpoint: + address: + socketAddress: + address: 8.8.8.8 + portValue: 8080 + loadBalancingWeight: 1 + loadBalancingWeight: 1 + locality: + region: httproute/default/httproute-7/rule/0/backend/0 +- clusterName: httproute/default/httproute-8/rule/0 + endpoints: + - lbEndpoints: + - endpoint: + address: + socketAddress: + address: 7.7.7.7 + portValue: 8080 + loadBalancingWeight: 1 + loadBalancingWeight: 1 + locality: + region: httproute/default/httproute-8/rule/0/backend/0 +- clusterName: envoyextensionpolicy/default/policy-for-gateway/0/grpc-backend + endpoints: + - loadBalancingWeight: 1 + locality: + region: envoyextensionpolicy/default/policy-for-gateway/0/grpc-backend/backend/0 +- clusterName: httproute/default/httproute-9/rule/0 + endpoints: + - lbEndpoints: + - endpoint: + address: + socketAddress: + address: 7.7.7.7 + portValue: 8080 + loadBalancingWeight: 1 + loadBalancingWeight: 1 + locality: + region: httproute/default/httproute-9/rule/0/backend/0 diff --git a/internal/xds/translator/testdata/out/xds-ir/lua.listeners.yaml b/internal/xds/translator/testdata/out/xds-ir/lua.listeners.yaml index d4ea335813..fd4b91045b 100644 --- a/internal/xds/translator/testdata/out/xds-ir/lua.listeners.yaml +++ b/internal/xds/translator/testdata/out/xds-ir/lua.listeners.yaml @@ -15,26 +15,13 @@ maxConcurrentStreams: 100 httpFilters: - disabled: true - name: envoy.filters.http.lua/envoyextensionpolicy/default/policy-for-http-route/lua/0 + name: envoy.filters.http.filter_chain.eep.listener typedConfig: - '@type': type.googleapis.com/envoy.extensions.filters.http.lua.v3.Lua - defaultSourceCode: - inlineString: function envoy_on_request(request_handle) request_handle:logInfo('Goodbye.') - end + '@type': type.googleapis.com/envoy.extensions.filters.http.filter_chain.v3.FilterChainConfig - disabled: true - name: envoy.filters.http.lua/envoyextensionpolicy/envoy-gateway/policy-for-gateway/lua/0 + name: envoy.filters.http.filter_chain.eep.route typedConfig: - '@type': type.googleapis.com/envoy.extensions.filters.http.lua.v3.Lua - defaultSourceCode: - inlineString: function envoy_on_response(response_handle) response_handle:logWarn('Goodbye.') - end - - disabled: true - name: envoy.filters.http.lua/envoyextensionpolicy/envoy-gateway/policy-for-gateway/lua/1 - typedConfig: - '@type': type.googleapis.com/envoy.extensions.filters.http.lua.v3.Lua - defaultSourceCode: - inlineString: function envoy_on_response(response_handle) response_handle:logError('Hello.') - end + '@type': type.googleapis.com/envoy.extensions.filters.http.filter_chain.v3.FilterChainConfig - name: envoy.filters.http.router typedConfig: '@type': type.googleapis.com/envoy.extensions.filters.http.router.v3.Router @@ -55,3 +42,267 @@ maxConnectionsToAcceptPerSocketEvent: 1 name: envoy-gateway/gateway-1/http perConnectionBufferLimitBytes: 32768 +- address: + socketAddress: + address: 0.0.0.0 + portValue: 10081 + defaultFilterChain: + filters: + - name: envoy.filters.network.http_connection_manager + typedConfig: + '@type': type.googleapis.com/envoy.extensions.filters.network.http_connection_manager.v3.HttpConnectionManager + commonHttpProtocolOptions: + headersWithUnderscoresAction: REJECT_REQUEST + http2ProtocolOptions: + initialConnectionWindowSize: 1048576 + initialStreamWindowSize: 65536 + maxConcurrentStreams: 100 + httpFilters: + - disabled: true + name: envoy.filters.http.filter_chain.eep.listener + typedConfig: + '@type': type.googleapis.com/envoy.extensions.filters.http.filter_chain.v3.FilterChainConfig + - disabled: true + name: envoy.filters.http.filter_chain.eep.route + typedConfig: + '@type': type.googleapis.com/envoy.extensions.filters.http.filter_chain.v3.FilterChainConfig + - name: envoy.filters.http.router + typedConfig: + '@type': type.googleapis.com/envoy.extensions.filters.http.router.v3.Router + suppressEnvoyHeaders: true + mergeSlashes: true + normalizePath: true + pathWithEscapedSlashesAction: UNESCAPE_AND_REDIRECT + rds: + configSource: + ads: {} + initialFetchTimeout: 0s + resourceApiVersion: V3 + routeConfigName: envoy-gateway/gateway-1/http-2 + serverHeaderTransformation: PASS_THROUGH + statPrefix: http-10081 + useRemoteAddress: true + name: envoy-gateway/gateway-1/http-2 + maxConnectionsToAcceptPerSocketEvent: 1 + name: envoy-gateway/gateway-1/http-2 + perConnectionBufferLimitBytes: 32768 +- address: + socketAddress: + address: 0.0.0.0 + portValue: 10082 + defaultFilterChain: + filters: + - name: envoy.filters.network.http_connection_manager + typedConfig: + '@type': type.googleapis.com/envoy.extensions.filters.network.http_connection_manager.v3.HttpConnectionManager + commonHttpProtocolOptions: + headersWithUnderscoresAction: REJECT_REQUEST + http2ProtocolOptions: + initialConnectionWindowSize: 1048576 + initialStreamWindowSize: 65536 + maxConcurrentStreams: 100 + httpFilters: + - disabled: true + name: envoy.filters.http.filter_chain.eep.listener + typedConfig: + '@type': type.googleapis.com/envoy.extensions.filters.http.filter_chain.v3.FilterChainConfig + - disabled: true + name: envoy.filters.http.filter_chain.eep.route + typedConfig: + '@type': type.googleapis.com/envoy.extensions.filters.http.filter_chain.v3.FilterChainConfig + - name: envoy.filters.http.router + typedConfig: + '@type': type.googleapis.com/envoy.extensions.filters.http.router.v3.Router + suppressEnvoyHeaders: true + mergeSlashes: true + normalizePath: true + pathWithEscapedSlashesAction: UNESCAPE_AND_REDIRECT + rds: + configSource: + ads: {} + initialFetchTimeout: 0s + resourceApiVersion: V3 + routeConfigName: envoy-gateway/gateway-1/http-3 + serverHeaderTransformation: PASS_THROUGH + statPrefix: http-10082 + useRemoteAddress: true + name: envoy-gateway/gateway-1/http-3 + maxConnectionsToAcceptPerSocketEvent: 1 + name: envoy-gateway/gateway-1/http-3 + perConnectionBufferLimitBytes: 32768 +- address: + socketAddress: + address: 0.0.0.0 + portValue: 10083 + defaultFilterChain: + filters: + - name: envoy.filters.network.http_connection_manager + typedConfig: + '@type': type.googleapis.com/envoy.extensions.filters.network.http_connection_manager.v3.HttpConnectionManager + commonHttpProtocolOptions: + headersWithUnderscoresAction: REJECT_REQUEST + http2ProtocolOptions: + initialConnectionWindowSize: 1048576 + initialStreamWindowSize: 65536 + maxConcurrentStreams: 100 + httpFilters: + - disabled: true + name: envoy.filters.http.filter_chain.eep.listener + typedConfig: + '@type': type.googleapis.com/envoy.extensions.filters.http.filter_chain.v3.FilterChainConfig + - disabled: true + name: envoy.filters.http.filter_chain.eep.route + typedConfig: + '@type': type.googleapis.com/envoy.extensions.filters.http.filter_chain.v3.FilterChainConfig + - name: envoy.filters.http.router + typedConfig: + '@type': type.googleapis.com/envoy.extensions.filters.http.router.v3.Router + suppressEnvoyHeaders: true + mergeSlashes: true + normalizePath: true + pathWithEscapedSlashesAction: UNESCAPE_AND_REDIRECT + rds: + configSource: + ads: {} + initialFetchTimeout: 0s + resourceApiVersion: V3 + routeConfigName: envoy-gateway/gateway-1/http-4 + serverHeaderTransformation: PASS_THROUGH + statPrefix: http-10083 + useRemoteAddress: true + name: envoy-gateway/gateway-1/http-4 + maxConnectionsToAcceptPerSocketEvent: 1 + name: envoy-gateway/gateway-1/http-4 + perConnectionBufferLimitBytes: 32768 +- address: + socketAddress: + address: 0.0.0.0 + portValue: 10084 + defaultFilterChain: + filters: + - name: envoy.filters.network.http_connection_manager + typedConfig: + '@type': type.googleapis.com/envoy.extensions.filters.network.http_connection_manager.v3.HttpConnectionManager + commonHttpProtocolOptions: + headersWithUnderscoresAction: REJECT_REQUEST + http2ProtocolOptions: + initialConnectionWindowSize: 1048576 + initialStreamWindowSize: 65536 + maxConcurrentStreams: 100 + httpFilters: + - disabled: true + name: envoy.filters.http.filter_chain.eep.listener + typedConfig: + '@type': type.googleapis.com/envoy.extensions.filters.http.filter_chain.v3.FilterChainConfig + - disabled: true + name: envoy.filters.http.filter_chain.eep.route + typedConfig: + '@type': type.googleapis.com/envoy.extensions.filters.http.filter_chain.v3.FilterChainConfig + - name: envoy.filters.http.router + typedConfig: + '@type': type.googleapis.com/envoy.extensions.filters.http.router.v3.Router + suppressEnvoyHeaders: true + mergeSlashes: true + normalizePath: true + pathWithEscapedSlashesAction: UNESCAPE_AND_REDIRECT + rds: + configSource: + ads: {} + initialFetchTimeout: 0s + resourceApiVersion: V3 + routeConfigName: envoy-gateway/gateway-1/http-5 + serverHeaderTransformation: PASS_THROUGH + statPrefix: http-10084 + useRemoteAddress: true + name: envoy-gateway/gateway-1/http-5 + maxConnectionsToAcceptPerSocketEvent: 1 + name: envoy-gateway/gateway-1/http-5 + perConnectionBufferLimitBytes: 32768 +- address: + socketAddress: + address: 0.0.0.0 + portValue: 10085 + defaultFilterChain: + filters: + - name: envoy.filters.network.http_connection_manager + typedConfig: + '@type': type.googleapis.com/envoy.extensions.filters.network.http_connection_manager.v3.HttpConnectionManager + commonHttpProtocolOptions: + headersWithUnderscoresAction: REJECT_REQUEST + http2ProtocolOptions: + initialConnectionWindowSize: 1048576 + initialStreamWindowSize: 65536 + maxConcurrentStreams: 100 + httpFilters: + - disabled: true + name: envoy.filters.http.filter_chain.eep.listener + typedConfig: + '@type': type.googleapis.com/envoy.extensions.filters.http.filter_chain.v3.FilterChainConfig + - disabled: true + name: envoy.filters.http.filter_chain.eep.route + typedConfig: + '@type': type.googleapis.com/envoy.extensions.filters.http.filter_chain.v3.FilterChainConfig + - name: envoy.filters.http.router + typedConfig: + '@type': type.googleapis.com/envoy.extensions.filters.http.router.v3.Router + suppressEnvoyHeaders: true + mergeSlashes: true + normalizePath: true + pathWithEscapedSlashesAction: UNESCAPE_AND_REDIRECT + rds: + configSource: + ads: {} + initialFetchTimeout: 0s + resourceApiVersion: V3 + routeConfigName: envoy-gateway/gateway-1/http-7 + serverHeaderTransformation: PASS_THROUGH + statPrefix: http-10085 + useRemoteAddress: true + name: envoy-gateway/gateway-1/http-7 + maxConnectionsToAcceptPerSocketEvent: 1 + name: envoy-gateway/gateway-1/http-7 + perConnectionBufferLimitBytes: 32768 +- address: + socketAddress: + address: 0.0.0.0 + portValue: 10086 + defaultFilterChain: + filters: + - name: envoy.filters.network.http_connection_manager + typedConfig: + '@type': type.googleapis.com/envoy.extensions.filters.network.http_connection_manager.v3.HttpConnectionManager + commonHttpProtocolOptions: + headersWithUnderscoresAction: REJECT_REQUEST + http2ProtocolOptions: + initialConnectionWindowSize: 1048576 + initialStreamWindowSize: 65536 + maxConcurrentStreams: 100 + httpFilters: + - disabled: true + name: envoy.filters.http.filter_chain.eep.listener + typedConfig: + '@type': type.googleapis.com/envoy.extensions.filters.http.filter_chain.v3.FilterChainConfig + - disabled: true + name: envoy.filters.http.filter_chain.eep.route + typedConfig: + '@type': type.googleapis.com/envoy.extensions.filters.http.filter_chain.v3.FilterChainConfig + - name: envoy.filters.http.router + typedConfig: + '@type': type.googleapis.com/envoy.extensions.filters.http.router.v3.Router + suppressEnvoyHeaders: true + mergeSlashes: true + normalizePath: true + pathWithEscapedSlashesAction: UNESCAPE_AND_REDIRECT + rds: + configSource: + ads: {} + initialFetchTimeout: 0s + resourceApiVersion: V3 + routeConfigName: envoy-gateway/gateway-1/http-8 + serverHeaderTransformation: PASS_THROUGH + statPrefix: http-10086 + useRemoteAddress: true + name: envoy-gateway/gateway-1/http-8 + maxConnectionsToAcceptPerSocketEvent: 1 + name: envoy-gateway/gateway-1/http-8 + perConnectionBufferLimitBytes: 32768 diff --git a/internal/xds/translator/testdata/out/xds-ir/lua.routes.yaml b/internal/xds/translator/testdata/out/xds-ir/lua.routes.yaml index 7c681e4751..88e2f3baf3 100644 --- a/internal/xds/translator/testdata/out/xds-ir/lua.routes.yaml +++ b/internal/xds/translator/testdata/out/xds-ir/lua.routes.yaml @@ -13,7 +13,20 @@ upgradeConfigs: - upgradeType: websocket typedPerFilterConfig: - envoy.filters.http.lua/envoyextensionpolicy/default/policy-for-http-route/lua/0: + envoy.filters.http.filter_chain.eep.listener: + '@type': type.googleapis.com/envoy.config.route.v3.FilterConfig + disabled: true + envoy.filters.http.filter_chain.eep.route: + '@type': type.googleapis.com/envoy.extensions.filters.http.filter_chain.v3.FilterChainConfigPerRoute + filterChain: + filters: + - name: envoy.filters.http.lua/0 + typedConfig: + '@type': type.googleapis.com/envoy.extensions.filters.http.lua.v3.Lua + defaultSourceCode: + inlineString: function envoy_on_request(request_handle) request_handle:logInfo('Goodbye.') + end + envoy.filters.http.lua/0: '@type': type.googleapis.com/envoy.extensions.filters.http.lua.v3.LuaPerRoute filterContext: mode: strict @@ -26,9 +39,268 @@ upgradeConfigs: - upgradeType: websocket typedPerFilterConfig: - envoy.filters.http.lua/envoyextensionpolicy/envoy-gateway/policy-for-gateway/lua/0: + envoy.filters.http.filter_chain.eep.listener: + '@type': type.googleapis.com/envoy.config.route.v3.FilterConfig + disabled: true + envoy.filters.http.filter_chain.eep.route: + '@type': type.googleapis.com/envoy.extensions.filters.http.filter_chain.v3.FilterChainConfigPerRoute + filterChain: + filters: + - name: envoy.filters.http.lua/0 + typedConfig: + '@type': type.googleapis.com/envoy.extensions.filters.http.lua.v3.Lua + defaultSourceCode: + inlineString: function envoy_on_response(response_handle) response_handle:logWarn('Goodbye.') + end + - name: envoy.filters.http.lua/1 + typedConfig: + '@type': type.googleapis.com/envoy.extensions.filters.http.lua.v3.Lua + defaultSourceCode: + inlineString: function envoy_on_response(response_handle) response_handle:logError('Hello.') + end +- ignorePortInHostMatching: true + name: envoy-gateway/gateway-1/http-2 + virtualHosts: + - domains: + - www.example.com + name: envoy-gateway/gateway-1/http-2/www_example_com + routes: + - match: + pathSeparatedPrefix: /foo + name: httproute/default/httproute-3/rule/0/match/0/www_example_com + route: + cluster: httproute/default/httproute-2/rule/0 + upgradeConfigs: + - upgradeType: websocket + typedPerFilterConfig: + envoy.filters.http.filter_chain.eep.listener: + '@type': type.googleapis.com/envoy.config.route.v3.FilterConfig + disabled: true + envoy.filters.http.filter_chain.eep.route: + '@type': type.googleapis.com/envoy.extensions.filters.http.filter_chain.v3.FilterChainConfigPerRoute + filterChain: + filters: + - name: envoy.filters.http.lua/0 + typedConfig: + '@type': type.googleapis.com/envoy.extensions.filters.http.lua.v3.Lua + defaultSourceCode: + inlineString: function envoy_on_request(request_handle) request_handle:logInfo('Goodbye.') + end + envoy.filters.http.lua/0: + '@type': type.googleapis.com/envoy.extensions.filters.http.lua.v3.LuaPerRoute + filterContext: + mode: strict + token_header: x-api-key + typedPerFilterConfig: + envoy.filters.http.filter_chain.eep.listener: + '@type': type.googleapis.com/envoy.extensions.filters.http.filter_chain.v3.FilterChainConfigPerRoute + filterChain: + filters: + - name: envoy.filters.http.lua/listener/0 + typedConfig: + '@type': type.googleapis.com/envoy.extensions.filters.http.lua.v3.Lua + defaultSourceCode: + inlineString: function envoy_on_request(request_handle) request_handle:logInfo('Goodbye + from gateway.') end + envoy.filters.http.lua/listener/0: + '@type': type.googleapis.com/envoy.extensions.filters.http.lua.v3.LuaPerRoute + filterContext: + mode: strict + token_header: x-api-key +- ignorePortInHostMatching: true + name: envoy-gateway/gateway-1/http-3 + virtualHosts: + - domains: + - www.example.com + name: envoy-gateway/gateway-1/http-3/www_example_com + routes: + - match: + pathSeparatedPrefix: /foo + name: httproute/default/httproute-3/rule/0/match/0/www_example_com + route: + cluster: httproute/default/httproute-3/rule/0 + upgradeConfigs: + - upgradeType: websocket + typedPerFilterConfig: + envoy.filters.http.filter_chain.eep.listener: + '@type': type.googleapis.com/envoy.extensions.filters.http.filter_chain.v3.FilterChainConfigPerRoute + filterChain: + filters: + - name: envoy.filters.http.lua/listener/0 + typedConfig: + '@type': type.googleapis.com/envoy.extensions.filters.http.lua.v3.Lua + defaultSourceCode: + inlineString: function envoy_on_request(request_handle) request_handle:logInfo('Goodbye + from gateway.') end + envoy.filters.http.lua/listener/0: + '@type': type.googleapis.com/envoy.extensions.filters.http.lua.v3.LuaPerRoute + filterContext: + mode: strict + token_header: x-api-key +- ignorePortInHostMatching: true + name: envoy-gateway/gateway-1/http-4 + virtualHosts: + - domains: + - www.example.com + name: envoy-gateway/gateway-1/http-4/www_example_com + routes: + - match: + pathSeparatedPrefix: /foo + name: httproute/default/httproute-4/rule/0/match/0/www_example_com + route: + cluster: httproute/default/httproute-4/rule/0 + upgradeConfigs: + - upgradeType: websocket + typedPerFilterConfig: + envoy.filters.http.filter_chain.eep.listener: '@type': type.googleapis.com/envoy.config.route.v3.FilterConfig - config: {} - envoy.filters.http.lua/envoyextensionpolicy/envoy-gateway/policy-for-gateway/lua/1: + disabled: true + envoy.filters.http.filter_chain.eep.route: + '@type': type.googleapis.com/envoy.extensions.filters.http.filter_chain.v3.FilterChainConfigPerRoute + filterChain: + filters: + - name: envoy.filters.http.ext_proc/0 + typedConfig: + '@type': type.googleapis.com/envoy.extensions.filters.http.ext_proc.v3.ExternalProcessor + grpcService: + envoyGrpc: + authority: grpc-backend.default:8000 + clusterName: envoyextensionpolicy/default/policy-for-http-route/0/grpc-backend + timeout: 10s + processingMode: + requestHeaderMode: SKIP + requestTrailerMode: SKIP + responseHeaderMode: SKIP + responseTrailerMode: SKIP + - match: + pathSeparatedPrefix: /bar + name: httproute/default/httproute-5/rule/0/match/0/www_example_com + route: + cluster: httproute/default/httproute-5/rule/0 + upgradeConfigs: + - upgradeType: websocket + typedPerFilterConfig: + envoy.filters.http.filter_chain.eep.listener: + '@type': type.googleapis.com/envoy.extensions.filters.http.filter_chain.v3.FilterChainConfigPerRoute + filterChain: + filters: + - name: envoy.filters.http.lua/listener/0 + typedConfig: + '@type': type.googleapis.com/envoy.extensions.filters.http.lua.v3.Lua + defaultSourceCode: + inlineString: function envoy_on_request(request_handle) request_handle:logInfo('Goodbye + from gateway.') end +- ignorePortInHostMatching: true + name: envoy-gateway/gateway-1/http-5 + virtualHosts: + - domains: + - app-a.example.com + name: envoy-gateway/gateway-1/http-5/app-a_example_com + routes: + - match: + prefix: / + name: httproute/default/httproute-6/rule/0/match/0/app-a_example_com + route: + cluster: httproute/default/httproute-6/rule/0 + upgradeConfigs: + - upgradeType: websocket + typedPerFilterConfig: + envoy.filters.http.filter_chain.eep.listener: + '@type': type.googleapis.com/envoy.extensions.filters.http.filter_chain.v3.FilterChainConfigPerRoute + filterChain: + filters: + - name: envoy.filters.http.lua/listener/0 + typedConfig: + '@type': type.googleapis.com/envoy.extensions.filters.http.lua.v3.Lua + defaultSourceCode: + inlineString: function envoy_on_request(request_handle) request_handle:logInfo('tenant-A + script.') end + - domains: + - app-b.example.com + name: envoy-gateway/gateway-1/http-6/app-b_example_com + routes: + - match: + prefix: / + name: httproute/default/httproute-7/rule/0/match/0/app-b_example_com + route: + cluster: httproute/default/httproute-7/rule/0 + upgradeConfigs: + - upgradeType: websocket + typedPerFilterConfig: + envoy.filters.http.filter_chain.eep.listener: + '@type': type.googleapis.com/envoy.extensions.filters.http.filter_chain.v3.FilterChainConfigPerRoute + filterChain: + filters: + - name: envoy.filters.http.lua/listener/0 + typedConfig: + '@type': type.googleapis.com/envoy.extensions.filters.http.lua.v3.Lua + defaultSourceCode: + inlineString: function envoy_on_request(request_handle) request_handle:logInfo('tenant-B + script.') end +- ignorePortInHostMatching: true + name: envoy-gateway/gateway-1/http-7 + virtualHosts: + - domains: + - www.example.com + name: envoy-gateway/gateway-1/http-7/www_example_com + routes: + - match: + pathSeparatedPrefix: /foo + name: httproute/default/httproute-8/rule/0/match/0/www_example_com + route: + cluster: httproute/default/httproute-8/rule/0 + upgradeConfigs: + - upgradeType: websocket + typedPerFilterConfig: + envoy.filters.http.filter_chain.eep.listener: + '@type': type.googleapis.com/envoy.extensions.filters.http.filter_chain.v3.FilterChainConfigPerRoute + filterChain: + filters: + - name: envoy.filters.http.lua/listener/0 + typedConfig: + '@type': type.googleapis.com/envoy.extensions.filters.http.lua.v3.Lua + defaultSourceCode: + inlineString: function envoy_on_request(request_handle) request_handle:logInfo('Gateway + Lua.') end + - name: envoy.filters.http.ext_proc/listener/0 + typedConfig: + '@type': type.googleapis.com/envoy.extensions.filters.http.ext_proc.v3.ExternalProcessor + grpcService: + envoyGrpc: + authority: grpc-backend.default:8000 + clusterName: envoyextensionpolicy/default/policy-for-gateway/0/grpc-backend + timeout: 10s + processingMode: + requestHeaderMode: SKIP + requestTrailerMode: SKIP + responseHeaderMode: SKIP + responseTrailerMode: SKIP +- ignorePortInHostMatching: true + name: envoy-gateway/gateway-1/http-8 + virtualHosts: + - domains: + - www.example.com + name: envoy-gateway/gateway-1/http-8/www_example_com + routes: + - match: + pathSeparatedPrefix: /foo + name: httproute/default/httproute-9/rule/0/match/0/www_example_com + route: + cluster: httproute/default/httproute-9/rule/0 + upgradeConfigs: + - upgradeType: websocket + typedPerFilterConfig: + envoy.filters.http.filter_chain.eep.listener: '@type': type.googleapis.com/envoy.config.route.v3.FilterConfig - config: {} + disabled: true + typedPerFilterConfig: + envoy.filters.http.filter_chain.eep.listener: + '@type': type.googleapis.com/envoy.extensions.filters.http.filter_chain.v3.FilterChainConfigPerRoute + filterChain: + filters: + - name: envoy.filters.http.lua/listener/0 + typedConfig: + '@type': type.googleapis.com/envoy.extensions.filters.http.lua.v3.Lua + defaultSourceCode: + inlineString: function envoy_on_request(request_handle) request_handle:logInfo('Gateway + Lua.') end diff --git a/internal/xds/translator/testdata/out/xds-ir/wasm.clusters.yaml b/internal/xds/translator/testdata/out/xds-ir/wasm.clusters.yaml index 786a45c183..bae73f7ce1 100644 --- a/internal/xds/translator/testdata/out/xds-ir/wasm.clusters.yaml +++ b/internal/xds/translator/testdata/out/xds-ir/wasm.clusters.yaml @@ -44,6 +44,75 @@ name: httproute/default/httproute-2/rule/0 perConnectionBufferLimitBytes: 32768 type: EDS +- circuitBreakers: + thresholds: + - maxRetries: 1024 + commonLbConfig: {} + connectTimeout: 10s + dnsLookupFamily: V4_PREFERRED + edsClusterConfig: + edsConfig: + ads: {} + resourceApiVersion: V3 + serviceName: httproute/default/httproute-3/rule/0 + ignoreHealthOnHostRemoval: true + loadBalancingPolicy: + policies: + - typedExtensionConfig: + name: envoy.load_balancing_policies.least_request + typedConfig: + '@type': type.googleapis.com/envoy.extensions.load_balancing_policies.least_request.v3.LeastRequest + localityLbConfig: + localityWeightedLbConfig: {} + name: httproute/default/httproute-3/rule/0 + perConnectionBufferLimitBytes: 32768 + type: EDS +- circuitBreakers: + thresholds: + - maxRetries: 1024 + commonLbConfig: {} + connectTimeout: 10s + dnsLookupFamily: V4_PREFERRED + edsClusterConfig: + edsConfig: + ads: {} + resourceApiVersion: V3 + serviceName: httproute/default/httproute-4/rule/0 + ignoreHealthOnHostRemoval: true + loadBalancingPolicy: + policies: + - typedExtensionConfig: + name: envoy.load_balancing_policies.least_request + typedConfig: + '@type': type.googleapis.com/envoy.extensions.load_balancing_policies.least_request.v3.LeastRequest + localityLbConfig: + localityWeightedLbConfig: {} + name: httproute/default/httproute-4/rule/0 + perConnectionBufferLimitBytes: 32768 + type: EDS +- circuitBreakers: + thresholds: + - maxRetries: 1024 + commonLbConfig: {} + connectTimeout: 10s + dnsLookupFamily: V4_PREFERRED + edsClusterConfig: + edsConfig: + ads: {} + resourceApiVersion: V3 + serviceName: httproute/default/httproute-5/rule/0 + ignoreHealthOnHostRemoval: true + loadBalancingPolicy: + policies: + - typedExtensionConfig: + name: envoy.load_balancing_policies.least_request + typedConfig: + '@type': type.googleapis.com/envoy.extensions.load_balancing_policies.least_request.v3.LeastRequest + localityLbConfig: + localityWeightedLbConfig: {} + name: httproute/default/httproute-5/rule/0 + perConnectionBufferLimitBytes: 32768 + type: EDS - circuitBreakers: thresholds: - maxRetries: 1024 diff --git a/internal/xds/translator/testdata/out/xds-ir/wasm.endpoints.yaml b/internal/xds/translator/testdata/out/xds-ir/wasm.endpoints.yaml index 05442a9a15..a18e45814d 100644 --- a/internal/xds/translator/testdata/out/xds-ir/wasm.endpoints.yaml +++ b/internal/xds/translator/testdata/out/xds-ir/wasm.endpoints.yaml @@ -22,3 +22,39 @@ loadBalancingWeight: 1 locality: region: httproute/default/httproute-2/rule/0/backend/0 +- clusterName: httproute/default/httproute-3/rule/0 + endpoints: + - lbEndpoints: + - endpoint: + address: + socketAddress: + address: 7.7.7.7 + portValue: 8080 + loadBalancingWeight: 1 + loadBalancingWeight: 1 + locality: + region: httproute/default/httproute-3/rule/0/backend/0 +- clusterName: httproute/default/httproute-4/rule/0 + endpoints: + - lbEndpoints: + - endpoint: + address: + socketAddress: + address: 7.7.7.7 + portValue: 8080 + loadBalancingWeight: 1 + loadBalancingWeight: 1 + locality: + region: httproute/default/httproute-4/rule/0/backend/0 +- clusterName: httproute/default/httproute-5/rule/0 + endpoints: + - lbEndpoints: + - endpoint: + address: + socketAddress: + address: 7.7.7.7 + portValue: 8080 + loadBalancingWeight: 1 + loadBalancingWeight: 1 + locality: + region: httproute/default/httproute-5/rule/0/backend/0 diff --git a/internal/xds/translator/testdata/out/xds-ir/wasm.listeners.yaml b/internal/xds/translator/testdata/out/xds-ir/wasm.listeners.yaml index 816aaff401..e960ad6855 100644 --- a/internal/xds/translator/testdata/out/xds-ir/wasm.listeners.yaml +++ b/internal/xds/translator/testdata/out/xds-ir/wasm.listeners.yaml @@ -15,107 +15,13 @@ maxConcurrentStreams: 100 httpFilters: - disabled: true - name: envoy.filters.http.wasm/envoyextensionpolicy/default/policy-for-http-route/wasm/0 + name: envoy.filters.http.filter_chain.eep.listener typedConfig: - '@type': type.googleapis.com/envoy.extensions.filters.http.wasm.v3.Wasm - config: - configuration: - '@type': type.googleapis.com/google.protobuf.StringValue - value: '{"parameter1":{"key1":"value1"},"parameter2":{"key2":{"key3":"value3"}}}' - failOpen: true - name: wasm-filter-4 - vmConfig: - code: - remote: - httpUri: - cluster: wasm_cluster - timeout: 10s - uri: https://envoy-gateway:18002/fe571e7b1ef5dc626ceb2c2c86782a134a92989a2643485238951696ae4334c3.wasm - retryPolicy: - numRetries: 10 - retryBackOff: - baseInterval: 1s - maxInterval: 30s - sha256: a1f0b78b8c1320690327800e3a5de10e7dbba7b6c752e702193a395a52c727b6 - runtime: envoy.wasm.runtime.v8 - vmId: envoyextensionpolicy/default/policy-for-http-route/wasm/0 + '@type': type.googleapis.com/envoy.extensions.filters.http.filter_chain.v3.FilterChainConfig - disabled: true - name: envoy.filters.http.wasm/envoyextensionpolicy/envoy-gateway/policy-for-gateway/wasm/0 + name: envoy.filters.http.filter_chain.eep.route typedConfig: - '@type': type.googleapis.com/envoy.extensions.filters.http.wasm.v3.Wasm - config: - configuration: - '@type': type.googleapis.com/google.protobuf.StringValue - value: '{"parameter1":{"key1":"value1","key2":"value2"},"parameter2":"value3"}' - name: wasm-filter-1 - vmConfig: - code: - remote: - httpUri: - cluster: wasm_cluster - timeout: 10s - uri: https://envoy-gateway.envoy-gateway-system.svc.cluster.local:18002/5c90b9a82642ce00a7753923fabead306b9d9a54a7c0bd2463a1af3efcfb110b.wasm - retryPolicy: - numRetries: 10 - retryBackOff: - baseInterval: 1s - maxInterval: 30s - sha256: 746df05c8f3a0b07a46c0967cfbc5cbe5b9d48d0f79b6177eeedf8be6c8b34b5 - runtime: envoy.wasm.runtime.v8 - vmId: envoyextensionpolicy/envoy-gateway/policy-for-gateway/wasm/0 - - disabled: true - name: envoy.filters.http.wasm/envoyextensionpolicy/envoy-gateway/policy-for-gateway/wasm/1 - typedConfig: - '@type': type.googleapis.com/envoy.extensions.filters.http.wasm.v3.Wasm - config: - configuration: - '@type': type.googleapis.com/google.protobuf.StringValue - value: '{"parameter1":"value1","parameter2":"value2"}' - name: wasm-filter-2 - rootId: my-root-id - vmConfig: - code: - remote: - httpUri: - cluster: wasm_cluster - timeout: 10s - uri: https://envoy-gateway.envoy-gateway-system.svc.cluster.local:18002/7abf116e5cd5a20389604a5ba0f3bd04fdf76f92181fe67506b42c2ee596d3fd.wasm - retryPolicy: - numRetries: 10 - retryBackOff: - baseInterval: 1s - maxInterval: 30s - sha256: 314100af781b98a8ca175d5bf90a8bf76576e20a2f397a88223404edc6ebfd46 - runtime: envoy.wasm.runtime.v8 - vmId: envoyextensionpolicy/envoy-gateway/policy-for-gateway/wasm/1 - - disabled: true - name: envoy.filters.http.wasm/envoyextensionpolicy/envoy-gateway/policy-for-gateway/wasm/2 - typedConfig: - '@type': type.googleapis.com/envoy.extensions.filters.http.wasm.v3.Wasm - config: - configuration: - '@type': type.googleapis.com/google.protobuf.StringValue - value: "" - name: envoyextensionpolicy/envoy-gateway/policy-for-gateway/wasm/2 - vmConfig: - code: - remote: - httpUri: - cluster: wasm_cluster - timeout: 10s - uri: https://envoy-gateway.envoy-gateway-system.svc.cluster.local:18002/42d30b4a4cc631415e6e48c02d244700da327201eb273f752cacf745715b31d9.wasm - retryPolicy: - numRetries: 10 - retryBackOff: - baseInterval: 1s - maxInterval: 30s - sha256: 2a19e4f337e5223d7287e7fccd933fb01905deaff804292e5257f8c681b82bee - environmentVariables: - hostEnvKeys: - - SOME_KEY - - ANOTHER_KEY - runtime: envoy.wasm.runtime.v8 - vmId: envoyextensionpolicy/envoy-gateway/policy-for-gateway/wasm/2 + '@type': type.googleapis.com/envoy.extensions.filters.http.filter_chain.v3.FilterChainConfig - name: envoy.filters.http.router typedConfig: '@type': type.googleapis.com/envoy.extensions.filters.http.router.v3.Router @@ -136,3 +42,47 @@ maxConnectionsToAcceptPerSocketEvent: 1 name: envoy-gateway/gateway-1/http perConnectionBufferLimitBytes: 32768 +- address: + socketAddress: + address: 0.0.0.0 + portValue: 10081 + defaultFilterChain: + filters: + - name: envoy.filters.network.http_connection_manager + typedConfig: + '@type': type.googleapis.com/envoy.extensions.filters.network.http_connection_manager.v3.HttpConnectionManager + commonHttpProtocolOptions: + headersWithUnderscoresAction: REJECT_REQUEST + http2ProtocolOptions: + initialConnectionWindowSize: 1048576 + initialStreamWindowSize: 65536 + maxConcurrentStreams: 100 + httpFilters: + - disabled: true + name: envoy.filters.http.filter_chain.eep.listener + typedConfig: + '@type': type.googleapis.com/envoy.extensions.filters.http.filter_chain.v3.FilterChainConfig + - disabled: true + name: envoy.filters.http.filter_chain.eep.route + typedConfig: + '@type': type.googleapis.com/envoy.extensions.filters.http.filter_chain.v3.FilterChainConfig + - name: envoy.filters.http.router + typedConfig: + '@type': type.googleapis.com/envoy.extensions.filters.http.router.v3.Router + suppressEnvoyHeaders: true + mergeSlashes: true + normalizePath: true + pathWithEscapedSlashesAction: UNESCAPE_AND_REDIRECT + rds: + configSource: + ads: {} + initialFetchTimeout: 0s + resourceApiVersion: V3 + routeConfigName: envoy-gateway/gateway-1/http-listener-scope + serverHeaderTransformation: PASS_THROUGH + statPrefix: http-10081 + useRemoteAddress: true + name: envoy-gateway/gateway-1/http-listener-scope + maxConnectionsToAcceptPerSocketEvent: 1 + name: envoy-gateway/gateway-1/http-listener-scope + perConnectionBufferLimitBytes: 32768 diff --git a/internal/xds/translator/testdata/out/xds-ir/wasm.routes.yaml b/internal/xds/translator/testdata/out/xds-ir/wasm.routes.yaml index 1e07a621d5..e756a97c8f 100644 --- a/internal/xds/translator/testdata/out/xds-ir/wasm.routes.yaml +++ b/internal/xds/translator/testdata/out/xds-ir/wasm.routes.yaml @@ -13,9 +13,37 @@ upgradeConfigs: - upgradeType: websocket typedPerFilterConfig: - envoy.filters.http.wasm/envoyextensionpolicy/default/policy-for-http-route/wasm/0: + envoy.filters.http.filter_chain.eep.listener: '@type': type.googleapis.com/envoy.config.route.v3.FilterConfig - config: {} + disabled: true + envoy.filters.http.filter_chain.eep.route: + '@type': type.googleapis.com/envoy.extensions.filters.http.filter_chain.v3.FilterChainConfigPerRoute + filterChain: + filters: + - name: envoy.filters.http.wasm/0 + typedConfig: + '@type': type.googleapis.com/envoy.extensions.filters.http.wasm.v3.Wasm + config: + configuration: + '@type': type.googleapis.com/google.protobuf.StringValue + value: '{"parameter1":{"key1":"value1"},"parameter2":{"key2":{"key3":"value3"}}}' + failOpen: true + name: wasm-filter-4 + vmConfig: + code: + remote: + httpUri: + cluster: wasm_cluster + timeout: 10s + uri: https://envoy-gateway:18002/fe571e7b1ef5dc626ceb2c2c86782a134a92989a2643485238951696ae4334c3.wasm + retryPolicy: + numRetries: 10 + retryBackOff: + baseInterval: 1s + maxInterval: 30s + sha256: a1f0b78b8c1320690327800e3a5de10e7dbba7b6c752e702193a395a52c727b6 + runtime: envoy.wasm.runtime.v8 + vmId: envoyextensionpolicy/default/policy-for-http-route/wasm/0 - match: pathSeparatedPrefix: /bar name: httproute/default/httproute-2/rule/0/match/0/www_example_com @@ -24,12 +52,202 @@ upgradeConfigs: - upgradeType: websocket typedPerFilterConfig: - envoy.filters.http.wasm/envoyextensionpolicy/envoy-gateway/policy-for-gateway/wasm/0: + envoy.filters.http.filter_chain.eep.listener: '@type': type.googleapis.com/envoy.config.route.v3.FilterConfig - config: {} - envoy.filters.http.wasm/envoyextensionpolicy/envoy-gateway/policy-for-gateway/wasm/1: + disabled: true + envoy.filters.http.filter_chain.eep.route: + '@type': type.googleapis.com/envoy.extensions.filters.http.filter_chain.v3.FilterChainConfigPerRoute + filterChain: + filters: + - name: envoy.filters.http.wasm/0 + typedConfig: + '@type': type.googleapis.com/envoy.extensions.filters.http.wasm.v3.Wasm + config: + configuration: + '@type': type.googleapis.com/google.protobuf.StringValue + value: '{"parameter1":{"key1":"value1","key2":"value2"},"parameter2":"value3"}' + name: wasm-filter-1 + vmConfig: + code: + remote: + httpUri: + cluster: wasm_cluster + timeout: 10s + uri: https://envoy-gateway.envoy-gateway-system.svc.cluster.local:18002/5c90b9a82642ce00a7753923fabead306b9d9a54a7c0bd2463a1af3efcfb110b.wasm + retryPolicy: + numRetries: 10 + retryBackOff: + baseInterval: 1s + maxInterval: 30s + sha256: 746df05c8f3a0b07a46c0967cfbc5cbe5b9d48d0f79b6177eeedf8be6c8b34b5 + runtime: envoy.wasm.runtime.v8 + vmId: envoyextensionpolicy/envoy-gateway/policy-for-gateway/wasm/0 + - name: envoy.filters.http.wasm/1 + typedConfig: + '@type': type.googleapis.com/envoy.extensions.filters.http.wasm.v3.Wasm + config: + configuration: + '@type': type.googleapis.com/google.protobuf.StringValue + value: '{"parameter1":"value1","parameter2":"value2"}' + name: wasm-filter-2 + rootId: my-root-id + vmConfig: + code: + remote: + httpUri: + cluster: wasm_cluster + timeout: 10s + uri: https://envoy-gateway.envoy-gateway-system.svc.cluster.local:18002/7abf116e5cd5a20389604a5ba0f3bd04fdf76f92181fe67506b42c2ee596d3fd.wasm + retryPolicy: + numRetries: 10 + retryBackOff: + baseInterval: 1s + maxInterval: 30s + sha256: 314100af781b98a8ca175d5bf90a8bf76576e20a2f397a88223404edc6ebfd46 + runtime: envoy.wasm.runtime.v8 + vmId: envoyextensionpolicy/envoy-gateway/policy-for-gateway/wasm/1 + - name: envoy.filters.http.wasm/2 + typedConfig: + '@type': type.googleapis.com/envoy.extensions.filters.http.wasm.v3.Wasm + config: + configuration: + '@type': type.googleapis.com/google.protobuf.StringValue + value: "" + name: envoyextensionpolicy/envoy-gateway/policy-for-gateway/wasm/2 + vmConfig: + code: + remote: + httpUri: + cluster: wasm_cluster + timeout: 10s + uri: https://envoy-gateway.envoy-gateway-system.svc.cluster.local:18002/42d30b4a4cc631415e6e48c02d244700da327201eb273f752cacf745715b31d9.wasm + retryPolicy: + numRetries: 10 + retryBackOff: + baseInterval: 1s + maxInterval: 30s + sha256: 2a19e4f337e5223d7287e7fccd933fb01905deaff804292e5257f8c681b82bee + environmentVariables: + hostEnvKeys: + - SOME_KEY + - ANOTHER_KEY + runtime: envoy.wasm.runtime.v8 + vmId: envoyextensionpolicy/envoy-gateway/policy-for-gateway/wasm/2 +- ignorePortInHostMatching: true + name: envoy-gateway/gateway-1/http-listener-scope + virtualHosts: + - domains: + - listener-scope.example.com + name: envoy-gateway/gateway-1/http-listener-scope/listener-scope_example_com + routes: + - match: + pathSeparatedPrefix: /inherit + name: httproute/default/httproute-3/rule/0/match/0/listener_scope_example_com + route: + cluster: httproute/default/httproute-3/rule/0 + upgradeConfigs: + - upgradeType: websocket + - match: + pathSeparatedPrefix: /override + name: httproute/default/httproute-4/rule/0/match/0/listener_scope_example_com + route: + cluster: httproute/default/httproute-4/rule/0 + upgradeConfigs: + - upgradeType: websocket + typedPerFilterConfig: + envoy.filters.http.filter_chain.eep.listener: '@type': type.googleapis.com/envoy.config.route.v3.FilterConfig - config: {} - envoy.filters.http.wasm/envoyextensionpolicy/envoy-gateway/policy-for-gateway/wasm/2: + disabled: true + envoy.filters.http.filter_chain.eep.route: + '@type': type.googleapis.com/envoy.extensions.filters.http.filter_chain.v3.FilterChainConfigPerRoute + filterChain: + filters: + - name: envoy.filters.http.wasm/0 + typedConfig: + '@type': type.googleapis.com/envoy.extensions.filters.http.wasm.v3.Wasm + config: + configuration: + '@type': type.googleapis.com/google.protobuf.StringValue + value: "" + name: wasm-filter-route-override + vmConfig: + code: + remote: + httpUri: + cluster: wasm_cluster + timeout: 10s + uri: https://envoy-gateway.envoy-gateway-system.svc.cluster.local:18002/9d2e2b3c4d5e6f7a8b9c0d1e2f3a4b5c6d7e8f9a0b1c2d3e4f5a6b7c8d9e0f1a.wasm + retryPolicy: + numRetries: 10 + retryBackOff: + baseInterval: 1s + maxInterval: 30s + sha256: 9d2e2b3c4d5e6f7a8b9c0d1e2f3a4b5c6d7e8f9a0b1c2d3e4f5a6b7c8d9e0f1a + runtime: envoy.wasm.runtime.v8 + vmId: envoyextensionpolicy/default/policy-for-route-4/wasm/0 + - match: + pathSeparatedPrefix: /same-name + name: httproute/default/httproute-5/rule/0/match/0/listener_scope_example_com + route: + cluster: httproute/default/httproute-5/rule/0 + upgradeConfigs: + - upgradeType: websocket + typedPerFilterConfig: + envoy.filters.http.filter_chain.eep.listener: '@type': type.googleapis.com/envoy.config.route.v3.FilterConfig - config: {} + disabled: true + envoy.filters.http.filter_chain.eep.route: + '@type': type.googleapis.com/envoy.extensions.filters.http.filter_chain.v3.FilterChainConfigPerRoute + filterChain: + filters: + - name: envoy.filters.http.wasm/0 + typedConfig: + '@type': type.googleapis.com/envoy.extensions.filters.http.wasm.v3.Wasm + config: + configuration: + '@type': type.googleapis.com/google.protobuf.StringValue + value: "" + name: wasm-filter-listener + vmConfig: + code: + remote: + httpUri: + cluster: wasm_cluster + timeout: 10s + uri: https://envoy-gateway.envoy-gateway-system.svc.cluster.local:18002/8c1f1a2b3c4d5e6f7a8b9c0d1e2f3a4b5c6d7e8f9a0b1c2d3e4f5a6b7c8d9e0f.wasm + retryPolicy: + numRetries: 10 + retryBackOff: + baseInterval: 1s + maxInterval: 30s + sha256: 8c1f1a2b3c4d5e6f7a8b9c0d1e2f3a4b5c6d7e8f9a0b1c2d3e4f5a6b7c8d9e0f + runtime: envoy.wasm.runtime.v8 + vmId: envoyextensionpolicy/envoy-gateway/policy-for-gateway-listener/wasm/0 + typedPerFilterConfig: + envoy.filters.http.filter_chain.eep.listener: + '@type': type.googleapis.com/envoy.extensions.filters.http.filter_chain.v3.FilterChainConfigPerRoute + filterChain: + filters: + - name: envoy.filters.http.wasm/listener/0 + typedConfig: + '@type': type.googleapis.com/envoy.extensions.filters.http.wasm.v3.Wasm + config: + configuration: + '@type': type.googleapis.com/google.protobuf.StringValue + value: "" + name: wasm-filter-listener + vmConfig: + code: + remote: + httpUri: + cluster: wasm_cluster + timeout: 10s + uri: https://envoy-gateway.envoy-gateway-system.svc.cluster.local:18002/8c1f1a2b3c4d5e6f7a8b9c0d1e2f3a4b5c6d7e8f9a0b1c2d3e4f5a6b7c8d9e0f.wasm + retryPolicy: + numRetries: 10 + retryBackOff: + baseInterval: 1s + maxInterval: 30s + sha256: 8c1f1a2b3c4d5e6f7a8b9c0d1e2f3a4b5c6d7e8f9a0b1c2d3e4f5a6b7c8d9e0f + runtime: envoy.wasm.runtime.v8 + vmId: envoyextensionpolicy/envoy-gateway/policy-for-gateway-listener/wasm/0 diff --git a/internal/xds/translator/translator.go b/internal/xds/translator/translator.go index 87f7ba4f9b..c05afb268b 100644 --- a/internal/xds/translator/translator.go +++ b/internal/xds/translator/translator.go @@ -519,7 +519,7 @@ func (t *Translator) processHTTPListenerXdsTranslation( // Add all the other needed resources referenced by this filter to the // resource version table. - if err = patchResources(tCtx, httpListener.Routes); err != nil { + if err = patchResources(tCtx, httpListener, httpListener.Routes); err != nil { errs = errors.Join(errs, err) } } @@ -732,6 +732,10 @@ func (t *Translator) addRouteToRouteConfig( } for _, vHost := range vHostList { + if err = patchVirtualHost(vHost, httpListener); err != nil { + errs = errors.Join(errs, err) + } + // Check if an extension want to modify the Virtual Host we just generated // If no extension exists (or it doesn't subscribe to this hook) then this is a quick no-op. if err = processExtensionPostVHostHook(vHost, t.ExtensionManager); err != nil { diff --git a/internal/xds/translator/utils.go b/internal/xds/translator/utils.go index e2cdc3c88f..1d5c192557 100644 --- a/internal/xds/translator/utils.go +++ b/internal/xds/translator/utils.go @@ -10,12 +10,14 @@ import ( "fmt" "net/netip" "net/url" + "sort" "strconv" "strings" "time" corev3 "github.com/envoyproxy/go-control-plane/envoy/config/core/v3" routev3 "github.com/envoyproxy/go-control-plane/envoy/config/route/v3" + filterchainv3 "github.com/envoyproxy/go-control-plane/envoy/extensions/filters/http/filter_chain/v3" hcmv3 "github.com/envoyproxy/go-control-plane/envoy/extensions/filters/network/http_connection_manager/v3" "google.golang.org/protobuf/proto" "google.golang.org/protobuf/types/known/anypb" @@ -123,6 +125,137 @@ func perRouteFilterName(filterType egv1a1.EnvoyFilter, configName string) string return fmt.Sprintf("%s/%s", filterType, configName) } +// buildHCMFilterChainFilter returns a disabled envoy.filters.http.filter_chain placeholder +// filter with the given stable name. Shared by extension types (Lua, ExtProc, Wasm, +// DynamicModule) whose EnvoyExtensionPolicy API allows an ordered list of instances per +// listener/route but whose native Envoy filter can only be overridden with a single instance +// per route. The placeholder's name never changes as instances are added/removed, so the HCM's +// filter list stays stable (no LDS update / connection drain); the actual ordered list of +// instances is delivered separately via FilterChainConfigPerRoute in TypedPerFilterConfig. +func buildHCMFilterChainFilter(filterName string) (*hcmv3.HttpFilter, error) { + var ( + fcProto *filterchainv3.FilterChainConfig + fcAny *anypb.Any + err error + ) + fcProto = &filterchainv3.FilterChainConfig{} + + if err = fcProto.ValidateAll(); err != nil { + return nil, err + } + if fcAny, err = anypb.New(fcProto); err != nil { + return nil, err + } + + return &hcmv3.HttpFilter{ + Name: filterName, + Disabled: true, + ConfigType: &hcmv3.HttpFilter_TypedConfig{ + TypedConfig: fcAny, + }, + }, nil +} + +// filterChainFilterNamePrefixForEEP is the stable HCM-level filter name shared by every +// EnvoyExtensionPolicy extension type (Lua, ExtProc, Wasm, DynamicModule) that is delivered via +// an envoy.filters.http.filter_chain placeholder. All extension types share the same two +// placeholders (this name, and this name + ".listener") rather than each getting their own, so +// adding/removing an instance of any extension type never changes the HCM's filter list. +const filterChainFilterNamePrefixForEEP = "envoy.filters.http.filter_chain.eep" + +// eepFCFilterName returns the stable HCM-level filter name for the shared, per-route +// EnvoyExtensionPolicy filter_chain placeholder. Every extension type (Lua, ExtProc, Wasm, +// DynamicModule) delivers its route-scoped instances through this single placeholder rather than +// each type getting its own, so adding/removing an instance of any type never changes the HCM's +// filter list. +func eepFCFilterName() string { + return filterChainFilterNamePrefixForEEP + ".route" +} + +// eepListenerFCFilterName returns the stable HCM-level filter name for the shared, per-listener +// (per-connection) EnvoyExtensionPolicy filter_chain placeholder. See eepFCFilterName. +func eepListenerFCFilterName() string { + return filterChainFilterNamePrefixForEEP + ".listener" +} + +// eepSubFilterPriority orders sub-filters within a shared filter_chain placeholder's inner +// FilterChain across extension types: Lua runs before ExtProc, which runs before Wasm, which +// runs before DynamicModule. Instances of the same type keep the relative order they were +// appended in (stable sort), which is already the ordered EnvoyExtensionPolicy list order. +func eepSubFilterPriority(name string) int { + switch { + case strings.HasPrefix(name, string(egv1a1.EnvoyFilterLua)): + return 0 + case strings.HasPrefix(name, string(egv1a1.EnvoyFilterExtProc)): + return 1 + case strings.HasPrefix(name, string(egv1a1.EnvoyFilterWasm)): + return 2 + case strings.HasPrefix(name, string(egv1a1.EnvoyFilterDynamicModules)): + return 3 + default: + return 99 + } +} + +// mergeFilterChainConfigPerRoute merges newFilters into the FilterChainConfigPerRoute already +// stored at existing (nil if none yet), re-sorting the combined inner FilterChain so that +// multiple extension types sharing the same filter_chain placeholder still run in a stable, +// predictable cross-type order instead of whatever order patchRoute/patchVirtualHost happened to +// be called in for this route/virtual host. +func mergeFilterChainConfigPerRoute(existing *anypb.Any, newFilters []*corev3.TypedExtensionConfig) (*anypb.Any, error) { + fc := &filterchainv3.FilterChainConfigPerRoute{FilterChain: &filterchainv3.FilterChain{}} + if existing != nil { + if err := existing.UnmarshalTo(fc); err != nil { + return nil, err + } + if fc.FilterChain == nil { + fc.FilterChain = &filterchainv3.FilterChain{} + } + } + + fc.FilterChain.Filters = append(fc.FilterChain.Filters, newFilters...) + sort.SliceStable(fc.FilterChain.Filters, func(i, j int) bool { + return eepSubFilterPriority(fc.FilterChain.Filters[i].Name) < eepSubFilterPriority(fc.FilterChain.Filters[j].Name) + }) + + return anypb.New(fc) +} + +// disableFilterOnRouteOnce disables filterName on the route unless some TypedPerFilterConfig is +// already set under that name. Several extension types can all want to disable the same shared +// filter_chain placeholder for a route that fully overrides listener-scoped extensions, so unlike +// enableFilterOnRoute this must tolerate being called more than once for the same route/filter. +func disableFilterOnRouteOnce(route *routev3.Route, filterName string) error { + if _, ok := route.GetTypedPerFilterConfig()[filterName]; ok { + return nil + } + return enableFilterOnRoute(route, filterName, &routev3.FilterConfig{Disabled: true}) +} + +// filterChainAlreadyHasType reports whether the FilterChainConfigPerRoute stored at existing (if +// any) already contains a sub-filter of the given type. Used by patchVirtualHost to stay +// idempotent per extension type: unlike the old per-type placeholder, the shared filter_chain key +// may already carry a different type's contribution, so "the key is set" no longer implies "this +// type already delivered its filters here". +func filterChainAlreadyHasType(existing *anypb.Any, filterType egv1a1.EnvoyFilter) (bool, error) { + if existing == nil { + return false, nil + } + fc := &filterchainv3.FilterChainConfigPerRoute{} + if err := existing.UnmarshalTo(fc); err != nil { + return false, err + } + if fc.FilterChain == nil { + return false, nil + } + for _, f := range fc.FilterChain.Filters { + if strings.HasPrefix(f.Name, string(filterType)) { + return true, nil + } + } + return false, nil +} + func hcmContainsFilter(mgr *hcmv3.HttpConnectionManager, filterName string) bool { for _, existingFilter := range mgr.HttpFilters { if existingFilter.Name == filterName { diff --git a/internal/xds/translator/wasm.go b/internal/xds/translator/wasm.go index 16b3500ab6..51997a747d 100644 --- a/internal/xds/translator/wasm.go +++ b/internal/xds/translator/wasm.go @@ -7,6 +7,9 @@ package translator import ( "errors" + "fmt" + "slices" + "strconv" "time" corev3 "github.com/envoyproxy/go-control-plane/envoy/config/core/v3" @@ -44,13 +47,21 @@ type wasm struct{} var _ httpFilter = &wasm{} -// patchHCM builds and appends the wasm Filters to the HTTP Connection Manager -// if applicable, and it does not already exist. -// Note: this method creates a wasm filter for each route that contains an wasm config. -// The filter is disabled by default. It is enabled on the route level. +// patchHCM adds disabled envoy.filters.http.filter_chain placeholder filters to the HTTP +// Connection Manager: one for per-listener (per-connection) Wasm and one for per-route Wasm. +// +// Both placeholders are added together as soon as either scope has a Wasm policy anywhere on +// this listener, even if the other scope currently has none. This keeps the HCM's filter set +// stable across that kind of policy churn too: e.g. adding a per-listener Wasm policy later to +// a listener that already has per-route Wasm only changes route/virtual host +// TypedPerFilterConfig (an RDS update), never the listener's filter list (which would require +// an LDS update and a connection drain). +// +// Wasm has no native per-route override at all, while EG's EnvoyExtensionPolicy API allows an +// ordered list of Wasm filters per listener/route. The filter_chain filter wraps an ordered, +// named sub-chain of Wasm filters that is supplied separately (per virtual host for +// listener-scoped Wasm, per route for route-scoped Wasm). func (*wasm) patchHCM(mgr *hcmv3.HttpConnectionManager, irListener *ir.HTTPListener) error { - var errs error - if mgr == nil { return errors.New("hcm is nil") } @@ -58,54 +69,38 @@ func (*wasm) patchHCM(mgr *hcmv3.HttpConnectionManager, irListener *ir.HTTPListe return errors.New("ir listener is nil") } - for _, route := range irListener.Routes { - if !routeContainsWasm(route) { + hasListenerWasm := listenerContainsWasm(irListener) + hasRouteWasm := slices.ContainsFunc(irListener.Routes, routeContainsWasm) + if !hasListenerWasm && !hasRouteWasm { + return nil + } + + for _, filterName := range []string{eepListenerFCFilterName(), eepFCFilterName()} { + if hcmContainsFilter(mgr, filterName) { continue } - for _, ep := range route.EnvoyExtensions.Wasms { - if hcmContainsFilter(mgr, wasmFilterName(&ep)) { - continue - } - filter, err := buildHCMWasmFilter(&ep) - if err != nil { - errs = errors.Join(errs, err) - continue - } - mgr.HttpFilters = append(mgr.HttpFilters, filter) + filter, err := buildHCMFilterChainFilter(filterName) + if err != nil { + return err } + mgr.HttpFilters = append(mgr.HttpFilters, filter) } - return errs + return nil } -// buildHCMWasmFilter returns a wasm HTTP filter from the provided IR HTTPRoute. -func buildHCMWasmFilter(wasm *ir.Wasm) (*hcmv3.HttpFilter, error) { - var ( - wasmProto *wasmfilterv3.Wasm - wasmAny *anypb.Any - err error - ) - - if wasmProto, err = wasmConfig(wasm); err != nil { - return nil, err - } - if wasmAny, err = anypb.New(wasmProto); err != nil { - return nil, err - } - - // All wasm filters for all Routes are aggregated on HCM and disabled by default - // Per-route config is used to enable the relevant filters on appropriate routes - return &hcmv3.HttpFilter{ - Name: wasmFilterName(wasm), - Disabled: true, - ConfigType: &hcmv3.HttpFilter_TypedConfig{ - TypedConfig: wasmAny, - }, - }, nil +// wasmSubFilterName returns the stable top-level filter name for the per-route Wasm slot index. +// The index is the execution slot within the ordered EnvoyExtensionPolicy Wasm list, so route +// 0th modules always bind to the same listener-level filter. +func wasmSubFilterName(idx int) string { + return perRouteFilterName(egv1a1.EnvoyFilterWasm, strconv.Itoa(idx)) } -func wasmFilterName(wasm *ir.Wasm) string { - return perRouteFilterName(egv1a1.EnvoyFilterWasm, wasm.Name) +// wasmListenerSubFilterName returns the stable HCM-level filter name for a listener-level Wasm +// slot. Using the envoy.filters.http.wasm prefix (instead of the raw policy name) ensures +// sortHTTPFilters assigns it the correct order relative to route-level slots. +func wasmListenerSubFilterName(idx int) string { + return fmt.Sprintf("%s/listener/%d", egv1a1.EnvoyFilterWasm, idx) } func wasmConfig(wasm *ir.Wasm) (*wasmfilterv3.Wasm, error) { @@ -183,8 +178,13 @@ func routeContainsWasm(irRoute *ir.HTTPRoute) bool { return irRoute.EnvoyExtensions != nil && len(irRoute.EnvoyExtensions.Wasms) > 0 } +// listenerContainsWasm returns true if Wasms exist at listener scope. +func listenerContainsWasm(irListener *ir.HTTPListener) bool { + return irListener != nil && irListener.EnvoyExtensions != nil && len(irListener.EnvoyExtensions.Wasms) > 0 +} + // patchResources patches the cluster resources for the http wasm code source. -func (*wasm) patchResources(_ *types.ResourceVersionTable, _ []*ir.HTTPRoute) error { +func (*wasm) patchResources(_ *types.ResourceVersionTable, _ *ir.HTTPListener, _ []*ir.HTTPRoute) error { // EG always serves the Wasm module through the built-in HTTP server, which // has been configured in the bootstrap configuration. So we don't need to // create a cluster for the Wasm module. @@ -192,7 +192,14 @@ func (*wasm) patchResources(_ *types.ResourceVersionTable, _ []*ir.HTTPRoute) er } // patchRoute patches the provided route with the wasm config if applicable. -// Note: this method enables the corresponding wasm filter for the provided route. +// +// A nil EnvoyExtensions means no route-scoped policy owns this route: it keeps inheriting the +// listener-scoped Wasms delivered at VirtualHost scope by patchVirtualHost. +// +// A non-nil EnvoyExtensions means a more specific (xRoute or route rule) policy owns this route +// and fully replaces — never merges with — the listener-scoped policy. The extension count is +// intentionally not checked: an empty result (e.g. fail-open invalid Wasm) still represents a +// more specific policy that owns this route and must suppress the lower-scope Wasms. func (*wasm) patchRoute(route *routev3.Route, irRoute *ir.HTTPRoute, _ *ir.HTTPListener) error { if route == nil { return errors.New("xds route is nil") @@ -204,13 +211,87 @@ func (*wasm) patchRoute(route *routev3.Route, irRoute *ir.HTTPRoute, _ *ir.HTTPL return nil } - for _, ep := range irRoute.EnvoyExtensions.Wasms { - filterName := wasmFilterName(&ep) - if err := enableFilterOnRoute(route, filterName, &routev3.FilterConfig{ - Config: &anypb.Any{}, - }); err != nil { + // A non-nil EnvoyExtensions means a more specific route policy owns this route and fully + // replaces the listener-scoped policy. The extension count is intentionally not checked + // here: an empty result (e.g. fail-open invalid Wasm) still represents a more specific + // policy that owns this route and must suppress the lower-scope Wasm. + if err := disableFilterOnRouteOnce(route, eepListenerFCFilterName()); err != nil { + return err + } + + var newFilters []*corev3.TypedExtensionConfig + for idx := range irRoute.EnvoyExtensions.Wasms { + cfg, err := wasmConfig(&irRoute.EnvoyExtensions.Wasms[idx]) + if err != nil { + return err + } + cfgAny, err := anypb.New(cfg) + if err != nil { return err } + newFilters = append(newFilters, &corev3.TypedExtensionConfig{ + Name: wasmSubFilterName(idx), + TypedConfig: cfgAny, + }) + } + + if len(newFilters) == 0 { + return nil + } + + merged, err := mergeFilterChainConfigPerRoute(route.GetTypedPerFilterConfig()[eepFCFilterName()], newFilters) + if err != nil { + return err + } + if route.TypedPerFilterConfig == nil { + route.TypedPerFilterConfig = make(map[string]*anypb.Any) + } + route.TypedPerFilterConfig[eepFCFilterName()] = merged + return nil +} + +// patchVirtualHost enables the listener-scoped Wasm filters at VirtualHost scope so a listener's +// policy does not bleed into virtual hosts belonging to a different listener that shares the same +// RouteConfiguration. Delivery via VirtualHost TypedPerFilterConfig goes through RDS, so policy +// changes do not trigger listener drains. +func (*wasm) patchVirtualHost(vh *routev3.VirtualHost, httpListener *ir.HTTPListener) error { + if !listenerContainsWasm(httpListener) { + return nil + } + + filterName := eepListenerFCFilterName() + existing := vh.GetTypedPerFilterConfig()[filterName] + alreadyDelivered, err := filterChainAlreadyHasType(existing, egv1a1.EnvoyFilterWasm) + if err != nil { + return err + } + if alreadyDelivered { + return nil + } + + var newFilters []*corev3.TypedExtensionConfig + for idx := range httpListener.EnvoyExtensions.Wasms { + cfg, err := wasmConfig(&httpListener.EnvoyExtensions.Wasms[idx]) + if err != nil { + return err + } + cfgAny, err := anypb.New(cfg) + if err != nil { + return err + } + newFilters = append(newFilters, &corev3.TypedExtensionConfig{ + Name: wasmListenerSubFilterName(idx), + TypedConfig: cfgAny, + }) + } + + merged, err := mergeFilterChainConfigPerRoute(existing, newFilters) + if err != nil { + return err + } + if vh.TypedPerFilterConfig == nil { + vh.TypedPerFilterConfig = make(map[string]*anypb.Any) } + vh.TypedPerFilterConfig[filterName] = merged return nil } diff --git a/release-notes/current/breaking_changes/9131-xds-layout-per-route-filterchain.md b/release-notes/current/breaking_changes/9131-xds-layout-per-route-filterchain.md new file mode 100644 index 0000000000..520f375955 --- /dev/null +++ b/release-notes/current/breaking_changes/9131-xds-layout-per-route-filterchain.md @@ -0,0 +1 @@ +The xDS layout for EnvoyExtensionPolicies (both Gateway/listener-targeted and HTTPRoute-targeted) has changed. Any EnvoyPatchPolicy rules or extension-server logic that reads or patches the old extension filter names or per-route config shape will break and must be updated to match the new layout. diff --git a/test/e2e/testdata/lua-http.yaml b/test/e2e/testdata/lua-http.yaml index af509b24a4..c93669c4a1 100644 --- a/test/e2e/testdata/lua-http.yaml +++ b/test/e2e/testdata/lua-http.yaml @@ -7,6 +7,7 @@ metadata: spec: parentRefs: - name: same-namespace + - name: all-namespaces hostnames: ["www.example.com"] rules: - matches: @@ -43,6 +44,7 @@ metadata: spec: parentRefs: - name: same-namespace + - name: all-namespaces hostnames: ["www.example.com"] rules: - matches: @@ -101,6 +103,23 @@ data: --- apiVersion: gateway.envoyproxy.io/v1alpha1 kind: EnvoyExtensionPolicy +metadata: + name: lua-for-gateway + namespace: gateway-conformance-infra +spec: + targetRefs: + - group: gateway.networking.k8s.io + kind: Gateway + name: same-namespace + lua: + - type: Inline + inline: | + function envoy_on_response(response_handle) + response_handle:headers():add("X-Custom-Response-Header", "gateway") + end +--- +apiVersion: gateway.envoyproxy.io/v1alpha1 +kind: EnvoyExtensionPolicy metadata: name: example-lua-1 namespace: gateway-conformance-infra diff --git a/test/e2e/tests/lua_http.go b/test/e2e/tests/lua_http.go index e2dc561ea4..92c87438e7 100644 --- a/test/e2e/tests/lua_http.go +++ b/test/e2e/tests/lua_http.go @@ -8,18 +8,33 @@ package tests import ( + "context" + "fmt" "testing" + "time" + "github.com/prometheus/common/model" "k8s.io/apimachinery/pkg/types" + "k8s.io/apimachinery/pkg/util/wait" gwapiv1 "sigs.k8s.io/gateway-api/apis/v1" "sigs.k8s.io/gateway-api/conformance/utils/http" "sigs.k8s.io/gateway-api/conformance/utils/kubernetes" "sigs.k8s.io/gateway-api/conformance/utils/suite" + "sigs.k8s.io/gateway-api/conformance/utils/tlog" "github.com/envoyproxy/gateway/internal/gatewayapi" "github.com/envoyproxy/gateway/internal/gatewayapi/resource" + "github.com/envoyproxy/gateway/test/utils/prometheus" ) +// maxExpectedLuaVMCount bounds the "lua.lua_vm_count" gauge (added in +// https://github.com/envoyproxy/envoy/pull/45871) for this test's fixture. lua-http.yaml +// configures 4 distinct Lua scripts (gateway-level, route1, route2, route4), and each +// configured script accounts for at most (concurrency + 1) VMs. This is a generous cap on +// concurrency to catch a real blow-up (e.g. a VM created per-route or per-request) without +// being sensitive to the worker thread count of the CI machine. +const maxExpectedLuaVMCount = 4 * 33 + func init() { ConformanceTests = append(ConformanceTests, HTTPLuaTest) } @@ -55,20 +70,15 @@ var HTTPLuaTest = suite.ConformanceTest{ Headers: map[string]string{ "X-Custom-Lua-Header": "lua_value_1", }, - AbsentHeaders: []string{"X-Custom-Lua-Another-Header"}, + AbsentHeaders: []string{ + "X-Custom-Response-Header", // gateway policy never took effect + "X-Custom-Lua-Another-Header", + }, }, Namespace: ns, } - req := http.MakeRequest(t, &expectedResponse, gwAddr, "HTTP", "http") - cReq, cResp, err := suite.RoundTripper.CaptureRoundTrip(req) - if err != nil { - t.Errorf("failed to get expected response: %v", err) - } - - if err := http.CompareRoundTrip(t, &req, cReq, cResp, expectedResponse); err != nil { - t.Errorf("failed to compare request and response: %v", err) - } + http.MakeRequestAndExpectEventuallyConsistentResponse(t, suite.RoundTripper, suite.TimeoutConfig, gwAddr, expectedResponse) }) t.Run("http route with lua filter 2", func(t *testing.T) { @@ -97,22 +107,17 @@ var HTTPLuaTest = suite.ConformanceTest{ "X-Custom-Lua-Header": "lua_value_2", "X-Custom-Lua-Another-Header": "lua_another_value", }, + AbsentHeaders: []string{ + "X-Custom-Response-Header", // gateway policy never took effect + }, }, Namespace: ns, } - req := http.MakeRequest(t, &expectedResponse, gwAddr, "HTTP", "http") - cReq, cResp, err := suite.RoundTripper.CaptureRoundTrip(req) - if err != nil { - t.Errorf("failed to get expected response: %v", err) - } - - if err := http.CompareRoundTrip(t, &req, cReq, cResp, expectedResponse); err != nil { - t.Errorf("failed to compare request and response: %v", err) - } + http.MakeRequestAndExpectEventuallyConsistentResponse(t, suite.RoundTripper, suite.TimeoutConfig, gwAddr, expectedResponse) }) - t.Run("http route without lua filter", func(t *testing.T) { + t.Run("http route fallback to gateway policy", func(t *testing.T) { ns := "gateway-conformance-infra" routeNN := types.NamespacedName{Name: "example-route-3-without-lua", Namespace: ns} gwNN := types.NamespacedName{Name: "same-namespace", Namespace: ns} @@ -133,21 +138,18 @@ var HTTPLuaTest = suite.ConformanceTest{ Path: "/route3", }, Response: http.Response{ - StatusCodes: []int{200}, - AbsentHeaders: []string{"X-Custom-Lua-Header", "X-Custom-Lua-Another-Header"}, + StatusCodes: []int{200}, + Headers: map[string]string{ + "X-Custom-Response-Header": "gateway", // fallback to gateway policy + }, + AbsentHeaders: []string{ + "X-Custom-Lua-Header", "X-Custom-Lua-Another-Header", + }, }, Namespace: ns, } - req := http.MakeRequest(t, &expectedResponse, gwAddr, "HTTP", "http") - cReq, cResp, err := suite.RoundTripper.CaptureRoundTrip(req) - if err != nil { - t.Errorf("failed to get expected response: %v", err) - } - - if err := http.CompareRoundTrip(t, &req, cReq, cResp, expectedResponse); err != nil { - t.Errorf("failed to compare request and response: %v", err) - } + http.MakeRequestAndExpectEventuallyConsistentResponse(t, suite.RoundTripper, suite.TimeoutConfig, gwAddr, expectedResponse) }) t.Run("http route with lua filter context", func(t *testing.T) { @@ -174,11 +176,83 @@ var HTTPLuaTest = suite.ConformanceTest{ Headers: map[string]string{ "X-Lua-Filter-Context": "hello_from_filter_context", }, + AbsentHeaders: []string{ + "X-Custom-Response-Header", // gateway policy never took effect + }, }, Namespace: ns, } http.MakeRequestAndExpectEventuallyConsistentResponse(t, suite.RoundTripper, suite.TimeoutConfig, gwAddr, expectedResponse) }) + + t.Run("http route without lua filter", func(t *testing.T) { + ns := "gateway-conformance-infra" + routeNN := types.NamespacedName{Name: "example-route-3-without-lua", Namespace: ns} + gwNN := types.NamespacedName{Name: "all-namespaces", Namespace: ns} + gwAddr := kubernetes.GatewayAndRoutesMustBeAccepted(t, suite.Client, suite.TimeoutConfig, suite.ControllerName, kubernetes.NewGatewayRef(gwNN), &gwapiv1.HTTPRoute{}, false, routeNN) + + ancestorRef := gwapiv1.ParentReference{ + Group: gatewayapi.GroupPtr(gwapiv1.GroupName), + Kind: gatewayapi.KindPtr(resource.KindGateway), + Namespace: gatewayapi.NamespacePtr(gwNN.Namespace), + Name: gwapiv1.ObjectName(gwNN.Name), + } + EnvoyExtensionPolicyMustBeAccepted(t, suite.Client, types.NamespacedName{Name: "example-lua-1", Namespace: ns}, suite.ControllerName, ancestorRef) + + expectedResponse := http.ExpectedResponse{ + Request: http.Request{ + Host: "www.example.com", + Path: "/route3", + }, + Response: http.Response{ + StatusCodes: []int{200}, + AbsentHeaders: []string{ + "X-Custom-Response-Header", // no policy for all-namespaces gatweway + "X-Custom-Lua-Header", "X-Custom-Lua-Another-Header", + }, + }, + Namespace: ns, + } + + http.MakeRequestAndExpectEventuallyConsistentResponse(t, suite.RoundTripper, suite.TimeoutConfig, gwAddr, expectedResponse) + }) + + // Regression check for https://github.com/envoyproxy/envoy/issues/9355-style VM blow-ups: + // the fixture above configures 4 distinct Lua scripts (gateway-level + 3 route-level), + // so the "lua.lua_vm_count" gauge should settle at a small, bounded value rather than + // growing per-route or per-request. + t.Run("lua vm count stays bounded", func(t *testing.T) { + // Sum across all "same-namespace" proxy replicas/pods so multi-replica setups + // don't produce more than one time series. + promQL := `sum(envoy_lua_lua_vm_count{app_kubernetes_io_component="proxy", app_kubernetes_io_managed_by="envoy-gateway", app_kubernetes_io_name="envoy", gateway_envoyproxy_io_owning_gateway_name="same-namespace"})` + + if err := wait.PollUntilContextTimeout(context.TODO(), time.Second, time.Minute, true, + func(_ context.Context) (done bool, err error) { + v, err := prometheus.QueryPrometheus(suite.Client, promQL) + if err != nil { + tlog.Logf(t, "failed to query prometheus: %v", err) + return false, nil + } + if v != nil && v.Type() == model.ValVector { + vectorVal := v.(model.Vector) + // Wait for the gauge to appear (present and non-zero) before judging it, + // since it's only populated once Envoy has loaded the Lua filter config. + if len(vectorVal) == 1 && vectorVal[0].Value > 0 { + tlog.Logf(t, "got lua_vm_count value: %v", vectorVal[0].Value) + if vectorVal[0].Value > maxExpectedLuaVMCount { + // Fail outright instead of retrying: once the gauge is reporting, + // exceeding the bound means VMs are leaking/duplicating, and more + // polling won't make that false. + return false, fmt.Errorf("lua_vm_count %v exceeds expected bound %d", vectorVal[0].Value, maxExpectedLuaVMCount) + } + return true, nil + } + } + return false, nil + }); err != nil { + t.Errorf("failed to get expected lua_vm_count metric: %v", err) + } + }) }, } diff --git a/test/e2e/tests/wasm_http.go b/test/e2e/tests/wasm_http.go index 095588d874..03d769ff17 100644 --- a/test/e2e/tests/wasm_http.go +++ b/test/e2e/tests/wasm_http.go @@ -80,10 +80,11 @@ var HTTPWasmTest = suite.ConformanceTest{ // filters"), so each of the 2 wasm-configured routes above gets its own dedicated Wasm // filter/VM even though both reference the same underlying .wasm module. The // process-wide "wasm.wasm_vm_count" gauge should therefore read exactly 3* worker thread. + tlog.Logf(t, "concurrency: %d", runtime.NumCPU()) t.Run("wasm vm count is per-route", func(t *testing.T) { promQL := `sum(envoy_wasm_wasm_vm_count{app_kubernetes_io_component="proxy", app_kubernetes_io_managed_by="envoy-gateway", app_kubernetes_io_name="envoy", gateway_envoyproxy_io_owning_gateway_name="same-namespace"})` - // 3 is the count of routes - expectedCount := model.SampleValue(3 * runtime.NumCPU()) + // 2 is the count of routes with WASM + expectedCount := model.SampleValue(2 * (runtime.NumCPU() + 2)) tlog.Logf(t, "expected to got %v", expectedCount) if err := wait.PollUntilContextTimeout(context.TODO(), time.Second, time.Minute, true, func(_ context.Context) (done bool, err error) {