Kubernetes 提供 ConfigMaps 和 Secrets 作為管理應用程式組態的機制,提升應用程式可移植性和安全性。ConfigMaps 適用於儲存非敏感的組態資訊,可以作為環境變數或檔案掛載到 Pod 中。Secrets 則專門用於儲存敏感資料,例如密碼、API 金鑰等,也支援多種掛載方式。實務上,建議將 ConfigMaps 和 Secrets 掛載為 Volume,以便動態更新組態而無需重新佈署 Pod。更進一步,可以結合 KMS 提供者加密 Secrets 資料,提升安全性。本文也探討 RBAC 的最佳實踐,包含如何定義角色、規則和角色繫結,以實作更細粒度的許可權控制,保護 Kubernetes 叢集的安全。

Kubernetes 中的組態管理:ConfigMaps 與 Secrets

在現代化的應用程式開發中,將組態資訊與應用程式分離是實作應用可移植性的關鍵。Kubernetes 提供了兩種重要的資源:ConfigMaps 和 Secrets,用於管理和注入組態資料到應用程式中。本文將探討這兩種資源的使用方法、最佳實踐以及它們在 Kubernetes 中的作用。

ConfigMaps:管理非敏感組態資訊

ConfigMaps 是一種用於將非敏感的組態資訊注入到應用程式中的 Kubernetes 資源。它可以提供鍵值對或複雜的資料,如 JSON、XML 或自定義的組態資料。ConfigMaps 不僅可以為 Pod 提供組態資訊,還可以為更複雜的系統服務(如控制器、CRD、運算子等)提供資訊。

使用 ConfigMaps

要使用 ConfigMaps 中的資料,可以將其作為掛載到 Pod 中的 Volume,或作為環境變數注入。

以下是一個建立 ConfigMap 的範例:

apiVersion: v1
kind: ConfigMap
metadata:
  name: nginx-http-config
  namespace: myapp-prod
data:
  config: |
    http {
      server {
        location / {
          root /data/html;
        }
        location /images/ {
          root /data;
        }
      }
    }

將 ConfigMap 掛載到 Pod 中

apiVersion: apps/v1
kind: Deployment
metadata:
  name: mywebapp
  namespace: myapp-prod
spec:
  containers:
  - name: nginx
    image: nginx
    ports:
    - containerPort: 8080
    volumeMounts:
    - mountPath: /etc/nginx
      name: nginx-config
  volumes:
  - name: nginx-config
    configMap:
      name: nginx-http-config
      items:
      - key: config
        path: nginx.conf

內容解密:

此 YAML 組態檔定義了一個名為 mywebapp 的 Deployment 資源,內含一個名為 nginx 的容器,使用 nginx 映象,並將 ConfigMap nginx-http-config 中的 config 鍵值對掛載到容器的 /etc/nginx/nginx.conf 檔案中。

Secrets:管理敏感資訊

Secrets 用於管理敏感資訊,如密碼、OAuth token 或 SSH key。與 ConfigMaps 類別似,Secrets 也可以被掛載到 Pod 中或作為環境變數注入。

使用 Secrets

Kubernetes 中的 Secrets 有三種型別:

  1. generic:用於儲存一般的鍵值對,可以從檔案、目錄或字串文字建立。
  2. docker-registry:用於儲存 Docker registry 的驗證資訊。
  3. tls:用於儲存 TLS 憑證和私鑰。

以下是一個建立 generic Secret 的範例:

kubectl create secret generic mysecret --from-literal=key1=$3cr3t1 --from-literal=key2=@3cr3t2

將 Secret 掛載到 Pod 中

apiVersion: apps/v1
kind: Deployment
metadata:
  name: mywebapp
  namespace: myapp-prod
spec:
  containers:
  - name: nginx
    image: nginx
    ports:
    - containerPort: 8080
    volumeMounts:
    - mountPath: /usr/var/nginx/html/keys
      name: api-key
  volumes:
  - name: api-key
    secret:
      name: myapp-api-key
      secretName: myapikey

內容解密:

此 YAML 組態檔定義了一個名為 mywebapp 的 Deployment 資源,內含一個名為 nginx 的容器,使用 nginx 映象,並將 Secret myapp-api-key 中的 myapikey 鍵值對掛載到容器的 /usr/var/nginx/html/keys 目錄中。

ConfigMaps 和 Secrets 的最佳實踐

在使用 ConfigMaps 和 Secrets 時,需要注意以下最佳實踐:

  • 為了支援動態變更組態資訊而不需重新佈署 Pod,應將 ConfigMaps 和 Secrets 掛載為 Volume,並組態應用程式監視檔案變更。
  • 注意 Secrets 的預設儲存方式是在 etcd 中以明文儲存,因此需要確保 etcd 環境的安全性。
  • 使用 KMS 提供者來加密 Secrets 資料。

Kubernetes 組態管理最佳實踐

在 Kubernetes 中,ConfigMap 和 Secret 是用於管理應用程式組態的重要資源。本文將介紹使用 ConfigMap 和 Secret 的最佳實踐,包括如何正確地掛載、更新和管理組態資料,以及如何確保敏感資料的安全。

正確使用 volumeMounts

在使用 volumeMounts 時,需要注意以下幾點:

  1. 建立 ConfigMap/Secret 並掛載到 Pod:在 Pod 的規格中新增 ConfigMap/Secret 作為 volume,並將其掛載到容器的檔案系統中。每個 ConfigMap/Secret 中的屬性名稱將成為掛載目錄中的新檔案,檔案內容為 ConfigMap/Secret 中指定的值。

apiVersion: v1 kind: ConfigMap metadata: name: config-file data: config: | { “iotDevice”: { “name”: “remoteValve”, “username”: “CC:22:3D:E3:CE:30”, “port”: 51826, “pin”: “031-45-154” } }


   ```yaml
apiVersion: v1
kind: Pod
metadata:
  name: myapp-pod
spec:
  containers:
  - name: myapp-container
    image: myapp-image
    volumeMounts:
    - name: config-volume
      mountPath: /etc/config
  volumes:
  - name: config-volume
    configMap:
      name: config-file

內容解密:

  • 上述範例展示瞭如何建立一個名為 config-file 的 ConfigMap,並將其掛載到 Pod 中的 /etc/config 目錄。
  • ConfigMap 中的 config 屬性被轉化為掛載目錄中的一個檔案,檔案內容為 JSON 格式的組態資料。
  1. 避免使用 subPath:避免使用 volumeMounts.subPath 屬性掛載 ConfigMap/Secret,因為這會阻止資料在更新 ConfigMap/Secret 時動態更新。

組態管理的最佳實踐

  1. ConfigMap/Secret 必須存在於名稱空間中:在使用 ConfigMap/Secret 之前,必須確保它們已經存在於 Pod 所在的名稱空間中。可以使用 optional 標誌來防止 Pod 因 ConfigMap/Secret 不存在而無法啟動。

  2. 使用准入控制器:使用准入控制器來確保特定的組態資料存在或防止未設定特定組態值的佈署。

  3. 使用 Helm 管理應用程式:如果使用 Helm 來發布應用程式,可以利用生命週期鉤子確保 ConfigMap/Secret 範本在 Deployment 被應用之前被佈署。

將 ConfigMap/Secret 資料注入環境變數

  1. 使用 envFrom 或 configMapRef/secretRef:可以將 ConfigMap/Secret 中的所有鍵值對掛載為環境變數,或使用 configMapKeyRefsecretKeyRef 指定個別鍵值。

apiVersion: v1 kind: ConfigMap metadata: name: mysql-config data: mysqldb: myappdb1 user: mysqluser1

apiVersion: v1 kind: Secret metadata: name: mysql-secret type: Opaque data: rootpassword: YWRtJasdhaW4= userpassword: MWYyZDigKJGUyfgKJBmU2N2Rm

apiVersion: apps/v1 kind: Deployment metadata: name: myapp-db-deploy spec: selector: matchLabels: app: myapp-db template: metadata: labels: app: myapp-db spec: containers: - name: myapp-db-instance image: mysql env: - name: MYSQL_ROOT_PASSWORD valueFrom: secretKeyRef: name: mysql-secret key: rootpassword - name: MYSQL_USER valueFrom: configMapKeyRef: name: mysql-config key: user


   #### 內容解密:
   - 上述範例展示瞭如何將 ConfigMap 和 Secret 中的資料注入到 Deployment 中的環境變數。
   - 使用 `secretKeyRef` 和 `configMapKeyRef` 指定個別鍵值,將其對映到環境變數中。

### Secret 的最佳實踐

1. **停用自動掛載 API Credential**:如果工作負載不需要直接存取 Kubernetes API,可以停用 Service Account 的自動掛載 API Credential,以減少對 API Server 的呼叫。

   ```yaml
apiVersion: v1
kind: ServiceAccount
metadata:
  name: app1-svcacct
automountServiceAccountToken: false

內容解密:

  • 上述範例展示瞭如何停用 Service Account 的自動掛載 API Credential。
  • 這可以減少對 Control Plane 的呼叫,從而提高叢集的效能。

更新 ConfigMap/Secret

  1. 更新 Deployment:當 ConfigMap/Secret 更新時,需要更新 Deployment 以使新的組態資料生效。可以使用 CI/CD 管道來更新 ConfigMap/Secret 的名稱和 Deployment 中的參照,從而觸發 Deployment 的更新。

  2. 使用 Helm 的 annotation:如果使用 Helm,可以利用 annotation 中的 checksum/config 來檢查 ConfigMap/Secret 的 sha256 校驗和,當資料變更時觸發 Helm 更新 Deployment。

apiVersion: apps/v1 kind: Deployment spec: template: metadata: annotations: checksum/config: {{ include (print $.Template.BasePath “/configmap.yaml”) . | sha256sum }}


   #### 內容解密:
   - 上述範例展示瞭如何使用 Helm 的 annotation 中的 `checksum/config` 來檢查 ConfigMap/Secret 的 sha256 校驗和。
   - 當 ConfigMap/Secret 的資料變更時,會觸發 Helm 更新 Deployment。

## Kubernetes 安全管理的最佳實踐

在現代的雲端原生環境中,Kubernetes 已成為容器協調的事實標準。隨著其在企業環境中的廣泛採用,安全性的重要性也日益增加。本文將探討 Kubernetes 中的安全管理,特別是在 Secrets 管理和 RBAC(根據角色的存取控制)方面的最佳實踐。

### Secrets 管理

在 Kubernetes 中,Secrets 用於儲存敏感資訊,如資料函式庫密碼、API 金鑰等。正確管理 Secrets 至關重要,以防止未經授權的存取。

#### 使用外部儲存系統

Kubernetes 的 Secrets API 設計了一個可插拔的架構,允許根據需求組態實際的 Secrets 儲存。諸如 HashiCorp Vault、Aqua Security、Twistlock、AWS Secrets Manager、Google Cloud KMS 或 Azure Key Vault 等解決方案,可以使用更高階別的加密和稽核功能來儲存 Secrets 資料。

```yml
apiVersion: v1
kind: ServiceAccount
metadata:
  name: app1-svcacct
automountServiceAccountToken: false

將 imagePullSecrets 分配給 ServiceAccount

可以將 imagePullSecrets 分配給 ServiceAccount,讓 Pod 自動掛載 Secrets,而無需在 Pod 的 spec 中宣告。

# 首先建立 docker-registry secret
kubectl create secret docker-registry registryKey \
  --docker-server=myreg.azurecr.io \
  --docker-username=myreg \
  --docker-password=$up3r$3cr3tP@ssw0rd \
  --docker-email=ignore@dummy.com

# 為名稱空間中的預設 ServiceAccount 打補丁
kubectl patch serviceaccount default -p '{"imagePullSecrets": [{"name": "registryKey"}]}'

#### 內容解密:

此段落展示如何使用 kubectl 命令建立一個用於身份驗證的 docker-registry 型別的 Secret,並且將其分配給預設的 ServiceAccount。這樣,所有使用該 ServiceAccount 的 Pod 都能自動使用該 Secret 提取映像。

  • kubectl create secret docker-registry:建立一個 docker-registry 型別的 Secret,用於儲存 Docker 倉函式庫的身份驗證資訊。
  • --docker-server--docker-username--docker-password--docker-email:指定 Docker 倉函式庫的相關資訊。
  • kubectl patch serviceaccount:修改指定的 ServiceAccount,在此案例中是預設的 ServiceAccount,將 imagePullSecrets 設定為剛才建立的 Secret。

使用 CI/CD 功能

在 CI/CD 管道中,可以從安全的保險箱或加密儲存中取得 Secrets,並使用硬體安全模組(HSM)。這樣可以實作職責分離,安全團隊可以建立和加密 Secrets,而開發人員只需參考預期的 Secret 名稱。

RBAC(根據角色的存取控制)

在大型分散式環境中,通常需要某種安全機制來防止對關鍵系統的未經授權存取。Kubernetes 使用 RBAC 來實作細粒度的存取控制。

RBAC 的三個主要組成部分

  1. 主體(Subject):被檢查存取權的主體,通常是使用者、ServiceAccount 或群組。
  2. 規則(Rule):定義對特定物件或物件群組可以執行的操作。
  3. 角色繫結(RoleBinding):將主體對映到特定的角色。
kind: Role
apiVersion: rbac.authorization.k8s.io/v1
metadata:
  namespace: default
  name: pod-viewer
rules:
- apiGroups: [""]
  resources: ["pods"]
  verbs: ["get", "watch", "list"]

#### 內容解密:

此 YAML 清單定義了一個名為 pod-viewer 的 Role,該 Role 允許對預設名稱空間中的 Pod 物件執行 getwatchlist 操作。

  • kind: Role:指定這是一個 Role 物件,用於定義在特定名稱空間內的許可權。
  • apiGroups: [""]:指定所屬的 API 群組,空字串表示核心 API 群組。
  • resources: ["pods"]:指定該 Role 可以存取的資源型別,在此案例中是 Pod。
  • verbs: ["get", "watch", "list"]:定義允許的操作,包括取得、監看和列出 Pod 物件。

圖表說明

@startuml
skinparam backgroundColor #FEFEFE
skinparam defaultTextAlignment center
skinparam rectangleBackgroundColor #F5F5F5
skinparam rectangleBorderColor #333333
skinparam arrowColor #333333

title 圖表說明

rectangle "被檢查存取權" as node1
rectangle "定義可執行操作" as node2
rectangle "繫結到主體" as node3
rectangle "實作存取控制" as node4

node1 --> node2
node2 --> node3
node3 --> node4

@enduml

圖表翻譯: 此圖示闡述了 RBAC 的工作流程。主體(使用者或 ServiceAccount)根據規則被檢查存取權,規則定義了對特定資源可執行的操作。這些規則被封裝在角色中,並透過角色繫結將角色分配給主體,從而實作對 Kubernetes 資源的存取控制。