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就是解密後的內容。

在這裏插入圖片描述

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-sademo-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

歡迎關注公衆號 [陳一樂],一起學習,一起成長

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章