在 Kubernetes 的世界裡,Secret 是我們拿來存放敏感資訊的標準做法——不管是資料庫連線字串、API Token 還是各種帳號密碼,通通往 Secret 裡面丟就對了。不過如果你曾經用 kubectl get secret -o yaml 看過 Secret 的內容,應該馬上就會發現一件事:所謂的「秘密」根本就是 base64 編碼而已,隨便一個 base64 -d 就能還原明文,這跟沒加密有什麼兩樣?
本篇文章就來聊聊 K8s 原生 Secret 到底有哪些安全上的隱憂,以及社群和業界提供了哪些替代方案來補強這個缺口。
原生 Secret 的三大洩漏途徑
簡單歸納,Secret 的明文內容可能從以下三個地方被不該看到的人取得:
| 洩漏途徑 | 說明 |
|---|---|
| etcd 儲存層 | API Server 的所有資源都存在 etcd 裡,預設是明文(base64 decode 後的原文)直接寫入 |
| API Server | 只要有足夠的 RBAC 權限,任何節點都能透過 API 拿到 Secret 內容 |
| Worker Node 檔案系統 | Secret 以 volume 掛載進 Pod 後,在節點上可以直接讀取對應的 tmpfs 檔案 |
範例情境
假設我們建立一個 Secret,裡面放了使用者名稱 ******** 和密碼 ********:
apiVersion: v1
kind: Secret
metadata:
name: mysecret
type: Opaque
data:
username: ********
password: ********
接著建一個 Pod,把這個 Secret 當作 volume 掛進去:
apiVersion: v1
kind: Pod
metadata:
name: mypod
spec:
containers:
- name: mypod
image: docker.io/containerstack/alpine-stress
command:
- top
volumeMounts:
- name: foo
mountPath: "/etc/foo"
readOnly: true
volumes:
- name: foo
secret:
secretName: mysecret
Pod 跑起來之後,進到容器裡面直接 cat /etc/foo/password 就能看到明文,這是預期行為。但問題在於,不只容器內部,其他途徑也能輕鬆拿到這些資料。
從 etcd 直接撈資料
etcd 是 K8s 的後端資料庫,如果有人能存取 etcd 的資料檔案,用 hexdump 就能直接看到 Secret 的明文內容:
# hexdump -C /var/lib/etcd/member/snap/db | grep -A 5 -B 5 hello
從 Kubernetes 1.7 開始已經支援 etcd 的靜態加密(Encryption at Rest),但這需要額外設定,不是預設啟用的。
從 API Server 查詢
這是最常見的情境,只要擁有對應的 RBAC 權限:
$ kubectl get secret mysecret -o yaml
拿到的 base64 字串,隨手一個 echo "xxxx" | base64 -d 就破解了。在大型團隊裡,很多不該看到這些資訊的人可能都有相關權限。
從 Node 上讀取檔案
在 Worker Node 上,Secret 會被掛載到 tmpfs:
# mount | grep foo
tmpfs on /var/lib/kubelet/pods/<pod-uid>/volumes/kubernetes.io~secret/foo type tmpfs (rw,relatime)
# cat /var/lib/kubelet/pods/<pod-uid>/volumes/kubernetes.io~secret/foo/password
只要有 Node 的 SSH 權限,就能直接讀到 Secret 明文。
GitOps 時代讓問題更嚴重
現在越來越多團隊採用 GitOps 的理念,所有 K8s manifest 都會放進 Git 版本控制。這代表 Secret 的 YAML 檔(即使是 base64 編碼)也會存在 Git repo 裡面,等於又多了一個洩漏的管道。任何能 clone 這個 repo 的人,都能輕鬆解碼看到原始內容。

第三方解決方案一覽
要真正確保 Secret 的安全,光靠原生功能是不夠的。以下整理幾個主流的第三方方案:
| 方案 | 類型 | 特色 |
|---|---|---|
| Sealed Secrets | 加密後存入 Git | 使用非對稱加密,只有叢集內的 Controller 能解密 |
| HashiCorp Vault | 外部 KMS | 業界最成熟的方案,支援 Sidecar Injector 和 CSI Driver |
| External Secrets Operator | 外部同步 | 從 AWS/GCP/Azure 等雲端 KMS 同步 Secret 到 K8s |
| mozilla/sops | 加密檔案編輯器 | 支援多種 KMS 後端,可整合 GitOps 流程 |
| Kamus | 應用層加密 | 以 Service Account 為單位加密,透過 init container 解密 |
| kubesec | Secret 值加密 | 僅加密 Secret 中的資料欄位,支援 AWS/GCP KMS 和 GPG |
Sealed Secrets — 最適合 GitOps 的方案
Bitnami 推出的 Sealed Secrets 是目前在 GitOps 場景下最受歡迎的選擇之一。它的運作原理是:
- 叢集內部署一個 SealedSecret Controller,持有一對 RSA 金鑰
- 使用
kubesealCLI 工具搭配 Controller 的公鑰,將 Secret 加密為 SealedSecret 資源 - SealedSecret 可以安全地放進 Git——因為只有叢集內的 Controller 才有私鑰能解密
- Controller 監聽到 SealedSecret 資源後,自動解密並建立對應的 K8s Secret

值得注意的是,SealedSecret Controller 的金鑰本身也是用普通 Secret 儲存的,這算是一個已知的限制。
HashiCorp Vault — 企業級首選
Vault 對 K8s 提供兩種整合方式:
Agent Sidecar Injector:透過 Mutation Webhook 自動注入 init container 和 sidecar,負責從 Vault 取得並解密機密資料,寫入指定的 volume 路徑。Sidecar 還會定期更新 Secret,應用程式只需要讀取檔案即可。
spec:
template:
metadata:
annotations:
vault.hashicorp.com/agent-inject: "true"
vault.hashicorp.com/agent-inject-secret-helloworld: "secrets/helloworld"
vault.hashicorp.com/role: "myapp"
Vault CSI Provider:透過 Secrets Store CSI Driver 介面,以 volume 的形式將 Vault 中的 Secret 掛載到 Pod 裡。
External Secrets Operator — 雲原生整合
如果你的團隊已經在使用雲端供應商的 KMS 服務(如 AWS Secrets Manager、GCP Secret Manager、Azure Key Vault),External Secrets Operator 會是最無痛的選擇。它透過 CRD 定義 ExternalSecret 資源,自動從外部 KMS 拉取機密資訊並建立 K8s Secret。
不過要注意,這種方式的 Secret 在 K8s 叢集內仍然是明文儲存的,主要解決的是「不把 Secret 放進 Git」和「統一管理外部金鑰」的問題。
Secrets Store CSI Driver — 社群標準方案
Kubernetes SIG 維護的 Secrets Store CSI Driver 提供了一個標準化的介面,可以搭配不同的 Provider(Vault、Azure、GCP 等)使用:
apiVersion: secrets-store.csi.x-k8s.io/v1alpha1
kind: SecretProviderClass
metadata:
name: my-provider
spec:
provider: vault
parameters:
# provider-specific parameters
Pod 只需要掛載對應的 CSI volume,就能透過檔案系統存取解密後的 Secret。
我的建議
以我自己的經驗來說,沒有單一方案能解決所有問題,實務上建議採取多層防禦:
- 基本功先做好:啟用 etcd Encryption at Rest、嚴格設計 RBAC 權限、限制 Node SSH 存取
- GitOps 場景:用 Sealed Secrets 或 sops 加密後再 commit
- 企業環境:導入 Vault 或雲端 KMS,搭配 External Secrets Operator 或 CSI Driver
- 最小權限原則:不是每個開發者都需要
get secret的權限
總之,K8s 原生的 Secret 只是一個最基本的資源抽象,base64 編碼從來就不是加密。在正式環境中,一定要搭配額外的安全措施,別讓你的「秘密」變成公開的秘密。

發佈留言