Kubernetes python 客户端:身份验证问题

Kubernetes python client: authentication issue

我们使用 kubernetes python 客户端 (4.0.0) 结合 google 的 kubernetes 引擎 (master + nodepools 运行 k8s 1.8.4) 定期调度kubernetes 上的工作负载。我们用来创建 pod、附加到日志并报告 pod 结束状态的脚本的简化版本如下所示:

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 身份验证提供程序进行,为此我通过 运行 在调度程序上手动设置 kubectl container cluster get-credentials 获得了初始访问令牌。在某些随机时间范围内,某些 API 调用会导致 API 服务器发出 401 响应。我的猜测是,只要访问令牌过期就会发生这种情况,并且脚本会尝试获取新的访问令牌。然而,多个脚本 运行 同时在调度程序上运行,导致多次获得新的 API 密钥,其中只有一个仍然有效。我尝试了多种方法来解决这个问题(使用 persist_config=True,在重新加载配置后重试 401,...)但没有成功。由于我不完全了解 gcp 身份验证和 kubernetes python 客户端配置是如何工作的(并且两者的文档都很少),所以我有点一头雾水。

我们应该使用其他身份验证方法而不是 gcp 身份验证提供程序吗?这是 kubernetes python 客户端中的错误吗?我们应该使用多个配置文件吗?

为了向您的 API 服务器进行身份验证,您可以使用基于角色的访问控制 (RBAC),它可以定义一系列角色来管理对您的 API 的身份验证和访问。

这是基于通过使用绑定将角色和集群角色授予不同的用户或服务帐户。这些角色包括一些代表一组权限的规则,并且可以定义为作用于命名空间(角色)或整个集群(集群角色)。

启用 RBAC 的第一步是使用以下选项启动 API 服务器:

--authorization-mode=RBAC

您可以使用 kubectl 命令定义特定角色。例如,如果您想在命名空间(例如 acme)上向用户(例如 Bob)授予管理员集群角色,您可以使用此命令:

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

您可以查看 here 了解有关 RBAC 的更多信息,包括您可以授予用户或服务帐户的所有可能角色和集群角色。

最终我们通过使用不记名令牌身份验证解决了这个问题,而不是依赖默认的 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>

之后你应该找到API服务器的IP地址,以及kubernetes集群的集群CA证书。这可以通过转到 google 云控制台上的 kubernetes 引擎详细信息页面来完成。将证书内容复制到本地文件中。

您现在可以使用承载令牌通过kubernetes python 客户端进行身份验证,如下所示:

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))

我有一个使用 Kubernetes 客户端的 python 容器,并且正在寻找一种方法让它在集群中执行时使用服务帐户,但在本地执行时加载已安装的 kube 配置。找了好久才找到load_incluster_config(),集群执行时会根据容器的service account自动配置。我现在在本地 运行 时打开一个环境变量。这可能对您有帮助:

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