本文介紹在基於Intel® TDX安全特性的g8i執行個體中,使用BigDL PPML解決方案運行分布式的全鏈路安全的Spark巨量資料分析應用。
背景資訊
隨著越來越多的企業選擇將資料和計算資源遷移上雲,如何在雲上保護巨量資料分析和人工智慧應用的資料安全和隱私,是資料科學家和雲端服務供應商共同面臨的挑戰。
基於BigDL PPML解決方案,在阿里雲TDX執行個體中運行標準的人工智慧和巨量資料處理應用(例如Apache Spark、Apache Flink、TensorFlow、PyTorch等),可以保證資料轉送的安全性、資料使用的安全性、應用程式的完整性。更多資訊,請參見BigDL-PPML。
Intel® Trusted Domain Extension(Intel® TDX)以硬體安全保障資訊安全,不依賴韌體和宿主機的安全狀態,為您提供物理級的加密計算環境。
阿里雲g8i執行個體基於Intel® TDX技術(下文簡稱為TDX執行個體),提供了TDX加密計算能力,打造了基於硬體層級的更高安全等級的可信機密環境,保障應用和資料的機密性與完整性不受惡意軟體的破壞。
BigDL PPML(BigDL Privacy Preserving Machine Learning)基於Intel® TDX技術構建了一整套解決方案,能夠讓您進行非常安全的資料分析和AI應用。
技術架構
基於BigDL PPML,您可以在加密資料環境中,運行現有的分布式巨量資料分析和AI應用程式(例如Apache Spark、Apache Flink、TensorFlow、PyTorch、OpenVINO等),無需修改任何代碼。巨量資料分析和AI應用程式運行在基於阿里雲TDX執行個體的Kubernetes叢集上,其計算和記憶體受Intel® TDX保護。在底層,BigDL PPML自動為分布式應用程式啟用端到端安全機制,包括: TDX保護。在底層,BigDL PPML自動為分布式應用程式啟用端到端安全機制,包括:
在基於TDX執行個體的Kubernetes叢集上提供和證明可信叢集環境。
通過KMS進行密鑰管理,用於分布式資料加密、解密。
安全的分散式運算和通訊。
如上圖所示,BigDL PPML方案基於Intel® TDX的阿里雲TDX執行個體,部署Kubernetes叢集環境。從資料流角度,所有資料均以加密方式儲存在資料湖和資料倉儲中。
BigDL PPML Worker節點載入機密資料,通過遠程證明以及密鑰管理系統擷取資料密鑰,在阿里雲TDX執行個體中進行解密。
使用巨量資料和人工智慧的計算架構,對資料進行分布式預先處理、模型訓練以及模型推理等。
將最終結果、資料或者模型,以加密方式寫回到分布式儲存中。
另外在各節點之間的資料均被加密傳輸(AES加密、TLS等),從而做到全鏈路的隱私保護和資料安全。
操作步驟
本文以運行Spark巨量資料分析為例,介紹如何基於阿里雲TDX執行個體,運行分布式的端到端安全的巨量資料分析應用(本文以運行Simple Query用例為例)。更多巨量資料AI應用使用說明,請參見BigDL PPML Tutorials & Examples。
步驟一:部署Kubernetes叢集及運行環境
本文中Kubernetes叢集使用1個Master節點,2個Worker節點。總節點數量須與購買執行個體數量一致。您可以根據實際業務,選擇節點數量。
建立具備Intel® TDX安全特性的g8i執行個體。
具體操作,請參見自訂購買執行個體。您需要注意以下參數:
執行個體規格:運行Simple Query用例的最小執行個體規格為32 vCPU 64 GiB,本文使用ecs.g8i.8xlarge
鏡像:Alibaba Cloud Linux 3.2104 LTS 64位
公網IP:分配公網IPv4地址
購買執行個體數量:3
遠端連線ECS執行個體。
具體操作,請參見串連方式概述。
部署Kubernetes叢集並進行安全配置。
在已建立的g8i執行個體中,部署Kubernetes叢集。
具體操作,請參見Creating a cluster with kubeadm。
執行如下命令,在Kubernetes叢集的Master節點上進行安全配置(RBAC配置)。
kubectl create serviceaccount spark kubectl create clusterrolebinding spark-role --clusterrole=edit --serviceaccount=default:spark --namespace=default
建立PersistentVolume。
以root使用者,執行如下命令,建立pv-volume.yaml。
vim pv-volume.yaml
按
i
鍵進入編輯模式。在pv-volume.yaml中添加如下內容。
apiVersion: v1 kind: PersistentVolume metadata: name: task-pv-volume labels: type: local spec: storageClassName: manual capacity: storage: 10Gi accessModes: - ReadWriteOnce hostPath: path: "/mnt/data"
按
Esc
鍵,輸入:wq
,儲存並退出編輯模式。分別執行如下命令,建立並查看已建立的PersistentVolume。
kubectl apply -f pv-volume.yaml kubectl get pv task-pv-volume
建立PersistentVolumeClaim。
以root使用者,執行如下命令,建立pv-claim.yaml。
vim pv-claim.yaml
按
i
鍵進入編輯模式。在pv-claim.yaml中添加如下內容。
apiVersion: v1 kind: PersistentVolumeClaim metadata: name: task-pv-claim spec: storageClassName: manual accessModes: - ReadWriteOnce resources: requests: storage: 3Gi
按
Esc
鍵,輸入:wq
,儲存並退出編輯模式。分別執行如下命令,建立並查看已建立的PersistentVolumeClaim。
kubectl apply -f pv-claim.yaml kubectl get pvc task-pv-claim
步驟二:加密訓練資料
在Kubernetes叢集的每個節點上,執行如下命令,擷取BigDL PPML鏡像。
該鏡像用於運行標準的Spark應用,提供資料加密、解密等功能。
docker pull intelanalytics/bigdl-ppml-trusted-bigdata-gramine-reference-16g:2.3.0-SNAPSHOT
產生訓練資料people.csv。
在Kubernetes叢集的Master節點上,下載訓練資料指令碼generate_people_csv.py。
wget https://github.com/intel-analytics/BigDL/raw/main/ppml/scripts/generate_people_csv.py
執行如下命令,產生訓練資料people.csv。
python generate_people_csv.py </save/path/of/people.csv> <num_lines>
說明</save/path/of/people.csv>請修改為實際的people.csv路徑,如/home/user。
<num_lines>請修改為訓練資料people.csv的行數,如500。
執行如下命令,將訓練資料people.csv移到指定目錄。
sudo scp /home/user/people.csv /mnt/data/simplekms/
重要/home/user
請替換成實際的使用者目錄。/mnt/data/simplekms/
僅為樣本,本文中/mnt/data/simplekms/
用於存放加密、解密資料,後文中存在/mnt/data/simplekms/
時不再單獨說明。
在Master節點上,執行如下命令,運行bigdl-ppml-client容器。
該容器用來加密、解密訓練資料。
說明/home/user/kuberconfig:/root/.kube/config
請根據實際運行程式的使用者進行修改,例如:使用root時:
/root/kuberconfig:/root/.kube/config
使用普通使用者(如test)時:
/home/test/kuberconfig:/root/.kube/config
export K8S_MASTER=k8s://$(kubectl cluster-info | grep 'https.*6443' -o -m 1) echo The k8s master is $K8S_MASTER . export SPARK_IMAGE=intelanalytics/bigdl-ppml-trusted-bigdata-gramine-reference-16g:2.3.0-SNAPSHOT sudo docker run -itd --net=host \ -v /etc/kubernetes:/etc/kubernetes \ -v /home/user/kuberconfig:/root/.kube/config \ -v /mnt/data:/mnt/data \ -e RUNTIME_SPARK_MASTER=$K8S_MASTER \ -e RUNTIME_K8S_SPARK_IMAGE=$SPARK_IMAGE \ -e RUNTIME_PERSISTENT_VOLUME_CLAIM=task-pv-claim \ --name bigdl-ppml-client \ $SPARK_IMAGE bash docker exec -it bigdl-ppml-client bash
在Master節點上,加密訓練資料people.csv。
執行如下命令,使用APPID、APIKEY產生primarykey。
您可以使用simple kms自行產生1~12位長度的APPID、APIKEY。本樣本中,APPID為98463816****,APIKEY為15780936****,--primaryKeyPath指定primarykey儲存的位置。
java -cp '/ppml/spark-3.1.3/conf/:/ppml/spark-3.1.3/jars/*:/ppml/bigdl-2.3.0-SNAPSHOT/jars/*' \ com.intel.analytics.bigdl.ppml.examples.GeneratePrimaryKey \ --primaryKeyPath /mnt/data/simplekms/primaryKey \ --kmsType SimpleKeyManagementService \ --simpleAPPID 98463816**** \ --simpleAPIKEY 15780936****
建立加密指令碼encrypt.py。
執行如下命令,切換到
/mnt/data/simplekms
目錄下。cd /mnt/data/simplekms
執行如下命令,建立並開啟encrypt.py檔案。
sudo vim encrypt.py
按
i
進入編輯模式。在encrypt.py檔案中,添加如下內容。
# encrypt.py from bigdl.ppml.ppml_context import * args = {"kms_type": "SimpleKeyManagementService", "app_id": "98463816****", "api_key": "15780936****", "primary_key_material": "/mnt/data/simplekms/primaryKey" } sc = PPMLContext("PPMLTest", args) csv_plain_path = "/mnt/data/simplekms/people.csv" csv_plain_df = sc.read(CryptoMode.PLAIN_TEXT) \ .option("header", "true") \ .csv(csv_plain_path) csv_plain_df.show() output_path = "/mnt/data/simplekms/encrypted-input" sc.write(csv_plain_df, CryptoMode.AES_CBC_PKCS5PADDING) \ .mode('overwrite') \ .option("header", True) \ .csv(output_path)
按
Esc
鍵,輸入:wq
,儲存並退出編輯模式。
在bigdl-ppml-client容器中,執行如下命令,使用APPID、APIKEY、primarykey加密people.csv。
加密後的資料儲存在
/mnt/data/simplekms/encrypted-output
下。java \ -cp '/ppml/spark-3.1.3/conf/:/ppml/spark-3.1.3/jars/*:/ppml/bigdl-2.3.0-SNAPSHOT/jars/*' \ -Xmx1g org.apache.spark.deploy.SparkSubmit \ --master 'local[4]' \ --conf spark.network.timeout=10000000 \ --conf spark.executor.heartbeatInterval=10000000 \ --conf spark.python.use.daemon=false \ --conf spark.python.worker.reuse=false \ --py-files /ppml/bigdl-2.3.0-SNAPSHOT/python/bigdl-ppml-spark_3.1.3-2.3.0-SNAPSHOT-python-api.zip,/ppml/bigdl-2.3.0-SNAPSHOT/python/bigdl-spark_3.1.3-2.3.0-SNAPSHOT-python-api.zip,/ppml/bigdl-2.3.0-SNAPSHOT/python/bigdl-dllib-spark_3.1.3-2.3.0-SNAPSHOT-python-api.zip \ /mnt/data/simplekms/encrypt.py
在每個Worker節點,分別執行如下命令,複製Master節點的
/mnt/data/simplekms
到每個Worker節點上。cd /mnt/data sudo scp -r user@192.168.XXX.XXX:/mnt/data/simplekms .
說明user請替換成實際的Master節點使用者名稱,192.168.XXX.XXX請修改為實際的Master節點IP。
步驟三:運行基於BigDL PPML的巨量資料分析用例
在bigdl-ppml-client容器中,向Kubernetes叢集提交Spark任務,運行Simple Query用例。
說明spark.driver.host=192.168.XXX.XXX請修改為實際的Master節點IP地址。
${SPARK_HOME}/bin/spark-submit \ --master $RUNTIME_SPARK_MASTER \ --deploy-mode client \ --name spark-simplequery-tdx \ --conf spark.driver.memory=4g \ --conf spark.executor.cores=4 \ --conf spark.executor.memory=4g \ --conf spark.executor.instances=2 \ --conf spark.driver.host=192.168.XXX.XXX \ --conf spark.kubernetes.authenticate.driver.serviceAccountName=spark \ --conf spark.cores.max=8 \ --conf spark.kubernetes.container.image=$RUNTIME_K8S_SPARK_IMAGE \ --class com.intel.analytics.bigdl.ppml.examples.SimpleQuerySparkExample \ --conf spark.network.timeout=10000000 \ --conf spark.executor.heartbeatInterval=10000000 \ --conf spark.kubernetes.executor.deleteOnTermination=false \ --conf spark.driver.extraClassPath=local://${BIGDL_HOME}/jars/* \ --conf spark.executor.extraClassPath=local://${BIGDL_HOME}/jars/* \ --conf spark.kubernetes.file.upload.path=/mnt/data \ --conf spark.kubernetes.driver.volumes.persistentVolumeClaim.${RUNTIME_PERSISTENT_VOLUME_CLAIM}.options.claimName=${RUNTIME_PERSISTENT_VOLUME_CLAIM} \ --conf spark.kubernetes.driver.volumes.persistentVolumeClaim.${RUNTIME_PERSISTENT_VOLUME_CLAIM}.mount.path=/mnt/data \ --conf spark.kubernetes.executor.volumes.persistentVolumeClaim.${RUNTIME_PERSISTENT_VOLUME_CLAIM}.options.claimName=${RUNTIME_PERSISTENT_VOLUME_CLAIM} \ --conf spark.kubernetes.executor.volumes.persistentVolumeClaim.${RUNTIME_PERSISTENT_VOLUME_CLAIM}.mount.path=/mnt/data \ --jars local:///ppml/bigdl-2.3.0-SNAPSHOT/jars/bigdl-ppml-spark_3.1.3-2.3.0-SNAPSHOT.jar \ local:///ppml/bigdl-2.3.0-SNAPSHOT/jars/bigdl-ppml-spark_3.1.3-2.3.0-SNAPSHOT.jar \ --inputPartitionNum 8 \ --outputPartitionNum 8 \ --inputEncryptModeValue AES/CBC/PKCS5Padding \ --outputEncryptModeValue AES/CBC/PKCS5Padding \ --inputPath /mnt/data/simplekms/encrypted-input \ --outputPath /mnt/data/simplekms/encrypted-output \ --primaryKeyPath /mnt/data/simplekms/primaryKey \ --kmsType SimpleKeyManagementService \ --simpleAPPID 98463816**** \ --simpleAPIKEY 15780936****
在Master節點上,監控任務運行狀態。
執行如下命令,查看driver和executor名和運行狀態。
kubectl get pod
當運行狀態由
Running
變成Completed
實,說明Spark任務已運行完成。執行如下命令,查看pod日誌。
kubectl logs simplequery-xxx-exec-1
說明simplequery-xxx-exec-1請替換為上一步查詢到的simplequery名。
當pod日誌中限制
Finished
時,說明Spark任務已運行完成。
步驟四:解密結果
將各個Worker節點上的encrypted-output目錄下的
.meta
和part-XXXX.csv.cbc
檔案上傳到Master節點encrypted-output目錄中。上傳完成後,Master節點上的encrypted-output資料如下所示。
在Master節點上的
/mnt/data/simplekms
目錄下,建立decrypt.py檔案。執行如下命令,切換到
/mnt/data/simplekms
目錄。cd /mnt/data/simplekms
執行如下命令,建立並開啟decrypt.py檔案。
sudo vim decrypt.py
按
i
進入編輯模式。在decrypt.py檔案中,添加如下內容。
from bigdl.ppml.ppml_context import * args = {"kms_type": "SimpleKeyManagementService", "app_id": "98463816****", "api_key": "15780936****", "primary_key_material": "/mnt/data/simplekms/primaryKey" } sc = PPMLContext("PPMLTest", args) encrypted_csv_path = "/mnt/data/simplekms/encrypted-output" csv_plain_df = sc.read(CryptoMode.AES_CBC_PKCS5PADDING) \ .option("header", "true") \ .csv(encrypted_csv_path) csv_plain_df.show() output_path = "/mnt/data/simplekms/decrypted-output" sc.write(csv_plain_df, CryptoMode.PLAIN_TEXT) \ .mode('overwrite') \ .option("header", True)\ .csv(output_path)
按
Esc
鍵,輸入:wq
,儲存並退出編輯模式。
在Master節點上,執行如下命令,解密
encrypted_csv_path
目錄下的資料。使用APPID、APIKEY、primarykey進行解密,解密後的資料
part-XXXX.csv
儲存在/mnt/data/simplekms/decrypted-output
目錄下。java \ -cp '/ppml/spark-3.1.3/conf/:/ppml/spark-3.1.3/jars/*:/ppml/bigdl-2.3.0-SNAPSHOT/jars/*' \ -Xmx1g org.apache.spark.deploy.SparkSubmit \ --master 'local[4]' \ --conf spark.network.timeout=10000000 \ --conf spark.executor.heartbeatInterval=10000000 \ --conf spark.python.use.daemon=false \ --conf spark.python.worker.reuse=false \ --py-files /ppml/bigdl-2.3.0-SNAPSHOT/python/bigdl-ppml-spark_3.1.3-2.3.0-SNAPSHOT-python-api.zip,/ppml/bigdl-2.3.0-SNAPSHOT/python/bigdl-spark_3.1.3-2.3.0-SNAPSHOT-python-api.zip,/ppml/bigdl-2.3.0-SNAPSHOT/python/bigdl-dllib-spark_3.1.3-2.3.0-SNAPSHOT-python-api.zip \ /mnt/data/simplekms/decrypt.py
在Windows系統中查看該解密後資料,顯示如下: