一、Secret介紹
在Kubernetes集群資源中,Secret對象與ConfigMap對象類似,但它主要是用於存儲小片敏感的需要加密的數據,例如密碼,token和SSH key密鑰等等。這類數據當然也可以存放在Pod的定義中或者鏡像中,但是放在Secret中是為了更方便的控制如何使用數據,更加安全和靈活,並減少信息暴露的風險。在secret中存儲的數據都需要通過base64進行轉換加密后存放。Secret解決了密碼、token、密鑰等敏感數據的配置問題,使用Secret可以避免把這些敏感數據以明文的形式暴露到鏡像或者Pod Spec中。用戶可以創建自己的secret,系統也會有自己的secret。
Secret一旦被創建,則可以通過以下三種方式來使用:
-> 在創建Pod時,通過為pod指定Service Account來自動使用該Secret,主要用於API Server鑒權的過程;
-> 通過掛載Secret到Pod來使用它。即作為volume的一個域被一個或多個容器掛載;
-> Docker鏡像下載時使用,通過指定Pod的spc.ImagePullSecret來引用。一般用於私有倉庫登錄拉取鏡像。即在拉取鏡像的時候被kubelet引用。
Kubernetes集群中有內建的Secrets:即由ServiceAccount創建的API證書附加的秘鑰,Kubernetes會自動生成的用來訪問apiserver的Secret,所有Pod會默認使用這個Secret與apiserver通信。這是Kubernetes 默認的行為,也可以通過自定義的方式禁用或者創建我們所需要的Secret。
二、Secret 類型和使用
-> Opaque:使用base64編碼存儲信息,可以通過base64 --decode解碼獲得原始數據,因此安全性弱。
-> kubernetes.io/dockerconfigjson:用於存儲docker registry的認證信息。
-> kubernetes.io/service-account-token (即Service Account):用於被 serviceaccount 引用。serviceaccout 創建時,Kubernetes 會默認創建對應的 secret。Pod 如果使用了 serviceaccount,對應的 secret 會自動掛載到 Pod 的 /run/secrets/kubernetes.io/serviceaccount 目錄中。Service Account 是內置secret,使用 API 憑證自動創建和附加secret。Kubernetes 自動創建包含訪問API憑據的secret,並自動修改pod以使用此類型的secret。如果需要,可以禁用或覆蓋自動創建和使用API憑據。但是,如果需要的只是安全地訪問apiserver,則推薦這樣的工作流程。
第一種類型: Opaque Secret
Opaque類型的Secret,其value為base64編碼后的值。
1)從文件中創建Secret:分別創建兩個名為username.txt和password.txt的文件
[root@k8s-master01 ~]# echo -n "shibo" > ./username.txt [root@k8s-master01 ~]# echo -n "shibo@123" > ./password.txt
使用kubectl create secret命令創建secret,該命令將這些文件打包到一個Secret中並在API server中創建了一個對象。
[root@k8s-master01 ~]# kubectl create secret generic shibo-secret --from-file=./username.txt --from-file=./password.txt secret/shibo-secret created
2)使用描述文件創建Secret: 首先使用base64對數據進行編碼
[root@k8s-master01 ~]# echo -n 'kevin_bo' | base64 a2V2aW5fYm8= [root@k8s-master01 ~]# echo -n 'kevin@123' | base64 a2V2aW5AMTIz
創建一個類型為Secret的描述文件
[root@k8s-master01 ~]# cat secret.yaml apiVersion: v1 kind: Secret metadata: name: mysecret type: Opaque data: username: a2V2aW5fYm8= password: a2V2aW5AMTIz
執行創建
[root@k8s-master01 ~]# kubectl create -f secret.yaml secret/mysecret created
查看此Secret
[root@k8s-master01 ~]# kubectl get secret|grep "shibo" shibo-secret Opaque 2 2m27s [root@k8s-master01 ~]# kubectl get secret shibo-secret -o yaml apiVersion: v1 data: password.txt: c2hpYm9AMTIz username.txt: c2hpYm8= kind: Secret metadata: creationTimestamp: "2019-06-26T11:20:17Z" name: shibo-secret namespace: default resourceVersion: "1152263" selfLink: /api/v1/namespaces/default/secrets/shibo-secret uid: 607ea323-9804-11e9-90d4-005056ac7c81 type: Opaque [root@k8s-master01 ~]# kubectl describe secret/shibo-secret Name: shibo-secret Namespace: default Labels: <none> Annotations: <none> Type: Opaque Data ==== username.txt: 5 bytes password.txt: 9 bytes
需要注意:默認情況下,get 和 describe 命令都不會顯示文件的內容。這是為了防止將secret中的內容被意外暴露給從終端日志記錄中刻意尋找它們的人。
3)Secret的使用
創建好Secret之后,可以通過兩種方式使用:
-> 以Volume方式
-> 以環境變量方式
Secret 可以作為數據卷被掛載,或作為環境變量暴露出來以供 pod 中的容器使用。它們也可以被系統的其他部分使用,而不直接暴露在 pod 內。例如,它們可以保存憑據,系統的其他部分應該用它來代表您與外部系統進行交互。
在 Pod 中的 volume 里使用 Secret:
-> 創建一個 secret 或者使用已有的 secret。多個 pod 可以引用同一個 secret。
-> 修改您的 pod 的定義在 spec.volumes[] 下增加一個 volume。可以給這個 volume 隨意命名,它的 spec.volumes[].secret.secretName 必須等於 secret 對象的名字。
-> 將下面的配置
spec.containers[].volumeMounts[]
加到需要用到該 secret 的容器中。指定下面的配置
spec.containers[].volumeMounts[].readOnly = true
並設置下面內容為想要該 secret 出現的尚未使用的目錄。
spec.containers[].volumeMounts[].mountPath
-> 修改鏡像並且/或者命令行讓程序從該目錄下尋找文件。Secret的data映射中的每一個鍵都成為了mountPath下的一個文件名。
3.1 將Secret掛載到Volume中 (下面是一個在pod中使用volume掛載secret的例子)
apiVersion: v1 kind: Pod metadata: name: mypod spec: containers: - name: mypod image: redis volumeMounts: - name: data mountPath: "/etc/data" readOnly: true volumes: - name: data secret: secretName: shibo-secret
進入Pod查看掛載的Secret:
# ls /etc/data password.txt username.txt # cat /etc/data/username.txt kevin # cat /etc/data/password.txt kevin@123
想要用的每個secret都需要在spec.volumes 中指明。如果pod中有多個容器,每個容器都需要自己的volumeMounts配置塊,但是每個secret只需要一個spec.volumes。還可以打包多個文件到一個secret中,或者使用的多個secret,怎樣方便就怎樣來。也可以向特性路徑映射secret密鑰。
還可以控制Secret key映射在 volume 中的路徑,可以使用 spec.volumes[].secret.items字段修改每個key的目標路徑。也就是說可以只掛載Secret中特定的key:
apiVersion: v1 kind: Pod metadata: name: mypod spec: containers: - name: mypod image: redis volumeMounts: - name: data mountPath: "/etc/data" readOnly: true volumes: - name: data secret: secretName: shibo-secret items: - key: username path: my-group/my-username
需要注意,在這種情況下:
username 存儲在 /etc/data/my-group/my-username中
password 未被掛載
如果使用了 spec.volumes[].secret.items,只有在 items 中指定的 key 被影射。要使用 secret 中所有的 key,所有這些都必須列在 items 字段中。所有列出的密鑰必須存在於相應的 secret 中。否則,不會創建卷。
3.2 將Secret設置為環境變量
apiVersion: v1 kind: Pod metadata: name: secret-env-pod spec: containers: - name: mycontainer image: redis env: - name: SECRET_USERNAME valueFrom: secretKeyRef: name: shibo-secret key: username - name: SECRET_PASSWORD valueFrom: secretKeyRef: name: shibo-secret key: password restartPolicy: Never
第二種類型:kubernetes.io/dockerconfigjson
kubernetes.io/dockerconfigjson用於存儲docker registry的認證信息,可以直接使用kubectl create secret命令創建:
[root@k8s-master01 ~]# kubectl create secret docker-registry myregistrykey --docker-server=DOCKER_REGISTRY_SERVER --docker-username=DOCKER_USER --docker-password=DOCKER_PASSWORD --docker-email=DOCKER_EMAIL secret/myregistrykey created
查看secret的內容:
[root@k8s-master01 ~]# kubectl get secret|grep myregistrykey myregistrykey kubernetes.io/dockerconfigjson 1 54s [root@k8s-master01 ~]# kubectl get secret myregistrykey -o yaml apiVersion: v1 data: .dockerconfigjson: eyJhdXRocyI6eyJET0NLRVJfUkVHSVNUUllfU0VSVkVSIjp7InVzZXJuYW1lIjoiRE9DS0VSX1VTRVIiLCJwYXNzd29yZCI6IkRPQ0tFUl9QQVNTV09SRCIsImVtYWlsIjoiRE9DS0VSX0VNQUlMIiwiYXV0aCI6IlJFOURTMFZTWDFWVFJWSTZSRTlEUzBWU1gxQkJVMU5YVDFKRSJ9fX0= kind: Secret metadata: creationTimestamp: "2019-06-26T11:35:22Z" name: myregistrykey namespace: default resourceVersion: "1153734" selfLink: /api/v1/namespaces/default/secrets/myregistrykey uid: 7b769a8a-9806-11e9-90d4-005056ac7c81 type: kubernetes.io/dockerconfigjson
通過 base64 對 secret 中的內容解碼:
[root@k8s-master01 ~]# echo "eyJhdXRocyI6eyJET0NLRVJfUkVHSVNUUllfU0VSVkVSIjp7InVzZXJuYW1lIjoiRE9DS0VSX1VTRVIiLCJwYXNzd29yZCI6IkRPQ0tFUl9QQVNTV09SRCIsImVtYWlsIjoiRE9DS0VSX0VNQUlMIiwiYXV0aCI6IlJFOURTMFZTWDFWVFJWSTZSRTlEUzBWU1gxQkJVMU5YVDFKRSJ9fX0=" | base64 --decode {"auths":{"DOCKER_REGISTRY_SERVER":{"username":"DOCKER_USER","password":"DOCKER_PASSWORD","email":"DOCKER_EMAIL","auth":"RE9DS0VSX1VTRVI6RE9DS0VSX1BBU1NXT1JE"}}}
在創建 Pod 的時候,通過 imagePullSecrets 來引用剛創建的 myregistrykey:
apiVersion: v1 kind: Pod metadata: name: data spec: containers: - name: data image: janedoe/awesomeapp:v1 imagePullSecrets: - name: myregistrykey
第三種類型:kubernetes.io/service-account-token
用於被 serviceaccount 引用。serviceaccout 創建時 Kubernetes 會默認創建對應的 secret。Pod 如果使用了 serviceaccount,對應的 secret 會自動掛載到 Pod 的 /run/secrets/kubernetes.io/serviceaccount 目錄中。
[root@k8s-master01 ~]# kubectl run kevin_nginx --image nginx deployment "nginx" created [root@k8s-master01 ~]# kubectl get pods NAME READY STATUS RESTARTS AGE kevin_nginx-3137573019-md1u2 1/1 Running 0 13s [root@k8s-master01 ~]# kubectl exec kevin_nginx-3137573019-md1u2 ls /run/secrets/kubernetes.io/serviceaccount ca.crt namespace token