GRPC Proxy not working

I’m attempting to use a proxy for GRPC, but it doesn’t seem to actually use it. From what I’ve seen in other docs, setting HTTP_PROXY and/or HTTPS_PROXY should cause the k6/net/grpc to utilize the environment variables and proxy grpc calls. When I attempt to set it and use example/grpc.js it goes directly to the destination vs going through the proxy. HTTP calls work fine utilizing the environment variable, just not GRPC. Any help would be greatly appreciated.

Below is the output from my test run which was against k6’s own example/grpc.js. Note there is no proxy running and I would expect an error vs all working normally. If I run the same test utilizing HTTP calls, I see errors as expected relating to not being able to connect with localhost:5555.

HTTP_PROXY=localhost:5555 k6 run grpc.js

          /\      |‾‾| /‾‾/   /‾‾/   
     /\  /  \     |  |/  /   /  /    
    /  \/    \    |     (   /   ‾‾\  
   /          \   |  |\  \ |  (‾)  | 
  / __________ \  |__| \__\ \_____/ .io

  execution: local
     script: grpc.js
     output: -

  scenarios: (100.00%) 1 scenario, 1 max VUs, 10m30s max duration (incl. graceful stop):
           * default: 1 iterations for each of 1 VUs (maxDuration: 10m0s, gracefulStop: 30s)

INFO[0000] {"name":"3 Hasta Way, Newton, NJ 07860, USA","location":{"latitude":410248224,"longitude":-747127767}}  source=console


     ✓ status is OK

Hey @jbeltz,
welcome to the community forum :wave:

Did you try to use HTTPS_PROXY? k6 under the hood uses the grpc-go client and as you can read from its documentation the HTTP_PROXY variable is not expected to work after go1.16 (the latest k6 release was built using go1.20).

You can read the details in the dedicated issue

Let me know if it helps.

Yes, @codebien I have also tried using HTTPS_PROXY, and neither work. I have debugged the k6 code and it seems it might be an issue in the Grpc-Go code link where the logic goes into the if below. I have “hacked” the code in that area and added the proxy logic that doesn’t normally get called when fn is set. This “fixes” it but it definitely doesn’t end up calling FN anymore so it definitely needs fixed by someone who knows the code better :slight_smile:. What I don’t understand is if it is an issue in Grpc-Go or intentional when DialContext is used and the caller is expected to deal with proxies.

	if fn != nil {
...
		if networkType == "unix" && !strings.HasPrefix(address, "\x00") {
			// Supported unix targets are either "unix://absolute-path" or
			// "unix:relative-path".
			if filepath.IsAbs(address) {
				return fn(ctx, "unix://"+address)
			}
			return fn(ctx, "unix:"+address)
		}
        // Hack: do proxy logic 
		if !ok {
			networkType, address = parseDialTarget(address)
		}
		if networkType == "tcp" && useProxy {
                         // with proxy on we go in here.
			return proxyDial(ctx, address, grpcUA)
		}
        // end of hack!
		return fn(ctx, address)
	}

I will add that I utilized grpc-go’s helloworld example and was able to get HTTPS_PROXY to work with it because it doesn’t use DialContext but Dial (see below) which doesn’t have fn set and drops into the normal proxy logic.

	conn, err := grpc.Dial(*addr, grpc.WithTransportCredentials(insecure.NewCredentials()))

Hey @jbeltz,
you’re right, the proxy logic is never invoked. We’re using a custom dialer that makes the fn variable not nil so the logic doesn’t enter the proxy’s branch.

I’m going to open an issue and we will discuss it internally. I will post here the issue so you can subscribe to it.

2 Likes

@codebien Thank you!

Hey @jbeltz,
I opened the issue grpc: Support HTTPS_PROXY · Issue #3175 · grafana/k6 · GitHub so you can subscribe.

I will update you if we have more details or an eventual implementation.