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:
- 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.
- 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
Split out of #2679 at @yliaog's request — that issue covered the kubeconfig
proxy-urlfield, fixed in #2680. This one is about the environment variables.What happened (please include outputs or screenshots):
HTTP_PROXYandHTTPS_PROXYare ignored when the client configuration is built byload_kube_config().Configuration.proxystaysNoneand requests go direct.Only
ALL_PROXYworks. That makes the commonly suggested workaround for proxy setups ("just exportHTTPS_PROXY") ineffective on theload_kube_config()path, which is the path almost every user takes.What you expected to happen:
HTTPS_PROXY(orHTTP_PROXY) is honoured for the cluster endpoint, as it is forcurl,kubectl, and client-go.How to reproduce it (as minimally and precisely as possible):
The same asymmetry end to end, against a cluster reachable only through a proxy (the setup from #2679):
Configuration.proxyafterload_kube_config()HTTPS_PROXYNoneHTTP_PROXYNoneALL_PROXYRoot cause
Configuration.__init__resolves the proxy from the environment by the scheme ofself.host:python/kubernetes/client/configuration.py
Lines 339 to 347 in 9c3456a
But
hostis a property, not the constructor argument:python/kubernetes/client/configuration.py
Lines 663 to 666 in 9c3456a
and
server_indexis set to0whenever nohostargument is passed:python/kubernetes/client/configuration.py
Line 247 in 9c3456a
With
server_index = 0,hostreturnsget_host_settings()[0]['url'], which is""for this spec. Sourlparse("").schemeis'',proxies.get('')misses, and only theproxies.get("all")fallback can match — which is whyALL_PROXYis the one variable that works.load_kube_config()constructs the object with nohost:python/kubernetes/base/config/kube_config.py
Lines 781 to 784 in 9c3456a
so it always takes the broken path. The loader assigns the real server afterwards — and the
hostsetter does resetserver_indextoNone— but by then the proxy has already been resolved in__init__. Passinghost=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:
hostis known — a change inkubernetes/base/config/kube_config.py, which is developer-written and patchable in this repo.Configuration.__init__so it uses the effective base path rather than the generatedhostproperty. This is inkubernetes/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_proxyenv var handling).Environment:
9c3456a351594b59a19862d9caec1e78e7b4e287), also reproduced on released 36.0.3/kind bug