Kubernetes之ServiceAccount + Secret + RBAC实现访问APIServer

API Server作为Kubernetes网关,是访问和管理资源对象的唯一入口,一个Pod如果要想访问API Server需要经过以下步骤

第一步:对客户端访问进行认证操作,确认是否具有访问k8s权限  #这步就是Pod引用Service Account,决定是否能访问API Server
    token(共享秘钥)
    SSL(双向SSL认证)
....通过任何一个认证即表示认证通过,进入下一步
第二步:授权检查,确认是否对资源具有相关的权限   #这步就是创建一个ClusterRole或者Role,然后ClusterRoleBinding或者RoleBinding把ClusterRole和Server Account绑定到一起,决定该Service Account有权限访问API Server的哪些资源,比如Deployment、Pod之类的
    ABAC(基于属性的访问控制)
    RBAC(基于角色的访问控制)
    NODE(基于节点的访问控制)
    WEB HOOK(自定义HTTP回调方法的访问控制)
第三步:准入控制(对操作资源相关联的其他资源是否有权限操作)

ServiceAccount

一.ServiceAccount和User Account介绍

Kubernetes中账号区分为:Service Account(服务账户)和User Account(用户账户),它们的设计及用途如下

1).User Account介绍

User Account是给Kubernetes集群外部使用的,例如运维或者集群管理员,使用kubectl 命令时就是用的User Account账户

User Account是全局性;在集群所有NameSpace中,名称具有唯一性.

用户名称可以在kubeconfig中查看

[root@Centos8 ~]# cd ~/.kube/
[root@Centos8 .kube]# ls
cache  config  http-cache
[root@Centos8 .kube]# cat config
...
    users:
    - name: kubernetes-admin
...

2)Service Account介绍

Service Account是给运行在Pod里的程序使用的身份认证,Pod容器的进程需要访问API Server时用的就是Service Account账户

Service Account仅局限在它所在的NameSpace,只有该NameSpace下的Pod引用这个Service Account才有权限,每个NameSpace创建时都会自动创建一个Secret(访问API Server时用的Token和CA)和一个Service Account,然后Service Account引用Secret;

如果每个Pod不指定Service Account的话,就会自动引用该NameSpace下默认的Service Account,此时该Pod可以访问API Server了;

Service Account为服务提供了一种方便的认证机制,但是Service Accoun不关心授权问题,Pod绑定该Service Account之后,仅仅是能访问API Server了,但是能访问API Server的哪些资源(Deployment、Pod、ConfigMap之类的资源),需要配合RBAC来为Service Account授权

二.默认的Service Account

Service Account仅局限它所在的NameSpace,所以在创建NameSpace时会自动创建一个默认的SA,而SA创建时,也会创建对应的Secret,下面操作验证

1)创建命名空间

[root@Centos8 .kube]# kubectl create ns vfan
namespace/vfan created

2)查看SA

[root@Centos8 .kube]# kubectl get sa -n vfan
NAME      SECRETS   AGE
default   1         67s

3)查看SA引用的默认Secret

[root@Centos8 .kube]# kubectl describe sa default -n vfan
Name:                default
Namespace:           vfan
Labels:              <none>
Annotations:         <none>
Image pull secrets:  <none>
Mountable secrets:   default-token-wwbc8
Tokens:              default-token-wwbc8
Events:              <none>

[root@Centos8 ~]# kubectl get secret -n vfan
NAME                  TYPE                                  DATA   AGE
default-token-wwbc8   kubernetes.io/service-account-token   3      3m15s

可以看到,创建ns时默认创建了SA,SA默认创建了一个 kubernetes.io/service-account-token类型的secret

所有引用该SA的Pod都能访问API Server了

4)创建一个Pod

文件名:pods.yaml
apiVersion: v1 kind: Pod metadata: name: test
namespace: vfan spec: containers: - name: test image: radial/busyboxplus:curl stdin: true
tty: true

为什么pod使用镜像: radial/busyboxplus:curl ,是为了方便执行 curl命令来进行验证

5)查看Pod引用默认的SA

[root@Centos8 rbac]# kubectl describe pod test -n vfan
...
Containers:
  test:
    Mounts:
      /var/run/secrets/kubernetes.io/serviceaccount from default-token-wwbc8 (ro)
Volumes:
  default-token-wwbc8:
    Type:        Secret (a volume populated by a Secret)
    SecretName:  default-token-wwbc8
    Optional:    false
...
说明:每个Pod在创建后都会引用这个default的Service Account,除非指定了其他的Service Account
每个Container启动后都会挂载对应的ServiceAccount引用的Secret里的token、namespace、ca.crt到/var/run/secrets/kubernetes.io/serviceaccount下

6)进入Pod查看挂载的Token、CA、namespace信息

/test $ ls -l /var/run/secrets/kubernetes.io/serviceaccount/
total 0
lrwxrwxrwx    1 root     root            13 Nov 27 09:00 ca.crt -> ..data/ca.crt
lrwxrwxrwx    1 root     root            16 Nov 27 09:00 namespace -> ..data/namespace
lrwxrwxrwx    1 root     root            12 Nov 27 09:00 token -> ..data/token
##说明:
可以看到已将ca.crt 、namespace和token放到容器内了,那么这个容器就可以用Token和CA通过https的请求访问apiserver了

7)进入Pod测试访问API Server的权限

#kubectl exec -it test -n vfan
$curl --cacert /var/run/secrets/kubernetes.io/serviceaccount/ca.crt --header "Authorization:Bearer $(cat /var/run/secrets/kubernetes.io/serviceaccount/token)" https://$KUBERNETES_SERVICE_HOST:$KUBERNETES_SERVICE_PORT/api/v1/namespaces/$(cat/var/run/secrets/kubernetes.io/serviceaccount/namespace)/pods
{
  "kind": "Status",
  "apiVersion": "v1",
  "metadata": {

  },
  "status": "Failure",
  "message": "pods is forbidden: User "system:serviceaccount:mynamespace:default" cannot list resource "pods" in API group "" at the cluster scope",
  "reason": "Forbidden",
  "details": {
    "kind": "pods"
  },
  "code": 403   ##表示403无法访问,没权限

###注意:
虽然该Pod的能访问API Server了,还得通过RBAC为该Service Account授权,来决定该ServiceAccount有权限访问API Server的哪些资源,比如Deployment、Pod、Node、Configmap等资源

授权

接下来就要通过RBAC给default这个service account授权,来让default这个Service Account拥有list pod的权限

一、添加ClusterRole

#cat example-clusterrole.yaml

apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
  name: example-clusterrole
rules:
- apiGroups:
  - ""
  resources:
  - nodes
  - nodes/proxy
  - nodes/metrics
  - services
  - endpoints
  - pods
  - ingress
  verbs:
  - get
  - list
  - watch
- nonResourceURLs:
  - /metrics
  verbs:
  - get

二、通过ClusterRoleBinding把ClusterRole和ServiceAccount绑定到一起,Service Account就有ClusterRole定义的权限了

通过ClusterRoleBinding给所有NameSpace下的default Service Account授权

apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
  name: example-clusterrolebinding
subjects:
- kind: Group
  name: system:serviceaccounts
  apiGroup: rbac.authorization.k8s.io
roleRef:
  kind: ClusterRole
  name: example-clusterrole
  apiGroup: rbac.authorization.k8s.io

二、也可以通过ClusterRoleBinding给单独一个NameSpace下的defult Service Account授权 (可以跟上面的二选一,是给所有授权,还是单独一个授权)

apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
  annotations:
  name: example-clusterrolebinding
roleRef:
  apiGroup: rbac.authorization.k8s.io
  kind: ClusterRole
  name: exampe-clusterrole
subjects:
- kind: ServiceAccount
  name: default
  namespace: vfan

三、再次进入容器,通过执行curl命令获取所有pod,执行成功

#kubectl attach -it test -n vfan
$curl --cacert /var/run/secrets/kubernetes.io/serviceaccount/ca.crt --header "Authorization:Bearer $(cat /var/run/secrets/kubernetes.io/serviceaccount/token)" https://$KUBERNETES_SERVICE_HOST:$KUBERNETES_SERVICE_PORT/api/v1/namespaces/$(cat/var/run/secrets/kubernetes.io/serviceaccount/namespace)/pods
...
"imageID": "docker-pullable://radial/busyboxplus@sha256:a68c05ab1112fd90ad7b14985a48520e9d26dbbe00cb9c09aa79fdc0ef46b372",
            "containerID": "docker://d6b1a94caa364392ac7e3c07dd99faa1c80f15fe6f757aa54509ea778b6c93aa",
            "started": true
          }
        ],
        "qosClass": "BestEffort"
      }
    }
  ]
原文地址:https://www.cnblogs.com/chadiandianwenrou/p/14070120.html