feat(encryption) [15/N] write encrypted parquet data files - #2701
Conversation
xanderbailey
left a comment
There was a problem hiding this comment.
Thanks carrying the flame on the encryption work. Have made a couple of comments to get us started.
58df8f8 to
0783948
Compare
0783948 to
b80ebbf
Compare
cc5fca7 to
74c54db
Compare
| type R = ParquetWriter; | ||
|
|
||
| async fn build(&self, output_file: OutputFile) -> Result<Self::R> { | ||
| let key_metadata = self |
There was a problem hiding this comment.
Confirmed that in rolling_writer as well, we build this again with new dek for each new parquet file
| /// When writing into an existing Iceberg table, prefer | ||
| /// [`Self::from_table_properties`], which derives `WriterProperties` from | ||
| /// the table's `write.parquet.*` properties. |
There was a problem hiding this comment.
curious to know if we should deprecate new and new_with_match_mode in favor of from_table_properties. Or update the comment to prefer the latter in all cases?
There was a problem hiding this comment.
I would add a comment in the doc here that encrypted writing is not supported with this constructor. I would honestly be in favour of removing this constructor since it's not used in this crate and nor should it be. I don't think we should do that in this PR but it would be a good follow-up IMO.
There was a problem hiding this comment.
also would like to know @blackmwk's recommendation here 🙏
xanderbailey
left a comment
There was a problem hiding this comment.
Few more comments and a test for the writer would be great. Maybe also something that shows datafusion writer works but that can be a follow up
| /// When writing into an existing Iceberg table, prefer | ||
| /// [`Self::from_table_properties`], which derives `WriterProperties` from | ||
| /// the table's `write.parquet.*` properties. |
There was a problem hiding this comment.
I would add a comment in the doc here that encrypted writing is not supported with this constructor. I would honestly be in favour of removing this constructor since it's not used in this crate and nor should it be. I don't think we should do that in this PR but it would be a good follow-up IMO.
5a0ea6f to
9832f50
Compare
9832f50 to
2ba0884
Compare
mbutrovich
left a comment
There was a problem hiding this comment.
First pass, thanks @aarushigupta132!
| table.metadata().current_schema(), | ||
| )?; | ||
|
|
||
| // The planner encrypted the file. |
There was a problem hiding this comment.
Not sure what this means
blackmwk
left a comment
There was a problem hiding this comment.
Thanks @aarushigupta132 , just finished first round of review.
| .build(); | ||
| Self::new_with_match_mode(props, schema, FieldMatchMode::Id) | ||
|
|
||
| let data_encryption_key_size = table_props |
There was a problem hiding this comment.
I prefer to make this part of TableProperties, e.g. add a data_entryption_key_size method
| } | ||
|
|
||
| #[tokio::test] | ||
| async fn test_iceberg_write_exec_encrypted() -> Result<()> { |
There was a problem hiding this comment.
This only tested write, not read. I perfer to use sqllogictest to set table properties, and test read and write encrypted parquet files.
There was a problem hiding this comment.
I believe a complete read-write test would require removing this check (as this would be a commit)
I would like to follow-up with more round trip tests, whenever we remove this gate.
Would you recommend doing all the mentioned in this pr or should i just remove this datafusion test here and add in a follow up pr?
There was a problem hiding this comment.
In this case you could crate an issue to track adding integration tests to for encryption. This test is too difficult to maintain, and I think the ParquetWriter ut is enough for this pr.
| /// | ||
| /// Returns `None` when the table is not configured for encryption. | ||
| /// Returns an error when `encryption.data-key-length` is not a valid AES key length. | ||
| pub(crate) fn data_encryption_key_size(props: &TableProperties) -> Result<Option<AesKeySize>> { |
There was a problem hiding this comment.
In fact, I mean make this part of TableProperties struct, which feels more natural.
|
|
||
| /// Generates a `StandardKeyMetadata` carrying a fresh random DEK of | ||
| /// `key_size` together with a fresh random AAD prefix. | ||
| pub fn generate(key_size: AesKeySize) -> Self { |
There was a problem hiding this comment.
Make this crate private. StandKeyMetadata should be generated by EncryptionManager
| } | ||
|
|
||
| #[tokio::test] | ||
| async fn test_iceberg_write_exec_encrypted() -> Result<()> { |
There was a problem hiding this comment.
In this case you could crate an issue to track adding integration tests to for encryption. This test is too difficult to maintain, and I think the ParquetWriter ut is enough for this pr.
6f56a91 to
57f6604
Compare
| })?; | ||
|
|
||
| Ok(writer_properties | ||
| .clone() |
There was a problem hiding this comment.
nit: Do we really need this clone if we already have into_builder?
833a201 to
bb90c29
Compare
ab6ce0b to
d76ad77
Compare
|
thank you @blackmwk for all the reviews! apologies i was a bit preoccupied last week but it is resolved now, happy to iterate with full speed |
1d8daea to
6015e0a
Compare
|
@blackmwk gentle ping here 🙏 |
blackmwk
left a comment
There was a problem hiding this comment.
Thanks @aarushigupta132 for this pr!
Which issue does this PR close?
Working towards #2034.
What changes are included in this PR?
Adds support for writing Iceberg data files with Parquet Modular Encryption:
ParquetWriterBuilder::with_encryption_manageropts a writer into encryption, generating a per-file DEK from the table'sEncryptionManagerand recording its key metadata on the resultingDataFile.Are these changes tested?
Yes, unit tests cover the encrypted write path for
ParquetWriterandRollingFileWriter.