apache / apisix

The Cloud-Native API Gateway
https://apisix.apache.org/blog/
Apache License 2.0
14.3k stars 2.49k forks source link

Accessing upstream using a http or https proxy #10292

Open markokocic opened 11 months ago

markokocic commented 11 months ago

Description

In many cases, where Apisix is running behind a corporate firewall, the only way to access some external or internal endpoints is through a http or https_proxy or sockes_proxy. Is it / how it is possible to define a proxy for an upsteam?

How are you dealing with proxies?

Could some documentation be added on the topic?

Environment

Revolyssup commented 11 months ago

Well if some traffic comes and goes through the proxy server, then the proxy server will act as the upstream and client for apisix for that traffic. Depending on what you're using as the proxy server, you'll have to configure both apisix and proxy server. In your case, what are you using as proxy server?

markokocic commented 11 months ago

Depending on what you're using as the proxy server, you'll have to configure both apisix and proxy server.

There's nothing to configure on the proxy server side. It's the same standard regular http proxy server that you put in your browser network settings to connect to the internet, or in a http_proxy and https_proxy environment variables in a Linux shell, so that curl, wget and other utilities can pick it up. Apisix/Nginx doesn't pick the environment variables and doesn't provide a way to configure http_proxy for accessing network. Or at least I couldn't find it.

markokocic commented 11 months ago

I found that openid-connect plugin has configurable proxy_opts to access OpenID server through http_proxy.

https://apisix.apache.org/docs/apisix/plugins/openid-connect/

That's exactly what we would need for upstream to allow us to configure upstreams that are only accessible through proxy.

oyiadin commented 11 months ago

When it comes to http_proxy, you can configure APISIX as follows: create an upstream with pass_host="pass" and set nodes[].host to your proxy's IP address. The HTTP proxy server could just handle it well.

As for https_proxy, please note that APISIX (which is essentially based on Nginx) doesn't support forwarding the HTTP CONNECT method. So achieving this functionality might require modifying the code of APISIX, and potentially even Nginx itself.

It's important to understand that proxy_opts controls the request sent by lua codes of openid-connect, rather than the "forwarded request" sent by Nginx to the upstream. The reason the former can be controlled is that it's constructed and sent from Lua code. However, the latter is constructed and sent from the original Nginx code, and there are no any related parameters available for it.

markokocic commented 11 months ago

Ok, since APISIX upstreams relies on Nginx, looks like it will never support https_proxy, since Nginx doesn't have any plans to add it.

The only solution so far that I found working is to use an external relay application like redsocks that will intercept outgoing https requests and forward them to the actual HTTP CONNECT proxy. That redirection can be set up on Linux level using iptables.

I used https://github.com/ncarlier/dockerfiles/tree/master/redsocks as a starting point to implement proxying upstreams.

Maybe it would be good to update upstream documentation to explicitly mention that proxies are not supported, and a possible workaround.

wojja commented 7 months ago

I also stumbled accross this problem. I would actually be fine to use http_proxy.

@oyiadin could you please elobarate on your suggestion?

When it comes to http_proxy, you can configure APISIX as follows: create an upstream with pass_host="pass" and set nodes[].host to your proxy's IP address. The HTTP proxy server could just handle it well.

I do not really unterstand how this is supposed to work. If I set up a route and upstream in apisix.yaml like this, how does the HTTP proxy knows that it should forward the request to https://apisix.apache.org?

routes:
  -
    uri: "/apisix"
    upstream_id: 1
upstreams:
  -
    id: 1
    nodes:
      "company.proxy": 1
    scheme: "http"
    pass_host: "pass"