Skip to content

HTTP_PROXY/HTTPS_PROXY ignored by load_kube_config(): proxy scheme resolved before the host is known #2681

Description

@yurnov

Split out of #2679 at @yliaog's request — that issue covered the kubeconfig proxy-url field, fixed in #2680. This one is about the environment variables.

What happened (please include outputs or screenshots):

HTTP_PROXY and HTTPS_PROXY are ignored when the client configuration is built by load_kube_config(). Configuration.proxy stays None and requests go direct.

Only ALL_PROXY works. That makes the commonly suggested workaround for proxy setups ("just export HTTPS_PROXY") ineffective on the load_kube_config() path, which is the path almost every user takes.

What you expected to happen:

HTTPS_PROXY (or HTTP_PROXY) is honoured for the cluster endpoint, as it is for curl, kubectl, and client-go.

How to reproduce it (as minimally and precisely as possible):

$ HTTPS_PROXY=http://127.0.0.1:8888 python -c "
from kubernetes.client import Configuration
print(repr(Configuration().proxy))
print(repr(Configuration(host='https://example:6443').proxy))"
None
'http://127.0.0.1:8888'

The same asymmetry end to end, against a cluster reachable only through a proxy (the setup from #2679):

env var set Configuration.proxy after load_kube_config() API call
HTTPS_PROXY None fails
HTTP_PROXY None fails
ALL_PROXY set works

Root cause

Configuration.__init__ resolves the proxy from the environment by the scheme of self.host:

# urllib3 does not read proxy environment variables itself:
# https://github.com/urllib3/urllib3/issues/1785
if proxy is None or no_proxy is None:
proxies = getproxies()
if proxy is None:
scheme = urlparse(self.host).scheme
proxy = proxies.get(scheme) or proxies.get("all")
if no_proxy is None:
no_proxy = proxies.get("no")

scheme = urlparse(self.host).scheme
proxy = proxies.get(scheme) or proxies.get("all")

But host is a property, not the constructor argument:

@property
def host(self) -> str:
"""Return generated host."""
return self.get_host_from_settings(self.server_index, variables=self.server_variables)

@property
def host(self) -> str:
    """Return generated host."""
    return self.get_host_from_settings(self.server_index, variables=self.server_variables)

and server_index is set to 0 whenever no host argument is passed:

self.server_index = 0 if server_index is None and host is None else server_index

self.server_index = 0 if server_index is None and host is None else server_index

With server_index = 0, host returns get_host_settings()[0]['url'], which is "" for this spec. So urlparse("").scheme is '', proxies.get('') misses, and only the proxies.get("all") fallback can match — which is why ALL_PROXY is the one variable that works.

load_kube_config() constructs the object with no host:

if client_configuration is None:
config = type.__call__(Configuration)
loader.load_and_set(config)
Configuration.set_default(config)

if client_configuration is None:
    config = type.__call__(Configuration)
    loader.load_and_set(config)

so it always takes the broken path. The loader assigns the real server afterwards — and the host setter does reset server_index to None — but by then the proxy has already been resolved in __init__. Passing host= explicitly is what makes the working case above work.

Possible fixes

Two options, and I'd like guidance on which is preferred before writing a patch:

  1. Re-evaluate the environment proxy in the loader once host is known — a change in kubernetes/base/config/kube_config.py, which is developer-written and patchable in this repo.
  2. Fix the resolution order in Configuration.__init__ so it uses the effective base path rather than the generated host property. This is in kubernetes/client/configuration.py, which is generated (kubernetes/.openapi-generator/FILES), so it would need whatever hotfix/regeneration flow you prefer.

Happy to implement either. Given #2147's history I'd rather not touch generated files without agreement first.

Anything else we need to know?:

Related: #2679 / #2680 (kubeconfig proxy-url, fixed), #2520 (no_proxy env var handling).

Environment:

  • Python client version: master (9c3456a351594b59a19862d9caec1e78e7b4e287), also reproduced on released 36.0.3
  • Python version: 3.12.3
  • OS: Linux

/kind bug

Metadata

Metadata

Assignees

No one assigned

    Labels

    kind/bugCategorizes issue or PR as related to a bug.

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions