Kubernetes之Service Account

原创
半兽人 发表于: 2018-11-08   最后更新时间: 2023-06-30 20:09:32  
{{totalSubscript}} 订阅, 7,182 游览

Service Account是一种账号,但并不是给Kubernetes的集群的用户(系统管理员、运维人员、租户用户等),而是给运行在Pod里的进程用的,它为Pod里的进程提供必要的身份证明。

Pod 中访问 Kubernetes API Server 服务的时候,是以 Service 方式访问服务名为 kubernetes 这个服务的,而kubernetes服务又只在 HTTPS 安全端口 443 上提供服务,那么如何进行身份认证呢?

通过查看源码获知这是在用一种类似HTTP Token的新的认证方式--ServiceAccount Auth,Pod中的客户端调用Kubernetes API的时候,在HTTP Header中传递了一个 Token 字符串,这类似于之前提到的HTTP Token认证方式,存在以下几个不同点:

  • 此处的Token的内容来源于Pod里指定路径下的一个文件(/run/secrets/kubernetes.io/serviceaccount/token),这种token是动态生成的,确切的说,是由KubernetesController进程用API Server的私钥(--service-account-private-key-file指定的私钥)签名生成的一个JWT Secret。

  • 官方提供的客户端REST框架代码里,通过HTTPS方式与API Server建立链接后,会用Pod里指定路径下的一个CA证书(/run/secrets/kubernetes.io/serviceaccount/ca.crt)验证API Server发来的证书,验证是否是被CA证书签名的合法证书。

  • API Server收到这个Token以后,采用自己的私钥(实际是使用参数service-account-key-file指定的私钥,如果此参数没有设置,则默认采用tls-private-key-file指定的参数,即自己的私钥),对token进行合法性验证。

明白原理之后。接下来分析认证过程中涉及的Pod中的三个文件:

  • /run/secrets/kubernetes.io/serviceaccount/token
  • /run/secrets/kubernetes.io/serviceaccount/ca.crt
  • /run/secrets/kubernetes.io/serviceaccount/namespace(客户端采用这里指定的namespace作为参数调用Kubernetes API)

这三个文件由于参与到Pod进程与API Server认证的过程中,起到了类似Secret(私密凭据)的作用,所以他们被称为Kubernetes Secret对象。Secret从属于ServiceAccount资源对象,属于Service Account的一部分,一个ServiceAccount对象里面可以包括多个不同的Secret对象,分别用于不同目的的认证活动。

下面通过命令来直观的加深对ServiceAccount的认识:

查看系统中ServiceAccount对象,可以看到一个名为default的Service Account对象,包含一个名为default-token-xxx的Secret,这个Secret同时是“Mountable secrets”,表明他是需要被Mount到Pod上的。

  • kubectl describe serviceaccounts
  • kubectl describe secrets default-token-xxx

default-token-xxx包括三个数据项:

  • token
  • ca.crt
  • namespace

联想到“Mountable secrets”的标记,以及之前看到的Pod中的三个文件的文件名:每个namespace下有一个名为default的默认的ServiceAccount对象,这个ServiceAccount里有一个名为Tokens的可以作作为Volume一样被Mount到Pod里的Secret,当Pod启动时这个Secret会被自动Mount到Pod的指定目录下,用来协助完成Pod中的进程访问API Server时的身份鉴权过程。

  • 一个ServiceAccount可以包括多个Secrets对象:

  • 名为Tokens的Secret用于访问API Server的Secret,也被称为ServiceAccountSecret;

  • 名为Image Pull secrets的Secret用于下载容器镜像时的认证过程,通常镜像库运行在Insecure模式下,所以这个Secret为空;

用户自定义的其他Secret,用于用户的进程;

如果一个Pod在定义时没有指定spec.service.AccountName属性,则系统会自动为其赋值为“Default”,即使用同一namespace下默认的ServiceAccount,如果某个Pod需要使用非default的ServiceAccount,需要在定义时指定:

apiVersion: v1
kind: Pod
metadata:
  name: mypod
spec:
  containers:
    - name: mycontainer
      image: null
  serviceAccountName: myserviceaccount

Kubernetes之所以要创建两套独立的账号系统,原因如下:

  • User账号是给人用的,ServiceAccount是给Pod里的进程使用的,面向对象不同;
  • User账号是全局性的,ServiceAccount则属于某个具体的Namespace;
  • 通常来说,User账号是与后端的用户数据库同步的,创建一个新用户通常要走一套复杂的业务流程才能实现,ServiceAccount的创建则需要极轻量级实现方式,集群管理员可以很容易为某些特定任务组创建一个ServiceAccount。
  • 对于这两种不同的账户,其审计要求通常不同;
  • 对于一个复杂的系统来说,多个组件通常拥有各种账号的配置信息,ServiceAccount是Namespace隔离的,可以针对组件进行一对一的定义,同时具备很好的“便携性”。

下面深入分析Service Account与Secret相关的一些运行机制:

Controller manager创建了ServiceAccountController与Token Controllerl两个安全相关的控制器。

其中ServiceAccountController一直监听Service Account和Namespace的事件,如果一个Namespace中没有default Service Account,那么Service Account Controller就会为该Namespace创建一个默认的(default)的Service Account,这就是我们之前看到的每个namespace下都有一个名为default的ServiceAccount的原因。

如果Controller manager进程在启动时指定了API Server私钥(service-account-private-key-file)参数,那么Controller manager会创建Token Controller。

Token Controller也监听Service Account的事件,如果发现新建的Service Account里没有对应的Service Account Secret,则会用API Server私钥创建一个Token(JWT Token),并用该Token、CA证书Namespace名称等三个信息产生一个新的Secret对象,然后放入刚才的Service Account中;如果监听到的事件是删除Service Account事件,则自动删除与该Service Account相关的所有Secret。

此外,Token Controller对象同时监听Secret的创建、修改和删除事件,并根据事件的不同做不同的处理。

当我们在API Server的鉴权过程中启用了Service Account类型的准入控制器,即在kube-apiserver的启动参数中包括下面的内容时:

--admission_control=ServiceAccount

则针对Pod新增或修改的请求,Service Account准入控制器会验证Pod里Service Account是否合法。

  1. 如果spec.serviceAccount域没有被设置,则Kubernetes默认为其制定名字为default的Serviceaccount;

  2. 如果Pod的spec.serviceAccount域指定了default以外的ServiceAccount,而该ServiceAccount没有事先被创建,则该Pod将操作失败;

  3. 如果在Pod中没有指定“ImagePullSecrets”,那么该spec.serviceAccount域指定的ServiceAccount的“ImagePullSecrets”会被加入该Pod;

  4. 给Pod添加一个新的Volume,在该Volume中包含ServiceAccountSecret中的Token,并将Volume挂载到Pod中所有容器的指定目录下(/var/run/secrets/kubernetes.io/serviceaccount);

所以,综上所述,ServiceAccount正常运行需要以下几个控制器:

  • Admission Controller
  • Service Account Controller
  • Token Controller
更新于 2023-06-30

Marion 3年前

段落开头的service写错了。

半兽人 -> Marion 3年前

我太粗糙了,感谢。

查看kubernetes更多相关的文章或提一个关于kubernetes的问题,也可以与我们一起分享文章