陈同学
微服务
Accelerator
About
# K8s 安全访问:ServiceAccount > [官方:Kubernetes API 访问控制](https://kubernetes.io/zh/docs/reference/access-authn-authz/controlling-access/) > [官方:K8s 认证模块](https://kubernetes.io/zh/docs/reference/access-authn-authz/authorization/#authorization-modules) > [官方:管理 Service Accounts](https://kubernetes.io/zh/docs/reference/access-authn-authz/service-accounts-admin/) > [官方:使用准入控制插件](https://kubernetes.io/zh/docs/reference/access-authn-authz/admission-controllers/) 本文介绍 ServiceAccount(服务账户,简称sa)的相关内容。 访问 K8s Api Server 需要授权,有几种角色需要访问 apiserver: * 运维用户:通过 `kubectl` 交互,api server 会绑定一个特定用户,一般是admin用户。 * Pod 内容器进程:一般使用特定的 sa 访问,sa属于namespace级别。 * 其他客户端:可通过REST API交互。 ## namespace 与默认 sa 每个namespace都会创建默认的sa,下面是例子: ```bash $ 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 如下: ```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数据。 ```bash kubectl get secret default-token-9vcx8 -o yaml -n demo ``` 该 secret 属性如下(token、ca.crt属性仅截取了部分)。 ```yaml 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](https://jwt.io) 工具在线解密。 将base64解密后的ca.crt内容填入公钥文件位置,JWT Token放入左侧,PAYLOAD就是解密后的内容。  ## Pod 与 默认 sa 创建Pod时若未指定sa,将采用当前namespace 的 `default` sa。 下面创建一个nginx Pod。 ```bash kubectl create -n demo -f - <<EOF apiVersion: v1 kind: Pod metadata: name: nginx spec: containers: - name: nginx-container image: nginx EOF ``` 再看看 Pod 的数据。 ```base 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解密,下面是容器中挂载的三个文件: ```bash $ 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](https://kubernetes.io/zh/docs/reference/access-authn-authz/admission-controllers/) (准入控制器) 会自动进行处理,准入控制器属于 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. ```yaml kubectl create -f - <<EOF apiVersion: v1 kind: ServiceAccount metadata: name: demo-sa EOF ``` `kubectl get sa demo-sa -o yaml` 拿到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` 策略。 ```yaml 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` 用于拉取镜像。 ```yaml 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相关内容后如下: ```yaml 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 ```
本文由
cyj
创作,可自由转载、引用,但需署名作者且注明文章出处。
文章标题:
K8s 安全访问:ServiceAccount
文章链接:
https://chenyongjun.vip/articles/150
扫码或搜索 cyjrun 关注微信公众号, 结伴学习, 一起努力