kubernetes-client / kubernetes-client/python

Broken websocket client on custom authorization header names

Open
#2,510 7 comments 0 reactions 1 assignee Claimed by @Sanil2108 View on GitHub
help wanted kind/bug
Dominant language
Python
Stars
7.7k
Forks
3.5k
Avg merge
1d 14h
Merged PRs (30d)
18

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.

Contributor guide

Open the contributing guide

Assessment

This issue has not been assessed yet.

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.