关于ServiceAccount以及在集群内访问K8S API

发布时间 2023-05-26 09:15:58作者: 不背锅运维

写在开篇

在之前的两篇文章中提到,有4种方式使用 ConfigMap 配置 Pod 中的容器,关于之前的两篇可参考:

本篇的实战场景就以访问API的方式读取 ConfigMap,也就是编写代码在 Pod 中运行,然后使用 K8S API 来读取 ConfigMap的内容。但是,这个场景涉及到服务账号、K8S集群内身份验证的相关知识点。为了控制篇幅(主要是文章太长,担心没人看到最后),打算再拆分两篇。本篇尽力先把涉及到的知识点搞清楚,下一篇再真正进入实战环节,例如写代码,制作镜像等等。

其实,这个实战场景,也刚好弥补了在之前分享过的 下篇(开始写代码):运维开发人员不得不看的K8S API实战》 中缺少的 “集群内进行身份验证” 的内容。

在继续之前,如果对K8S API的使用套路还一无所知,可结合参考:

K8S的账号类型

在K8S中,主要有两种账号类型:

  1. User Accounts(用户账号):用户账号用于标识和验证 Kubernetes 集群的用户。用户账号通常由集群管理员创建,并与相应的身份验证凭据(如用户名和密码、令牌等)关联。用户账号用于进行集群管理操作,如创建、删除和更新资源,以及访问集群中的敏感信息。
  2. Service Accounts(服务账号):服务账号是用于身份验证和授权 Pod 内的应用程序的一种机制。每个 Pod 都可以与一个 Service Account 相关联,并使用该 Service Account 进行与 Kubernetes API Server 的通信。服务账号通常用于在 Pod 内的应用程序与集群中的其他资源进行交互,如读取 ConfigMap、访问 Secrets 等。

更多信息可参考官方文档:authentication

关于ServiceAccount和在K8S集群内身份验证

上次的实战场景 《下篇(开始写代码):运维开发人员不得不看的K8S API实战》 主要是在K8S集群外进行身份验证,因为调用K8S API的代码是运行在集群外部。而这次的场景是:调用K8S API的代码运行在POD容器里,也就是要在K8S集群内部进行身份验证。

当调用K8S API的代码(应用程序代码)运行在POD里的容器时,Pod中的应用程序可以使用其关联的 ServiceAccount 去访问 API Server 中的 Kubernetes 资源(比如访问ConfigMap资源)。在访问资源时,ServiceAccount 会使用其所分配的 RBAC 角色来确定它有哪些权限。为了方便理解,我简单画了个图,如下:

图片

  • 身份认证:应用程序可以使用与之关联的 ServiceAccount 进行身份认证,以证明其对 Kubernetes 集群中的资源的合法访问权限。
  • 访问授权:通过与访问控制策略(如 Role、ClusterRole)结合使用,可以为 ServiceAccount 分配特定的角色和权限,从而限制应用程序对资源的访问范围和操作权限。

关于ServiceAccount的更多信息可参考官方文档:service-accounts

关于每个命名空间下默认的服务账号:default

官方文档提到:默认服务账户是Kubernetes在创建集群时自动为每个命名空间创建的一个ServiceAccount对象。每个命名空间中的服务账户默认情况下没有任何权限,除非启用了基于角色的访问控制(RBAC),此时Kubernetes会授予所有经过身份验证的主体默认的API发现权限。如果在一个命名空间中删除了ServiceAccount对象,控制平面会自动替换为一个新的ServiceAccount对象。如果在一个命名空间中部署一个Pod,并且没有手动为Pod分配一个ServiceAccount,Kubernetes会将该命名空间的默认ServiceAccount分配给该Pod。

接下来,查看一下默认命名空间(default)下的serviceaccount:

[root@k8s-b-master ~]# kubectl get serviceaccount
NAME      SECRETS   AGE
default   0         16d
[root@k8s-b-master ~]# kubectl get serviceaccount default -o yaml
apiVersion: v1
kind: ServiceAccount
metadata:
  creationTimestamp: "2023-04-30T03:24:16Z"
  name: default
  namespace: default
  resourceVersion: "359"
  uid: 47c8dccd-2d91-47cf-b0b7-ce4d02b610a8
[root@k8s-b-master ~]# 

创建一个名为goweb的自定义命名空间,创建后,在该命名空间下已经自动创建了一个名为default的serviceaccount对象:

[root@k8s-b-master ~]# kubectl create ns goweb
namespace/goweb created
[root@k8s-b-master ~]# kubectl get serviceaccount -n goweb
NAME      SECRETS   AGE
default   0         8s
[root@k8s-b-master ~]# kubectl get serviceaccount default -n goweb -o yaml
apiVersion: v1
kind: ServiceAccount
metadata:
  creationTimestamp: "2023-05-17T03:26:41Z"
  name: default
  namespace: goweb
  resourceVersion: "284809"
  uid: c0254d59-c625-4ef9-a619-1c51fdcfeef6
[root@k8s-b-master ~]# 

到了这里,可能会提出这样的问题:创建自定义的命名空间后,为什么会自动创建一个名为default的ServiceAccount?

这是因为ServiceAccount是用于身份验证和授权的一种机制,每个Pod都需要与一个ServiceAccount关联,以确定Pod在集群中的身份和权限。

默认的ServiceAccount是为了确保在创建Pod时不会发生错误。如果没有显式地指定Pod要使用的ServiceAccount,Kubernetes会自动将命名空间的默认ServiceAccount分配给该Pod。这样,Pod就能够获得基本的权限和凭据,以便与集群中的其他组件进行通信。

默认的ServiceAccount通常没有具体的权限,除非通过其他方式为其分配了角色和权限。默认情况下,它只拥有基本的API发现权限,允许Pod发现集群中的其他API资源。

可以通过为Pod显式指定不同的ServiceAccount来覆盖默认行为,以满足特定的安全需求和访问控制策略,这也就是下篇要做的事情:为 Pod配置ServiceAccount。

为Pod配置ServiceAccount的步骤

为控制篇幅,为Pod配置ServiceAccount,以及编写使用Go调用K8S API的代码、制作镜像等等均放到下篇分享。

为Pod配置ServiceAccount的步骤很简单,下面仅给出步骤,如下:

  1. 创建ServiceAccount
  2. 创建Role:定义所需的权限
  3. 创建RoleBinding,将ServiceAccount和Role关联起来
  4. 将ServiceAccount对象分配给Pod

更多信息可参考官方文档:configure-service-account

本文转载于WX公众号:不背锅运维(喜欢的盆友关注我们):https://mp.weixin.qq.com/s/1BbBLr4E564b6OdIpXjMjw