Kubernetes 靜態(tài)加密Secret數(shù)據(jù)

2022-06-08 14:42 更新

靜態(tài)加密 Secret 數(shù)據(jù)

本文展示如何啟用和配置靜態(tài) Secret 數(shù)據(jù)的加密

在開始之前

  • 你必須擁有一個 Kubernetes 的集群,同時你的 Kubernetes 集群必須帶有 kubectl 命令行工具。 建議在至少有兩個節(jié)點的集群上運行本教程,且這些節(jié)點不作為控制平面主機。 如果你還沒有集群,你可以通過 Minikube 構(gòu)建一個你自己的集群,或者你可以使用下面任意一個 Kubernetes 工具構(gòu)建:
    • Katacoda
    • 玩轉(zhuǎn) Kubernetes

    要檢查版本,請輸入 ?kubectl version?。

  • 需要 etcd v3.0 或者更高版本

配置并確定是否已啟用靜態(tài)數(shù)據(jù)加密

?kube-apiserver? 的參數(shù) ?--encryption-provider-config? 控制 API 數(shù)據(jù)在 etcd 中的加密方式。 該配置作為一個名為 ?EncryptionConfiguration? 的 API 提供。 下面提供了一個示例配置。

Caution:對于高可用配置(有兩個或多個控制平面節(jié)點),加密配置文件必須相同! 否則,?kube-apiserver? 組件無法解密存儲在 etcd 中的數(shù)據(jù)。

理解靜態(tài)數(shù)據(jù)加密 

apiVersion: apiserver.config.k8s.io/v1
kind: EncryptionConfiguration
resources:
  - resources:
      - secrets
    providers:
      - identity: {}
      - aesgcm:
          keys:
            - name: key1
              secret: c2VjcmV0IGlzIHNlY3VyZQ==
            - name: key2
              secret: dGhpcyBpcyBwYXNzd29yZA==
      - aescbc:
          keys:
            - name: key1
              secret: c2VjcmV0IGlzIHNlY3VyZQ==
            - name: key2
              secret: dGhpcyBpcyBwYXNzd29yZA==
      - secretbox:
          keys:
            - name: key1
              secret: YWJjZGVmZ2hpamtsbW5vcHFyc3R1dnd4eXoxMjM0NTY=

每個 ?resources ?數(shù)組項目是一個單獨的完整的配置。 ?resources.resources? 字段是要加密的 Kubernetes 資源名稱(?resource ?或 ?resource.group?)的數(shù)組。 ?providers ?數(shù)組是可能的加密 provider 的有序列表。

每個條目只能指定一個 provider 類型(可以是 ?identity ?或 ?aescbc?,但不能在同一個項目中同時指定二者)。 列表中的第一個 provider 用于加密寫入存儲的資源。 當(dāng)從存儲器讀取資源時,與存儲的數(shù)據(jù)匹配的所有 provider 將按順序嘗試解密數(shù)據(jù)。 如果由于格式或密鑰不匹配而導(dǎo)致沒有 provider 能夠讀取存儲的數(shù)據(jù),則會返回一個錯誤,以防止客戶端訪問該資源。

Caution: 如果通過加密配置無法讀取資源(因為密鑰已更改),唯一的方法是直接從底層 etcd 中刪除該密鑰。 任何嘗試讀取資源的調(diào)用將會失敗,直到它被刪除或提供有效的解密密鑰。

Providers:

名稱 加密類型 強度 速度 密鑰長度 其它事項
identity N/A N/A N/A 不加密寫入的資源。當(dāng)設(shè)置為第一個 provider 時,資源將在新值寫入時被解密。
secretbox XSalsa20 和 Poly1305 更快 32字節(jié) 較新的標(biāo)準(zhǔn),在需要高度評審的環(huán)境中可能不被接受。
aesgcm 帶有隨機數(shù)的 AES-GCM 必須每 200k 寫入一次 最快 16, 24 或者 32字節(jié) 建議不要使用,除非實施了自動密鑰循環(huán)方案。
aescbc 填充 PKCS#7 的 AES-CBC 32字節(jié) 由于 CBC 容易受到密文填塞攻擊(Padding Oracle Attack),不推薦使用。
kms 使用信封加密方案:數(shù)據(jù)使用帶有 PKCS#7 填充的 AES-CBC 通過數(shù)據(jù)加密密鑰(DEK)加密,DEK 根據(jù) Key Management Service(KMS)中的配置通過密鑰加密密鑰(Key Encryption Keys,KEK)加密 最強 32字節(jié) 建議使用第三方工具進行密鑰管理。為每個加密生成新的 DEK,并由用戶控制 KEK 輪換來簡化密鑰輪換。配置 KMS 提供程序

每個 provider 都支持多個密鑰 - 在解密時會按順序使用密鑰,如果是第一個 provider,則第一個密鑰用于加密。

Caution: 在 EncryptionConfig 中保存原始的加密密鑰與不加密相比只會略微地提升安全級別。 請使用 ?kms ?驅(qū)動以獲得更強的安全性。

默認情況下,?identity ?驅(qū)動被用來對 etcd 中的 Secret 提供保護,而這個驅(qū)動不提供加密能力。 ?EncryptionConfiguration ?的引入是為了能夠使用本地管理的密鑰來在本地加密 Secret 數(shù)據(jù)。

使用本地管理的密鑰來加密 Secret 能夠保護數(shù)據(jù)免受 etcd 破壞的影響,不過無法針對 主機被侵入提供防護。 這是因為加密的密鑰保存在主機上的 EncryptionConfig YAML 文件中,有經(jīng)驗的入侵者 仍能訪問該文件并從中提取出加密密鑰。

封套加密(Envelope Encryption)引入了對獨立密鑰的依賴,而這個密鑰并不保存在 Kubernetes 中。 在這種情況下,入侵者需要攻破 etcd、kube-apiserver 和第三方的 KMS 驅(qū)動才能獲得明文數(shù)據(jù),因而這種方案提供了比本地保存加密密鑰更高的安全級別。

加密你的數(shù)據(jù)

創(chuàng)建一個新的加密配置文件:

apiVersion: apiserver.config.k8s.io/v1
kind: EncryptionConfiguration
resources:
  - resources:
      - secrets
    providers:
      - aescbc:
          keys:
            - name: key1
              secret: <BASE 64 ENCODED SECRET>
      - identity: {}

遵循如下步驟來創(chuàng)建一個新的 Secret:

  1. 生成一個 32 字節(jié)的隨機密鑰并進行 base64 編碼。如果你在 Linux 或 macOS 上,請運行以下命令:
  2. head -c 32 /dev/urandom | base64
    
  3. 將這個值放入到 ?EncryptionConfiguration ?結(jié)構(gòu)體的 ?secret ?字段中。
  4. 設(shè)置 ?kube-apiserver? 的 ?--encryption-provider-config? 參數(shù),將其指向 配置文件所在位置。
  5. 重啟你的 API server。

Caution: 你的配置文件包含可以解密 etcd 內(nèi)容的密鑰,因此你必須正確限制主控節(jié)點的訪問權(quán)限, 以便只有能運行 kube-apiserver 的用戶才能讀取它。

驗證數(shù)據(jù)已被加密

數(shù)據(jù)在寫入 etcd 時會被加密。重新啟動你的 ?kube-apiserver? 后,任何新創(chuàng)建或更新的密碼在存儲時都應(yīng)該被加密。 如果想要檢查,你可以使用 ?etcdctl ?命令行程序來檢索你的加密內(nèi)容。

  1. 創(chuàng)建一個新的 secret,名稱為 ?secret1?,命名空間為 ?default?:
  2. kubectl create secret generic secret1 -n default --from-literal=mykey=mydata
    
  3. 使用 etcdctl 命令行,從 etcd 中讀取 Secret:
  4. ETCDCTL_API=3 etcdctl get /registry/secrets/default/secret1 [...] | hexdump -C
    

    這里的 ?[...]? 是用來連接 etcd 服務(wù)的額外參數(shù)。

  5. 驗證存儲的密鑰前綴是否為 ?k8s:enc:aescbc:v1:?,這表明 ?aescbc ?provider 已加密結(jié)果數(shù)據(jù)。
  6. 通過 API 檢索,驗證 Secret 是否被正確解密:
  7. kubectl describe secret secret1 -n default
    

    其輸出應(yīng)該包含 ?mykey: bXlkYXRh?,?mydata ?的內(nèi)容是被加密過的。

確保所有 Secret 都被加密

由于 Secret 是在寫入時被加密,因此對 Secret 執(zhí)行更新也會加密該內(nèi)容。

kubectl get secrets --all-namespaces -o json | kubectl replace -f -

上面的命令讀取所有 Secret,然后使用服務(wù)端加密來更新其內(nèi)容。

Note: 如果由于沖突寫入而發(fā)生錯誤,請重試該命令。 對于較大的集群,你可能希望通過命名空間或更新腳本來對 Secret 進行劃分。

輪換解密密鑰

在不發(fā)生停機的情況下更改 Secret 需要多步操作,特別是在有多個 ?kube-apiserver? 進程正在運行的 高可用環(huán)境中。

  1. 生成一個新密鑰并將其添加為所有服務(wù)器上當(dāng)前提供程序的第二個密鑰條目
  2. 重新啟動所有 ?kube-apiserver? 進程以確保每臺服務(wù)器都可以使用新密鑰進行解密
  3. 將新密鑰設(shè)置為 ?keys ?數(shù)組中的第一個條目,以便在配置中使用其進行加密
  4. 重新啟動所有 ?kube-apiserver? 進程以確保每個服務(wù)器現(xiàn)在都使用新密鑰進行加密
  5. 運行 ?kubectl get secrets --all-namespaces -o json | kubectl replace -f -? 以用新密鑰加密所有現(xiàn)有的 Secret
  6. 在使用新密鑰備份 etcd 后,從配置中刪除舊的解密密鑰并更新所有密鑰

當(dāng)只運行一個 ?kube-apiserver? 實例時,第 2 步可能可以忽略。

解密所有數(shù)據(jù) 

要禁用靜態(tài)加密,請將 ?identity ?provider 作為配置中的第一個條目并重新啟動所有 ?kube-apiserver? 進程。

apiVersion: apiserver.config.k8s.io/v1
kind: EncryptionConfiguration
resources:
  - resources:
      - secrets
    providers:
      - identity: {}
      - aescbc:
          keys:
            - name: key1
              secret: <BASE 64 ENCODED SECRET>

然后運行以下命令以強制解密所有 Secret:

kubectl get secrets --all-namespaces -o json | kubectl replace -f -


以上內(nèi)容是否對您有幫助:
在線筆記
App下載
App下載

掃描二維碼

下載編程獅App

公眾號
微信公眾號

編程獅公眾號