本文中含有需要您注意的重要提示信息,忽略该信息可能对您的业务造成影响,请务必仔细阅读。
云原生数据仓库 AnalyticDB MySQL 版Spark全密态计算引擎高性能版,在Spark全密态引擎基础版能力的基础上,支持Parquet模块化加密功能,且兼容社区版Spark、Hadoop、Hive等计算引擎,在保证数据传输与存储过程安全的同时,提升了数据处理效率。本文介绍如何通过Spark全密态计算引擎高性能版加密数据,并基于密文表执行SQL计算。
前提条件
集群的产品系列为企业版、基础版或湖仓版。
集群与OSS存储空间位于相同地域。
已创建Job型资源组。具体操作,请参见新建资源组。
已创建数据库账号。
如果是通过阿里云账号访问,只需创建高权限账号。具体操作,请参见创建高权限账号。
如果是通过RAM用户访问,需要创建高权限账号和普通账号并且将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>:<Base64 编码的主密钥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>:<Base64 编码的主密钥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")