AnalyticDB for MySQLApache Spark全密態計算引擎高效能版,在Apache Spark全密態引擎基礎版能力的基礎上,支援Parquet模組化加密功能,且相容社區版Spark、Hadoop、Hive等計算引擎,在保證資料轉送與預存程序安全的同時,提升了資料處理效率。本文介紹如何通過Apache Spark全密態計算引擎高效能版加密資料,並基於密文表執行SQL計算。
前提條件
叢集的產品系列為企業版、基礎版或湖倉版。
叢集與OSS儲存空間位於相同地區。
已建立資料庫帳號。
如果是通過阿里雲帳號訪問,只需建立高許可權帳號。
如果是通過RAM使用者訪問,需要建立高許可權帳號和普通帳號並且將RAM使用者綁定到普通帳號上。
已為RAM使用者授予AliyunADBFullAccess、AliyunADBSparkProcessingDataRole和AnalyticDB for MySQL庫表的讀寫權限。具體操作,請參見帳號授權。
資料準備
待加密的資料檔案格式必須為Parquet,您可以直接下載Spark全密態樣本資料,完成後續操作。
操作步驟
AnalyticDB for MySQL支援通過控制台和加密工具兩種方式加密明文資料。若您的資料存放區在本地,可以通過加密工具加密資料;若儲存在雲資料庫中,可以通過控制台加密資料。兩種加密方式用法的區別如下:
通過控制台加密資料:上傳明文資料至OSS,再加密。
通過加密工具加密資料:在本地加密資料,上傳密文至OSS。
通過控制台加密資料並建立密文表
將資料準備章節中的明文資料上傳至OSS儲存空間。本文樣本為
oss://testBucketName/adb/Spark/customer。具體操作,請參見簡單上傳。登入雲原生資料倉儲AnalyticDB MySQL控制台,在左上方選擇叢集所在地區。在左側導覽列,單擊集群清單,然後單擊目的地組群ID。
在左側導覽列,單擊。
在SQLConsole視窗,選擇Spark引擎和Job型資源群組。
執行以下語句,建立密文表。
開啟密態計算,設定使用者的主要金鑰,並建立資料庫。
-- 開啟native計算 SET spark.adb.native.enabled=true; -- 配置資源 SET spark.driver.resourceSpec=medium; SET spark.executor.instances=2; SET spark.executor.resourceSpec=medium; SET spark.app.name=Spark SQL Encryption Test; -- 開啟密文讀寫支援並設定主要金鑰列表,KMS Client 以及 CryptoFactory(開啟後引擎可同時支援明文和密文) SET spark.hadoop.parquet.encryption.key.list=kf:MDEyMzQ1Njc4OTAxMjM0****,kc1:bvCDwqcOJGSdZSEMLjfk****,kc2:kflI/sq+uf50Qhl1MmtG****; SET spark.hadoop.parquet.encryption.kms.client.class=io.glutenproject.encryption.InMemoryKMS; SET spark.hadoop.parquet.crypto.factory.class=org.apache.parquet.crypto.keytools.PropertiesDrivenCryptoFactory; --建立資料庫 CREATE database IF NOT EXISTS adb_external_db;參數說明:
參數
說明
spark.hadoop.parquet.encryption.key.list
使用者主要金鑰列表。一個主要金鑰對應一個密鑰ID,多個主要金鑰之間用半形逗號(,)分隔,每個主要金鑰ID與主要金鑰之間用半形冒號(:)分隔。格式為:
<主要金鑰ID1>:<Base64編碼的主要金鑰1>,<主要金鑰ID2>:<Base 64 編碼的主要金鑰2>。詳情請參見密鑰介紹。本文樣本為
kf:MDEyMzQ1Njc4OTAxMjdy****,kc1:bvCDwqcOJGSdZSEMLjfk****,kc2:kflI/sq+uf50Qhl1MmtG****警告您可以使用通用工具(例如:OpenSSL)隨機產生使用者主要金鑰。使用者主要金鑰是訪問加密資料的根憑據,一旦丟失密鑰,將無法再訪問已有的資料,請妥善保管使用者主要金鑰。
spark.hadoop.parquet.encryption.kms.client.class
KMS用戶端類名。固定填寫為
io.glutenproject.encryption.InMemoryKMS。spark.hadoop.parquet.crypto.factory.class
CryptoFactory類名。固定填寫為
org.apache.parquet.crypto.keytools.PropertiesDrivenCryptoFactory。建立外表
customer,用於儲存明文資料。LOCATION為明文資料所在的OSS路徑。本文樣本為oss://testBucketName/adb/Spark/customer。SET spark.adb.native.enabled=true; SET spark.hadoop.parquet.encryption.key.list=kf:MDEyMzQ1Njc4OTAxMjM0****,kc1:bvCDwqcOJGSdZSEMLjfk****,kc2:kflI/sq+uf50Qhl1MmtG****; SET spark.hadoop.parquet.encryption.kms.client.class=io.glutenproject.encryption.InMemoryKMS; SET spark.hadoop.parquet.crypto.factory.class=org.apache.parquet.crypto.keytools.PropertiesDrivenCryptoFactory; CREATE TABLE IF NOT EXISTS adb_external_db.customer ( c_custkey long, c_name string, c_address string, c_nationkey long, c_phone string, c_acctbal decimal(12, 2), c_mktsegment string, c_comment string ) USING parquet LOCATION 'oss://testBucketName/adb/Spark/customer';說明若
adb_external_db資料庫中已有明文表,可跳過該步驟。若資料存放區在其他雲資料庫中,需建立對應的外表。建立外表的文法請參見CREATE EXTERNAL TABLE。
建立外表
enc_customer,用於儲存密文資料。本文樣本將enc_customer外表的資料指定儲存在oss://testBucketName/adb/Spark/enc_customer。SET spark.adb.native.enabled=true; SET spark.hadoop.parquet.encryption.key.list=kf:MDEyMzQ1Njc4OTAxMjM0****,kc1:bvCDwqcOJGSdZSEMLjfk****,kc2:kflI/sq+uf50Qhl1MmtG****; SET spark.hadoop.parquet.encryption.kms.client.class=io.glutenproject.encryption.InMemoryKMS; SET spark.hadoop.parquet.crypto.factory.class=org.apache.parquet.crypto.keytools.PropertiesDrivenCryptoFactory; CREATE TABLE IF NOT EXISTS adb_external_db.enc_customer USING Parquet OPTIONS ( 'parquet.encryption.column.keys'='kc1:c_name;kc2:c_phone', 'parquet.encryption.footer.key'='kf' ) LOCATION 'oss://testBucketName/adb/Spark/enc_customer' AS SELECT * FROM adb_external_db.customer;參數說明:
參數
是否必填
說明
parquet.encryption.column.keys
是
使用密鑰ID所對應的主要金鑰加密列。一個主要金鑰可加密多個列,主要金鑰ID和列名之間用半形冒號(:)分隔,加密列之間用半形逗號(,)分隔,不同主要金鑰之間用半形分號(;)分隔。
parquet.encryption.footer.key
是
Footer密鑰,用來加密Parquet檔案的中繼資料等資訊。
說明Footer是位於Parquet檔案尾部的資料結構,一般用來隱藏檔的中繼資料資訊,例如:版本號碼、分組元資訊、列的元資訊以及密鑰元資訊等。
重要parquet.encryption.column.keys和parquet.encryption.footer.key參數必須同時設定,否則檔案不會被加密。
(可選)刪除外表
customer。DROP TABLE IF EXISTS adb_external_db.customer;重要DROP TABLE語句會刪除
customer外表,對應OSS中的中繼資料請手動刪除,避免明文資料泄露。
建立外表
enc_customer_output,將enc_customer表的SQL計算結果寫入enc_customer_output外表。enc_customer_output外表的資料指定儲存在oss://testBucketName/adb/Spark/enc_customer_output。SET spark.adb.native.enabled=true; SET spark.hadoop.parquet.encryption.key.list=kf:MDEyMzQ1Njc4OTAxMjM0****,kc1:bvCDwqcOJGSdZSEMLjfk****,kc2:kflI/sq+uf50Qhl1MmtG****; SET spark.hadoop.parquet.encryption.kms.client.class=io.glutenproject.encryption.InMemoryKMS; SET spark.hadoop.parquet.crypto.factory.class=org.apache.parquet.crypto.keytools.PropertiesDrivenCryptoFactory; CREATE TABLE IF NOT EXISTS adb_external_db.enc_customer_output USING Parquet OPTIONS ( 'parquet.encryption.column.keys'='kc1:c_name;kc2:c_phone', 'parquet.encryption.footer.key'='kf' ) LOCATION 'oss://testBucketName/adb/Spark/enc_customer_output' AS SELECT * FROM adb_external_db.enc_customer WHERE c_custkey < 15;解密計算結果。
建立外表
customer_output,將enc_customer_output表的資料解密後寫入customer_output外表。customer_output外表的資料指定儲存在oss://testBucketName/adb/Spark/customer_output。SET spark.adb.native.enabled=true; SET spark.hadoop.parquet.encryption.key.list=kf:MDEyMzQ1Njc4OTAxMjM0****,kc1:bvCDwqcOJGSdZSEMLjfk****,kc2:kflI/sq+uf50Qhl1MmtG****; SET spark.hadoop.parquet.encryption.kms.client.class=io.glutenproject.encryption.InMemoryKMS; SET spark.hadoop.parquet.crypto.factory.class=org.apache.parquet.crypto.keytools.PropertiesDrivenCryptoFactory; CREATE TABLE IF NOT EXISTS adb_external_db.customer_output USING Parquet LOCATION 'oss://testBucketName/adb/Spark/customer_output' AS SELECT * FROM adb_external_db.enc_customer_output;查詢
customer_output表資料。SELECT * FROM adb_external_db.customer_output;
通過加密工具加密資料並建立密文表
通過加密工具將儲存在本地的明文資料加密成密文資料集,加密工具的更多資訊,請參見Spark加密工具。
import org.apache.spark.sql.SparkSession import org.apache.spark.sql.functions._ import org.apache.spark.SparkConf // 初始化SparkSession,並輸入加解密相關的參數。 val conf = new SparkConf() .set("spark.hadoop.parquet.encryption.kms.client.class", "org.apache.parquet.crypto.keytools.mocks.InMemoryKMS") .set("spark.hadoop.parquet.encryption.key.list", "kf:MDEyMzQ1Njc4OTAxMjM0****,kc1:bvCDwqcOJGSdZSEMLjfk****,kc2:kflI/sq+uf50Qhl1MmtG****") .set("spark.hadoop.parquet.crypto.factory.class", "org.apache.parquet.crypto.keytools.PropertiesDrivenCryptoFactory") val spark = SparkSession.builder().appName("SquareDataFrame").config(conf).getOrCreate() // 讀取明文customer。 val df = spark.read.parquet("customer") // 對明文customer加密,其中name列使用kc1加密,footer使用kf加密,加密後的密文檔案為enc_customer。 df.write .option("parquet.encryption.column.keys" , "kc1:c_name") .option("parquet.encryption.footer.key" , "kf") // 密文資料集所在的本地路徑。 .parquet("enc_customer")參數說明:
參數
是否必填
說明
spark.hadoop.parquet.encryption.kms.client.class
是
KMS用戶端類名。
本地加密時需填寫為
org.apache.parquet.crypto.keytools.mocks.InMemoryKMS。控制台建立密文表時需填寫為
io.glutenproject.encryption.InMemoryKMS。
spark.hadoop.parquet.encryption.key.list
是
使用者主要金鑰列表。一個主要金鑰對應一個密鑰ID,多個主要金鑰之間用半形逗號(,)分隔,每個主要金鑰ID與主要金鑰之間用半形冒號(:)分隔。格式為:
<主要金鑰ID1>:<Base64編碼的主要金鑰1>,<主要金鑰ID2>:<Base 64 編碼的主要金鑰2>。詳情請參見密鑰介紹。本文樣本為
kf:MDEyMzQ1Njc4OTAxMjdy****,kc1:bvCDwqcOJGSdZSEMLjfk****,kc2:kflI/sq+uf50Qhl1MmtG****警告您可以使用通用工具(例如:OpenSSL)隨機產生使用者主要金鑰。使用者主要金鑰是訪問加密資料的根憑據,一旦丟失密鑰,將無法再訪問已有的資料,請妥善保管使用者主要金鑰。
spark.hadoop.parquet.crypto.factory.class
是
CryptoFactory類名。固定填寫為
org.apache.parquet.crypto.keytools.PropertiesDrivenCryptoFactory。parquet.encryption.column.keys
是
使用密鑰ID所對應的主要金鑰加密列。一個主要金鑰可加密多個列,主要金鑰ID和列名之間用半形冒號(:)分隔,加密列之間用半形逗號(,)分隔,不同主要金鑰之間用半形分號(;)分隔。
parquet.encryption.footer.key
是
Footer密鑰,用來加密Parquet檔案的中繼資料等資訊。
說明Footer是位於Parquet檔案尾部的資料結構,一般用來隱藏檔的中繼資料資訊,例如:版本號碼、分組元資訊、列的元資訊以及密鑰元資訊等。
將密文資料集
enc_customer.parquet上傳至OSS。本文樣本為oss://testBucketName/adb/Spark/enc_customer.parquet。具體操作,請參見簡單上傳。建立密文表。
登入雲原生資料倉儲AnalyticDB MySQL控制台,在左上方選擇叢集所在地區。在左側導覽列,單擊集群清單,然後單擊目的地組群ID。
在左側導覽列,單擊。
在SQLConsole視窗,選擇Spark引擎和Job型資源群組。
執行以下語句,建立密文表。
開啟native計算,並建立資料庫。
-- 開啟native計算 SET spark.adb.native.enabled=true; -- 配置資源 SET spark.driver.resourceSpec=medium; SET spark.executor.instances=2; SET spark.executor.resourceSpec=medium; -- 開啟密文讀寫支援並設定主要金鑰列表,KMS Client 以及 CryptoFactory(開啟後引擎可同時支援明文和密文) SET spark.hadoop.parquet.encryption.key.list=kf:MDEyMzQ1Njc4OTAxMjM0****,kc1:bvCDwqcOJGSdZSEMLjfk****,kc2:kflI/sq+uf50Qhl1MmtG****; SET spark.hadoop.parquet.encryption.kms.client.class=io.glutenproject.encryption.InMemoryKMS; SET spark.hadoop.parquet.crypto.factory.class=org.apache.parquet.crypto.keytools.PropertiesDrivenCryptoFactory; -- 建立資料庫 CREATE DATABASE IF NOT EXISTS adb_external_db;建立外表
enc_customer。LOCATION為密文資料集enc_customer所在的OSS路徑。本文樣本為oss://testBucketName/adb/Spark/enc_customer.parquet。SET spark.adb.native.enabled=true; SET spark.hadoop.parquet.encryption.key.list=kf:MDEyMzQ1Njc4OTAxMjM0****,kc1:bvCDwqcOJGSdZSEMLjfk****,kc2:kflI/sq+uf50Qhl1MmtG****; SET spark.hadoop.parquet.encryption.kms.client.class=io.glutenproject.encryption.InMemoryKMS; SET spark.hadoop.parquet.crypto.factory.class=org.apache.parquet.crypto.keytools.PropertiesDrivenCryptoFactory; CREATE TABLE IF NOT EXISTS adb_external_db.enc_customer USING parquet LOCATION 'oss://testBucketName/adb/Spark/enc_customer';
建立外表
enc_customer_output,將enc_customer表的SQL計算結果寫入enc_customer_output外表。enc_customer_output外表的資料指定儲存在oss://testBucketName/adb/Spark/enc_customer_output。SET spark.adb.native.enabled=true; SET spark.hadoop.parquet.encryption.key.list=kf:MDEyMzQ1Njc4OTAxMjM0****,kc1:bvCDwqcOJGSdZSEMLjfk****,kc2:kflI/sq+uf50Qhl1MmtG****; SET spark.hadoop.parquet.encryption.kms.client.class=io.glutenproject.encryption.InMemoryKMS; SET spark.hadoop.parquet.crypto.factory.class=org.apache.parquet.crypto.keytools.PropertiesDrivenCryptoFactory; CREATE TABLE IF NOT EXISTS adb_external_db.enc_customer_output USING Parquet OPTIONS ( 'parquet.encryption.column.keys'='kc1:c_name;kc2:c_phone', 'parquet.encryption.footer.key'='kf' ) LOCATION 'oss://testBucketName/adb/Spark/enc_customer_output' AS SELECT * FROM adb_external_db.enc_customer WHERE c_custkey < 15;下載密文結果並解密。
從OSS路徑
oss://testBucketName/adb/Spark/enc_customer_output下載密文計算結果到本地。具體操作,請參見下載檔案。解密計算結果密文資料集,並將解密後的檔案儲存在
customer_output中。// 解密密文資料集 val conf = new SparkConf() .set("spark.hadoop.parquet.encryption.kms.client.class", "org.apache.parquet.crypto.keytools.mocks.InMemoryKMS") .set("spark.hadoop.parquet.encryption.key.list", "kf:MDEyMzQ1Njc4OTAxMjM0****,kc1:bvCDwqcOJGSdZSEMLjfk****,kc2:kflI/sq+uf50Qhl1MmtG****") .set("spark.hadoop.parquet.crypto.factory.class", "org.apache.parquet.crypto.keytools.PropertiesDrivenCryptoFactory") val spark = SparkSession.builder().appName("SquareDataFrame").config(conf).getOrCreate() val df2 = spark.read.parquet("enc_customer_output") // 將解密後的檔案下載至本地 df2.write .parquet("customer_output")