欢迎访问博客原文
官方:Kubernetes API 访问控制
官方:K8s 认证模块
官方:管理 Service Accounts
官方:使用准入控制插件
本文介绍 ServiceAccount(服务账户,简称sa)的相关内容。
访问 K8s Api Server 需要授权,有几种角色需要访问 apiserver:
- 运维用户:通过
kubectl
交互,api server 会绑定一个特定用户,一般是admin用户。 - Pod 内容器进程:一般使用特定的 sa 访问,sa属于namespace级别。
- 其他客户端:可通过REST API交互。
namespace 与默认 sa
每个namespace都会创建默认的sa,下面是例子:
$ kubectl create namespace demo
namespace/demo created
$ kubectl get sa -n demo
NAME SECRETS AGE
default 1 24s
kubectl get sa default -o yaml -n demo
查看 default sa,yaml 如下:
apiVersion: v1
kind: ServiceAccount
metadata:
creationTimestamp: "2020-03-14T09:13:23Z"
name: default
namespace: demo
resourceVersion: "28056513"
selfLink: /api/v1/namespaces/demo/serviceaccounts/default
uid: 9b6b3184-8f8a-4f6a-bd56-8954ac9e4e71
secrets:
- name: default-token-9vcx8
sa 的 secret 长什么样?
可以看出,sa 使用了 default-token-9vcx8 这个 Secret,下面是其yaml数据。
kubectl get secret default-token-9vcx8 -o yaml -n demo
该 secret 属性如下(token、ca.crt属性仅截取了部分)。
apiVersion: v1
# secret 的三个数据属性字段
data:
ca.crt: LS0tLS1CRUdJTiBDR...
namespace: ZGVtbw==
token: ZXlKaGJHY2lPaUpTVXpJ...
kind: Secret
metadata:
annotations:
kubernetes.io/service-account.name: default
kubernetes.io/service-account.uid: 9b6b3184-8f8a-4f6a-bd56-8954ac9e4e71
creationTimestamp: "2020-03-14T09:13:23Z"
name: default-token-9vcx8
namespace: demo
resourceVersion: "28056512"
selfLink: /api/v1/namespaces/demo/secrets/default-token-9vcx8
uid: 6c685b56-66ef-4439-8fd0-1c59092129ff
type: kubernetes.io/service-account-token
几个重要的属性如下:
-
type: kubernetes.io/service-account-token
-
token :实际是JWT Token,采用 RS256 非对称算法。
-
ca.crt:证书,通过base64解密后可以看到证书内容。
data 中属性都是base64加密的,可通过 echo 内容 | base64 --decode
解密。
下面通过证书来解密JWT Token,这里采用 jwt.io Debugger 工具在线解密。
将base64解密后的ca.crt内容填入公钥文件位置,JWT Token放入左侧,PAYLOAD就是解密后的内容。
Pod 与 默认 sa
创建Pod时若未指定sa,将采用当前namespace 的 default
sa。
下面创建一个nginx Pod。
kubectl create -n demo -f - <<EOF
apiVersion: v1
kind: Pod
metadata:
name: nginx
spec:
containers:
- name: nginx-container
image: nginx
EOF
再看看 Pod 的数据。
kubectl describe pod nginx -n demo
下面是数据:
Name: nginx
Namespace: demo
Containers:
nginx-container:
Mounts:
/var/run/secrets/kubernetes.io/serviceaccount from default-token-9vcx8 (ro)
Conditions:
Volumes:
default-token-9vcx8:
Type: Secret (a volume populated by a Secret)
SecretName: default-token-9vcx8
Optional: false
default-token-9vcx8
是demo namespace下默认sa中的secret- 创建Pod时将该sa的secret自动作为volume挂载到了容器中
- 挂载的目录下就是
default-token-9vcx8
包含的三个属性,即:JWT token、JWT 公钥、namespace,都已自动通过base64解密,下面是容器中挂载的三个文件:
$ ls -l /var/run/secrets/kubernetes.io/serviceaccount
total 0
lrwxrwxrwx 1 root root 13 Mar 14 09:47 ca.crt -> ..data/ca.crt
lrwxrwxrwx 1 root root 16 Mar 14 09:47 namespace -> ..data/namespace
lrwxrwxrwx 1 root root 12 Mar 14 09:47 token -> ..data/token
Pod 中 sa 自动处理机制(准入控制器)
Pod 未指定 sa 时,Admission Controller (准入控制器) 会自动进行处理,准入控制器属于 apiserver 的一部分,当 pod 被创建或更新时,它会同步地修改 pod。
该插件默认激活,当Pod创建or更新时,会执行如下策略:
- 若 Pod 未设置 sa,自动将其 sa 设置为
default
- 若 Pod 未设置
ImagePullSecrets
,自动将 sa 中ImagePullSecrets
添加到Pod - 将 sa 的 secret 中用于API访问的token以 volume形式挂载到容器中
其中第二点非常重要,可以用于自动处理 Docker Registry 的安全凭证。
sa 中的 Secret 来自何方(Token管理器)?
sa 属于一种安全凭证,其中包含Secret,那Secret又是如何添加到sa中的?先演示效果。
下面创建一个sa.
kubectl create -f - <<EOF
apiVersion: v1
kind: ServiceAccount
metadata:
name: demo-sa
EOF
kubectl get sa demo-sa -o yaml
拿到yaml如下:
apiVersion: v1
kind: ServiceAccount
metadata:
creationTimestamp: "2020-03-14T12:30:19Z"
name: demo-sa
namespace: default
resourceVersion: "28078771"
selfLink: /api/v1/namespaces/default/serviceaccounts/demo-sa
uid: 83b4c80f-ef7d-4ccc-83dc-b88ca3230bcf
secrets:
- name: demo-sa-token-qsz5d
Secret demo-sa-token-qsz5d
是自动创建的,kubernetes.io/service-account-token
类型。
各namespace 中 kubernetes.io/service-account-token 类型的 Secret 中的公钥都是一样的。
给sa创建secret是由 Token Manager(Token 管理器) 以异步的方式完成,处理策略如下:
- sa 创建时,自动为其创建 secret 以支持API访问
- sa 删除时,自动删除关联的 secret
- 删除 sa 中的 secret 时,自动为其创建新的 secret
利用 sa 自动处理 ImagePullSecret
当Pod未指定 ImagePullSecrets时,会自动使用sa的secret,从而替Pod统一屏蔽掉拉取镜像的 Secret。
为sa添加 imagePullSecrets
即可,当然也可以动态变更namespace的 default
sa,添加后后续创建的所有Pod就会自动添加 imagePullSecrets
策略。
kubectl create -f - <<EOF
apiVersion: v1
kind: ServiceAccount
metadata:
name: demo-sa
imagePullSecrets:
- name: registry-tecent-secret
EOF
下面创建Pod演示,需指定 spec.serviceAccountName
为上面的 demo-sa
,demo-sa
中的 registry-tecent-secret
用于拉取镜像。
kubectl create -f - <<EOF
apiVersion: v1
kind: Pod
metadata:
name: nginx
spec:
serviceAccountName: demo-sa
containers:
- name: nginx-container
image: nginx
EOF
查看Pod的yaml数据,仅保留sa相关内容后如下:
apiVersion: v1
kind: Pod
spec:
containers:
- image: nginx
name: nginx-container
# 使用了 demo-sa 中的 secret 并挂载到容器中
volumeMounts:
- mountPath: /var/run/secrets/kubernetes.io/serviceaccount
name: demo-sa-token-qcpns
readOnly: true
# Token Manager 自动将sa中secret设置到了Pod中
imagePullSecrets:
- name: registry-tecent-secret
serviceAccount: demo-sa
serviceAccountName: demo-sa
欢迎关注公众号 [陈一乐],一起学习,一起成长