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: testnamespace: 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" } } ]