6.4 Service Account
6.4 Service Account
Service Account 也是一种账号,但它并不是给Kubernetes集群的用户(系统管理员、运维人员、租户用户等)用的,而是给运行在Pod里的进程用的。它为Pod里的进程提供了必须的身份证明。
在正常情况下,为了确保Kubernetes集群的安全,API Server 都会对客户端进行身份认证,认证失败的客户端无法进行API 调用,此外,在Pod 中访问Kubernetes API Server 服务时,是以Service 方式访问名为 Kubernetes 的这个服务的,而Kubernetes 服务又只在HTTPS 安全端口 443 上提供。
通过查看官方源码,发现这是一种类似HTTP Token的新认证方式—— Service Account Auth,Pod 中的客户端调用 Kubernetes API 时,在HTTP Header 中传递了一个Token 字符串,这类似于之前提到的HTTP Token 认证方式,但有以下几个不同之处。
- 这个Token 的内容来自Pod 里指定路径下的一个文件 (/run/secrets/kubernetes.io/serviceaccount/token),这种Token 是动态生成的。确切的说,是由Kubernetes Controller 进程用 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/serviceacclount/ca.crt
- /run/secrets/kubernetes.io/serviceaccount/namespace (客户端采用这里指定的namespace 作为参数调用 Kubernetes API )
这三个文件由于参与到Pod 进程与API Server 认证的过程中,起到了类似secret(私密凭据)的作用,所以它们被称为 Kubernetes Secret对象。Secret从属于Service Account 资源对象,属于Service Account 的一部分,在一个Service Account 对象里面可以包括多个不同的Secret 对象,分别用于不同目的认证活动。
首先,查看系统中的Service Account 对象,看到一个名为 default 的Service Account 对象,包含一个名为 default-token-5ms94 ,这个Secret同时是Mountable secrets,表明它是需要被挂载到Pod上的。

看看 default-token-5ms94 内容
[root@master ~]# kubectl describe secret default-token-5ms94
Name: default-token-5ms94
Namespace: default
Labels: <none>
Annotations: kubernetes.io/service-account.name: default
kubernetes.io/service-account.uid: 37795f9e-c570-4a35-ad74-c742aeca13e8
Type: kubernetes.io/service-account-token
Data
====
ca.crt: 1066 bytes
namespace: 7 bytes
token: eyJhbGciOiJSUzI1NiIsImtpZCI6IlJ3ZUlwWmlJbWJxOWR0djYzbEpoajFEWXZValhTNU4yalFwV054MzAxbmcifQ.eyJpc3MiOiJrdWJlcm5ldGVzL3NlcnZpY2VhY2NvdW50Iiwia3ViZXJuZXRlcy5pby9zZXJ2aWNlYWNjb3VudC9uYW1lc3BhY2UiOiJkZWZhdWx0Iiwia3ViZXJuZXRlcy5pby9zZXJ2aWNlYWNjb3VudC9zZWNyZXQubmFtZSI6ImRlZmF1bHQtdG9rZW4tNW1zOTQiLCJrdWJlcm5ldGVzLmlvL3NlcnZpY2VhY2NvdW50L3NlcnZpY2UtYWNjb3VudC5uYW1lIjoiZGVmYXVsdCIsImt1YmVybmV0ZXMuaW8vc2VydmljZWFjY291bnQvc2VydmljZS1hY2NvdW50LnVpZCI6IjM3Nzk1ZjllLWM1NzAtNGEzNS1hZDc0LWM3NDJhZWNhMTNlOCIsInN1YiI6InN5c3RlbTpzZXJ2aWNlYWNjb3VudDpkZWZhdWx0OmRlZmF1bHQifQ.TehTRgjk-JHewy3qZTn3VCRyq_qreoPLJveXvZutxGLi4bmtit8hTUNqHbOvA5W0Fxkk66LAkxWoNU_niwvBTBboXPuXZzjhqtCNcbd3lXJz5zha3Ur9HGeRCpm8H8CYiRR7RomtAQr3iV79B4mC4GHyKfphIh5UXHNA1E2LQTn7rOeacDjKvDYfpBOT5uav21P7lrgWys_ALlVZpw9rxDrkqoQY51nZ8Vejt9cYA-Csh-PFRlAVCj0ATX-NUXGl7V4_EHIwRStpngXDgyUVNiZfCrZS8ksu3B1Nj1wrf111n1SvazruoHeAbvoJ2wRVTtwJCSk1DJi2TwHeG5YAKQ
从上面的输出信息可以看到,default-token-5ms94
包含三个数据,分别是 token、ca.crt、namespace。 联想到Mountable secrets的标记,以及之前看到的Pod中的三个文件说明,在每个Namespace 下都有一个名为default 的默认Service Account对象,在这个 Service Account里面有一个名为tokens的可以当作Volume被挂载到Pod里的Secret,当Pod启动时,这个 Secret会自动被挂载到Pod的指定目录下,用来协助完成Pod中的进程访问API Server时的身份鉴权。

其中:
(1)、名为Tokens的Secret 用于访问API Server的Secret,也被称为 Service Account Secret 。
(2)、名为imagePullSecrets 的Secret用于下载容器镜像时的认证过程,通常镜像库运行在Insecure 模式下,所以这个Secret为空。
(3)、用户自定义的其他Secret,用于用户的进程。
如果一个Pod在定义时没有指定 spec.serviceAccountName
属性,则系统会自动为其赋值为 default ,即大家都用同一个Namespace下的默认Service Account 。如果某个Pod需要使用非 default 的Service Account,则需要在定义时指定:
apiVersion: v1
kind: Pod
metadata:
name: mypod
spec:
containers:
- name: mycontainer
image: nginx:v1
serviceAccountName: myserviceaccount
Kubernetes 之所以要创建两套独立的账号系统,原因如下 :
- User 账号是给别人使用的,Service Account 是给Pod 里的进程使用的。面向的对象不同
- User 账号是全局性的,Service Account 则属于某个具体的Namespace 。
- 通常来说,User账号是与后端的用户数据库同步的,创建一个新用户通常要走一套复杂的业务流程才能实现,Service Account 的创建则需要极轻量级的实现方式,集群管理员可以很容易地为某些特定任务创建一个Service Account。
- 对于这两种不同的账号,其审计要求通常不同
- 对于一个复杂的系统来说,多个组件 通常拥有各种账号的配置信息,Service Account 是Namespace 隔离的,可以针对组件进行一对一的定义,同时具备很好的“便携性”.
我们知道 Controller manager 创建了 ServiceAccount Controller 与 Token Controller 这两个安全相关的控制器。其中 ServiceAccount Controlled 一直监听 ServiceAccount和namespace 的事件,如果在一个Namespace中没有default Service Account ,那么ServiceAccount Controller会为该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对象,然后放入刚才的ServiceAccount 中;如果监听到的事件是删除 Service Account 事件,则自动删除与该 Service Account 相关的所有 Secret 。此外,Token Controller 对象同时监听 Secret 的创建、修改和删除事件,并根据事件做不同的处理。
当我们在 API Server 的鉴权过程中启用了 Service Account 类型的准入控制器,即在 kube-apiserver 启动参数中包括下面的内容时:
--admission_control=ServiceAccount
则针对Pod 新增或修改的请求,Service Account 准入控制器会验证Pod里的Service Account 是否合法。
(1)、如果sepc.serviceAccount 域没有被设置,则Kubernetes默认为其指定名称为 default 的 Service Account
(2)、如果Pod 的 spec.serviceAccount指定了 default 以外的ServiceAccount ,而该ServiceAccount 没有被事先创建,则该Pod操作失败
(3)、如果在Pod中没有指定ImagePullSecrets,那么这个spec.serviceAccount 域指定的ServerAccount的 imagePullSecrets 会被加入该Pod中
(4)、给Pod 添加一个特殊的Volume,在该Volume中包含ServiceAccountSecret 中的Token,并将Volume挂载到Pod中所有容器的指定目录下(/var/run/secrets/kubenetes.io/serviceaccount
)
综上所述,Service Account在正常工作离不开以下几个控制器:
- Admission Controll
- Token Controll
- ServiceAccount Controller