Kubernetes Secret 使用指南
什麼是 Secrets?
Kubernetes Secrets 是一個 API 物件,用於存儲和管理敏感資訊,如密碼、OAuth 權杖、SSH 金鑰等。Secrets 類似於 ConfigMap,但專門設計用於保存機密資料,提供了額外的安全性保護。
Secrets 的主要功能:
- 敏感資料存儲:安全地存儲密碼、金鑰、憑證等敏感資訊
- 資料加密:在 etcd 中以 Base64 編碼存儲(可配置加密)
- 存取控制:透過 RBAC 控制對敏感資料的存取
- 多種類型支援:支援不同類型的機密資料格式
為什麼使用 Secrets?
相較於將敏感資料硬編碼在應用程式或 ConfigMap 中,Secrets 提供了更安全的管理方式:
- 安全性:敏感資料與應用程式程式碼分離
- 存取控制:精細的權限管理和審計功能
- 靈活性:支援多種掛載和使用方式
- 合規性:符合企業安全和合規要求
Secrets 類型和配置
Opaque Secrets(通用型)
最常用的 Secret 類型,用於存儲任意的使用者定義資料:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
| apiVersion: v1 kind: Secret metadata: name: dockertest-secret namespace: dockertest-namespace labels: app: dockertest type: Opaque data: username: cm9vdA== password: MTIzNDU2 api-key: YWJjZGVmZ2hpams= stringData: database-url: "postgresql://user:pass@localhost:5432/db" secret-token: "my-secret-token-value"
|
Docker Registry Secrets
用於私有映像倉庫的身份驗證:
1 2 3 4 5 6 7 8
| apiVersion: v1 kind: Secret metadata: name: docker-registry-secret namespace: dockertest-namespace type: kubernetes.io/dockerconfigjson data: .dockerconfigjson: eyJhdXRocyI6eyJyZWdpc3RyeS5leGFtcGxlLmNvbSI6eyJ1c2VybmFtZSI6InVzZXIiLCJwYXNzd29yZCI6InBhc3MiLCJhdXRoIjoiZFhObGNqcHdZWE56In19fQ==
|
TLS Secrets
用於存儲 TLS 憑證和私鑰:
1 2 3 4 5 6 7 8 9
| apiVersion: v1 kind: Secret metadata: name: tls-secret namespace: dockertest-namespace type: kubernetes.io/tls data: tls.crt: LS0tLS1CRUdJTi... tls.key: LS0tLS1CRUdJTi...
|
Service Account Token Secrets
用於服務帳戶權杖:
1 2 3 4 5 6 7 8
| apiVersion: v1 kind: Secret metadata: name: service-account-secret namespace: dockertest-namespace annotations: kubernetes.io/service-account.name: "my-service-account" type: kubernetes.io/service-account-token
|
在 Pod 中使用 Secrets
方法一:作為環境變數
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34
| apiVersion: apps/v1 kind: Deployment metadata: name: dockertest-deployment namespace: dockertest-namespace spec: replicas: 1 selector: matchLabels: app: dockertest template: metadata: labels: app: dockertest spec: containers: - name: dockertest image: docker.io/pcion123/tinydocker:0.0.10 env: - name: DB_USERNAME valueFrom: secretKeyRef: name: dockertest-secret key: username - name: DB_PASSWORD valueFrom: secretKeyRef: name: dockertest-secret key: password envFrom: - secretRef: name: dockertest-secret
|
方法二:作為檔案掛載
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41
| apiVersion: apps/v1 kind: Deployment metadata: name: app-with-secret-files namespace: dockertest-namespace spec: replicas: 1 selector: matchLabels: app: app-with-secrets template: metadata: labels: app: app-with-secrets spec: containers: - name: app image: nginx:alpine volumeMounts: - name: secret-volume mountPath: /etc/secrets readOnly: true - name: secret-token mountPath: /etc/token/secret-token subPath: secret-token readOnly: true volumes: - name: secret-volume secret: secretName: dockertest-secret defaultMode: 0400 - name: secret-token secret: secretName: dockertest-secret items: - key: secret-token path: secret-token mode: 0444
|
方法三:用於 Image Pull Secrets
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
| apiVersion: apps/v1 kind: Deployment metadata: name: private-image-deployment namespace: dockertest-namespace spec: replicas: 1 selector: matchLabels: app: private-app template: metadata: labels: app: private-app spec: imagePullSecrets: - name: docker-registry-secret containers: - name: app image: private-registry.example.com/my-app:latest
|
建立和管理 Secrets
使用 kubectl 指令建立
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25
| kubectl create secret generic my-secret \ --from-literal=username=admin \ --from-literal=password=secretpassword \ -n dockertest-namespace
kubectl create secret generic file-secret \ --from-file=ssh-privatekey=/path/to/ssh/key \ --from-file=ssh-publickey=/path/to/ssh/key.pub \ -n dockertest-namespace
kubectl create secret docker-registry regcred \ --docker-server=registry.example.com \ --docker-username=myuser \ --docker-password=mypassword \ --docker-email=myemail@example.com \ -n dockertest-namespace
kubectl create secret tls tls-secret \ --cert=path/to/tls.crt \ --key=path/to/tls.key \ -n dockertest-namespace
|
管理指令
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
| kubectl get secrets -n dockertest-namespace
kubectl describe secret dockertest-secret -n dockertest-namespace
kubectl get secret dockertest-secret -n dockertest-namespace -o yaml
kubectl get secret dockertest-secret -n dockertest-namespace -o jsonpath='{.data.username}' | base64 -d
kubectl edit secret dockertest-secret -n dockertest-namespace
kubectl delete secret dockertest-secret -n dockertest-namespace
|
更新 Secrets
1 2 3 4 5 6 7 8 9
| kubectl apply -f secret.yaml
kubectl patch secret dockertest-secret -n dockertest-namespace \ --type merge -p '{"stringData":{"new-key":"new-value"}}'
kubectl replace -f updated-secret.yaml
|
實際應用範例
範例一:資料庫連線配置
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35
| apiVersion: v1 kind: Secret metadata: name: database-secret namespace: dockertest-namespace type: Opaque stringData: DB_HOST: "postgresql.example.com" DB_PORT: "5432" DB_NAME: "myapp" DB_USERNAME: "appuser" DB_PASSWORD: "super-secret-password" DB_URL: "postgresql://appuser:super-secret-password@postgresql.example.com:5432/myapp" --- apiVersion: apps/v1 kind: Deployment metadata: name: database-app namespace: dockertest-namespace spec: replicas: 1 selector: matchLabels: app: database-app template: metadata: labels: app: database-app spec: containers: - name: app image: docker.io/pcion123/tinydocker:0.0.10 envFrom: - secretRef: name: database-secret
|
範例二:多服務認證配置
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
| apiVersion: v1 kind: Secret metadata: name: service-credentials namespace: dockertest-namespace type: Opaque stringData: API_KEY: "sk-1234567890abcdef" API_SECRET: "secret-key-abcdef123456" OAUTH_CLIENT_ID: "my-client-id" OAUTH_CLIENT_SECRET: "my-client-secret" JWT_SECRET: "jwt-signing-secret-key" GITHUB_TOKEN: "ghp_1234567890abcdef" SLACK_WEBHOOK: "https://hooks.slack.com/services/..."
|
範例三:SSL/TLS 憑證配置
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33
| apiVersion: v1 kind: Secret metadata: name: app-tls-secret namespace: dockertest-namespace type: kubernetes.io/tls data: tls.crt: | LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0t... tls.key: | LS0tLS1CRUdJTiBQUklWQVRFIEtFWS0tLS0t... --- apiVersion: networking.k8s.io/v1 kind: Ingress metadata: name: app-ingress namespace: dockertest-namespace spec: tls: - hosts: - app.example.com secretName: app-tls-secret rules: - host: app.example.com http: paths: - path: / pathType: Prefix backend: service: name: app-service port: number: 80
|
安全性最佳實務
Secret 管理
- 最小權限原則:只授予必要的 Secret 存取權限
- 定期輪換:定期更新密碼和金鑰
- 版本控制:避免將 Secret 內容提交到版本控制系統
- 環境分離:為不同環境使用獨立的 Secret
存取控制
- RBAC 配置:使用 Role-Based Access Control 限制存取
- 命名空間隔離:利用命名空間隔離不同應用的 Secret
- ServiceAccount 管理:為不同應用使用專用的 ServiceAccount
- 審計日誌:啟用 Secret 存取的審計記錄
加密和存儲
- 靜態加密:啟用 etcd 中 Secret 的加密
- 傳輸加密:確保 API 通信使用 TLS
- 記憶體保護:避免將 Secret 寫入磁碟交換區
- 備份安全:確保備份中的 Secret 也被加密
應用程式整合
- 環境變數 vs 檔案:根據安全要求選擇適當的掛載方式
- 檔案權限:設定適當的檔案權限和擁有者
- 程序隔離:避免在日誌或錯誤訊息中洩露 Secret
- 清理策略:應用程式退出時清理記憶體中的敏感資料
疑難排解
常見問題
1. Pod 無法存取 Secret
1 2 3 4 5 6 7 8
| kubectl get secret dockertest-secret -n dockertest-namespace
kubectl describe pod <pod-name> -n dockertest-namespace
kubectl auth can-i get secrets --as=system:serviceaccount:dockertest-namespace:default
|
2. Secret 資料解碼問題
1 2 3 4 5 6 7 8
| kubectl get secret dockertest-secret -n dockertest-namespace -o yaml
echo "cm9vdA==" | base64 -d
kubectl get secret dockertest-secret -n dockertest-namespace -o jsonpath='{.data.username}' | base64 -d
|
3. Image Pull Secret 失效
1 2 3 4 5 6 7 8 9 10 11 12 13
| docker login registry.example.com
kubectl delete secret regcred -n dockertest-namespace kubectl create secret docker-registry regcred \ --docker-server=registry.example.com \ --docker-username=newuser \ --docker-password=newpassword \ -n dockertest-namespace
kubectl describe pod <pod-name> -n dockertest-namespace
|
4. Secret 更新後 Pod 未重新載入
1 2 3 4 5 6 7 8
| kubectl rollout restart deployment dockertest-deployment -n dockertest-namespace
kubectl rollout status deployment dockertest-deployment -n dockertest-namespace
kubectl exec -it <pod-name> -n dockertest-namespace -- env | grep DB_PASSWORD
|
進階配置
使用外部 Secret 管理器
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35
| apiVersion: external-secrets.io/v1beta1 kind: SecretStore metadata: name: vault-backend namespace: dockertest-namespace spec: provider: vault: server: "https://vault.example.com" path: "secret" version: "v2" auth: tokenSecretRef: name: "vault-token" key: "token" --- apiVersion: external-secrets.io/v1beta1 kind: ExternalSecret metadata: name: vault-secret namespace: dockertest-namespace spec: refreshInterval: 15s secretStoreRef: name: vault-backend kind: SecretStore target: name: myapp-secret creationPolicy: Owner data: - secretKey: password remoteRef: key: secret/myapp property: password
|
自動 Secret 輪換
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
| apiVersion: batch/v1 kind: CronJob metadata: name: secret-rotation namespace: dockertest-namespace spec: schedule: "0 2 * * 0" jobTemplate: spec: template: spec: containers: - name: rotate-secrets image: secret-rotator:latest command: - /bin/sh - -c - | # 更新 Secret 的腳本邏輯 kubectl patch secret dockertest-secret \ --type merge \ -p '{"stringData":{"password":"'$(generate-new-password)'"}}' restartPolicy: OnFailure
|
透過正確使用和管理 Kubernetes Secrets,您可以安全地處理應用程式的敏感資料,確保符合企業安全標準,同時保持應用程式的靈活性和可維護性。