122 lines
4.0 KiB
Bash
Executable File
122 lines
4.0 KiB
Bash
Executable File
#!/bin/bash
|
|
|
|
set -exu -o pipefail
|
|
|
|
if [ "$#" -ne 5 ]; then
|
|
echo "Usage: ./zprox localport grpcaddr grpcport assetsaddr assetsport"
|
|
echo "localport: the port envoy proxy should listen"
|
|
echo "grpcaddr, grpcport: the addr+port of the gRPC service"
|
|
echo "assetsaddr, assetsport: the ip+port of the web server serving zpages assets (html, js, etc)"
|
|
exit 1
|
|
fi
|
|
|
|
|
|
TEMP=$(mktemp --suffix=.yaml)
|
|
function finish {
|
|
rm "$TEMP"
|
|
}
|
|
trap finish EXIT
|
|
|
|
readonly LOCAL_PORT=$1
|
|
readonly GRPC_ADDR=$2
|
|
readonly GRPC_PORT=$3
|
|
readonly ASSETS_ADDR=$4
|
|
readonly ASSETS_PORT=$5
|
|
|
|
readonly GDEBUG_TOKEN_NAME="gdebug-xsrf-token"
|
|
|
|
cat > "$TEMP" <<TERMINATOR
|
|
static_resources:
|
|
listeners:
|
|
- name: my_listener
|
|
address:
|
|
socket_address:
|
|
address: 0.0.0.0
|
|
port_value: $LOCAL_PORT
|
|
filter_chains:
|
|
- filters:
|
|
- name: envoy.http_connection_manager
|
|
config:
|
|
codec_type: auto
|
|
stat_prefix: ingress_http
|
|
route_config:
|
|
name: local_route
|
|
virtual_hosts:
|
|
- name: local_service
|
|
domains:
|
|
- "*"
|
|
routes:
|
|
- match:
|
|
prefix: "/"
|
|
headers:
|
|
- name: "Content-Type"
|
|
prefix_match: "application/grpc-web"
|
|
route:
|
|
cluster: local_service_grpc
|
|
- match:
|
|
prefix: "/"
|
|
route:
|
|
cluster: local_service_web
|
|
http_filters:
|
|
- name: envoy.lua
|
|
config:
|
|
inline_code: |
|
|
function envoy_on_request(request_handle)
|
|
-- hyphens are special characters in lua search patterns and must be escaped with a %
|
|
function esc_hyphens(s)
|
|
result, _ = string.gsub(s, "%-", "%%%-")
|
|
return result
|
|
end
|
|
headers = request_handle:headers()
|
|
content_type = headers:get("content-type")
|
|
if content_type and string.find(content_type, esc_hyphens("application/grpc-web")) then
|
|
xsrf_header = headers:get("$GDEBUG_TOKEN_NAME")
|
|
-- There can be only one cookie header: https://tools.ietf.org/html/rfc6265#section-5.4
|
|
cookies = headers:get("cookie") or ""
|
|
-- The token value is a base64 encoded binary and may have trailing = characters for padding
|
|
-- This is written as two statements because of lua's str matching limitations
|
|
xsrf_cookie = string.match(cookies, esc_hyphens("^$GDEBUG_TOKEN_NAME=(%w+=*)")) or string.match(cookies, esc_hyphens("; $GDEBUG_TOKEN_NAME=(%w+=*)"))
|
|
-- ~= means "not equals" in lua
|
|
if xsrf_header == nil or xsrf_header == "" or xsrf_cookie == nil or xsrf_cookie == "" or xsrf_header ~= xsrf_cookie then
|
|
request_handle:logInfo("rejecting request: xsrf token not set")
|
|
request_handle:respond({[":status"] = "401"}, "$GDEBUG_TOKEN_NAME must be set")
|
|
end
|
|
end
|
|
end
|
|
- name: envoy.grpc_web
|
|
config: {}
|
|
- name: envoy.router
|
|
access_log:
|
|
name: envoy.file_access_log
|
|
config:
|
|
path: "/dev/stdout"
|
|
clusters:
|
|
- name: local_service_grpc
|
|
connect_timeout: 0.250s
|
|
type: strict_dns
|
|
lb_policy: round_robin
|
|
http2_protocol_options: {}
|
|
hosts:
|
|
- socket_address:
|
|
address: $GRPC_ADDR
|
|
port_value: $GRPC_PORT
|
|
- name: local_service_web
|
|
connect_timeout: 0.250s
|
|
type: strict_dns
|
|
lb_policy: round_robin
|
|
hosts:
|
|
- socket_address:
|
|
address: $ASSETS_ADDR
|
|
port_value: $ASSETS_PORT
|
|
admin:
|
|
access_log_path: "/tmp/envoy/admin_access.log"
|
|
address:
|
|
socket_address:
|
|
address: 0.0.0.0
|
|
port_value: 9901
|
|
TERMINATOR
|
|
|
|
|
|
|
|
/usr/local/bin/envoy --v2-config-only -c "$TEMP"
|