K8s 安全访问:ServiceAccount

欢迎访问博客原文
官方: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

几个重要的属性如下:

  • typekubernetes.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就是解密后的内容。

K8s 安全访问:ServiceAccount_第1张图片

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 - <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 - <apiVersion: v1
kind: ServiceAccount
metadata:
  name: demo-sa
imagePullSecrets:
- name: registry-tecent-secret
EOF

下面创建Pod演示,需指定 spec.serviceAccountName 为上面的 demo-sademo-sa 中的 registry-tecent-secret 用于拉取镜像。

kubectl create -f - <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

欢迎关注公众号 [陈一乐],一起学习,一起成长

你可能感兴趣的:(k8s,kubernetes,k8s,ServiceAccount,准入控制器,Token管理器)