使用 Parquet 模組化加密
IBM Analytics Engine 無伺服器支援 Parquet 模組化加密,這是 Parquet 標準的新新增項目,容許在寫入 Parquet 檔案時加密機密直欄,並在讀取加密檔案時解密這些直欄。 請參閱 Parquet 模組化加密。
除了確保隱私之外,Parquet 加密還會保護儲存資料的完整性。 系統會偵測對檔案內容進行的任何竄改,並觸發讀取器端異常狀況。
主要特性包括:
-
Parquet 加密和解密在 Spark 工作程式中執行。 因此,機密資料及加密金鑰對儲存體不可見。
-
標準 Parquet 特性(如編碼、壓縮、直欄式投射及述詞推入)在 Parquet 模組化加密格式的檔案中會繼續照常運作。
-
您可以選擇 Parquet 規格中定義的兩個加密演算法之一。 這兩個演算法皆支援直欄加密,但是:
- 預設演算法
AES-GCM提供完整保護,防止竄改 Parquet 檔案中的資料和 meta 資料組件。 - 替代演算法
AES-GCM-CTR支援 Parquet 檔案的局部完整性保護。 僅會防止竄改 meta 資料部分(而非資料部分)。 此演算法的優點是相較於AES-GCM演算法,它具有較低的傳輸量額外負擔。
- 預設演算法
-
您可以選擇要加密的直欄。 其他直欄不會加密,從而減少傳輸量額外負擔。
-
不同的直欄可以使用不同的金鑰來加密。
-
依預設,將會加密主要 Parquet meta 資料模組(檔案標底),以隱藏檔案綱目及機密直欄清單。 不過,您可以選擇不加密檔案標底,以便讓舊式讀取器 (例如尚未支援 Parquet 加密的其他 Spark 發行套件) 能夠讀取已加密檔案中未加密的直欄。
-
加密金鑰可透過下列兩種方式之一進行管理:
- 直接透過您的應用程式。 請參閱 應用程式的金鑰管理。
- 透過 IBM® Key Protect for IBM Cloud®,這是一個集中式金鑰管理系統 (KMS),用於產生、管理及毀損 IBM Analytics Engine使用的加密金鑰。 請參閱 Key Management by Key Protect{: {: external}}。
IBM® Key Protect for IBM Cloud® 可協助您管理加密金鑰,方法是與 IBM Cloud Identity and Access Management (IAM) 角色對齊。
附註: 只需要管理主要加密金鑰 (MEK) (由您的應用程式或 Key Protect來管理)。 資料加密金鑰 (DEK) 會由 Spark/Parquet 自動處理。 如需 Parquet 加密內金鑰處理的詳細資料,請參閱 加密金鑰處理的內部。
對於每個機密直欄,您必須指定要用於加密的主要金鑰。 此外,必須為每一個已加密檔案 (資料頁框) 的標底指定主要金鑰-因為標底會保留 meta 資料 (例如綱目及機密直欄清單),也可能是機密。 依預設,標底金鑰將用於標底加密。 但是,如果您選擇純文字標底模式,則不會加密標底,且金鑰僅會用於標底的完整性驗證。
加密參數可以透過標準 Spark Hadoop 配置傳遞,例如透過在應用程式 SparkContext的 Hadoop 配置中設定配置值:
sc.hadoopConfiguration.set("<parameter name>" , "<parameter value>")或者,您可以透過 write 選項來傳遞參數值:
<data frame name>.write .option("<parameter name>" , "<parameter value>") .parquet("<write path>")
使用 Parquet 加密執行的必要參數
寫入加密資料需要下列參數:
-
要加密的具有主要加密金鑰的直欄清單:
parameter name: "parquet.encryption.column.keys" parameter value: "<master key ID>:<column>,<column>;<master key ID>:<column>,.." -
標底金鑰:
parameter name: "parquet.encryption.footer.key" parameter value: "<master key ID>"例如:
dataFrame.write .option("parquet.encryption.footer.key" , "k1") .option("parquet.encryption.column.keys" , "k2:SSN,Address;k3:CreditCard") .parquet("<path to encrypted files>")重要事項: 如果既未設定
"parquet.encryption.column.keys"參數,也未設定"parquet.encryption.footer.key"參數,則不會加密檔案。 如果僅設定其中一個參數,則會擲出異常狀況,因為這些參數對於加密檔案是必要的。 -
實作
EncryptionPropertiesFactory的類別:parameter name: "parquet.crypto.factory.class" parameter value: "com.ibm.parquet.key.management.IBMKeyToolsFactory"重要事項: 如果未設定
"parquet.crypto.factory.class",則加密 Factory 不會加密檔案。
選用參數
在寫入加密資料時,可以使用下列選用參數:
-
加密演算法
AES-GCM-CTR依預設,Parquet 加密會使用
AES-GCM演算法來提供完整保護,防止竄改 Parquet 檔案中的資料和 meta 資料。 但是,由於 Spark 2.3.0 在 Java 8 上執行,而 Java 8 不支援 CPU 硬體中的 AES 加速(僅在 Java 9 中新增了此支援),因此資料完整性驗證的額外負擔在某些狀況下可能會影響工作量傳輸量。若要補償此情況,您可以關閉資料完整性驗證支援,並使用替代演算法
AES-GCM-CTR來寫入加密檔案,這只會驗證 meta 資料組件的完整性,不會驗證資料組件的完整性,且相較於AES-GCM演算法,傳輸量額外負擔會較低。parameter name: "parquet.encryption.algorithm" parameter value: "AES_GCM_CTR_V1" -
適用於舊式讀取器的純文字標底模式
依預設,將會加密主要 Parquet meta 資料模組(檔案標底),以隱藏檔案綱目及機密直欄清單。 不過,您可以決定不加密檔案標底,以啟用其他 Spark 及 Parquet 讀取器 (尚不支援 Parquet 加密) 來讀取已加密檔案中未加密的直欄。 若要關閉標底加密,請設定下列參數:
parameter name: "parquet.encryption.plaintext.footer" parameter value: "true"重要事項:
"parquet.encryption.footer.key"參數也必須在純文字標底模式中指定。 雖然標底未加密,但會使用金鑰來簽署標底內容,這表示新讀取器可以驗證其完整性。 舊式讀取器不受新增標底簽章的影響。
用法範例
適用於 Python 及 Scala 的下列範例程式碼 Snippet,顯示如何建立資料框架、寫入加密的 Parquet 檔,以及從加密的 Parquet 檔進行讀取。
-
Python: 寫入加密資料
from pyspark.sql import RowsquaresDF = spark.createDataFrame( sc.parallelize(range(1, 6)) .map(lambda i: Row(int_column=i, square_int_column=i ** 2))) sc._jsc.hadoopConfiguration().set("parquet.crypto.factory.class", "com.ibm.parquet.key.management.IBMKeyToolsFactory") sc._jsc.hadoopConfiguration().set("encryption.key.list", "key1: AAECAwQFBgcICQoLDA0ODw==, key2: AAECAAECAAECAAECAAECAA==") encryptedParquetPath = "squares.parquet.encrypted"squaresDF.write\ .option("parquet.encryption.column.keys", "key1:square_int_column")\ .option("parquet.encryption.footer.key", "key2")\ .parquet(encryptedParquetPath) -
Python: 讀取加密資料
sc._jsc.hadoopConfiguration().set("parquet.crypto.factory.class", "com.ibm.parquet.key.management.IBMKeyToolsFactory") sc._jsc.hadoopConfiguration().set("parquet.encryption.key.list", "key1: AAECAwQFBgcICQoLDA0ODw==, key2: AAECAAECAAECAAECAAECAA==") encryptedParquetPath = "squares.parquet.encrypted" parquetFile = spark.read.parquet(encryptedParquetPath) parquetFile.show() -
Scala: 寫入加密資料
case class SquareItem(int_column: Int, square_int_column: Double) val dataRange = (1 to 6).toList val squares = sc.parallelize(dataRange.map(i => new SquareItem(i, scala.math.pow(i,2)))) sc.hadoopConfiguration.set("parquet.crypto.factory.class","com.ibm.parquet.key.management.IBMKeyToolsFactory") sc.hadoopConfiguration.set("parquet.encryption.key.list","key1: AAECAwQFBgcICQoLDA0ODw==, key2: AAECAAECAAECAAECAAECAA==") val encryptedParquetPath = "squares.parquet.encrypted" squares.toDS().write .option("parquet.encryption.column.keys", "key1:square_int_column") .option("parquet.encryption.footer.key", "key2") .parquet(encryptedParquetPath) -
Scala: 讀取加密資料
sc.hadoopConfiguration.set("parquet.crypto.factory.class","com.ibm.parquet.key.management.IBMKeyToolsFactory") sc.hadoopConfiguration.set("parquet.encryption.key.list","key1: AAECAwQFBgcICQoLDA0ODw==, key2: AAECAAECAAECAAECAAECAA==") val encryptedParquetPath = "squares.parquet.encrypted" val parquetFile = spark.read.parquet(encryptedParquetPath) parquetFile.show()
加密金鑰處理的內容
寫入 Parquet 檔時,會為每個加密直欄及標底產生隨機資料加密金鑰 (DEK)。 這些金鑰可用來加密 Parquet 檔中的資料及 meta 資料模組。
然後,資料加密金鑰會使用金鑰加密金鑰 (KEK) 進行加密,該金鑰也是在 Spark/Parquet 內針對每個主要金鑰而產生。 金鑰加密金鑰使用主要加密金鑰 (MEK) 進行加密,如果主要金鑰由應用程式管理,則在本端; 如果主要金鑰由 IBM® Key Protect for IBM Cloud®管理,則在 KeyProtect 服務中。
已加密的資料加密金鑰及金鑰加密金鑰,會與主要金鑰身分一起儲存在 Parquet 檔 meta 資料中。 每個金鑰加密金鑰皆具有唯一身分(在本端產生為安全隨機 16 位元組值),該身分也會儲存在檔案 meta 資料中。 金鑰加密金鑰由存取記號快取,因此如果每個已加密直欄或檔案使用相同的主要加密金鑰,則不需要與 KeyProtect 服務互動。
讀取 Parquet 檔時,會從檔案 meta 資料中擷取主要加密金鑰 (MEK) 的 ID、已加密的金鑰加密金鑰 (KEK) 及其 ID,以及已加密的資料加密金鑰 (DEK)。
金鑰加密金鑰會使用主要加密金鑰解密,如果主要金鑰由應用程式管理,則在本端解密; 如果主要金鑰由 IBM® Key Protect for IBM Cloud®管理,則在 KeyProtect 服務中解密。 金鑰加密金鑰由存取記號快取,因此如果每個解密直欄或檔案使用相同的金鑰加密金鑰,則不需要與 KeyProtect 服務互動。 然後,會在本端使用金鑰加密金鑰 (KEK) 來解密資料加密金鑰 (DEK)。
金鑰輪替 (選用特性)
封套加密實務有一個進階選項,可 輪換 (變更) 主要金鑰,以將由於已受損的 MEK 而造成機密資料洩漏的風險降至最低。 無法變更 DEK,因為這表示完全重新加密 Parquet 檔案。 會使用新的 MEK (以及透通重新產生的 KEK) 來重新加密 DEK。
若要在 Parquet 檔案中啟用金鑰旋轉,您必須在寫入 parquet 檔案時,將 Hadoop 配置中的 "parquet.encryption.key.material.store.internally" 參數設為 "false"。
設定此參數之後,Parquet 會將金鑰 (以 MEK 包裝) 儲存在個別的小型檔案中,而不是儲存在 Parquet 檔案內。 執行金鑰輪替時,只會取代小型金鑰資料檔案。 不需要修改 Parquet 檔案 (通常不可變)。 大部分 KMS 系統都支援金鑰輪替,方法是取代所儲存主要金鑰的內容,並保持 MEK ID 完整 (但更新金鑰版本)。 在使用者或管理者使用 KMS 特定 API 在 KMS 實例內執行主要金鑰輪替之後,可以透過呼叫下列指令來觸發 Parquet 金鑰輪替機制 (例如,由相同的管理者):
public static void KeyToolkit.rotateMasterKeys(String folderPath, Configuration hadoopConfig)
執行金鑰輪替時,folderPath 中所有金鑰資料檔案中的每個 KEK 都會以舊 MEK 版本解除包裝,以啟用解密 DEK。 會針對每一個主要金鑰 ID 產生新的 KEK,並以新的 MEK 版本包裝。 建立新的 KEK,而不是重複使用舊的 KEK,不僅表示安全已改善,而且後續資料讀取作業的效能也會增加。 這是因為由管理者執行的單一金鑰輪替處理程序會在不同處理程序所建立的多個檔案之間運作,這表示相同 MEK ID 有許多不同的 KEK。 金鑰輪替處理程序會將舊
KEK 取代為單一新的 KEK,這可讓讀取器針對每一個主要金鑰執行與 KMS 的單一解除包裝互動。
如需如何使用金鑰替換的範例:
- 如需依應用程式管理金鑰,請參閱 依應用程式管理金鑰中的金鑰替換。
- 如需使用 Key Protect進行金鑰管理,請參閱 使用 Key Protect進行金鑰替換金鑰管理。
進一步瞭解
請參閱下列範例 Notebook,以瞭解如何使用 Parquet Encryption: