ServiceAccount
Kubernetes中所有的访问,无论外部内部,都会通过API Server处理,访问Kubernetes资源前需要经过认证与授权。
- Authentication:用于识别用户身份的认证,Kubernetes分外部服务账号和内部服务账号,采取不同的认证机制,具体请参见认证与ServiceAccount。
- Authorization:用于控制用户对资源访问的授权,对访问的授权目前主要使用RBAC机制,将在RBAC介绍。
认证与ServiceAccount
Kubernetes的用户分为服务账户(ServiceAccount)和普通账户两种类型。
- 服务账户与Namespace绑定,关联一套凭证,存储在Secret中,Pod创建时挂载Secret,从而允许与API Server之间调用。
- Kubernetes中没有代表普通账户的对象,这类账户默认由外部服务独立管理,比如CCE的用户是由IAM管理的。
普通账号并不是这里要讨论的内容,这里主要关注ServiceAccount。
ServiceAccount同样是Kubernetes中的资源,与Pod、ConfigMap类似,且作用于独立的命名空间,也就是ServiceAccount是属于命名空间级别的,创建命名空间时会自动创建一个名为default的ServiceAccount。
使用下面命令可以查看ServiceAccount。
$ kubectl get sa NAME SECRETS AGE default 1 30d
同时Kubernetes还会为ServiceAccount自动创建一个Secret,使用下面命令可以查看到。
$ kubectl describe sa default Name: default Namespace: default Labels: <none> Annotations: <none> Image pull secrets: <none> Mountable secrets: default-token-vssmw Tokens: default-token-vssmw Events: <none>
在Pod的定义文件中,可以用指定账户名称的方式将一个ServiceAccount赋值给一个Pod,如果不指定就会使用默认的ServiceAccount。当API Server接收到一个带有认证Token的请求时,API Server会用这个Token来验证发送请求的客户端所关联的ServiceAccount是否允许执行请求的操作。
创建ServiceAccount
使用如下命令就可以创建ServiceAccount:
$ kubectl create serviceaccount sa-example serviceaccount/sa-example created $ kubectl get sa NAME SECRETS AGE default 1 30d sa-example 1 2s
可以看到已经创建了与ServiceAccount相关联的Token。
$ kubectl describe sa sa-example Name: sa-example Namespace: default Labels: <none> Annotations: <none> Image pull secrets: <none> Mountable secrets: sa-example-token-c7bqx Tokens: sa-example-token-c7bqx Events: <none>
查看Secret的内容,可以发现ca.crt、namespace和token三个数据。
$ kubectl describe secret sa-example-token-c7bqx Name: sa-example-token-c7bqx ... Data ==== ca.crt: 1082 bytes namespace: 7 bytes token: <Token的内容>
在Pod中使用ServiceAccount
Pod中使用ServiceAccount非常方便,只需要指定ServiceAccount的名称即可。
apiVersion: v1 kind: Pod metadata: name: sa-example spec: serviceAccountName: sa-example containers: - image: nginx:alpine name: container-0 resources: limits: cpu: 100m memory: 200Mi requests: cpu: 100m memory: 200Mi imagePullSecrets: - name: default-secret
创建并查看这个Pod,可以看到Pod挂载了sa-example-token-c7bqx,也就是sa-example这个ServiceAccount对应的Token,即Pod使用这个Token来做认证。
$ kubectl create -f sa-pod.yaml pod/sa-example created $ kubectl get pod NAME READY STATUS RESTARTS AGE sa-example 0/1 running 0 5s $ kubectl describe pod sa-example ... Containers: sa-example: Mounts: /var/run/secrets/kubernetes.io/serviceaccount from sa-example-token-c7bqx (ro)
进入Pod内部,还可以看到对应的文件,如下所示。
$ kubectl exec -it sa-example -- /bin/sh / # cd /run/secrets/kubernetes.io/serviceaccount /run/secrets/kubernetes.io/serviceaccount # ls ca.crt namespace token
如上,在容器应用中,就可以使用ca.crt和Token来访问API Server。
下面来验证认证是否能生效。在Kubernetes集群中,默认为API Server创建了一个名为kubernetes的Service,通过这个Service可以访问API Server。
$ kubectl get svc NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE kubernetes ClusterIP 10.247.0.1 <none> 443/TCP 34
进入Pod,使用curl命令直接访问会得到如下返回信息,表示并没有权限。
$ kubectl exec -it sa-example -- /bin/sh / # curl https://kubernetes curl: (60) SSL certificate problem: unable to get local issuer certificate More details here: https://curl.haxx.se/docs/sslcerts.html curl failed to verify the legitimacy of the server and therefore could not establish a secure connection to it. To learn more about this situation and how to fix it, please visit the web page mentioned above.
使用ca.crt和Token做认证,先将ca.crt放到CURL_CA_BUNDLE这个环境变量中,curl命令使用CURL_CA_BUNDLE指定证书;再将Token的内容放到TOKEN中,然后带上TOKEN访问API Server。
# export CURL_CA_BUNDLE=/var/run/secrets/kubernetes.io/serviceaccount/ca.crt # TOKEN=$(cat /var/run/secrets/kubernetes.io/serviceaccount/token) # curl -H "Authorization: Bearer $TOKEN" https://kubernetes { "kind": "Status", "apiVersion": "v1", "metadata": { }, "status": "Failure", "message": "forbidden: User \"system:serviceaccount:default:sa-example\" cannot get path \"/\"", "reason": "Forbidden", "details": { }, "code": 403 }
可以看到,已经能够通过认证了,但是API Server返回的是cannot get path \"/\"",表示没有权限访问,这说明还需要得到授权后才能访问,授权机制将在RBAC中介绍。