如何使用 Mozilla SOPS 優雅的管理你的 Kubernetes Secret
默認情況下,Kubernetes Secret(機密信息)以 base64 編碼存儲在YAML文件中。因為信息缺乏加密通常會導致如何安全地存儲秘密的問題。當然您也不想將敏感的配置數據放入 git 存儲庫,因為它只是經過base64編碼而已。
echo <base64_representation> | base64 -d.
一個典型的解決方案是使用Azure Key Vault或HashiCorp Vault 等服務來保留敏感數據。可以使用Secrets Store CIS 驅動程序將這些服務與 Kubernetes 集成。但是,依賴附加服務意味著除了 Kubernetes 之外,您還必須管理和維護該服務。此外,根據您用于存儲敏感數據的服務,某些敏感配置必須存儲在某處以配置 CIS 驅動程序。
作為替代方案,您可以使用Mozilla SOPS (SOPS)來加密和解密您的 Kubernetes 機密文件。通過 SOPS 加密的信息可以存儲在源代碼版本控制中。加密的信息將在部署到 Kubernetes 之前在本地解密。本文演示了如何將YAMLSOPS 與 Azure Key Vault 結合使用來加密和解密 Kubernetes 機密(文件),這允許您將信息與其他 Kubernetes 清單直接存儲在 git 中。
什么是 Mozilla SOPS
Mozilla的標準操作程序(加解密操作)是一個與平臺無關的CLI,用于不同格式的編輯加密的文件-包括yaml,json,ini,binary,和其它。SOPS 支持多個后端使用密鑰進行加密和解密。以下是五個最受歡迎的支持場景:
- PGP
- Azure 密鑰保管庫
- 知識管理系統
- GCP知識管理系統
- HashiCorp 金庫
為了針對 Azure Key Vault 進行身份驗證,SOPS 按以下順序嘗試多種身份驗證模式:
- 客戶憑證
- 客戶證書
- 用戶名密碼
- 托管服務身份 (MSI)
- Azure CLI 身份驗證
盡管 Azure CLI 身份驗證無障礙,但我建議您在本地開發機器上使用 Azure 服務主體 (SP)。要在 Kubernetes 中使用 SOPS 解密機密(例如,如果您使用 GitOps 運算符,例如 Flux),您應該考慮使用托管服務標識 (MSI) 和 Azure AD Pod 標識的組合。(有關詳細的演練,請考慮官方全量文檔https://www.thorsten-hans.com/encrypt-your-kubernetes-secrets-with-mozilla-sops/?utm_source=hs_email&utm_medium=email&_hsenc=p2ANqtz-8D9JEMI3MsO2qdM0KGA0m3685hu1H0RBcgBj6rDozFznQ7_Ra-tmzdJYwuE7Hf2TfjXwqk#:~:text=flux%20documentation%20for%20a%20detailed%20walk-through)。
預配 Azure 服務主體 (SP)
若要創建新的 Azure SP,請使用以下命令:
# create a service principal
az ad sp create-for-rbac -n sp-sops-keyvault -o json
# {
# "appId": "00000000-0000-0000-000000000000",
# "displayName": "http://sp-sops-keyvault",
# "name": "http://sp-sops-keyvault",
# "password": "00000000-0000-0000-000000000000",
# "tenant": "<your_tenant_identifier>
# }
SOPS(以及一些即將推出的命令)需要存儲在環境變量中的進行身份驗證。也就是說,您可以使用以下命令快速將appId、tenant和存儲password在本地環境變量中export:
export AZURE_CLIENT_ID=<appId>
export AZURE_CLIENT_SECRET=<password>
export AZURE_TENANT_ID=<tenant>
如果您想將 SOPS 集成到您的 CI 管道中,請考慮使用存儲庫機密(這是在 GitHub 上下文中調用敏感配置數據的方式)或有競爭力的解決方案來處理您的 CI 系統中的敏感數據。
預配 Azure Key Vault 實例
你需要一個 Azure Key Vault 實例。使用 Azure CLI 預配新的 Azure Key Vault 非常簡單,如以下代碼段所示:
# create a new Resource Group
az group create -n rg-sops-sample -l germanywestcentral
# create a Key Vault instance
az keyvault create -n kv-sops-sample \
-g rg-sops-sample \
-l germanywestcentral
# create an access policy for the SP
az keyvault set-policy -n kv-sops-sample \
-g rg-sops-sample \
--spn $AZURE_CLIENT_ID \
--key-permissions encrypt decrypt
在 Azure Key Vault 中創建用于加密和解密的密鑰
此時,您必須在我們新創建的 Azure Key Vault 實例中創建用于加密和解密的實際密鑰:
# create an key for encryption / decryption
az keyvault key create -n sops-sample-key \
--vault-name kv-sops-sample \
--ops encrypt decrypt \
--protection software
除了身份驗證信息,SOPS 還需要我們剛剛創建的密鑰的標識符。同樣,使用 Azure CLI 并將標識符存儲在環境變量中:
# read and store key identifier
export KEY_ID=$(az keyvault key show -n sops-sample-key \
--vault-name kv-sops-sample \
--query key.kid -o tsv)
安裝 Mozilla SOPS
如前所述,SOPS 是一個跨平臺的 CLI。您可以從 GitHub 下載 CLI,網址為https://github.com/mozilla/sops/releases。確保可執行文件作為PATH變量的一部分放在文件夾中。
# download sops cli for macOS
curl -O -L -C - https://github.com/mozilla/sops/releases/download/v3.7.1/sops-v3.7.1.darwin
# move and rename the cli to /usr/bin
sudo mv sops-v3.7.1.darwin /usr/bin/sops
# make it executable
sudo chmod +x /usr/bin/sops
# latest macOS may prevent you from using SOPS CLI
# use System Preferences > Security & Privacy to whitelist SOPS
加密 Kubernetes Secret
首先,使用kubectl以下命令創建一個常規的 Kubernetes 密鑰:
# create the Kubernetes secret
kubectl create secret generic demo \
--from-literal mysecret=secret_value \
-o yaml \
--dry-run=client > secret.encoded.yml
# print the contents of secret.encoded.yml
cat secret.encoded.yml
# apiVersion: v1
# data:
# mysecret: c2VjcmV0X3ZhbHVl
# kind: Secret
# metadata:
# creationTimestamp: null
# name: demo
如您所見,密鑰存儲在其base64表示中?,F在,使用 SOPS CLI 創建密鑰的加密變體。特別是在考慮在 Flux 中解密機密時,請確保您提供--encrypted-regex參數并將加密限制為僅存儲在data和 中的值stringData。
# encrypt secret.encoded.yml using SOPS
sops --encrypt --encrypted-regex '^(data|stringData)$' \
--azure-kv $KEY_ID secret.encoded.yml > secret.encrypted.yml
# print the contents of secret.encrypted.yml
cat secret.encrypted.yml
# apiVersion: v1
# data:
# mysecret: ENC[AES256_GCM,data:gz/WAjWte3bCnNm6e+G4ow==,iv:VB4pAv833tDdD4n76h4CqEZNpGdwA3V1QGWp7PK/Jfc=,tag:CcUy3rti4XcWArmHANVS8Q==,type:str]
# kind: Secret
# metadata:
# creationTimestamp: null
# name: demo
# sops:
# kms: []
# gcp_kms: []
# azure_kv:
# - vault_url: https://kv-sops-sample.vault.azure.net
# name: sops-sample-key
# version: ee44c0c0cc9e4620aa4f4c86c4942047
# created_at: "2021-08-02T20:55:40Z"
# enc: EjszDACgiDP8rW3wzs-7fAmFzlAhCq0-R9YlA9cuPcq78EXEeNTC8OnlSdXQAGdGrgE9oylu1HKZa4RB9GxzzVDav8uNVPp67NPmC4-teeA5iRE4jqlp1An6sG6CpkZGcAmKWpfj_DEWecqrNGWSLTA2hI_HKwG5xNkFh9Myik6732W-XL65IFqgepcFrNIzeHetznO0j1iISNXqMeJjeCnZ6Qq0jcXUMIfQnXjAllKfjSukiT3A3GlWxP0j50Z328t-JHi5RowYHT-hC8FDOdR_U95sqnFd27RgEXmbDIU6IGvP3vmCiZJz4YQCPXaGhySvFY6qCEoCbCSC4RaoWw
# hc_vault: []
# age: []
# lastmodified: "2021-08-02T20:55:41Z"
# mac: ENC[AES256_GCM,data:AmKRnzoImfIzPa3JBcuxUKRrse5uZwJGukpLj1wxed3R7lsUN+QAV1+WkfNyeMoW5C3ek7j20Xpbvzi+MgP8zcQOwWSwA79Svgz3hKMn9eTRTfgU+4jYezIIHCwkv61MTN8RGW5AhOInYP8oRPW3zKD+SbBO/Jeu7SC+/oVn07I=,iv:S4Th+0quL84lhJtA/lugEv+iLc+WhWEYPSlXGWKhd/M=,tag:CUGg8+UM7gNSzfjJx1Ua1w==,type:str]
# pgp: []
# encrypted_regex: ^(data|stringData)$
# version: 3.7.1
默認情況下,信息的加密版本包含有關 Azure Key Vault 以及用于加密和解密的密鑰的基本信息。此信息使解密變得容易,您將在幾分鐘后看到。但是,您也可以提供自定義.sops.yaml配置文件以從實際機密文件中刪除此元數據。此時,您可以刪除密鑰的編碼版本,并使用以下命令將加密版本添加到 git:
# delete encoded version of the secret
rm secret.encoded.yml
# add encrypted secret to source control and commit it
git add secret.encrypted.yml
git commit -m 'chore: add encrypted secret'
解密 Kubernetes Secrets 以進行部署
要將密鑰部署到 Kubernetes,您必須對其進行解密。同樣,SOPS CLI 可以提供幫助。解密后的密鑰可以直接通過管道傳輸到kubectl部署,如以下代碼段所示:
# decrypt and deploy the secret
sops --decrypt secret.encrypted.yml | kubectl apply -f -
將密碼回顯服務器部署到 Kubernetes
將機密信息存儲在 Kubernetes 中,您可以配置 echo 容器,它將通過HTTP. 注意envFrom清單的一部分。先前創建的機密信息填充到環境變量:
apiVersion: v1
kind: Pod
metadata:
name: echo
labels:
app: echo
spec:
containers:
- image: thorstenhans/env-via-http:0.0.1
name: main
ports:
- containerPort: 5000
protocol: TCP
envFrom:
- secretRef:
name: demo
optional: true
resources:
requests:
cpu: 50m
memory: 32Mi
limits:
cpu: 100m
memory: 48Mi
部署后,使用簡單的端口轉發并curl驗證部署:
# deploy the sample pod
kubectl apply -f pod.yml
# verify pod is running
kubectl get po
#
# NAME READY STATUS RESTARTS AGE
# echo-74bc9c6d74-vh5lr 1/1 Running 0 4m38s
# activate port forwarding
kubectl port-forward echo-74bc9c6d74-vh5lr --port 8080:5000
#
# Forwarding from 127.0.0.1:8080 -> 5000
# Forwarding from [::1]:8080 -> 5000
# start a new terminal session
# issue an HTTP request to the echo pod with curl
curl http://localhost:8080 | jq
您應該獲得一個JSON包含 Pod 內所有可用環境變量的對象,包括mysecret解密值為的環境變量secret_value。
{
"hostName": "echo-74bc9c6d74-vh5lr",
"envVars": [
"KUBERNETES_SERVICE_PORT=443",
"KUBERNETES_PORT=tcp://10.0.0.1:443",
"HOSTNAME=echo-74bc9c6d74-vh5lr",
"SHLVL=1",
"PORT=5000",
"HOME=/root",
"mysecret=secret_value",
"KUBERNETES_PORT_443_TCP_ADDR=10.0.0.1",
"PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin",
"KUBERNETES_PORT_443_TCP_PORT=443",
"KUBERNETES_PORT_443_TCP_PROTO=tcp",
"KUBERNETES_SERVICE_PORT_HTTPS=443",
"KUBERNETES_PORT_443_TCP=tcp://10.0.0.1:443",
"KUBERNETES_SERVICE_HOST=10.0.0.1",
"PWD=/"
]
}
結論
能夠在源代碼控制中安全地存儲機密信息非常好。SOPS 使加密和解密秘密的過程變得輕松。與 Azure Key Vault 等服務的無縫集成非常棒。團隊會發現這種方法非常有用,尤其是在從傳統持續部署過渡到GitOps 期間。還值得一提的是,SOPS 與Flux無縫集成,Flux是基于 GitOps Toolkit 的最流行的持續交付解決方案之一。