跳至主要内容

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)進行更高級別的數據加密和管理。