envoy: gRPC Json Transcoder + Options Request from Web Browsers causes 404 for envoy config without a "/" as a matching path
If you are reporting any crash or any potential security issue, do not open an issue in this repo. Please report the issue via emailing envoy-security@googlegroups.com where the issue will be triaged appropriately.
Title: One line description gRPC Json Transcoder + Options Request from Web Browsers causes 404 for envoy config without a “/” as a matching path
Description:
What issue is being seen? Describe what should be happening instead of the bug, for example: Envoy should not crash, the expected value isn’t returned, etc.
CORS + gRPC-JSON transcoder do not translate requests downstream when “/” not specified as a route. OPTIONS returns 404. When multiple clusters are configures - one cannot use “/” as a route, which previously filed bugs have used as a “dummy” route to overcome this issue.
Config:
Include the config used to configure Envoy.
admin:
address:
socket_address: { address: 0.0.0.0, port_value: 9901 }
layered_runtime:
layers:
- name: disable_apple_dns
static_layer:
envoy.restart_features.use_apple_api_for_dns_lookups: false
static_resources:
listeners:
- name: listener1
address:
socket_address: { address: 0.0.0.0, port_value: 5000 }
filter_chains:
- filters:
- name: envoy.filters.network.http_connection_manager
typed_config:
"@type": type.googleapis.com/envoy.extensions.filters.network.http_connection_manager.v3.HttpConnectionManager
stat_prefix: grpc_json
access_log:
- name: envoy.access_loggers.stdout
typed_config:
"@type": type.googleapis.com/envoy.extensions.access_loggers.stream.v3.StdoutAccessLog
codec_type: AUTO
route_config:
name: local_route
virtual_hosts:
- name: local_service
domains: ["*"]
cors:
allow_origin_string_match:
- prefix: "*"
allow_methods: GET, POST, OPTIONS
allow_headers: authorization,keep-alive,user-agent,cache-control,content-type,content-transfer-encoding,x-accept-content-transfer-encoding,x-accept-response-streaming,x-user-agent,x-grpc-web
expose_headers: grpc-status,grpc-message,x-envoy-upstream-service-time
routes:
# NOTE: by default, matching happens based on the gRPC route, and not on the incoming request path.
# Reference: https://www.envoyproxy.io/docs/envoy/latest/configuration/http_filters/grpc_json_transcoder_filter#route-configs-for-transcoded-requests
- match: { prefix: "/commerce.catalog" }
route: { cluster: rust, timeout: 60s }
- match: { prefix: "/fs" }
route: { cluster: rust, timeout: 60s }
- match: { prefix: "/stream" }
route: { cluster: rust, timeout: 60s }
- match: { prefix: "/core.profile" }
route: { cluster: rust, timeout: 60s }
- match: { prefix: "/commerce.order" }
route: { cluster: netty, timeout: 60s }
- match: { prefix: "/commerce.session" }
route: { cluster: netty, timeout: 60s }
- match: { prefix: "/core.auth.AuthenticationApi" }
route: { cluster: netty, timeout: 60s }
- match: { prefix: "/" }
route: { cluster: rust, timeout: 60s }
http_filters:
- name: envoy.filters.http.cors
- name: envoy.filters.http.grpc_json_transcoder
typed_config:
"@type": type.googleapis.com/envoy.extensions.filters.http.grpc_json_transcoder.v3.GrpcJsonTranscoder
proto_descriptor: "/tmp/envoy/proto.pb"
services: ["commerce.catalog.CatalogApi", "commerce.order.OrderApi", "commerce.session.SessionApi", "stream.StreamApi", "core.profile.ProfileApi", "core.auth.AuthenticationApi", "fs.FileApi", "fs.StorageApi"]
print_options:
add_whitespace: true
always_print_primitive_fields: true
always_print_enums_as_ints: true
preserve_proto_field_names: true
- name: envoy.filters.http.router
clusters:
- name: rust
connect_timeout: 30.00s
type: LOGICAL_DNS
lb_policy: ROUND_ROBIN
typed_extension_protocol_options:
envoy.extensions.upstreams.http.v3.HttpProtocolOptions:
"@type": type.googleapis.com/envoy.extensions.upstreams.http.v3.HttpProtocolOptions
explicit_http_config:
http2_protocol_options:
# Configure an HTTP/2 keep-alive to detect connection issues and reconnect
# to the admin server if the connection is no longer responsive.
connection_keepalive:
interval: 30s
timeout: 5s
load_assignment:
cluster_name: rust
endpoints:
- lb_endpoints:
- endpoint:
address:
socket_address:
# WARNING: "docker.for.mac.localhost" has been deprecated from Docker v18.03.0.
# If you're running an older version of Docker, please use "docker.for.mac.localhost" instead.
# Reference: https://docs.docker.com/docker-for-mac/release-notes/#docker-community-edition-18030-ce-mac59-2018-03-26
address: localhost # 172.0.0.1 #host.docker.internal
port_value: 50051
- name: netty
connect_timeout: 30.00s
type: LOGICAL_DNS
lb_policy: ROUND_ROBIN
typed_extension_protocol_options:
envoy.extensions.upstreams.http.v3.HttpProtocolOptions:
"@type": type.googleapis.com/envoy.extensions.upstreams.http.v3.HttpProtocolOptions
explicit_http_config:
http2_protocol_options:
# Configure an HTTP/2 keep-alive to detect connection issues and reconnect
# to the admin server if the connection is no longer responsive.
connection_keepalive:
interval: 30s
timeout: 5s
load_assignment:
cluster_name: netty
endpoints:
- lb_endpoints:
- endpoint:
address:
socket_address:
# WARNING: "docker.for.mac.localhost" has been deprecated from Docker v18.03.0.
# If you're running an older version of Docker, please use "docker.for.mac.localhost" instead.
# Reference: https://docs.docker.com/docker-for-mac/release-notes/#docker-community-edition-18030-ce-mac59-2018-03-26
address: localhost # 172.0.0.1 #host.docker.internal
port_value: 6565
Logs:
Include the access logs and the Envoy logs.
Note: If there are privacy concerns, sanitize the data prior to sharing.
Call Stack:
If the Envoy binary is crashing, a call stack is required. Please refer to the Bazel Stack trace documentation.
About this issue
- Original URL
- State: open
- Created 3 years ago
- Reactions: 2
- Comments: 18 (2 by maintainers)
This is still an issue in the latest version
I think this happens because there usually is no mapping for CORS preflight requests (HTTP method
OPTIONS) in proto files. Thus grpc_json_transcoder filter will not match any routes and router will return a 404. In this case CORS filter is most probably bypassed.You should be able to prevent this by adding additional bindings for HTTP OPTIONS method to each RPC in your proto file (not tested yet):
You then need to make sure that the upstream properly handles those requests. It should at least reply with status code 200 I think.
Another workaround is to add a separate route for OPTIONS requests to envoy configuration (note that this CORS configuration is insecure!):
Please note that according to my testing CORS filter should come after grpc_json_transcoder if you want it to add
access-control-allow-*headers not only to preflight (OPTIONS) requests but also to the “real” (GET, PUT, POST, …) requests.This issue relates to #6608 (with a cleaner fix + https://github.com/envoyproxy/envoy/issues/6608#issuecomment-1827354781) and #7833 I think.
Also see #8262 for why
direct_responsebypasses CORS filter. That’s the reason why I added all those response_headers_to_add to the configuration. When using a route likeroute: {cluster: cluster-grpc-upstream}instead ofdirect_response, this is not needed.