iT邦幫忙

2023 iThome 鐵人賽

DAY 15
0
DevOps

第一次參賽就學 Kubernetes系列 第 15

[Day 15] Secret

  • 分享至 

  • xImage
  •  

不知不覺就寫了半個月了,每天下班的行程就是趕著寫文章。

Secret

在前一篇有提到 ConfigMap,是將非敏感性的資料以明文的方式儲存。這篇提到的 Secret 則是專門用來儲存敏感資訊,例如資料庫 host、帳號、密碼或 keys(例如:API key)。儲存在 sercret 時是以編碼的形式儲存,意思是 secret 只能儲存經編碼(base64)後的資料。

事實上在 secret 中僅是將資料編碼後儲存,並非加密後儲存。將專案上傳到公開的 repository 像是 GitHub 時切記勿把 secret 資料也上傳!因為他人拿到後一樣可以 decode(解碼) 回去。若是要確保 secret 的安全性,建議啟用靜態加密(Encryption at Rest),將 secret 中的敏感信息進行加密後再存儲到 etcd,例如建立一把 secret key 對 secret 的資料進行加密。

另外就是在相同的 namespace 下,任何 pod 或 deployment 皆可以直接存取到相同 namespace 下的 secret。

編碼(encode) & 解碼(decode)

在 Linux 或 macOS 環境下編碼。

echo -n 'data' | base64
ZGF0YQ==

解碼(因指令和輸出會被紀錄下來,故不建議在實務中使用該命令)。

echo 'ZGF0YQ==' | base64 --decode
data%  

在實務上建議以下方式查看。

kubectl get secret db-user-pass -o jsonpath='{.data.password}' | base64 --decode

建立 secret

建立 secret 的方式有幾種:

1. 以設定檔的方式建立

建立 test-secret.yaml

apiVersion: v1
kind: Secret
metadata:
  name: test-secret
data:
  username: bXktYXBw          # 注意這邊是經編碼後的資料
  password: Mzk1MjgkdmRnN0pi  # 注意這邊是經編碼後的資料

再執行指令。

kubectl creat -f test-secret.yaml

直接透過指令建立

例如直接在指令中填上 raw data。

kubectl create secret generic test-secret --from-literal='username=my-app' --from-literal='password=39528$vdg7Jb'

2. 使用檔案方式建立

建立兩份檔案。

echo -n 'admin' > ./username.txt
echo -n 'S!B\*d$zDsb=' > ./password.txt

建立 secret。

kubectl create secret generic db-user-pass \
    --from-file=username=./username.txt \
    --from-file=password=./password.txt

使用 secret 於 pod 環境變數

pod 可藉由三種方式使用 secret:

  1. 透過 envFrom 注入所有定義於 secret 的資料
  2. 透過 valueFrom 使用單個 secret 中的資料
  3. 透過 volume 形式注入

1. 透過 envFrom

建立 secret。

kubectl create secret generic test-secret --from-literal=username='my-app' --from-literal=password='39528$vdg7Jb'

secret/test-secret created

建立 pod-secret-envFrom.yaml

apiVersion: v1
kind: Pod
metadata:
  name: envfrom-secret
spec:
  containers:
  - name: envars-test-container
    image: nginx
    envFrom: # 這邊會使用所有定義在 secret 中的 data
    - secretRef:
        name: test-secret

執行。

kubectl create -f pod-secret-envFrom.yaml

pod/envfrom-secret created

進入 pod 中查看變數。

kubectl exec -it envfrom-secret -- /bin/sh -c 'echo "username: $username\npassword: $password\n"'

username: my-app
password: 39528$vdg7Jb

2. 透過 valueFrom 注入

建立 secret。

kubectl create secret generic backend-user --from-literal=backend-username='backend-admin'

secret/backend-user created

建立 pod-single-secret-env-variable.yaml

apiVersion: v1
kind: Pod
metadata:
  name: env-single-secret
spec:
  containers:
  - name: envars-test-container
    image: nginx
    env:
    - name: SECRET_USERNAME
      valueFrom:
        secretKeyRef:
          name: backend-user
          key: backend-username # 將 backend-user 中的 backend-username 賦予給 SECRET_USERNAME 變數

執行。

kubectl create -f pod-single-secret-env-variable.yaml

pod/env-single-secret created

進入 pod 中查看變數。

kubectl exec -it env-single-secret -- /bin/sh -c 'echo $SECRET_USERNAME'

backend-admin

3. 透過 volume 形式

建立兩個 pods,一個使用 secret 中的生產環境變數,另一個用測試環境的環境變數。

建立生產環境。

kubectl create secret generic prod-db-secret --from-literal=username=produser --from-literal=password=Y4nys7f11

secret/prod-db-secret created

建立測試環境。

kubectl create secret generic test-db-secret --from-literal=username=testuser --from-literal=password=iluvtests

secret/test-db-secret created

為避免變數中有特殊字元,若需要可使用單引號(')來圍住資料。

建立 pod.yaml,這邊會是以 volume 的形式使用 secret 資料。

cat <<EOF > pod.yaml
apiVersion: v1
kind: List
items:
- kind: Pod
  apiVersion: v1
  metadata:
    name: prod-db-client-pod
    labels:
      name: prod-db-client
  spec:
    volumes:
    - name: secret-volume 
      secret: # 這邊定義使用的 secret
        secretName: prod-db-secret # 這邊定義 secret name
    containers:
    - name: db-client-container
      image: myClientImage
      volumeMounts:
      - name: secret-volume
        readOnly: true
        mountPath: "/etc/secret-volume" # secret 的資料會儲存在容器中該路徑 /etc/secret-volume/ 下
- kind: Pod
  apiVersion: v1
  metadata:
    name: test-db-client-pod
    labels:
      name: test-db-client
  spec:
    volumes:
    - name: secret-volume
      secret: # 這邊定義使用的 secret
        secretName: test-db-secret # 這邊定義 secret name
    containers:
    - name: db-client-container
      image: myClientImage
      volumeMounts:
      - name: secret-volume
        readOnly: true
        mountPath: "/etc/secret-volume" # secret 的資料會儲存在容器中該路徑 /etc/secret-volume/ 下
EOF

建立 pods。

kubectl create -f pod.yaml

pod/prod-db-client-pod created
pod/test-db-client-pod created

實際使用 kubectl get pods 可能會看到 pods 的 STATUSInvalidImageName 是正常的,因為文件上並沒有實際寫出這個 image 的來源,文件應僅是單純講解在 yaml 檔中要如何使用 secret。


參考來源

  1. Certified Kubernetes Administrator (CKA) with Practice Tests
  2. Kubernetes - Distribute Credentials Securely Using Secrets

上一篇
[Day 14] ConfigMap
下一篇
[Day 16] 範例:部署 Java 程式到 Kubernetes
系列文
第一次參賽就學 Kubernetes30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言