系列文章目录


文章目录

  • 系列文章目录
  • 前言
  • 一、默认的ServiceAccount
  • 二、自定义的ServiceAccount
  • 2.1 创建自定义的ServiceAccount
  • 2.2 在Pod中使用自定义的serviceAccount
  • 总结



前言

Servic Account(服务账号):是指由Kubernetes API管理的账号,用于为Pod之中的服务进程在访问Kubernetes API时提供身份标识。Service Account通常绑定于特定的名称空间,由API Server创建,或者通过API调用手动创建。
User Account(用户账号):独立于Kubernetes之外的其他服务管理用户账号,例如由管理员分发秘钥、Keystone一类的用户存储(账号库)、甚至是保函有用户名和密码列表的文件等。

(1) User Account是为人设计的,而Service Account则是为Pod中的进程调用Kubernetes API而设计;
(2) User Account是跨namespace的,而Service Account则是仅局限它所在的namespace,每个namespace都会自动创建一个default service account。

kubernetes国内仓库 kubernetes service account_云原生

看上图,左上角是user访问K8S集群,左下角是Pod访问K8S集群,都需要 apiserver 授权认证。左下角的Pod需要访问k8s的资源,需要通过中间 apiserver 的认证、授权、准入控制 三个东西,这就需要一个serviceAccount,帮助它完成这个过程,才能访问k8s的资源。

ServiceAccount服务账号简称为 sa 账号,其作用是 Pod 访问 K8S 集群的资源,分为两种,一种是新建任何一个命名空间的时候,默认创建/每个命名空间自带的 sa 账号,另一种是自定义的 sa 账号。


一、默认的ServiceAccount

serviceAccount的作用是是给集群内pod里面的进程使用,用来访问集群内的资源,所以每个ns都会一个一个名称为default的命名空间,如下:

kubernetes国内仓库 kubernetes service account_kubernetes国内仓库_02

自己建一个命名空间,也会有一个默认的sa

kubernetes国内仓库 kubernetes service account_云原生_03

同时也可以自定义serviceAccount。

为什么使用了serviceAccount就可以认证集群? 因为每个sa下面都会拥有的一个加密的token,使用 secrets 存储

这个secrets(加密token)本质上等同于userAccount的认证集群的三种凭证文件:X509客户端证书,静态token文件,静态账号密码文件,都是连接集群的认证信息,serviceAccount只有一种形式,作用于服务账号,userAccount多种形式,绑定 user或者 userGroup就可以了,作用于用户账号。

既然这个ns-monitor命名空间下,有这样一个名为default的serviceAccount,我们就来使用一下这个serviceAccount,如下,新建一个Pod使用这个serviceAccount:

kubernetes国内仓库 kubernetes service account_容器_04

查看一下正在运行的 kind: daemonSet 资源 node-exporter,但是没有找到对serviceAccount的引用,因为任何拉取镜像的运行资源 (pod replicaset deployment statefulset deamonset job/cronjob) ,对于serviceAccount(serviceAccount类型的secrets)的引用,都是在底层的Pod里面的,所以要看pod,如下:

kubernetes国内仓库 kubernetes service account_Pod_05

查看daemonset底层运行的pod,找到了对于serviceAccount类型type的secrets的引用,如下:

kubernetes国内仓库 kubernetes service account_云原生_06


至此,这个名为default的serviceAccount就被pod使用了,这个pod使用了这个serviceAccount(其实是加载了这个serviceAccount关联的secrets)之后,就可以访问k8s集群内的资源。

注意,任何一个Pod都需要有一个 serviceAccount 才能在 kubernetes 集群中正常运行,如果没有,就会报错 cannot found /var/run/secrets/kubernetes.io/serviceaccount 文件,解决这个常见错误,就是因为没有 serviceAccount .

那么,为什么pod启动通过volume加载了type类型为serviceAccount的secrets之后,就可以访问到k8s里面资源呢?我们看一下这个secrets到底存储的哪些数据data (secrets类似一个加密的configmap,可以简单理解为配置文件,里面存储了数据)

一个 secrets (type:serviceAccount) 里面包含的data是:加密的ca.crt、加密的namespace、加密的token,如下:

kubernetes国内仓库 kubernetes service account_Pod_07

在创建Pod资源时,如果没有指定一个service account,系统会自动在与该Pod相同的namespace下为其指派一个default service account。而pod和apiserver之间进行通信的账号,称为serviceAccountName。

通过上面可以看出每个Pod无论定义与否都会有一个存储卷,这个存储卷为default-token-* token令牌,这就是Pod和serviceaccount认证信息。通过secret进行定义,由于认证信息属于敏感信息,所以需要保存在secret资源当中,并以存储卷的方式挂载到Pod当中。从而让Pod内运行的应用通过对应的secret中的信息来连接apiserver,并完成认证。每个namespace中都有一个默认的叫做default的service account资源。进行查看名称空间内的secret,也可以看到对应的default-token。让当前名称空间中所有的pod在连接apiserver时可以使用的预制认证信息,从而保证pod之间的通信。

另外,sa 和 secret 的关系是: sa 使用 secret 保存存放。其实,sa 和 secret 都是在 kube-system 命名空间,secret 相当于 configmap (因为要存放着token所以加密),一定是被pod使用了,一个 pod 使用一个 sa,与 apiserver 交互,一个 sa 可以被 多个pod 使用。

注意:user 和 userGroup 不是 一个类型资源,不可以用 kubectl get xxx 查看

kubernetes国内仓库 kubernetes service account_kubernetes国内仓库_08


kubernetes国内仓库 kubernetes service account_kubernetes_09

二、自定义的ServiceAccount

2.1 创建自定义的ServiceAccount

#查看serviceaccount资源
[root@k8s-master ~]# kubectl get sa     
NAME      SECRETS   AGE
default   1         7d19h
#创建一个名为admin的serviceaccount资源
[root@k8s-master ~]# kubectl create serviceaccount admin    
serviceaccount/admin created
#查看serviceaccount资源
[root@k8s-master ~]# kubectl get sa     
NAME      SECRETS   AGE
admin     1         7s
default   1         7d19h
#查看serviceaccount资源admin的详细信息,可以看出已经自动生成了一个Tokens:admin-token-lc826
[root@k8s-master ~]# kubectl describe sa/admin    
Name:                admin
Namespace:           default
Labels:              <none>
Annotations:         <none>
Image pull secrets:  <none>
Mountable secrets:   admin-token-lc826
Tokens:              admin-token-lc826
Events:              <none>
#查看secret,可以查看也生成了一个admin-token-lc826的secret资源
[root@k8s-master ~]# kubectl get secret    
NAME                  TYPE                                  DATA   AGE
admin-token-lc826     kubernetes.io/service-account-token   3      50s
......

kubernetes国内仓库 kubernetes service account_kubernetes_10

2.2 在Pod中使用自定义的serviceAccount

每个Pod对象均可关联其所属名称空间中的一个Service Account资源,且只能关联一个,这个ServiceAccount就是Pod进去K8S集群的凭证,也是通过 apiserver 的凭证,有了这个ServiceAccount,这个Pod才可以运行在k8s集群上。不过,一个Service Account资源可由所属名称空间中的多个Pod对象共享使用。

即在同一个命名空间内(这是前提条件,pod与serviceAccount不能跨命名空间关联),一个pod只能使用一个serviceAccount,不能不使用serviceAccount,也不能使用多个serviceAccount,但是命名空间里面的一个serviceAccount可以被多个pod使用。

那么,同一个命名空间里面,pod可以选择n个serviceAccount中的一个来使用。不同的serviceAccount有什么不同呢?其实就是看 rbac 机制中,serviceAccount绑定了什么 role,因为权限是在role上的。

如果是人,可以通过 user/userGroup 两种方式中任何一种来绑定 role,如果是pod,只能通过 sa 账号来绑定role。

创建Pod时,通过“spec.serviceAccountName”进行定义。示例如下:

[root@k8s-master manfests]# vim pod-sa-demo.yaml    #编辑资源清单文件
apiVersion: v1
kind: Pod
metadata:
  name: pod-sa-demo
  namespace: default
  labels:
    app: myapp
    tier: frontend
spec:
  containers:
  - name: myapp
    image: ikubernetes/myapp:v1
    ports:
    - name: http
      containerPort: 80
  serviceAccountName: admin    #指定serviceAccount资源名称
  
[root@k8s-master manfests]# kubectl apply -f pod-sa-demo.yaml 
pod/pod-sa-demo created
[root@k8s-master manfests]# kubectl get pods -l app=myapp
NAME          READY   STATUS    RESTARTS   AGE
pod-sa-demo   1/1     Running   0          9s
[root@k8s-master manfests]# 
[root@k8s-master manfests]# kubectl describe pods/pod-sa-demo
Name:         pod-sa-demo
Namespace:    default
......
Volumes:
  admin-token-lc826:
    Type:        Secret (a volume populated by a Secret)
    SecretName:  admin-token-lc826      #这里可以看出挂载token就是上面创建的sa所生成的那个
    Optional:    false
......

kubernetes国内仓库 kubernetes service account_Pod_11


kubernetes国内仓库 kubernetes service account_容器_12

一个sa账号,有三个属性,

ca.crt: 这证书是每个集群独一份的,这个集群中所有主从节点 /etc/kubernetes/pki/ca.crt 目录下,都存放着,是 kubelet 运行所必须的

namespace:同一个集群不同命名空间不同,这个是命名空间独一份的

token: 这个和 sa 账号绑定role 有关,是指sa具有哪些权限,这个 token 就是 bearer token 持有者证书,直接拿到 Postman 上就可以向 k8s 发送 https 请求。

kubernetes国内仓库 kubernetes service account_kubernetes国内仓库_13

总结

总结一下,梳理出ServiceAccount服务账号一条线,kind: serviceAccount 作为k8s集群内的一类资源,每个命名空间都会一个名为default的默认的serviceAccount,默认不指定的情况下,这个命名空间下所有的pod都是使用名为default的默认的serviceAccount,这个serviceAccount是通过secrets存储的,这个secrets等效加密的configmap,就是配置文件一类东西,type是serviceAccount,包含的data是:加密的namespace、加密的ca.crt、加密的token,有了这些data,这个命名空间下的Pod在启动的时候通过volume挂盘的方式,将secrets加载到整个Pod里面,Pod的进程就可以访问k8s集群内的资源了。

然后,这种用在serviceAccount上的secrets只是一种类型type的secrets,secrets还有两种其他类型type的,普通字符串和imagePullSecrets,顺便一起学习了。

最后,还可以自定义ServiceAccount,再重新分析一遍,加深理解。

这里面有一个难以搞清的概念,那就是对于一一对应关系的serviceAccount和secrets,如下图:

kubernetes国内仓库 kubernetes service account_Pod_14

serviceAccount和secret的区别:本质不同,serviceAccount 本质是服务账号,是 pod 连接 k8s 集群的凭证;secret是一种加密的存储方式,使用键值对存储,存储在 etcd 里面,另一种不加密的键值对存储是 configmap,secret 包含三种,都是使用 base64 加密,三种secret中其中一种是存储 serviceAccount 的 secret。

serviceAccount和secret的联系:serviceAccount 使用 secret 加密存储中 etcd 里面,加密方式是 base64,这种secret data里面三个加密属性,ca.crt namespace token.