天天看點

Kubernetes_梳理出ServiceAccount服務賬号一條線

作者:毛奇志

前言

看圖,如下:

Kubernetes_梳理出ServiceAccount服務賬号一條線

左下角的Pod需要通路k8s的資源,需要通過中間 apiserver 的認證、授權、準入控制 三個東西,這就需要一個serviceAccount,幫助它完成這個過程,才能通路k8s的資源。

一、每個命名空間都會一個有個serviceAccount

serviceAccount的作用是是給叢集内pod裡面的程序使用,用來通路叢集内的資源,是以每個ns都會一個一個名稱為default的命名空間,如下:

Kubernetes_梳理出ServiceAccount服務賬号一條線

同時也可以自定義serviceAccount

為什麼使用了serviceAccount就可以認證叢集,因為每個sa下面都會擁有的一個加密的token,使用 secrets 存儲,

這個secrets(加密token)本質上等同于userAccount的認證叢集的三種憑證檔案:X509用戶端證書,靜态token檔案,靜态賬号密碼檔案。

既然這個ns-monitor命名空間下,有這樣一個名為default的serviceAccount,我們就來使用一下這個serviceAccount,如下,建立一個Pod使用這個serviceAccount:

Kubernetes_梳理出ServiceAccount服務賬号一條線

檢視一下正在運作的 kind: daemonSet 資源 node-exporter,但是沒有找到對serviceAccount的引用,因為任何拉取鏡像的運作資源 (pod replicaset deployment statefulset deamonset job/cronjob) ,對于serviceAccount(serviceAccount類型的secrets)的引用,都是在底層的Pod裡面的,是以要看pod,如下:

Kubernetes_梳理出ServiceAccount服務賬号一條線

檢視daemonset底層運作的pod,找到了對于serviceAccount類型type的secrets的引用,如下:

Kubernetes_梳理出ServiceAccount服務賬号一條線

至此,這個名為default的serviceAccount就被pod使用了,這個pod使用了這個serviceAccount(其實是加載了這個serviceAccount關聯的secrets)之後,就可以通路k8s叢集内的資源。

那麼,為什麼pod啟動通過volume加載了type類型為serviceAccount的secrets之後,就可以通路到k8s裡面資源呢?我們看一下這個secrets到底存儲的哪些資料data (secrets類似一個加密的configmap,可以簡單了解為配置檔案,裡面存儲了資料)

一個 secrets (type:serviceAccount) 裡面包含的data是:加密的ca.crt、加密的namespace、加密的token,如下:

Kubernetes_梳理出ServiceAccount服務賬号一條線

二、Secret三種type

Kubernetes提供了Secret來處理敏感資訊,目前Secret的類型有3種,通過type屬性指定:

Opaque(default): 任意字元串,使用base64編碼存儲資訊,可以通過base64 --decode解碼獲得原始資料,是以安全性弱。

kubernetes.io/service-account-token: 作用于ServiceAccount,就是上面說的。

kubernetes.io/dockercfg: 作用于Docker registry,使用者下載下傳docker鏡像認證使用。

type類型 建立secret的方式 使用這個secret的方式
Opaque(default) kubectl 指令手動建立 拉取鏡像的Pod yaml檔案中,volume檔案挂盤或者env使用
kubernetes.io/service-account-token 建立命名空間會自動建立一個預設的serviceAccount,這個serviceAccount裡面會自動建立一個type為serviceAccount的secret;kubectl 指令手動建立,自定義的serviceAccount被建立起來,會自動建立一個type為serviceAccount的secret 運作的Pod通過volume檔案挂盤使用這個type為serviceAccount的secret
kubernetes.io/dockercfg kubectl 指令手動建立 所有需要拉取鏡像的場景/kind類型,可以是Pod,也可以是replicasets deployment statefulset daemonset job/cronjob,yaml檔案中被imagePullSecrets屬性使用,用來拉取鏡像的賬号密碼

2.1 Opaque(default)

Opaque類型的Secret的value為base64位編碼後的值

2.1.1 Secret建立的兩種方式

建立方式1:從檔案中建立Secret

echo -n "admin" > ./username.txt
echo -n "1f2d1e2e67df" > ./password.txt
           
kubectl create secret generic db-user-pass --from-file=./username.txt --from-file=./password.txt
           
kubectl get secret
           

示範如下:

Kubernetes_梳理出ServiceAccount服務賬号一條線

建立方式2:使用yaml檔案建立Secret

(1)對資料進行64位編碼
echo -n 'admin' | base64
echo -n '1f2d1e2e67df' | base64
           
(2)定義mysecret.yaml檔案
apiVersion: v1
kind: Secret
metadata:
  name: mysecret
type: Opaque
data:
  username: YWRtaW4=
  password: MWYyZDFlMmU2N2Rm
           
(3)根據yaml檔案建立資源并檢視
kubectl create -f ./secret.yaml
kubectl get secret
kubectl get secret mysecret -o yaml
           

示範如下:

Kubernetes_梳理出ServiceAccount服務賬号一條線

2.1.2 Secret使用的兩種方式

  • 以Volume方式
  • 以環境變量方式

使用方式1:以Volume方式使用Secret

kubectl apply -f mypod.yaml
apiVersion: v1
kind: Pod
metadata:
  name: mypod
spec:
  containers:
  - name: mypod
    image: redis
    volumeMounts:
    - name: foo
      mountPath: "/etc/foo"
      readOnly: true
  volumes:
  - name: foo
    secret:
      secretName: mysecret
           
kubectl exec -it pod-name bash  ## 進去
ls /etc/foo
cat /etc/foo/username
cat /etc/foo/password
           

以Volume方式使用Secret,示範如下:

Kubernetes_梳理出ServiceAccount服務賬号一條線

使用方式2:将Secret設定為環境變量

kubectl get secret mysecret -o yaml
vi secret-env-pod.yaml
kubectl apply -f secret-env-pod.yaml
kubectl get pod 
kubectl exec -it 具體pod名稱 bash
           
apiVersion: v1
kind: Pod
metadata:
  name: secret-env-pod
spec:
  containers:
  - name: mycontainer
    image: redis
    env:
      - name: SECRET_USERNAME
        valueFrom:
          secretKeyRef:
            name: mysecret
            key: username
      - name: SECRET_PASSWORD
        valueFrom:
          secretKeyRef:
            name: mysecret
            key: password
  restartPolicy: Never
           

示範如下:

Kubernetes_梳理出ServiceAccount服務賬号一條線

小結:secret兩種方式被建立,建立完之後都可以被pod裡面的container去使用

使用的方式:環境變量(container下面的env)、參數(container下面的args)、volume目錄挂載(container下面的volume)

2.2 kubernetes.io/service-account-token

Kubernetes_梳理出ServiceAccount服務賬号一條線

一般來說,k8s資源有不同的kind。

configmap secret user usergroup serviceAccount 不需要運作具體的程式,是以不需要 image: 屬性拉取鏡像

pod replicasets deployment statefulset daemonset job/cronjob 需要運作具體的程式,是以需要 image: 屬性拉取鏡像

另外,從來沒有一種kind: UserAccount類型的資源

2.3 kubernetes.io/dockercfg

在需要安全驗證的環境中拉取鏡像的時候,需要通過使用者名和密碼。

apiVersion: v1
kind: Secret
metadata:
  name: myregistrykey
  namespace: awesomeapps
data:
  .dockerconfigjson: UmVhbGx5IHJlYWxseSByZWVlZWVlZWVlZWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWxsbGxsbGxsbGxsbGxsbGxsbGxsbGxsbGxsbGxsbGx5eXl5eXl5eXl5eXl5eXl5eXl5eSBsbGxsbGxsbGxsbGxsbG9vb29vb29vb29vb29vb29vb29vb29vb29vb25ubm5ubm5ubm5ubm5ubm5ubm5ubm5ubmdnZ2dnZ2dnZ2dnZ2dnZ2dnZ2cgYXV0aCBrZXlzCg==
type: kubernetes.io/dockerconfigjson
           

或者直接通過指令建立

kubectl create secret docker-registry myregistrykey \
 --docker-server=DOCKER_REGISTRY_SERVER --docker-username=DOCKER_USER \
 --docker-password=DOCKER_PASSWORD --docker-email=DOCKER_EMAIL
           

接下來拉取鏡像的時候,就可以使用了

apiVersion: v1
kind: Pod
metadata:
  name: foo
  namespace: awesomeapps
spec:
  containers:
    - name: foo
      image: janedoe/awesomeapp:v1
  imagePullSecrets:
    - name: myregistrykey
           

其實本質上還是kubelet把這個認證放到了docker的目錄下面,如下:

cat ~/.docker/config.json 
{
    "auths": {
        "10.39.0.118": {
            "auth": "Y2hlbm1vOmNtMTM4MTE2NjY3ODY="
        },
        "10.39.0.12:5000": {
            "auth": "dXNlcjAxOjEyMzQ1YQ=="
        },
        "http://10.39.0.12:5000": {
            "auth": "dXNlcjAxOjEyMzQ1YQ=="
        }
    }
}
           

三、自定義ServiceAccount再分析一遍

3.1 Service Account建立

#檢視serviceaccount資源
[root@k8s-master ~]# kubectl get sa     
NAME      SECRETS   AGE
default   1         7d19h
#建立一個名為admin的serviceaccount資源
[root@k8s-master ~]# kubectl create serviceaccount admin    
serviceaccount/admin created
#檢視serviceaccount資源
[root@k8s-master ~]# kubectl get sa     
NAME      SECRETS   AGE
admin     1         7s
default   1         7d19h
#檢視serviceaccount資源admin的詳細資訊,可以看出已經自動生成了一個Tokens:admin-token-lc826
[root@k8s-master ~]# kubectl describe sa/admin    
Name:                admin
Namespace:           default
Labels:              <none>
Annotations:         <none>
Image pull secrets:  <none>
Mountable secrets:   admin-token-lc826
Tokens:              admin-token-lc826
Events:              <none>
#檢視secret,可以檢視也生成了一個admin-token-lc826的secret資源
[root@k8s-master ~]# kubectl get secret    
NAME                  TYPE                                  DATA   AGE
admin-token-lc826     kubernetes.io/service-account-token   3      50s
......
           
Kubernetes_梳理出ServiceAccount服務賬号一條線

3.2 在Pod中使用自定義的service account

每個Pod對象均可附加其所屬名稱空間中的一個Service Account資源,且隻能附加一個。不過,一個Service Account資源可由所屬名稱空間中的多個Pod對象共享使用。建立Pod時,通過“spec.serviceAccountName”進行定義。示例如下:

[root@k8s-master manfests]# vim pod-sa-demo.yaml    #編輯資源清單檔案
apiVersion: v1
kind: Pod
metadata:
  name: pod-sa-demo
  namespace: default
  labels:
    app: myapp
    tier: frontend
spec:
  containers:
  - name: myapp
    image: ikubernetes/myapp:v1
    ports:
    - name: http
      containerPort: 80
  serviceAccountName: admin    #指定serviceAccount資源名稱
  
[root@k8s-master manfests]# kubectl apply -f pod-sa-demo.yaml 
pod/pod-sa-demo created
[root@k8s-master manfests]# kubectl get pods -l app=myapp
NAME          READY   STATUS    RESTARTS   AGE
pod-sa-demo   1/1     Running   0          9s
[root@k8s-master manfests]# 
[root@k8s-master manfests]# kubectl describe pods/pod-sa-demo
Name:         pod-sa-demo
Namespace:    default
......
Volumes:
  admin-token-lc826:
    Type:        Secret (a volume populated by a Secret)
    SecretName:  admin-token-lc826      #這裡可以看出挂載token就是上面建立的sa所生成的那個
    Optional:    false
......
           
Kubernetes_梳理出ServiceAccount服務賬号一條線
Kubernetes_梳理出ServiceAccount服務賬号一條線
Kubernetes_梳理出ServiceAccount服務賬号一條線

總結

總結一下,梳理出ServiceAccount服務賬号一條線,kind: serviceAccount 作為k8s叢集内的一類資源,每個命名空間都會一個名為default的預設的serviceAccount,預設不指定的情況下,這個命名空間下所有的pod都是使用名為default的預設的serviceAccount,這個serviceAccount是通過secrets存儲的,這個secrets等效加密的configmap,就是配置檔案一類東西,type是serviceAccount,包含的data是:加密的namespace、加密的ca.crt、加密的token,有了這些data,這個命名空間下的Pod在啟動的時候通過volume挂盤的方式,将secrets加載到整個Pod裡面,Pod的程序就可以通路k8s叢集内的資源了。

然後,這種用在serviceAccount上的secrets隻是一種類型type的secrets,secrets還有兩種其他類型type的,普通字元串和imagePullSecrets,順便一起學習了。

最後,還可以自定義ServiceAccount,再重新分析一遍,加深了解。

這裡面有一個難以搞清的概念,那就是對于一一對應關系的serviceAccount和secrets,其實不用分的這麼清楚,serviceAccount是一個賬号,secrets是這個賬号裡面存儲的資料,然後一一綁定在一起,甚至簡單點了解,兩個東西作為一個整體,任何是一個東西都可以(因為很難分開)。

Kubernetes_梳理出ServiceAccount服務賬号一條線

繼續閱讀