kubernetes pod用户信息认证serviceAccount(29)

2023年 7月 16日 70.1k 0

在kubernets上有一些服务和客户端需要与api server交涉,并且集群内部会运行类似的pod资源,这些资源是需要访问api server的 ,如: CoreDNS,以及dashboard

dashboard提供一个web界面来管理kubernetes,通过service暴漏到外部,通过浏览器打开使用。当然会有通过dashboard来进行增删改查资源,那意味着dashboard这个pod就有可能去创建pod,甚至于名称空间等,那这种操作明显是需要与api server交涉的。如下图:

用户认证-3.png

与api server交涉的有两类:

  • 集群之外的客户端 ,集群之外的客户端每次访问api server使用api server监听的节点地址

如kubectl,kubectl并没有运行在节点之上,可以运行在任何系统上,只要有配置文件,都可以进行链接。外部的链接通过api server对外的通信监听的地址,与远程客户端通讯。如上图。

  • 集群内部POD客户端

pod有pod网络,pod工作在内部的网段内

集群内部范围api server是通过名称空间当中的kubernetes的service ip 10.96.0.1 进行通讯。将一个集群外部的服务以service的方式引入到集群内部来,事实上也是同一个主机上的,10.96.0.1也就是serviec所在的网络地址,pod本身也是可以和service通讯的,从而使得POD可以请求api server之上的服务。pod请求api service上的服务就是通过10.96.0.1进行的。如上图

[root@linuxea volume]# kubectl describe svc kubernetes
Name:              kubernetes
Namespace:         default
Labels:            component=apiserver
                   provider=kubernetes
Annotations:       <none>
Selector:          <none>
Type:              ClusterIP
IP:                10.96.0.1
Port:              https  443/TCP
TargetPort:        6443/TCP
Endpoints:         10.10.240.161:6443
Session Affinity:  None
Events:            <none>

但是,api server是需要认证的,api server将认证传递给客户端,客户端校验api server的身份,同时api server校验客户端的身份。那就意味着api server发送给客户端的身份中表明的ip地址不能只是宿主机10.10.240.161这一个ip地址,并且要有coredns的10.96.0.1这个ip地址。因为pod客户端在集群内访问的是10.96.0.1这个IP地址。那也就是说证书持有者名称必须有两条a记录解析到这两个ip。

serviceAccount

那也就是说证书持有者名称必须有两条a记录解析到这两个ip。任何pod只要需要访问到api server,api server必须要求认证pod,不认证就会被拒绝。而这个认证是由pod提供的,而serviceAccountName(服务账号名称)就是让pod链接api server进行认证用的账号。

  • kubernetes集群中有两类认证账号,一种是管理人员用户操作类(`userAccountName),第二种是服务账号(serviceAccountName),指运行在k8s集群上的pod,想访问当前k8s集群的api server的用户认证信息,服务帐户等。事实上每一种pod都会与api交互,只是权限大小不同而已

默认pod在运行时候,都会有相关信息,如下:

[root@linuxea ~]# kubectl describe pods satefulset-2
......
Volumes:
  default-token-k25gj:
    Type:        Secret (a volume populated by a Secret)
    SecretName:  default-token-k25gj
    Optional:    false
QoS Class:       BestEffort
Node-Selectors:  <none>
.....

default-token-k25gj的认证资源保存在Secret vloume存储卷的方式关联到pod当中,从而来完成认证链接信息的

其次,在名称空间中默认会创建一个secret的名称空间。default-token-k25gj

[root@linuxea ~]# kubectl get secret
NAME                    TYPE                                  DATA      AGE
default-token-k25gj     kubernetes.io/service-account-token   3         15d
redis-passwd            Opaque                                1         2d
tomcat-ingress-secret   kubernetes.io/tls                     2         14d

之前创建的 ingress-nginx名称空间,也有default-token-s7f97 ,这个token让这个名称空间所有的pod资源联系api server时候预置的认证信息,不过仅限获取当前pod于自身的相关属性,并不能去管理别人的

[root@linuxea ingress]# kubectl get secret -n ingress-nginx
NAME                                       TYPE                                  DATA      AGE
default-token-s7f97                        kubernetes.io/service-account-token   3         15d
nginx-ingress-serviceaccount-token-89ctc   kubernetes.io/service-account-token   3         15d

如果要扩展一个pod,就是用来管理其他的pod,或者说是管理类的其他资源对象,就必须手动创建一个service-account-token,并且创建pod时候附加手动定义的service-account-token,不去使用默认的即可。

  • 默认的service-account-token一般权限非常小,如果需要提升权限就需要手动定义。

创建serviceAccount

serviceAccount属于k8s标准资源,可以创建完成后,使用serviceAccountname加载定义的serviceAccount

可以使用create创建serviceAccount,而后指定属性即可创建,这些属性使用kubectl create serviceaccount -h可以看到。如果不指定任何属性,也可以给定一个名称。

  • serviceAccount本身是不带权限的,创建只是使他换了一个账号。而后使用RBAC授其他的权限给这个创建的serviceAccount。授权并不属于serviceAccount,可以使用一个专用的账号给POD使用,而后给这个专用的账号更大的权限使用。而默认的serviceAccount会让名称空间当中所有的pod都拥有这个权限。如果有这种专用的需求,就需要定义一个专用的账号来赋予权限。

命令行创建

--dry-run=false: If true, only print the object that would be sent, without sending it.。我们可在加上--dry-run测试

[root@linuxea ingress]#  kubectl create serviceaccount mysa --dry-run
serviceaccount/mysa created (dry run)

--o yaml指明输出格式,清单类型yaml

[root@linuxea ingress]#  kubectl create serviceaccount mysa -o yaml --dry-run
apiVersion: v1
kind: ServiceAccount
metadata:
  creationTimestamp: null
  name: mysa

可以使用--dry-run将结果>输出重定向到文件中,如:

kubectl create serviceaccount mysa -o yaml --dry-run > ./linuxea.yml,支持create的都可以这么做。当然,也可以指定一个pod名称来查看,如:kubectl get pods linuxea-tomcat-group-b77666d76-4h5mz -o yaml --export

serviceAccount简称sa,在使用kubectl get sa即可。此时能看到默认的一个sa

[root@linuxea ingress]# kubectl get sa
NAME      SECRETS   AGE
default   1         16d

创建sa

创建一个名称为admin-linuxeaserviceaccount

[root@linuxea ingress]# kubectl create serviceaccount admin-linuxea
serviceaccount/admin-linuxea created
[root@linuxea ingress]# kubectl get sa
NAME            SECRETS   AGE
admin-linuxea   1         3s
default         1         16d

创建完成系统会自动生成secret。而系统也会自动生成一个tokens信息

[root@linuxea ingress]# kubectl describe sa admin-linuxea
Name:                admin-linuxea
Namespace:           default
Labels:              <none>
Annotations:         <none>
Image pull secrets:  <none>
Mountable secrets:   admin-linuxea-token-4zpzk
Tokens:              admin-linuxea-token-4zpzk
Events:              <none>

生成的admin-linuxea-token-4zpzksecret

  • 这个secret仅用于这个sa链接当前api server的认证信息,并不包含权限信息,如果需要什么权限,则需要另外授权
[root@linuxea ingress]# kubectl get secret
NAME                        TYPE                                  DATA      AGE
admin-linuxea-token-4zpzk   kubernetes.io/service-account-token   3         1m

应用sa到pod

创建一个linuxea-sa-demo的pod,在spec中添加serviceAccountName: admin-linuxea,也就是之前创建的serviceAccount

[root@linuxea sa]# cat sa-demo.yaml 
apiVersion: v1
kind: Pod
metadata: 
  name: linuxea-sa-demo
  namespace: default
  labels:
    www: linuxea-com
    tier: backend
  annotations:
    www.linuxea.com/ops-by: "linuxea admin"
spec:
  containers:
  - name: linuxea-pod1-com
    image: "marksugar/nginx:1.14.a"
    ports:
      - containerPort: 80
  serviceAccountName: admin-linuxea

kubectl describe pods linuxea-sa-demo查看volumesadmin-linuxea-token-4zpzk:已在其中,type为Secret,如下:

[root@linuxea sa]# kubectl describe pods linuxea-sa-demo|tail -20
  Initialized       True 
  Ready             True 
  ContainersReady   True 
  PodScheduled      True 
Volumes:
  admin-linuxea-token-4zpzk:
    Type:        Secret (a volume populated by a Secret)
    SecretName:  admin-linuxea-token-4zpzk
    Optional:    false
QoS Class:       BestEffort
Node-Selectors:  <none>
Tolerations:     node.kubernetes.io/not-ready:NoExecute for 300s
                 node.kubernetes.io/unreachable:NoExecute for 300s
Events:
  Type    Reason     Age   From                         Message
  ----    ------     ----  ----                         -------
  Normal  Scheduled  33s   default-scheduler            Successfully assigned default/linuxea-sa-demo to linuxea.node-3.com
  Normal  Pulled     31s   kubelet, linuxea.node-3.com  Container image "marksugar/nginx:1.14.a" already present on machine
  Normal  Created    30s   kubelet, linuxea.node-3.com  Created container
  Normal  Started    30s   kubelet, linuxea.node-3.com  Started container

私有镜象认证的两种方式

在每一次提交资源清单到api server,api server传递至kubelet,而后创建并允许一个pod,而这个pod内的容器想要启动,就需要pull一个镜象仓库的镜象,而这个镜象参考需要认证。这个认证信息在之前的配置中使用Secret,并且定义,而后使用pod中的imagePullSecrets指明使用那个Secret对象,而这个Secret对象中包含了认证私有镜象仓库的账号和密码。

我们也可以在pod当中不使用imagePullSecrets来告诉pod怎么去认证下载镜象文件,而是用serviceAccountNameserviceAccountName相当于指定了sa账号,而这个sa账号附带可以认证到私有参考的认证信息的,如下:20181003.png在之前创建的sa -> admin-linuxea中Image pull secrets,也就是说创建的secrets可以直接定义在sa上,然后在把sa定义到pod上,这样sa通过Image pull secrets定义secrets也能完成image的资源认证。相比较imagePullSecrets,用户只能看见sa,对于sa来讲, 是或许不到secrets信息的,相对安全些

[root@linuxea sa]# kubectl describe sa admin-linuxea
Name:                admin-linuxea
Namespace:           default
Labels:              <none>
Annotations:         <none>
Image pull secrets:  <none>
Mountable secrets:   admin-linuxea-token-4zpzk
Tokens:              admin-linuxea-token-4zpzk
Events:              <none>

这样一来获取私有镜象认证就 有两种方式:1,imagePullSecrets字段指定认证的secrets对象2,在pod上定义serviceAccount,而后在pod附加即可Image pull secrets

相关文章

LeaferJS 1.0 重磅发布:强悍的前端 Canvas 渲染引擎
10分钟搞定支持通配符的永久有效免费HTTPS证书
300 多个 Microsoft Excel 快捷方式
一步步配置基于kubeadmin的kubevip高可用
istio全链路传递cookie和header灰度
REST Web 服务版本控制

发布评论