-
Notifications
You must be signed in to change notification settings - Fork 3.5k
Description
What happened (please include outputs or screenshots):
We use Kubernetes in our production, as per the security regulation, the API server requires a custom authorization header, say "MY-AUTH-TOKEN", instead of the default header name "Authorization". The token is more secure than the static service account token.
The kubernetes.client.configuration.Configuration class doesn't support the custom header name, but we can play a hack to workaround this:
from kubernetes import client
class MyConfiguration(client.Configuration):
def auth_settings(self):
auth = {}
if 'authorization' in self.api_key:
auth['BearerToken'] = {
'type': 'api_key',
'in': 'header',
'key': 'MY-AUTH-TOKEN', # set header name here
'value': self.get_api_key_with_prefix('authorization')
}
return auth
# usage
my_cfg = MyConfiguration(...)
v1 = client.CoreV1Api(client.ApiClient(my_cfg))
pod = v1.read_namespaced_pod('my-pod', 'my-ns')
However, this hack doesn't work on the kubernetes.stream.stream() call, the reason is the websocket client doesn't hornor the "auth_settings" in the configuration.
(code snippet in kubernetes.stream.ws_client.py)
def create_websocket(configuration, url, headers=None):
enableTrace(False)
# We just need to pass the Authorization, ignore all the other
# http headers we get from the generated code
header = []
if headers and 'authorization' in headers:
header.append("authorization: %s" % headers['authorization'])
...
Here the header name is hard coded as "authorization", any other custom headers are discarded.
As a result, the stream() call breaks, this breaks watching and exec.
What you expected to happen:
The websocket client should handle the auth headers in the same way as api client, see ApiClient.update_params_for_auth() impl.
The configuration object is passed in as the first parameter of create_websocket function, it has the ability to get the header name by calling configuration.auth_settings()["key"]
def create_websocket(configuration, url, headers=None):
enableTrace(False)
# We just need to pass the Authorization, ignore all the other
# http headers we get from the generated code
header = []
auth_settings = configuration.auth_settings().get('BearerToken')
if auth_settings:
if auth_settings['in'] == 'cookie':
header.append("Cookie: %s" % auth_settings['value'])
elif auth_settings['in'] == 'header':
header.append("%s: %s" % (auth_settings['key'], auth_settings['value']))
...
How to reproduce it (as minimally and precisely as possible):
Anything else we need to know?:
Environment:
- Kubernetes version (
kubectl version):
Any - OS (e.g., MacOS 10.13.6):
Any - Python version (
python --version)
Any - Python client version (
pip list | grep kubernetes)
This issue exists on all client versions.