iT邦幫忙

2026 iThome 鐵人賽

DAY 12
0
Kubernetes

初見 Kubernetes - 純網站後端開發踏入 K8s 世界的經驗分享系列 第 12 篇

Day 12 - ConfigMap 與 Secret:一般設定資料與敏感資料要如何分開

  • 分享至 

  • xImage
  •  

同一份 container image 通常要在開發、測試與正式環境運作,但資料庫位址、功能開關、憑證與密碼不應跟著 image 一起寫死,否則每次要異動都得進入 container 內調整,而重建新的 Pod 設定又會被還原。

Docker Compose 常用 environment variable 或 bind mount 解決這件事,而 Kubernetes 則提供 ConfigMap 與 Secret,讓設定資料在 image 之外被管理。

兩者都可以被 Pod 使用,但目的不同。今天主要會說明這兩者的差異:ConfigMap 放一般設定,Secret 敏感資料。

ConfigMap 與 Secret 的差別

ConfigMap Secret
適合內容 非敏感設定:功能開關、一般 URL、log level、應用參數 密碼、Token、私鑰、TLS certificate 與 private key 的組合、registry credential
Pod 使用方式 environment variable、command/args、Volume 檔案 environment variable、Volume 檔案、特定 Kubernetes 功能
data 欄位 一般字串設定 值必須是 Base64 編碼;建立時也可用 stringData 提供一般字串,API Server 會合併到 data。
安全意義 不提供保密性 專門表達敏感資料;可在 RBAC 中與 ConfigMap 分別授權,通常應採更嚴格的最小權限;但不是自動加密保險箱。

例如 ASP.NET Core 的一般 log level、非敏感功能開關或服務 URL,可以放在 ConfigMap;資料庫密碼、JWT signing key、客戶憑證私鑰,則應放在 Secret。

https://ithelp.ithome.com.tw/upload/images/20260925/20124323JmnySOU3rk.jpg

Pod 如何使用這些元件?

ConfigMap 與 Secret 最常見有兩種掛載方式:

  1. Environment variable:適合單一設定值,例如 ASPNETCORE_ENVIRONMENT、feature flag 或 endpoint。
  2. Volume 檔案:適合完整的設定檔、憑證或金鑰檔,讓應用程式按照既有的檔案路徑讀取。

Kubernetes 只負責把資料以環境變數或檔案提供給 container,它不會理解 ASP.NET Core 的 appsettings.json,也不會自動知道程式期望哪個檔名或哪個資料夾。

以 .NET 來舉例,可以把 ConfigMap/Secret 想成部署時提供給設定系統的來源。程式仍必須正確讀取 environment variable 或檔案。

Secret 的內容是 Base64

Secret 的 data 欄位需要 Base64 編碼,但 Base64 只是把資料換成文字表示方式,任何拿到資料的人都能解碼。它不是加密,也不能當成防止機密外洩的措施。

text
原始密碼 → Base64 編碼 → Secret.data
│
└─ 可被解碼,不等於安全保存

Kubernetes Secret 是否會以加密形式寫入 etcd,取決於叢集是否設定 encryption at rest。除此之外,還需要搭配 RBAC、Namespace 隔離、最小權限、審計與機密交付流程。

能建立 Pod 的權限本身也值得小心:若某個人能任意建立 Pod 並掛載同 Namespace 的 Secret,他可能不必直接讀取 Secret API,就能讓 container 印出其中內容。

因此 Secret 並不是「直接拿來用就是安安全的」,而是「它讓敏感資料被明確標示、以 Kubernetes 的敏感資料機制傳遞,並能套用相對應的治理」。Kubernetes 不會因為使用 Secret 就自動提供更嚴格的權限或 encryption at rest,這些仍需由叢集設定與 RBAC 明確落實。

ConfigMap 與 Secret 的 RBAC

ConfigMap 與 Secret 都是 Kubernetes API 資源,也都會經過 RBAC 授權。

Kubernetes 不會因為物件是 Secret,就自動拒絕所有讀取;若某個 Role 同時授與 configmaps 與 secrets 的 get、list 或 watch,被綁定的使用者便能讀取兩者。

真正的差異在於我們可以把它們寫成不同的 RBAC rule,並透過不同的 RoleBinding 綁給不同的人或 ServiceAccount。

例如一般開發人員可以檢視 Namespace 內的 ConfigMap,但沒有任何讀取 Secret 的權限;只有專責機密維運群組能讀取指定的 Secret。

# Namespace: catalog
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
  name: configmap-reader
rules:
  - apiGroups: [""]
    resources: ["configmaps"]
    verbs: ["get", "list", "watch"]
---
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
  name: developers-read-configmaps
subjects:
  - kind: Group
    name: developers
    apiGroup: rbac.authorization.k8s.io
roleRef:
  kind: Role
  name: configmap-reader
  apiGroup: rbac.authorization.k8s.io
---
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
  name: production-db-secret-reader
rules:
  - apiGroups: [""]
    resources: ["secrets"]
    resourceNames: ["production-db-credentials"]
    verbs: ["get"]
---
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
  name: security-operators-read-db-secret
subjects:
  - kind: Group
    name: security-operators
    apiGroup: rbac.authorization.k8s.io
roleRef:
  kind: Role
  name: production-db-secret-reader
  apiGroup: rbac.authorization.k8s.io

藉此看清楚角色邊界:

  • developers 只被綁定到 ConfigMap Role,不能用 API 讀取 Secret;
  • security-operators 才額外被綁定到指定 Secret 的 get 權限。

Role 是「可做什麼」,RoleBinding 是「把誰連到這個角色」;兩者都屬於 Namespace 範圍時,權限也只在該 Namespace 生效。

Secret 特別要小心 list 與 watch。官方文件明確指出,這兩個權限也可能讓主體取得 Secret 內容,所所以設定上也要特別小心。

對於只需要一個已知 Secret 的人或元件,優先考慮以 get 搭配 resourceNames 限定名稱;若不必透過 Kubernetes API 主動讀取 Secret,就不要授與 Pod 的 ServiceAccount secrets 讀取權限。

最後還有一個容易忽略的例外:能在同一個 Namespace 建立 Pod、Deployment 等工作負載的人,可能把該 Namespace 的 Secret 掛進自己建立的 Pod,進而間接讀到內容。

因此 Secret 保護不只看 secrets/get,也要限制工作負載建立權限、採 Namespace 隔離,並配合審計。這也是為什麼「能看 ConfigMap、不能看 Secret」只是最小權限設計的起點。

那為什麼不把所有設定都放 Secret?

把所有設定都放進 Secret,表面上看起來比較安全,其實會讓界線變模糊。

  • 非敏感設定被誤當成機密,維運者難以一眼看出真正需要保護的是什麼。
  • 一般設定的更新、檢視與差異比對會變得不方便。
  • Secret 應搭配更嚴格的存取、交付與輪替治理;這些成本不應套用到單純的 log level 或 feature flag。

反過來,也不要把密碼、私鑰或憑證放入 ConfigMap,只因為「比較容易看」。ConfigMap 官方文件明確指出它不提供保密性或加密。

常見的 Secret 類型

最常見的是 Opaque,用來放自訂 key-value 敏感資料。Kubernetes 也有一些具明確格式的類型:

  • kubernetes.io/tls:TLS 憑證與私鑰。
  • kubernetes.io/dockerconfigjson:container registry credential。
  • kubernetes.io/basic-auth:帳號密碼。

選擇明確 type 的好處是讓讀者看得懂用途,Kubernetes API 也能對部分必要 key 進行基本檢查;但它仍不會代替我們驗證憑證有效性或確保密碼安全。

實務案例:掛載成功,不代表程式讀得到

另一個案例中,ConfigMap 資源與 Volume 都已成功建立,但掛載路徑的單複數和程式預期不同。Kubernetes 看來沒有錯,container 裡也確實有檔案,只是程式讀的是另一個資料夾,因此設定完全沒有生效。

這類問題很像 .NET 設定檔放在正確硬碟、卻沒有被 ConfigurationBuilder 加入來源:檔案存在不代表程式一定會讀取。部署驗證除了看 kubectl get,也要確認 container 內的實際路徑、檔名與應用設定讀取邏輯。

今日結論

ConfigMap 用於非敏感設定,Secret 用於敏感資料;兩者都能以環境變數或檔案交給 Pod。Secret 的 data 只是 Base64 編碼,不能當成加密或完整的安全方案;還要透過 RBAC 將 ConfigMap 與 Secret 分別授權,並避免過度授與 Secret 的讀取與工作負載建立權限。

參考資料


上一篇
Day 11 - Service:ClusterIP、LoadBalancer、NodePort
下一篇
Day 13 - etcd:Kubernetes 如何保存叢集狀態
系列文
初見 Kubernetes - 純網站後端開發踏入 K8s 世界的經驗分享 共 16 篇
圖片
  熱門推薦
圖片
{{ item.channelVendor }} | {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言