歡迎訪問博客原文
官方: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
歡迎關注公衆號 [陳一樂],一起學習,一起成長