跳至主要内容

Volume - Secret

什麼是 Secret?

在 Kubernetes 中,Secret 是一種資源物件,用於安全地存儲敏感數據,例如密碼、OAuth token、SSH key 等。與 ConfigMap 類似,Secret 能夠以鍵值對的形式存儲數據,但它的數據會被加密或編碼以提高安全性。

Secret 的主要特點包括:

  • 敏感數據存儲:避免將敏感數據直接存放在 Pod 規範中。
  • 靈活使用:可作為環境變量、Volume 或文件的形式掛載到 Pod 中。
  • 安全性:通過 Base64 編碼存儲,並可以與 Kubernetes 中的 RBAC 一起使用來保護數據。

Secret 的類型

Kubernetes 提供了多種類型的 Secret,可以根據需求選擇合適的類型:

Secret 類型描述
Opaque默認類型,用於存儲任意鍵值對數據。
kubernetes.io/service-account-token用於存儲服務帳號的 token,自動創建並分配給 Pod。
kubernetes.io/dockercfg用於存儲 Docker 鏡像拉取的 ~/.dockercfg 文件。
kubernetes.io/dockerconfigjson用於存儲 Docker 鏡像拉取的 JSON 格式認證信息。
kubernetes.io/tls用於存儲 TLS 私鑰和證書(PEM 格式)。
bootstrap.kubernetes.io/token用於集群引導過程中的 token。

Secret 的生命週期

  1. 創建 Secret: Secret 可以通過 YAML 文件、Kubernetes CLI 或程序化的方式創建。
  2. 掛載到 Pod: Secret 可作為環境變量或 Volume 掛載到 Pod 中,供容器使用。
  3. 更新 Secret: Secret 可以被更新,更新後相關 Pod 將獲取新的數據。
  4. 刪除 Secret: 如果 Secret 被刪除,相關的 Pod 將無法訪問這些敏感數據。

Secret 的使用方式

1. 作為環境變量

Secret 可以作為 Pod 的環境變量,容器內應用程序可直接通過環境變量訪問。

2. 掛載為 Volume

Secret 可作為文件掛載到 Pod 的文件系統,應用程序可以從指定路徑讀取。

3. 使用於容器映像憑據

Secret 可以用來存儲 Docker 鏡像的認證信息,以便 Kubernetes 拉取私有鏡像。


注意事項

  1. Base64 編碼: Secret 資料是以 Base64 編碼的形式存儲,但這不是加密,因此不要將其視為完全安全的保護機制。
  2. 安全性
    • 使用 Kubernetes 的 RBAC 設定適當的存取權限。
    • 確保 Kubernetes 集群的 etcd 數據存儲是加密的。
  3. 更新影響: Secret 更新後,會立即影響掛載該 Secret 的 Pod。

Secret 的創立

使用指令建立

  1. 直接使用指令建立 Secret
kubectl.exe create secret generic test-secret --from-literal='username=my-account' --from-literal='password=my-password'
---

secret/test-secret created
  1. 查看 Secret,我們會發現 data 只顯示大小,不顯示內容。
kubectl.exe describe secrets test-secret
---

Name: test-secret
Namespace: default
Labels: <none>
Annotations: <none>

Type: Opaque

Data
====
password: 11 bytes
username: 10 bytes

使用 yaml 建立

在建立 Secret 的值時,我們必需先使用 base64 編碼,而 kubernetes 在我們正確掛載後會自動幫我們解碼回原本的值。

  1. 首先假設我們有 my-account 和 my-password 這兩個字串要當成我們的 username 和 password,首先我們需要對他做 base64 加密。
Linux
echo -n "my-account" | base64
echo -n "my-password" | base64
---

bXktYWNjb3VudA==
bXktcGFzc3dvcmQ=
Windows
[Convert]::ToBase64String([System.Text.Encoding]::UTF8.GetBytes("my-account"))
[Convert]::ToBase64String([System.Text.Encoding]::UTF8.GetBytes("my-password"))
---

bXktYWNjb3VudA==
bXktcGFzc3dvcmQ=
  1. 建立一個 test-secret.yaml,裡面的 kind 設定為 Secret,並且在 data 儲存 key-value,並且 value 必須要是 base64 後的數值。
test-secret.yaml
apiVersion: v1
kind: Secret
metadata:
name: test-secret
data:
username: bXktYWNjb3VudA==
password: bXktcGFzc3dvcmQ=
  1. 透過 kubectl 來執行他。
kubectl.exe apply -f test-secret.yaml
---

secret/test-secret created
  1. 並且查看一下結果,我們可以發現他只會顯示加密過後的大小,不會顯示內容。
kubectl.exe describe secrets test-secret
---

Name: test-secret
Namespace: default
Labels: <none>
Annotations: <none>

Type: Opaque

Data
====
password: 11 bytes
username: 10 bytes

實作 Secret

使用 Secret 作為環境變量

  1. 在上面建立 test-secret 之後,我們撰寫一個 pod 來使用這些 secret,我們可以使用 secretKeyRef,指定 Secret 名稱和 Key,就會自動映射到對應的環境變數。
secret-test-pod-key-value.yaml
apiVersion: v1
kind: Pod
metadata:
name: secret-test-pod
spec:
containers:
- name: test-container
image: nginx
env:
- name: USERNAME
valueFrom:
secretKeyRef: # 從 Secret 中引用值來設定環境變數
name: test-secret # Secret 的名稱為 test-secret
key: username # 取 Secret 中的 key 為 username 的值
- name: PASSWORD
valueFrom:
secretKeyRef:
name: test-secret # Secret 的名稱為 test-secret
key: password # 取 Secret 中的 key 為 password 的值
  1. 透過指令來運行這個 Pod
kubectl.exe apply -f .\secret-test-pod-key-value.yaml
---

pod/secret-test-pod created
  1. 我們可以連進去 Pod 查看是否成功注入
kubectl.exe exec -it pods/secret-test-pod -- bash
---

root@secret-test-pod:/#
  1. 透過輸出環境變數來查看是否成功 base64 解碼。
root@secret-test-pod:/# echo $USERNAME
root@secret-test-pod:/# echo $PASSWORD
---

my-account
my-password

使用 Secret 作為 Volume 掛載

  1. 在上面建立 test-secret 之後,我們撰寫一個 pod 來使用這些 secret,我們可以使用 Volume 掛載成檔案。
secret-test-pod-volume.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
  1. 透過指令來執行他。
kubectl.exe apply -f secret-test-pod-volume.yaml
---

pod/secret-test-pod created
  1. 進到 pod 裡面查看,會發現 Secret 被映射成檔案
kubectl.exe exec -it secret-test-pod -- bash
---

root@secret-test-pod:/#
root@secret-test-pod:/# ls /etc/secret-volume/
---

password username
  1. 查看裡面的內容會發現 kubernetes 已經幫我們成功解密。
root@secret-test-pod:/# cat /etc/secret-volume/username
root@secret-test-pod:/# cat /etc/secret-volume/password
---

my-account
my-password

延伸來聊聊 Secret 的安全性挑戰與限制

雖然 Kubernetes 的 Secret 提供了一種管理敏感數據的方式,但它本身並非完全安全,仍存在一些潛在的安全挑戰和限制。以下是一些 Secret 不那麼安全的原因,以及可能造成的影響:

1. Base64 只是編碼,非加密

Secret 的數據存儲於 etcd 中時是以 Base64 編碼 的形式保存,而不是加密。這意味著:

  • Base64 僅僅是將數據轉換為一種易於存儲和傳輸的格式,並不具備安全保護能力。
  • 如果有人取得了 Secret 的數據內容,解碼 Base64 是非常簡單且快速的。

建議

在創建 Secret 時,使用外部工具對敏感數據進行加密,再將加密後的內容存入 Secret 中。

2. etcd 中的存儲未必加密

Kubernetes 的 Secret 資料存儲於集群的 etcd 中。如果 etcd 沒有啟用加密存儲,這些數據將以明文的形式保存於磁碟上:

  • 攻擊者如果能存取 etcd,就能直接讀取到所有的 Secret 資料。
  • 預設情況下,etcd 的加密功能並未自動啟用,需要額外配置。

建議

啟用 etcd 數據存儲加密,並妥善保護 etcd 的存取權限(例如:限制誰可以存取 etcd 資料)。


3. 過於依賴 RBAC

Kubernetes 使用 RBAC(Role-Based Access Control) 來限制誰可以存取 Secret。但在以下情況下,RBAC 的保護可能失效:

  • RBAC 配置錯誤,允許不必要的角色訪問敏感數據。
  • 攻擊者獲得高權限的帳號,繞過了 Secret 的保護。
  • 過多的使用者擁有 Secret 的存取權,增加了資料洩露的風險。

建議

  • 嚴格配置 RBAC,限制 Secret 的存取權限,只允許最小必要的角色存取。
  • 定期審核 RBAC 規則,檢查是否有多餘的存取權。

4. Pod 中的掛載存在風險

Secret 通常以環境變量或 Volume 的形式掛載到 Pod 中,但這些方法可能導致數據洩露:

  • 如果 Pod 內的應用程序被攻擊或接管,攻擊者可以直接讀取 Secret 的內容。
  • 使用環境變量存取 Secret 時,敏感數據可能出現在應用程序的日誌中,因為很多應用程序會記錄環境變量。

建議

  • 優先使用 Volume 掛載,而非環境變量。
  • 確保應用程序避免將 Secret 的內容寫入日誌中。

5. Secret 無法應對節點級攻擊

如果攻擊者取得了 Kubernetes 節點的控制權,他們可能通過以下方式獲取 Secret:

  • 攻擊 kubelet,進一步取得 etcd 的存取權限。
  • 直接讀取掛載到容器內的 Secret 文件。

建議

  • 加強節點層級的安全防護,例如使用強化的節點映像、防火牆規則,以及啟用安全模組(如 SELinux 或 AppArmor)。
  • 定期更新和修補 Kubernetes 節點的安全漏洞。

6. Secret 更新的分發延遲

當 Secret 被更新時,Pod 並不會立刻獲取更新的內容。這可能導致:

  • Pod 在一段時間內仍然使用舊的 Secret 數據,無法及時應對敏感數據的變更。
  • 攻擊者可能利用這段時間窗口來攻擊系統。

建議

  • 配置 Pod 的自動重啟機制,確保更新 Secret 後,相關 Pod 能及時加載新的 Secret。
  • 使用側車容器(Sidecar)監控 Secret 的變更並動態加載。

結論

Kubernetes 的 Secret 提供了一個集中化管理敏感數據的方式,但並非完全安全。在實際使用中,應該結合其他安全機制來保護 Secret,例如:

  1. 啟用 etcd 加密。
  2. 嚴格管理 RBAC 訪問權限。
  3. 在 Pod 中謹慎掛載和使用 Secret。
  4. 配合外部工具(如 AWS Key Management、Google Cloud KMS)進行更高級別的數據加密和管理。