Skip to content
Merged
Show file tree
Hide file tree
Changes from 5 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions cpp/src/parquet/encryption/crypto_factory.h
Original file line number Diff line number Diff line change
Expand Up @@ -43,8 +43,8 @@ struct PARQUET_EXPORT EncryptionConfiguration {
/// ID of the master key for footer encryption/signing
std::string footer_key;

/// List of columns to encrypt, with master key IDs (see HIVE-21848).
/// Format: "masterKeyID:colName,colName;masterKeyID:colName..."
/// List of columns to encrypt, with column master key IDs (see HIVE-21848).
/// Format: "columnKeyID:colName,colName;columnKeyID:colName..."
/// Either
/// (1) column_keys must be set
/// or
Expand Down
76 changes: 76 additions & 0 deletions docs/source/cpp/parquet.rst
Original file line number Diff line number Diff line change
Expand Up @@ -585,6 +585,82 @@ More specifically, Parquet C++ supports:
* EncryptionWithFooterKey and EncryptionWithColumnKey modes.
* Encrypted Footer and Plaintext Footer modes.

Configuration
~~~~~~~~~~~~~

An example for writing a dataset using encrypted Parquet file format:

.. code-block:: cpp

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@jorisvandenbossche @AlenkaF @raulcd What is our preferred policy for code examples? Do we put them inline in the docs? Do we use separate files?

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Update: it seems we use literalinclude directives from C++ example files that are compiled as part of CI runs. See for example https://github.com/apache/arrow/blob/main/docs/source/cpp/dataset.rst#reading-datasets


#include <arrow/util/logging.h>

#include "arrow/dataset/file_parquet.h"
#include "arrow/dataset/parquet_encryption_config.h"
#include "arrow/testing/gtest_util.h"
#include "parquet/encryption/crypto_factory.h"

using arrow::internal::checked_pointer_cast;

auto crypto_factory = std::make_shared<parquet::encryption::CryptoFactory>();
parquet::encryption::KmsClientFactory kms_client_factory = ...;
crypto_factory->RegisterKmsClientFactory(std::move(kms_client_factory));
auto kms_connection_config = std::make_shared<parquet::encryption::KmsConnectionConfig>();

// Set write options with encryption configuration.
auto encryption_config =
std::make_shared<parquet::encryption::EncryptionConfiguration>(
std::string("footer_key"));
encryption_config->column_keys = "col_key: a";
auto parquet_encryption_config = std::make_shared<ParquetEncryptionConfig>();
// Directly assign shared_ptr objects to ParquetEncryptionConfig members
parquet_encryption_config->crypto_factory = crypto_factory;
parquet_encryption_config->kms_connection_config = kms_connection_config;
parquet_encryption_config->encryption_config = std::move(encryption_config);

auto file_format = std::make_shared<ParquetFileFormat>();
auto parquet_file_write_options =
checked_pointer_cast<ParquetFileWriteOptions>(file_format->DefaultWriteOptions());
parquet_file_write_options->parquet_encryption_config =
std::move(parquet_encryption_config);

// Write dataset.
arrow::Table table = ...;
auto dataset = std::make_shared<InMemoryDataset>(table);
EXPECT_OK_AND_ASSIGN(auto scanner_builder, dataset->NewScan());
EXPECT_OK_AND_ASSIGN(auto scanner, scanner_builder->Finish());

FileSystemDatasetWriteOptions write_options;
write_options.file_write_options = parquet_file_write_options;
write_options.base_dir = "example.parquet";
ARROW_CHECK_OK(FileSystemDataset::Write(write_options, std::move(scanner)));

Column encryption is configured by setting ``encryption_config->column_keys`` to a string
of the format ``"columnKeyID:colName,colName;columnKeyID:colName..."``.

Encrypting columns that have nested fields (for instance struct, map, or even list data types)
require configuring column keys for the inner fields, not the column itself.
Configuring a column key for the column itself causes this error (here column name is ``col``):

.. code-block::

OSError: Encrypted column col not in file schema

An example encryption configuration for columns with nested fields:

.. code-block:: cpp

auto table_schema = schema({
field("ListColumn", list(int32())),
field("MapColumn", map(utf8(), int32())),
field("StructColumn", struct_({field("f1", int32()), field("f2", utf8())})),
});

encryption_config->column_keys = "column_key_id: "
"ListColumn.list.element, "
"MapColumn.key_value.key, MapColumn.key_value.value, "
"StructColumn.f1, StructColumn.f2"


Miscellaneous
-------------

Expand Down
33 changes: 32 additions & 1 deletion docs/source/python/parquet.rst
Original file line number Diff line number Diff line change
Expand Up @@ -703,7 +703,7 @@ creating file encryption properties) includes the following options:
* ``footer_key``, the ID of the master key for footer encryption/signing.
* ``column_keys``, which columns to encrypt with which key. Dictionary with
master key IDs as the keys, and column name lists as the values,
e.g. ``{key1: [col1, col2], key2: [col3]}`` .
e.g. ``{key1: [col1, col2], key2: [col3]}``. See notes on nested fields below.
* ``encryption_algorithm``, the Parquet encryption algorithm.
Can be ``AES_GCM_V1`` (default) or ``AES_GCM_CTR_V1``.
* ``plaintext_footer``, whether to write the file footer in plain text (otherwise it is encrypted).
Expand Down Expand Up @@ -739,6 +739,37 @@ An example encryption configuration:
},
)

.. note::
Encrypting columns that have nested fields (for instance struct, map, or even list data types)

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

(same suggestions as for C++)

require configuring column keys for the inner fields, not the column itself.
Configuring a column key for the column itself causes this error (here column name is ``col``):

.. code-block::

OSError: Encrypted column col not in file schema

An example encryption configuration for columns with nested fields, where
all of the columns will be encrypted with the key identified by ``column_key_id``:
Comment thread
EnricoMi marked this conversation as resolved.
Outdated

.. code-block:: python

schema = pa.schema([
("ListColumn", pa.list_(pa.int32())),
("MapColumn", pa.map_(pa.string(), pa.int32())),
("StructColumn", pa.struct([("f1", pa.int32()), ("f2", pa.string())])),
])

encryption_config = pq.EncryptionConfiguration(
footer_key="footer_key_name",
column_keys={
"column_key_id": [
"ListColumn.list.element",
"MapColumn.key_value.key", "MapColumn.key_value.value",
"StructColumn.f1", "StructColumn.f2"
],
},
)

Decryption configuration
~~~~~~~~~~~~~~~~~~~~~~~~

Expand Down