-
Notifications
You must be signed in to change notification settings - Fork 4.2k
ARROW-9947: [Python] High-level Python API for Parquet encryption of files. #10450
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
31f8f76
d1df129
3773aaf
40d1f03
46f0bf2
7dbdc21
b203426
62f7c1a
9fe580c
b24b73f
146077a
7f06a2a
696162e
a44388a
9584f87
316302b
6b5d8ea
368890f
011c49d
5c3f68c
be154fd
4d1197e
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -57,6 +57,7 @@ echo "=== (${PYTHON_VERSION}) Building Arrow C++ libraries ===" | |
| : ${ARROW_MIMALLOC:=ON} | ||
| : ${ARROW_ORC:=ON} | ||
| : ${ARROW_PARQUET:=ON} | ||
| : ${PARQUET_REQUIRE_ENCRYPTION:=ON} | ||
| : ${ARROW_PLASMA:=ON} | ||
| : ${ARROW_S3:=ON} | ||
| : ${ARROW_TENSORFLOW:=ON} | ||
|
|
@@ -100,6 +101,7 @@ cmake \ | |
| -DARROW_ORC=${ARROW_ORC} \ | ||
| -DARROW_PACKAGE_KIND="python-wheel-manylinux${MANYLINUX_VERSION}" \ | ||
| -DARROW_PARQUET=${ARROW_PARQUET} \ | ||
| -DPARQUET_REQUIRE_ENCRYPTION=${PARQUET_REQUIRE_ENCRYPTION} \ | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Same question here: did you check that this works?
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I created a python-wheel-manylinux-2014 with PARQUET_REQUIRE_ENCRYPTION=ON and it worked fine. |
||
| -DARROW_PLASMA=${ARROW_PLASMA} \ | ||
| -DARROW_PYTHON=ON \ | ||
| -DARROW_RPATH_ORIGIN=ON \ | ||
|
|
@@ -143,6 +145,7 @@ export PYARROW_WITH_GANDIVA=${ARROW_GANDIVA} | |
| export PYARROW_WITH_HDFS=${ARROW_HDFS} | ||
| export PYARROW_WITH_ORC=${ARROW_ORC} | ||
| export PYARROW_WITH_PARQUET=${ARROW_PARQUET} | ||
| export PYARROW_WITH_PARQUET_ENCRYPTION=${PARQUET_REQUIRE_ENCRYPTION} | ||
| export PYARROW_WITH_PLASMA=${ARROW_PLASMA} | ||
| export PYARROW_WITH_S3=${ARROW_S3} | ||
| # PyArrow build configuration | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -36,6 +36,7 @@ set ARROW_GANDIVA=OFF | |
| set ARROW_HDFS=ON | ||
| set ARROW_ORC=OFF | ||
| set ARROW_PARQUET=ON | ||
| set PARQUET_REQUIRE_ENCRYPTION=ON | ||
| set ARROW_MIMALLOC=ON | ||
| set ARROW_S3=ON | ||
| set ARROW_TENSORFLOW=ON | ||
|
|
@@ -68,6 +69,7 @@ cmake ^ | |
| -DARROW_ORC=%ARROW_ORC% ^ | ||
| -DARROW_PACKAGE_KIND="python-wheel-windows" ^ | ||
| -DARROW_PARQUET=%ARROW_PARQUET% ^ | ||
| -DPARQUET_REQUIRE_ENCRYPTION=%PARQUET_REQUIRE_ENCRYPTION% ^ | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Same question...
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Checked the python-wheel-manylinux-2014. I expect the rest of the platforms to be run with CI/CD. Should I do anything special to trigger that? |
||
| -DARROW_PYTHON=ON ^ | ||
| -DARROW_S3=%ARROW_S3% ^ | ||
| -DARROW_TENSORFLOW=%ARROW_TENSORFLOW% ^ | ||
|
|
@@ -102,6 +104,7 @@ set PYARROW_WITH_GANDIVA=%ARROW_GANDIVA% | |
| set PYARROW_WITH_HDFS=%ARROW_HDFS% | ||
| set PYARROW_WITH_ORC=%ARROW_ORC% | ||
| set PYARROW_WITH_PARQUET=%ARROW_PARQUET% | ||
| set PYARROW_WITH_PARQUET_ENCRYPTION=%PARQUET_REQUIRE_ENCRYPTION% | ||
| set PYARROW_WITH_S3=%ARROW_S3% | ||
| set ARROW_HOME=C:\arrow-dist | ||
|
|
||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,98 @@ | ||
| // Licensed to the Apache Software Foundation (ASF) under one | ||
| // or more contributor license agreements. See the NOTICE file | ||
| // distributed with this work for additional information | ||
| // regarding copyright ownership. The ASF licenses this file | ||
| // to you under the Apache License, Version 2.0 (the | ||
| // "License"); you may not use this file except in compliance | ||
| // with the License. You may obtain a copy of the License at | ||
| // | ||
| // http://www.apache.org/licenses/LICENSE-2.0 | ||
| // | ||
| // Unless required by applicable law or agreed to in writing, | ||
| // software distributed under the License is distributed on an | ||
| // "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY | ||
| // KIND, either express or implied. See the License for the | ||
| // specific language governing permissions and limitations | ||
| // under the License. | ||
|
|
||
| #include "arrow/python/parquet_encryption.h" | ||
| #include "parquet/exception.h" | ||
|
|
||
| namespace arrow { | ||
| namespace py { | ||
| namespace parquet { | ||
| namespace encryption { | ||
|
|
||
| PyKmsClient::PyKmsClient(PyObject* handler, PyKmsClientVtable vtable) | ||
| : handler_(handler), vtable_(std::move(vtable)) { | ||
| Py_INCREF(handler); | ||
| } | ||
|
|
||
| PyKmsClient::~PyKmsClient() {} | ||
|
|
||
| std::string PyKmsClient::WrapKey(const std::string& key_bytes, | ||
| const std::string& master_key_identifier) { | ||
| std::string wrapped; | ||
| auto st = SafeCallIntoPython([&]() -> Status { | ||
| vtable_.wrap_key(handler_.obj(), key_bytes, master_key_identifier, &wrapped); | ||
| return CheckPyError(); | ||
| }); | ||
| if (!st.ok()) { | ||
| throw ::parquet::ParquetStatusException(st); | ||
| } | ||
| return wrapped; | ||
| } | ||
|
|
||
| std::string PyKmsClient::UnwrapKey(const std::string& wrapped_key, | ||
| const std::string& master_key_identifier) { | ||
| std::string unwrapped; | ||
| auto st = SafeCallIntoPython([&]() -> Status { | ||
| vtable_.unwrap_key(handler_.obj(), wrapped_key, master_key_identifier, &unwrapped); | ||
| return CheckPyError(); | ||
| }); | ||
| if (!st.ok()) { | ||
| throw ::parquet::ParquetStatusException(st); | ||
| } | ||
| return unwrapped; | ||
| } | ||
|
|
||
| PyKmsClientFactory::PyKmsClientFactory(PyObject* handler, PyKmsClientFactoryVtable vtable) | ||
| : handler_(handler), vtable_(std::move(vtable)) { | ||
| Py_INCREF(handler); | ||
| } | ||
|
|
||
| PyKmsClientFactory::~PyKmsClientFactory() {} | ||
|
|
||
| std::shared_ptr<::parquet::encryption::KmsClient> PyKmsClientFactory::CreateKmsClient( | ||
| const ::parquet::encryption::KmsConnectionConfig& kms_connection_config) { | ||
| std::shared_ptr<::parquet::encryption::KmsClient> kms_client; | ||
| auto st = SafeCallIntoPython([&]() -> Status { | ||
| vtable_.create_kms_client(handler_.obj(), kms_connection_config, &kms_client); | ||
| return CheckPyError(); | ||
| }); | ||
| if (!st.ok()) { | ||
| throw ::parquet::ParquetStatusException(st); | ||
| } | ||
| return kms_client; | ||
| } | ||
|
|
||
| arrow::Result<std::shared_ptr<::parquet::FileEncryptionProperties>> | ||
| PyCryptoFactory::SafeGetFileEncryptionProperties( | ||
| const ::parquet::encryption::KmsConnectionConfig& kms_connection_config, | ||
| const ::parquet::encryption::EncryptionConfiguration& encryption_config) { | ||
| PARQUET_CATCH_AND_RETURN( | ||
| this->GetFileEncryptionProperties(kms_connection_config, encryption_config)); | ||
| } | ||
|
|
||
| arrow::Result<std::shared_ptr<::parquet::FileDecryptionProperties>> | ||
| PyCryptoFactory::SafeGetFileDecryptionProperties( | ||
| const ::parquet::encryption::KmsConnectionConfig& kms_connection_config, | ||
| const ::parquet::encryption::DecryptionConfiguration& decryption_config) { | ||
| PARQUET_CATCH_AND_RETURN( | ||
| this->GetFileDecryptionProperties(kms_connection_config, decryption_config)); | ||
| } | ||
|
|
||
| } // namespace encryption | ||
| } // namespace parquet | ||
| } // namespace py | ||
| } // namespace arrow |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,109 @@ | ||
| // Licensed to the Apache Software Foundation (ASF) under one | ||
| // or more contributor license agreements. See the NOTICE file | ||
| // distributed with this work for additional information | ||
| // regarding copyright ownership. The ASF licenses this file | ||
| // to you under the Apache License, Version 2.0 (the | ||
| // "License"); you may not use this file except in compliance | ||
| // with the License. You may obtain a copy of the License at | ||
| // | ||
| // http://www.apache.org/licenses/LICENSE-2.0 | ||
| // | ||
| // Unless required by applicable law or agreed to in writing, | ||
| // software distributed under the License is distributed on an | ||
| // "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY | ||
| // KIND, either express or implied. See the License for the | ||
| // specific language governing permissions and limitations | ||
| // under the License. | ||
|
|
||
| #pragma once | ||
|
|
||
| #include <string> | ||
|
|
||
| #include "arrow/python/common.h" | ||
| #include "arrow/python/visibility.h" | ||
| #include "arrow/util/macros.h" | ||
| #include "parquet/encryption/crypto_factory.h" | ||
| #include "parquet/encryption/kms_client.h" | ||
| #include "parquet/encryption/kms_client_factory.h" | ||
|
|
||
| namespace arrow { | ||
| namespace py { | ||
| namespace parquet { | ||
| namespace encryption { | ||
|
|
||
| /// \brief A table of function pointers for calling from C++ into | ||
| /// Python. | ||
| class ARROW_PYTHON_EXPORT PyKmsClientVtable { | ||
| public: | ||
| std::function<void(PyObject*, const std::string& key_bytes, | ||
| const std::string& master_key_identifier, std::string* out)> | ||
| wrap_key; | ||
| std::function<void(PyObject*, const std::string& wrapped_key, | ||
| const std::string& master_key_identifier, std::string* out)> | ||
| unwrap_key; | ||
| }; | ||
|
|
||
| /// \brief A helper for KmsClient implementation in Python. | ||
| class ARROW_PYTHON_EXPORT PyKmsClient : public ::parquet::encryption::KmsClient { | ||
| public: | ||
| PyKmsClient(PyObject* handler, PyKmsClientVtable vtable); | ||
| ~PyKmsClient() override; | ||
|
|
||
| std::string WrapKey(const std::string& key_bytes, | ||
| const std::string& master_key_identifier) override; | ||
|
|
||
| std::string UnwrapKey(const std::string& wrapped_key, | ||
| const std::string& master_key_identifier) override; | ||
|
|
||
| private: | ||
| OwnedRefNoGIL handler_; | ||
| PyKmsClientVtable vtable_; | ||
| }; | ||
|
|
||
| /// \brief A table of function pointers for calling from C++ into | ||
| /// Python. | ||
| class ARROW_PYTHON_EXPORT PyKmsClientFactoryVtable { | ||
| public: | ||
| std::function<void( | ||
| PyObject*, const ::parquet::encryption::KmsConnectionConfig& kms_connection_config, | ||
| std::shared_ptr<::parquet::encryption::KmsClient>* out)> | ||
| create_kms_client; | ||
| }; | ||
|
|
||
| /// \brief A helper for KmsClientFactory implementation in Python. | ||
| class ARROW_PYTHON_EXPORT PyKmsClientFactory | ||
| : public ::parquet::encryption::KmsClientFactory { | ||
| public: | ||
| PyKmsClientFactory(PyObject* handler, PyKmsClientFactoryVtable vtable); | ||
| ~PyKmsClientFactory() override; | ||
|
|
||
| std::shared_ptr<::parquet::encryption::KmsClient> CreateKmsClient( | ||
| const ::parquet::encryption::KmsConnectionConfig& kms_connection_config) override; | ||
|
|
||
| private: | ||
| OwnedRefNoGIL handler_; | ||
| PyKmsClientFactoryVtable vtable_; | ||
| }; | ||
|
|
||
| /// \brief A CryptoFactory that returns Results instead of throwing exceptions. | ||
| class ARROW_PYTHON_EXPORT PyCryptoFactory : public ::parquet::encryption::CryptoFactory { | ||
| public: | ||
| arrow::Result<std::shared_ptr<::parquet::FileEncryptionProperties>> | ||
| SafeGetFileEncryptionProperties( | ||
| const ::parquet::encryption::KmsConnectionConfig& kms_connection_config, | ||
| const ::parquet::encryption::EncryptionConfiguration& encryption_config); | ||
|
|
||
| /// The returned FileDecryptionProperties object will use the cache inside this | ||
| /// CryptoFactory object, so please keep this | ||
| /// CryptoFactory object alive along with the returned | ||
| /// FileDecryptionProperties object. | ||
| arrow::Result<std::shared_ptr<::parquet::FileDecryptionProperties>> | ||
| SafeGetFileDecryptionProperties( | ||
| const ::parquet::encryption::KmsConnectionConfig& kms_connection_config, | ||
| const ::parquet::encryption::DecryptionConfiguration& decryption_config); | ||
| }; | ||
|
|
||
| } // namespace encryption | ||
| } // namespace parquet | ||
| } // namespace py | ||
| } // namespace arrow |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Are you just adding this blindly or did you check that building the MacOS wheels still works with this option?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This can also be checked by triggering crossbow to run the wheel tasks on the PR here?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Checked the python-wheel-manylinux-2014. I expect the rest to be run with CI/CD. Should I do anything special to trigger that?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes, for building and testing the wheels you need to trigger those builds manually with a comment. Will do that now.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks, @jorisvandenbossche !
It seems like there is a general problem with the Mac OS build:
CMake Error: The source directory "/Users/runner/work/crossbow/crossbow/build/build" does not appear to contain CMakeLists.txt.