What happened
After upgrading from kubernetes==35.0.0 to kubernetes==36.0.0, all API calls from pods using load_incluster_config() fail with 401 Unauthorized. The Bearer token is never sent in the Authorization header.
Root cause
In v36, Configuration.auth_settings() (auto-generated) checks for api_key['BearerToken']:
def auth_settings(self):
auth = {}
if 'BearerToken' in self.api_key:
auth['BearerToken'] = {
'type': 'api_key',
'in': 'header',
'key': 'authorization',
'value': self.get_api_key_with_prefix('BearerToken'),
}
return auth
But InClusterConfigLoader._set_config() (manually maintained in kubernetes/base/) still sets the old key:
def _set_config(self, client_configuration):
client_configuration.host = self.host
client_configuration.ssl_ca_cert = self.ssl_ca_cert
if self.token is not None:
client_configuration.api_key['authorization'] = self.token # <-- old key
Since auth_settings() looks for 'BearerToken' and load_incluster_config sets 'authorization', the token is never picked up by ApiClient.update_params_for_auth(), so no Authorization header is sent.
In v35, auth_settings() checked for 'authorization', so both sides agreed and everything worked.
How to reproduce
# Inside a pod with a service account
from kubernetes import client, config
config.load_incluster_config()
v1 = client.CoreV1Api()
v1.list_namespaced_pod('default', limit=1)
# => kubernetes.client.exceptions.UnauthorizedException: (401)
Verified that the token itself is valid — a direct urllib.request call with the same token from /var/run/secrets/kubernetes.io/serviceaccount/token returns 200.
Expected behavior
load_incluster_config() should set api_key['BearerToken'] (matching what auth_settings() expects), or auth_settings() should check for api_key['authorization'] (matching what load_incluster_config sets).
Environment
- Kubernetes cluster version: 1.31
- Python version: 3.13.12
- kubernetes client version: 36.0.0 (works fine on 35.0.0)
What happened
After upgrading from
kubernetes==35.0.0tokubernetes==36.0.0, all API calls from pods usingload_incluster_config()fail with401 Unauthorized. The Bearer token is never sent in the Authorization header.Root cause
In v36,
Configuration.auth_settings()(auto-generated) checks forapi_key['BearerToken']:But
InClusterConfigLoader._set_config()(manually maintained inkubernetes/base/) still sets the old key:Since
auth_settings()looks for'BearerToken'andload_incluster_configsets'authorization', the token is never picked up byApiClient.update_params_for_auth(), so no Authorization header is sent.In v35,
auth_settings()checked for'authorization', so both sides agreed and everything worked.How to reproduce
Verified that the token itself is valid — a direct
urllib.requestcall with the same token from/var/run/secrets/kubernetes.io/serviceaccount/tokenreturns 200.Expected behavior
load_incluster_config()should setapi_key['BearerToken'](matching whatauth_settings()expects), orauth_settings()should check forapi_key['authorization'](matching whatload_incluster_configsets).Environment