K8S叢集中使用JD KMS服務對敏感資料安全加密

2023-08-24 12:01:26

基本概念

KMS,Key Management Service,即金鑰管理服務,在K8S叢集中,以驅動和外掛的形式啟用對Secret,Configmap進行加密。以保護敏感資料,

驅動和外掛需要使用者按照需求進行客製化和實現自己的KMS外掛,外掛可以是gRPC伺服器或者啟用一個雲服務商提供的KMS外掛。

本文中演示使用的KMS 服務是京東雲艦中的KMS加密服務。

目前KMS分為V1,V2,本文基於V1進行演示。

架構

內部可以利用kms加密實現自己的加密演演算法,甚至國密演演算法。

當用戶新建secret資源時,kube-apiserver 會通過gRPC呼叫kms-plugin,而kms-plugin與加密伺服器通訊,進行資料加密。

此時如果通過直接獲取etcd中的原始資料,內容為密文資料。

當用戶獲取secret資源內容時,kube-apiserver 會通過gRPC呼叫kms-plugin,而kms-plugin與加密伺服器通訊,進行資料解密,將明文展示給使用者

操作步驟

需要一套已經執行的Kubernetes叢集服務,如果是多臺master節點,需要同時設定。

新建目錄

/etc/kubernetes/kms/jdcloud

新建 EncryptionConfiguration

該設定是kms基本的加密設定,包括加密資源物件,socket地址等等。

apiVersion: apiserver.config.k8s.io/v1
kind: EncryptionConfiguration
resources:
  - resources:
    - secrets # 這裡表示,只加密secret
    providers:
    - kms:
        name: myKmsPlugin
        endpoint: unix:///var/run/k8s-kms-plugin/kms-plugin.sock # 如果不以pod(jdcloud-kms-plugin.yaml)啟動,需要sock檔案放到master節點。
        cachesize: 100
        timeout: 3s
    - identity: {}

以上內容儲存在/etc/kubernetes/kms/jdcloud/apiserver-encryption.conf

新建 jdcloud kms plugin 設定

kms server的上聯資訊設定

{
  "AccessKey": "xxx", # 部署前,該引數需要預先知道,
  "SecretKey": "yyy", # 部署前,該引數需要預先知道。
  "KmsEndpoint": "kms.internal.cn-north-1.jdcloud-api.com", # 部署前,該引數需要預先知道。
  "KmsKeyId": "abcd", # 部署前,該引數需要預先知道。
  "KmsSchema": "http",
  "GRPCSocketPath": "/var/run/k8s-kms-plugin/kms-plugin.sock"
}

以上內容儲存在/etc/kubernetes/kms/jdcloud/jdcloud-kms-plugin.json

新建 jdcloud kms plugin 服務

該服務是啟動socket服務,並按照設定和上聯的kms server進行通訊,加密和解密資料,並通過socket服務和K8S APIServer互動。

該pod需要在kube-apiserver啟動之前啟動,否則與apiserver可能產生迴圈依賴。

apiVersion: v1
kind: Pod
metadata:
  creationTimestamp: null
  labels:
    component: jdcloud-kms-plugin
    tier: control-plane
  name: jdcloud-kms-plugin-node-01
  namespace: kube-system
spec:
  containers:
  - command:
    - /k8s-kms-plugin
    - -f=/etc/kubernetes/kms/jdcloud/jdcloud-kms-plugin.json # 指定json
    image: hub-pub.jdcloud.com/k8s/jdcloudsec/k8s-kms-plugin:v1.0.1 
    imagePullPolicy: IfNotPresent
    name: jdcloud-kms-plugin
    resources:
      requests:
        cpu: 250m
    volumeMounts:
    - mountPath: /etc/kubernetes/kms/jdcloud/jdcloud-kms-plugin.json # 注意路徑
      name: jdcloud-kms-plugin-configfile
      readOnly: true
    - mountPath: /var/run/k8s-kms-plugin/
      name: k8s-kms-plugin-unixsock-directory
      readOnly: false
  hostNetwork: true
  priorityClassName: system-cluster-critical
  volumes:
  - hostPath:
      path: /etc/kubernetes/kms/jdcloud/jdcloud-kms-plugin.json # 注意路徑
      type: File
    name: jdcloud-kms-plugin-configfile
  - hostPath:
      path: /var/run/k8s-kms-plugin/
      type: DirectoryOrCreate
    name: k8s-kms-plugin-unixsock-directory
status: {}

以上內容儲存在/etc/kubernetes/manifests/jdcloud-kms-plugin.yaml

修改 kube apiserver設定

...
    - --encryption-provider-config=/etc/kubernetes/kms/jdcloud/apiserver-encryption.conf
    image: hub-pub.jdcloud.com/k8s/kube-apiserver:v1.19.9-109
    imagePullPolicy: IfNotPresent
    livenessProbe:
...
    - mountPath: /etc/kubernetes/kms/jdcloud/apiserver-encryption.conf
      name: apiserver-encryption-conf
      readOnly: true
    - mountPath: /var/run/k8s-kms-plugin/
      name: k8s-kms-plugin-unixsock-directory
      readOnly: false
...
  - hostPath:
      path: /etc/kubernetes/kms/jdcloud/apiserver-encryption.conf
      type: File
    name: apiserver-encryption-conf
  - hostPath:
      path: /var/run/k8s-kms-plugin/
      type: DirectoryOrCreate
    name: k8s-kms-plugin-unixsock-directory

修改後儲存

驗證

在預設的名稱空間裡建立一個名為 secret1 的 Secret:

kubectl create secret generic secret1 -n default --from-literal=mykey=mydata

用 etcdctl 命令列,從 etcd 讀取出 Secret:

etcdctl.sh get /kubernetes.io/secrets/default/secret1 [...] | hexdump -C

結果為加密資料

驗證 Secret 在被 API server 獲取時已被正確解密:

kubectl describe secret secret1 -n default

該結果為明文,mykey: mydata

產品能力

在K8S叢集中,京東內部一直比較重視對敏感資料加密,特別是雲艦面對越來越多的金融行業客戶,加密服務基本是雲艦中的標準設定。

經過產品能力打磨和內部實現,KMS 加密服務和K8S自動化叢集以及一鍵設定建立都在雲艦內實現了很好的產品化能力,可以隨叢集建立,一鍵啟用KMS加密服務。

參考:

1. 使用 KMS 驅動進行資料加密

作者:京東科技 王曉飛

來源:京東雲開發者社群 轉載請註明來源