Клиент Python Kubernetes: проблема аутентификации

Мы используем клиент Python kubernetes (4.0.0) в сочетании с движком Google kubernetes (master + nodepools run k8s 1.8.4) для периодического планирования рабочих нагрузок на kubernetes. Упрощенная версия скрипта, который мы используем для создания модуля, прикрепления к журналам и отчета о конечном состоянии модуля, выглядит следующим образом:

config.load_kube_config(persist_config=False)
v1 = client.CoreV1Api()
v1.create_namespaced_pod(body=pod_specs_dict, namespace=args.namespace)
logging_response = v1.read_namespaced_pod_log(
    name=pod_name,
    namespace=args.namespace,
    follow=True,
    _preload_content=False
)
for line in logging_response:
    line = line.rstrip()
    logging.info(line)
status_response = v1.read_namespaced_pod_status(pod_name, namespace=args.namespace)
print("Pod ended in status: {}".format(status_response.status.phase))

Все работает довольно хорошо, однако у нас возникают некоторые проблемы с аутентификацией. Аутентификация происходит по умолчанию gcp auth-провайдера, для которого я получил начальный токен доступа, запустив kubectl container cluster get-credentials вручную по планировщику. На некоторых случайных таймфреймах некоторые вызовы API приводят к ответу 401 от сервера API. Я предполагаю, что это происходит всякий раз, когда токен доступа истек, и сценарий пытается получить новый токен доступа. Однако бывает так, что в планировщике одновременно выполняется несколько сценариев, что приводит к получению нового ключа API несколько раз, из которых только один остается действительным. Я опробовал несколько способов решить проблему (используйте persist_config=True, повторите попытку 401 после перезагрузки конфигурации,...) без какого-либо успеха. Так как я не полностью осознаю, как работает аутентификация gcp и конфиг клиента Python kubernetes (и документации для обоих довольно мало), я немного оставлен в неведении.

Должны ли мы использовать другой метод аутентификации вместо gcp Auth-провайдер? Это ошибка в клиенте Python kubernetes? Должны ли мы использовать несколько файлов конфигурации?

2 ответа

Решение

В конце концов, мы решили эту проблему, используя аутентификацию на основе токенов на предъявителя, вместо того, чтобы полагаться на метод аутентификации gcloud по умолчанию.

Вот шаги, которые я сделал для достижения этой цели.

Сначала создайте учетную запись службы в требуемом пространстве имен, создав файл со следующим содержимым.

apiVersion: v1
kind: ServiceAccount
metadata:
  name: <name_of_service_account>

Затем используйте этот файл для создания учетной записи службы

kubectl create -f <path_to_file> --namespace=<namespace_name>

С каждой учетной записью службы связан токен-носитель, который можно использовать для аутентификации. Этот токен на предъявителя автоматически устанавливается как секрет в пространство имен. Чтобы узнать, что это за токен, сначала найдите название секрета (имеет вид <service_account_name>-token-<random_string>), а затем используйте это имя для доступа к содержанию.

# To search for out service account's token name
kubectl get secrets --namespace=<namespace_name>

# To find the token name
kubectl describe secret/<secret_name>

После этого вы должны узнать IP-адрес сервера API и сертификат Cluster CA кластера kubernetes. Это можно сделать, перейдя на страницу сведений о движке kubernetes в облачной консоли Google. Скопируйте содержимое сертификата в локальный файл.

Теперь вы можете использовать токен-носитель для аутентификации через Python-клиент kubernetes следующим образом:

from kubernetes import client

configuration = client.Configuration()
configuration.api_key["authorization"] = '<bearer_token>'
configuration.api_key_prefix['authorization'] = 'Bearer'
configuration.host = 'https://<ip_of_api_server>'
configuration.ssl_ca_cert = '<path_to_cluster_ca_certificate>'

v1 = client.CoreV1Api(client.ApiClient(configuration))

У меня есть контейнер python, использующий клиент Kubernetes, и я искал способ, чтобы он использовал учетную запись службы при выполнении в кластере, но загружал смонтированную конфигурацию куба при выполнении локально. Мне потребовалось время, чтобы найти load_incluster_config(), который будет автоматически настраиваться на основе учетной записи службы контейнера при выполнении в кластере. Теперь я включаю env var при локальном запуске. Это может быть вам полезно:

https://github.com/kubernetes-client/python/blob/master/examples/in_cluster_config.py

Для аутентификации на вашем сервере API вы можете использовать управление доступом на основе ролей (RBAC), которое может определять ряд ролей для управления аутентификацией и доступом к вашему API.

Это основано на предоставлении ролей и ролей кластера различным пользователям или учетным записям служб с помощью привязок. Эти роли включают в себя некоторые правила, которые представляют собой набор разрешений и могут быть определены для работы с пространством имен (ролями) или целым кластером (ролями кластера).

Первый шаг для включения RBAC - запустить сервер API со следующей опцией:

--authorization-mode=RBAC

Вы можете определить конкретные роли с помощью команды kubectl. Например, если вы хотите предоставить роль кластера администратора пользователю (например, Бобу) в пространстве имен (например, acme), вы можете использовать эту команду:

kubectl create rolebinding bob-admin-binding --clusterrole=admin --user=bob --namespace=acme

Вы также можете определить роль кластера, чтобы пользователь (например, root) имел права администратора для всего кластера:

kubectl create clusterrolebinding root-cluster-admin-binding --clusterrole=cluster-admin --user=root

Если вы хотите использовать вместо этого служебные учетные записи, вы можете использовать такую ​​команду для предоставления ролей служебной учетной записи:

kubectl create rolebinding my-sa-view  --clusterrole=view --serviceaccount=my-namespace:my-sa --namespace=my-namespace

Вы можете проверить здесь для получения дополнительной информации о RBAC, включая все возможные роли и роли кластера, которые вы можете предоставить своей учетной записи пользователя или службы.