Utilisation du chiffrement modulaire Parquet

IBM Analytics Engine Serverless prend en charge le chiffrement modulaire Parquet, un nouvel ajout à la norme Parquet qui permet de chiffrer les colonnes sensibles lors de l'écriture de fichiers Parquet et de déchiffrer ces colonnes lors de la lecture des fichiers chiffrés. Voir chiffrement modulaire Parquet.

Outre qu'il veille à la confidentialité des données, le chiffrement Parquet protège l'intégrité des données stockées. Toute altération du contenu d'un fichier est détectée et déclenche une exception côté lecteur.

Principales caractéristiques :

  1. Les opérations de chiffrement et de déchiffrement Parquet ont lieu dans les noeurs worker Spark. Par conséquent, les données sensibles et les clés de chiffrement ne sont pas visibles par le stockage.

  2. Les fonctionnalités standard de Parquet, telles que l'encodage, la compression, la projection colonnaire et le "predicate push-down", continuent à fonctionner de la même manière sur les fichiers au format à chiffrement modulaire Parquet.

  3. Vous pouvez choisir l'un des deux algorithmes de chiffrement définis dans la spécification Parquet. Les deux algorithmes se prêtent au chiffrement de colonnes, mais :

    • AES-GCM, l'algorithme par défaut, assure une protection totale contre l'altération des données et des parties métadonnées dans les fichiers Parquet.
    • L'autre algorithme, AES-GCM-CTR, assure une protection partielle de l'intégrité des fichiers Parquet. Seules les parties métadonnées, et non les parties données, sont protégées contre la falsification. L'avantage de cet algorithme par rapport à AES-GCM est qu'il pénalise moins le débit de traitement.
  4. Vous pouvez choisir quelles colonnes sont à chiffrer. Les autres colonnes ne seront pas chiffrées, ce qui réduira d'autant le coût de traitement.

  5. Différentes colonnes peuvent être chiffrées avec des clés différentes.

  6. Par défaut, le module de métadonnées principal Parquet (le pied de page du fichier) est chiffré pour masquer le schéma du fichier et la liste des colonnes sensibles. Vous pouvez cependant choisir de ne pas chiffrer le pied de page des fichiers afin de permettre aux anciens lecteurs (tels que les autres distributions Spark qui ne supportent pas encore le chiffrement Parquet) de lire les colonnes non chiffrées dans les fichiers chiffrés.

  7. Les clés de chiffrement peuvent être gérées de deux manières :

    • Directement par votre application. Voir Gestion des clés par application.
    • Par IBM® Key Protect for IBM Cloud®, système de gestion centralisée des clés qui assure la génération, la gestion et la destruction des clés de chiffrement utilisées par IBM Analytics Engine. Voir Gestion des clés par Key Protect{: {: external}}.

    IBM® Key Protect for IBM Cloud® vous aide à gérer vos clés chiffrées en s'alignant sur les rôles IAM (Identity and Access Management) d'IBM Cloud.

    **Remarque **: Seules les clés de chiffrement maîtresses (MEK) ont besoin d'être gérées (soit par votre application, soit par Key Protect). Les clés de chiffrement de données (DEK) sont automatiquement prises en charge par Spark/Parquet. Pour des détails sur le traitement des clés au sein du chiffrement Parquet, consultez Aspects internes du traitement des clés de chiffrement.

    Pour chaque colonne sensible, vous devez indiquer quelle clé maîtresse utiliser pour le chiffrement. En outre, une clé principale doit être spécifiée pour le pied de page de chaque fichier chiffré (trame de données), car les pieds de page conservent les métadonnées, comme le schéma et la liste des colonnes sensibles, qui peuvent également être sensibles. Par défaut, la clé du pied de page sera utilisée pour le chiffrement du pied de page. Si toutefois vous optez pour le mode pied de page en clair, le pied de page ne sera pas chiffré et la clé ne sera utilisée que pour vérifier l'intégrité du pied de page.

    Les paramètres de chiffrement peuvent être passés par l'intermédiaire de la configuration standard Hadoop Spark, par exemple en spécifiant leurs valeurs dans la configuration Hadoop du contexte Spark de l'application :

    sc.hadoopConfiguration.set("<parameter name>" , "<parameter value>")
    

    Vous pouvez aussi passer des valeurs de paramètre via les options d'écriture (write) :

    <data frame name>.write
    .option("<parameter name>" , "<parameter value>")
    .parquet("<write path>")
    

Paramètres obligatoires pour l'exécution avec le chiffrement Parquet

Les paramètres suivants sont obligatoires pour écrire des données chiffrées :

  • Liste des colonnes à chiffrer, avec les clés de chiffrement maîtresses :

    parameter name: "parquet.encryption.column.keys"
    parameter value: "<master key ID>:<column>,<column>;<master key ID>:<column>,.."
    
  • Clé de pied de page :

    parameter name: "parquet.encryption.footer.key"
    parameter value: "<master key ID>"
    

    Exemple :

    dataFrame.write
    .option("parquet.encryption.footer.key" , "k1")
    .option("parquet.encryption.column.keys" , "k2:SSN,Address;k3:CreditCard")
    .parquet("<path to encrypted files>")
    

    Important : si ni le paramètre "parquet.encryption.column.keys" ni le paramètre "parquet.encryption.footer.key" n'est défini, le fichier n'est pas chiffré. Si un seul de ces paramètres est défini, une exception est générée car ces paramètres sont obligatoires pour les fichiers chiffrés.

  • La classe implémentant EncryptionPropertiesFactory:

    parameter name: "parquet.crypto.factory.class"
    parameter value: "com.ibm.parquet.key.management.IBMKeyToolsFactory"
    

    Important: Si "parquet.crypto.factory.class" n'est pas défini, le fichier n'est pas chiffré par une fabrique de chiffrement.

Paramètres facultatifs

Les paramètres optionnels suivants peuvent être utilisés lors de l'écriture de données chiffrées :

  • L'algorithme de chiffrement AES-GCM-CTR

    Par défaut, le chiffrement Parquet utilise AES-GCM, algorithme qui assure une protection totale contre l'altération des données et des métadonnées dans les fichiers Parquet. Cependant, étant donné que Spark 2.3.0 fonctionne sur Java 8, qui ne reconnaît pas l'accélération matérielle d'AES dans le processeur (le support de celle-ci n'ayant été ajouté que dans Java 9), le surcroît de traitement nécessaire à la vérification de l'intégrité des données peut affecter la vitesse de traitement de la charge de travail dans certains cas.

    Pour contrebalancer ce point, vous pouvez mettre hors fonction le support de vérification de l'intégrité des données et utiliser l'autre algorithme, AES-GCM-CTR, pour écrire les fichiers chiffrés. L'avantage de cet algorithme par rapport à AES-GCM est qu'il pénalise moins le débit de traitement, car il vérifie seulement les parties métadonnées, et non les parties données.

    parameter name: "parquet.encryption.algorithm"
    parameter value: "AES_GCM_CTR_V1"
    
  • Mode pied de page en clair pour les anciens lecteurs

    Par défaut, le module de métadonnées principal Parquet (le pied de page du fichier) est chiffré pour masquer le schéma du fichier et la liste des colonnes sensibles. Vous pouvez cependant choisir de ne pas chiffrer le pied de page des fichiers afin de permettre aux autres lecteurs Spark et Parquet (qui ne supportent pas encore le chiffrement Parquet) de lire les colonnes non chiffrées dans les fichiers chiffrés. Pour désactiver le chiffrement du pied de page, définissez le paramètre suivant :

    parameter name: "parquet.encryption.plaintext.footer"
    parameter value: "true"
    

    Important : le paramètre "parquet.encryption.footer.key" doit également être spécifié dans le mode de bas de page en texte en clair. Bien que le pied de page ne soit pas chiffré, la clé est utilisée pour signer le contenu du pied de page, ce qui signifie que les nouveaux lecteurs peuvent vérifier son intégrité. Les lecteurs existants ne sont pas affectés par l'ajout de la signature du pied de page.

Exemples d'utilisation

Les exemples de codes suivants, dont certains sont en Python et les autres, en Scala, montrent comment créer des dataframes (trames de données) écrits pour chiffrer des fichiers parquet et lire des fichiers parquet chiffrés.

  • Python : Ecriture de données chiffrées

    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 : Lecture de données chiffrées

    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 : Ecriture de données chiffrées

    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 : Lecture de données chiffrées

    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()
    

Aspects internes du traitement des clés de chiffrement

Lors de l'écriture d'un fichier Parquet, une clé de chiffrement de données (DEK, data encryption key) aléatoire est générée pour chaque colonne chiffrée ainsi que pour le pied de page (footer). Ces clés sont utilisées pour chiffrer les données et les modules de métadonnées dans le fichier Parquet.

La clé de chiffrement de données est alors chiffrée avec une clé de chiffrement de clé (KEK, key encryption key), laquelle est également générée à l'intérieur de Spark/Parquet pour chaque clé maîtresse. La clé de chiffrement de clé est chiffrée avec une clé de chiffrement maîtresse (MEK, master encryption key), soit localement si les clés maîtresses sont gérées par l'application, soit dans un service KeyProtect si les clés maîtresses sont gérées par IBM® Key Protect for IBM Cloud®.

Les clés de chiffrement de données et les clés de chiffrement de clé chiffrées sont stockées dans les métadonnées du fichier Parquet, conjointement avec l'identité de la clé maîtresse. Chaque clé de chiffrement de clé a une identité unique (générée localement sous la forme d'une valeur aléatoire sûre à 16 octets), également stockée dans les métadonnées du fichier. Les clés de chiffrement sont mises en cache par jeton d'accès, de sorte qu'il n'est pas nécessaire d'interagir avec le service KeyProtect pour chaque colonne ou fichier chiffré s'ils utilisent la même clé de chiffrement principal.

Lors de la lecture d'un fichier Parquet, l'identificateur de la clé de chiffrement maîtresse (MEK) et la clé de chiffrement de clé (KEK) chiffrée accompagnée de son identificateur, ainsi que la clé de chiffrement de données (DEK) chiffrée, sont extraits des métadonnées du fichier.

La clé de chiffrement de clé est déchiffrée avec la clé de chiffrement maîtresse, soit localement si les clés maîtresses sont gérées par l'application, soit dans un service KeyProtect si les clés maîtresses sont gérées par IBM® Key Protect for IBM Cloud®. Les clés de chiffrement de clé sont mises en cache par jeton d'accès, de sorte qu'il n'est pas nécessaire d'interagir avec le service KeyProtect pour chaque colonne ou fichier déchiffré s'ils utilisent la même clé de chiffrement de clé. La clé de chiffrement de données (DEK) sera décryptée localement, au moyen de la clé de chiffrement de clé (KEK).

Renouvellement de clé (fonction facultative)

La pratique de chiffrement d'enveloppe a une option avancée pour le renouvellement, afin de réduire le risque de fuite de données sensibles suite à l'altération des clés MEK. Les clés DEK ne peuvent pas être changés, parce que cela implique de chiffrer à nouveau entièrement les fichiers Parquet. Les nouvelles clés MEK (et les clés KEK, de façon transparente) sont utilisés pour rechiffrer les clés DEK.

Pour activer le renouvellement de clés dans les fichiers Parquet, vous devez affecter au paramètre "parquet.encryption.key.material.store.internally" la valeur "false" dans la configuration Hadoop lors de l'écriture des fichiers Parquet.

Avec ce jeu de paramètres, Parquet stocke les clés (encapsulées avec la clé MEK) dans des petits fichiers séparés, et non pas dans les fichiers Parquet. Lorsque le renouvellement des clés est effectuée, seuls les petits fichiers d'élément de clés sont remplacés. Il n'est pas nécessaire de modifier les fichiers Parquet (qui sont souvent inaltérables). La plupart des systèmes KMS prennent en charge le renouvellement de clés en remplaçant le contenu des clés principales stockées et en conservant l'ID MEK intact (mais en mettant à jour la version de clé). Une fois qu'un utilisateur ou un administrateur a renouvelé la clé principale à l'intérieur de l'instance KMS à l'aide de l'API KMS spécifique, le mécanisme de renouvellement de clé Parquet peut être déclenché (par exemple, par le même administrateur) en appelant :

public static void KeyToolkit.rotateMasterKeys(String folderPath, Configuration hadoopConfig)

Lors du renouvellement des clés, chaque clé KEK de tous les fichiers d'élément de clé de folderPath est désencapsulé avec l'ancienne version MEK pour permettre le déchiffrement de la clé DEK. Une nouvelle clé est générée pour chaque ID de clé principale et encapsulée avec la nouvelle version de la clé MEK. La création d'une nouvelle clé KEK, au lieu de réutiliser l'ancienne clé, non seulement renforce la sécurité, mais améliore également les performances des opérations de lecture de données ultérieures. En effet, un processus de renouvellement de clé unique, exécuté par l'administrateur, opère sur plusieurs fichiers créés par différents processus, ce qui signifie que plusieurs clés KEK sont différentes pour le même ID de clé MEK. Le renouvellement de clé remplace les anciennes clés KEK par une nouvelle clé KEK, ce qui permet aux lecteurs d'exécuter une seule interaction de désencapsulation avec une clé KMS pour chaque clé principale.

Pour des exemples d'utilisation du renouvellement de clé :

En savoir plus

Consultez l'exemple de bloc-notes suivant pour savoir comment utiliser le chiffrement Parquet :