K8s 的 Secret 是儲存應用程式敏感資訊的組件,但是如何管理以及傳遞敏感資訊到 K8s Secret 中是一個重要課題。
在本文中,我們將使用 External Secrets Operator 結合 GCP Secret Manager 和 GKE Secrets,可以安全且方便地使用 GCP 的 Secret Manager 服務來管理 GKE 的環境變數。此外,還將介紹在更新K8s Secret 物件時的痛點,每當我們更新 K8s 內部作為環境變數傳遞的 Secret 時,我們都需要重新啟動 pod 才能吃到新的環境變數,因此我們安裝 Reloader 來解決此問題。
Google Cloud Secret Manager 是一項安全且易於使用的服務,用於儲存和管理 API 金鑰、密碼和其他敏感資料。它讓開發人員可以集中儲存和輪替祕密,而無需在應用程式程式碼中直接管理它們。Secret Manager 提供版本控制、審核日誌和存取權限控制等功能,確保祕密的安全性與合規性。透過 Secret Manager,您可以保護敏感資訊,簡化祕密管理程序,並降低安全性漏洞的風險。
Kubernetes External Secrets Operator 解決了將敏感資料(例如密碼、憑證)安全儲存在 Kubernetes 叢集中的難題。它能讓你將這些機密資訊儲存在外部金鑰管理系統,例如 HashiCorp Vault、AWS Secrets Manager 或 Google Secret Manager,並將其安全地掛載到你的應用程式中。External Secrets Operator 會自動同步外部金鑰管理系統和 Kubernetes Secrets,確保你的應用程式始终使用最新的憑證,而無需將敏感資料直接儲存在叢集中。
Kubernetes Reloader 是一種 Kubernetes 工具,可幫助您在容器化應用程式更新時自動執行容器更新。它會監控組態變更,例如 ConfigMaps 和 Secrets,並在偵測到變更時觸發部署或 Pod 的滾動更新。這可讓開發人員無需手動重新啟動 Pod 或重新部署應用程式,即可輕鬆地更新設定、機密資訊和其他應用程式相依性,從而簡化部署程序並減少停機時間。
$ helm repo add external-secrets https://charts.external-secrets.io
$ helm pull external-secrets/external-secrets
$ helm install external-secrets \
external-secrets/external-secrets \
-n external-secrets \
--create-namespace \
--set installCRDs=true
啟用 GCP Secret Manager API
建立 ClusterSecretStore.yaml
apiVersion: external-secrets.io/v1beta1
kind: ClusterSecretStore
metadata:
name: gcp-secret-manager
namespace: external-secrets
labels:
# 打標籤方便分類
environment: ithome-202409-demo-2
spec:
provider:
gcpsm:
# 改成GCP Secret Manager專案ID
projectID: ithome-202409-demo-2
auth:
workloadIdentity:
# name of the cluster region
clusterLocation: us-central1
# name of the GKE cluster
clusterName: demo2-cluster
# reference the sa from above
serviceAccountRef:
name: external-secrets
namespace: external-secrets
到 GCP Secret Manager 頁面,建立 httpbin-eso 密鑰
加入兩個 Secret,要使用 JSON 格式
{
"eso-name": "httpbin-eso",
"ping": "pong"
}
創建 ExternalSecret httpbin-config.yaml
# test-deployment.yaml
apiVersion: external-secrets.io/v1beta1
kind: ExternalSecret
metadata:
name: httpbin-config
namespace: httpd
spec:
# 這將每1分鐘刷新一次金鑰。可以根據自己的要求保留時間。
refreshInterval: 1m
secretStoreRef:
name: gcp-secret-manager
kind: ClusterSecretStore
target:
# 輸入剛剛創建的GCP External Secret名稱 httpbin-eso
name: httpbin-eso
creationPolicy: Owner
dataFrom:
- extract:
key: httpbin-eso
這時會發現 K8s 的 Secret 物件已經從 GCP 的 Secret Manager 引入 httpbin-eso 然後創建出來了。
$ kubectl get secrets -n httpd
NAME TYPE DATA AGE
httpbin-eso Opaque 2 1m
創建 test-deployment.yaml,在 envFrom 添加 secretRef.name: httpbin-eso,從 K8s Secret 物件注入環境變數
# test-deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: httpbin
namespace: httpd
spec:
replicas: 1
selector:
matchLabels:
app: httpbin
template:
metadata:
labels:
app: httpbin
spec:
containers:
- image: specialyang/go-httpbin:v3
args:
- "--port=8090"
- "--version=v1"
imagePullPolicy: Always
name: go-httpbin
ports:
- containerPort: 8090
# 在這裡添加環境變數來源
envFrom:
- secretRef:
name: httpbin-eso
$ helm repo add stakater https://stakater.github.io/stakater-charts
$ helm repo update
$ helm install stakater/reloader
$ helm install reloader stakater/reloader -n reloader --create-namespace
預設情況下,reloader會偵測所有namespace的資源,如果要針對單一 Namespace 可使用 --set reloader.watchGlobally 為 false,以下範例為安裝在 reloader Namespace 並只偵測 foo Namespace 底下的資源
$ helm install reloader stakater/reloader -n reloader --set reloader.watchGlobally=false --namespace foo
將上面的 test-deployment.yaml 中的 metadata.annotations 新增 reloader.stakater.com/auto: "true"
metadata:
annotations:
reloader.stakater.com/auto: "true"
更新 GCP External Secret httpbin-eso,多一個 "version": "v1"
{
"eso-name": "httpbin-eso",
"ping": "pong",
"version": "v1"
}
等待 1 分鐘左右,可以看到 test-deployment 自動開始重啟,出現新的 Pod 了
$ kubectl get pod -n httpd
NAME READY STATUS RESTARTS AGE
httpbin-c66bfd5b6-ml5jk 1/1 Running 0 29s
進入 httpbin Pod 執行指令,印出 version 環境變數,確認環境變數有被 Pod 吃進去
$ exec kubectl exec -i -t -n httpd httpbin-c66bfd5b6-ml5jk -c go-httpbin -- sh
$ echo $version
v1
本文介紹了如何使用 GCP Secret Manager 和 K8s External Secrets 來安全管理和部署應用密鑰,並結合 K8s Reloader 實現自動更新。
首先,我們深入探討了將敏感信息存儲在 K8s Secret 中的風險,並引入了 GCP Secret Manager 作為更安全的替代方案。 接著,我們詳細介紹了如何利用 External Secrets Operator 將存儲在 GCP Secret Manager 中的密鑰同步到 GKE 集群中,從而實現應用程序對密鑰的安全訪問。
最後,我們展示了如何配置 K8s Reloader 來自動檢測 Secret 更新,並觸發 Deployment 重啟,從而確保應用程序始終使用最新的配置和密鑰。
通過這種方法,我們可以提高 GKE 應用程序的安全性,並簡化密鑰管理流程,實現更加安全、高效的雲原生應用部署。