為什麼需要 Secret#

ConfigMap 雖然方便,但它是以「明碼」儲存資料,並不適合放置 API Key、金鑰等敏感資訊。Kubernetes 提供 Secret 作為對應的選擇 — 用法與 ConfigMap 接近,但對敏感資料多了一層保護,避免隨意暴露。

不過要先講清楚:Secret 並沒有想像中那麼「安全」,後面會說明為什麼。

什麼是 Secret#

Secret 在基本操作上與 ConfigMap 大致相同,但定位不同:它是 Kubernetes 提供給開發者用來儲存敏感資料的機制。Kubernetes 自己也使用相同機制儲存 Access Token,控制 API 的存取權限。

Secret 主要有三種類型:

  • Service Account:由 Kubernetes 自動建立並掛載到 Pod,用來存取 Kubernetes API。位於 /run/secret/kubernetes.io/serviceaccount
  • Opaque:以 base64 編碼的 Secret,用來存放密碼、金鑰等。
  • docker-registry:當映像檔存放於私有 Registry 時使用,省去每次都要 docker login 的麻煩。

在 Pod 中存取 Secret 常見的方式:

  • 把 Secret 當作環境變數注入。
  • 把 Secret 以檔案形式掛載到 Pod 中的某個路徑。
  • 加入 docker-registry 類型的 Secret,讓 Kubernetes 自動處理私有 Registry 的登入。

建立 Secret#

建立 Secret 時,值必須先用 base64 編碼,掛載成功後 Kubernetes 會自動還原為原始值。

1. 將內容轉成 base64#

echo -n 'my-account' | base64
echo -n 'my-password' | base64

得到例如:

bXktYWNjb3VudA==
bXktcGFzc3dvcmQ=

2. 撰寫 Secret yaml#

# secret.yaml
apiVersion: v1
kind: Secret
metadata:
  name: test-secret
data:
  username: bXktYWNjb3VudA==
  password: bXktcGFzc3dvcmQ=
kubectl apply -f secret.yaml

3. 查看結果#

kubectl get secret test-secret
NAME          TYPE     DATA   AGE
test-secret   Opaque   2      15s
kubectl describe secret test-secret

describe 只會顯示 key 名稱與大小,不會直接印出值。

4. 直接用 kubectl 建立#

如果不想寫 yaml,也可以直接用指令:

kubectl create secret generic test-secret \
  --from-literal='username=my-account' \
  --from-literal='password=my-password'

generic 這個子命令表示使用本地資源或 key-value 建立 Secret。

在 Pod 中使用 Secret#

把剛剛建立的 test-secret 以檔案形式掛載:

# secret-test-pod.yaml
apiVersion: v1
kind: Pod
metadata:
  name: secret-test-pod
spec:
  containers:
    - name: test-container
      image: nginx
      volumeMounts:
        - name: secret-volume
          mountPath: /etc/secret-volume
  volumes:
    - name: secret-volume
      secret:
        secretName: test-secret

部署並確認:

kubectl apply -f secret-test-pod.yaml
kubectl get pod secret-test-pod

進入容器查看:

kubectl exec -it secret-test-pod -- sh
ls /etc/secret-volume

會看到 usernamepassword 兩個檔案:

cat /etc/secret-volume/username
# my-account

cat /etc/secret-volume/password
# my-password

可以看到掛載到容器中時,內容是「已經自動 base64 解碼後的原值」。

關於 Secret 並沒有想像中安全這件事#

從上面流程可以發現,只要擁有相關權限,就能輕易看到 Secret 的原值。雖然 Secret 在 etcd 中是以 base64 編碼存放,但 base64 並不是加密,本質上等同於明文。

因此:

  • 原生 Secret 並不適合直接拿來作為大型企業內保存高度敏感資料的方案。
  • 對 RBAC(角色權限)的設計挑戰也較高。

要讓原生 Secret 真的「安全」,通常需要同時做到:

  • etcd 加密。
  • API Server 嚴格的權限控制。
  • 強化 Node 權限與系統安全。

這些措施缺一不可,整體成本相當高。社群與雲端服務商因此提供了許多更進階的方案可以參考:

  • AWS Key Management Service(KMS)
  • Google Cloud KMS

理解 Secret 的限制有助於我們在不同情境下做出合理取捨:對於中小型應用,原生 Secret 足夠;對於高度敏感的場景,則應考慮搭配雲端 KMS 或專屬的 Secret 管理方案。

小結#

  • Secret 與 ConfigMap 用法相近,但定位是「敏感資料」的容器。
  • 內容以 base64 編碼,並非加密。
  • 真正落地時需要搭配 etcd 加密、RBAC 與外部 KMS 等機制,才能達到合適的安全等級。

原文出處#

  • GitHub:https://github.com/MikeHsu0618/2022-ithelp/tree/main/Day19
  • iThome:https://ithelp.ithome.com.tw/articles/10293943