-
Notifications
You must be signed in to change notification settings - Fork 4k
ARROW-10206: [C++][Python][FlightRPC] Allow disabling server validation #8325
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
3a66167
2af9074
7c62e14
90dce00
1b503e3
976f7f8
e02647d
136b03c
f1d44b9
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 |
|---|---|---|
|
|
@@ -30,10 +30,15 @@ | |
|
|
||
| #ifdef GRPCPP_PP_INCLUDE | ||
| #include <grpcpp/grpcpp.h> | ||
| #if defined(GRPC_NAMESPACE_FOR_TLS_CREDENTIALS_OPTIONS) | ||
| #include <grpcpp/security/tls_credentials_options.h> | ||
| #endif | ||
| #else | ||
| #include <grpc++/grpc++.h> | ||
| #endif | ||
|
|
||
| #include <grpc/grpc_security_constants.h> | ||
|
|
||
| #include "arrow/buffer.h" | ||
| #include "arrow/ipc/reader.h" | ||
| #include "arrow/ipc/writer.h" | ||
|
|
@@ -84,6 +89,9 @@ std::shared_ptr<FlightWriteSizeStatusDetail> FlightWriteSizeStatusDetail::Unwrap | |
| return std::dynamic_pointer_cast<FlightWriteSizeStatusDetail>(status.detail()); | ||
| } | ||
|
|
||
| FlightClientOptions::FlightClientOptions() | ||
| : write_size_limit_bytes(0), disable_server_verification(false) {} | ||
|
|
||
| FlightClientOptions FlightClientOptions::Defaults() { return FlightClientOptions(); } | ||
|
|
||
| struct ClientRpc { | ||
|
|
@@ -835,6 +843,31 @@ class GrpcMetadataReader : public FlightMetadataReader { | |
| std::shared_ptr<std::mutex> read_mutex_; | ||
| }; | ||
|
|
||
| namespace { | ||
| // Dummy self-signed certificate to be used because TlsCredentials | ||
| // requires root CA certs, even if you are skipping server | ||
| // verification. | ||
| #if defined(GRPC_NAMESPACE_FOR_TLS_CREDENTIALS_OPTIONS) | ||
| constexpr char BLANK_ROOT_PEM[] = | ||
| "-----BEGIN CERTIFICATE-----\n" | ||
| "MIICwzCCAaugAwIBAgIJAM12DOkcaqrhMA0GCSqGSIb3DQEBBQUAMBQxEjAQBgNV\n" | ||
| "BAMTCWxvY2FsaG9zdDAeFw0yMDEwMDcwODIyNDFaFw0zMDEwMDUwODIyNDFaMBQx\n" | ||
| "EjAQBgNVBAMTCWxvY2FsaG9zdDCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoC\n" | ||
| "ggEBALjJ8KPEpF0P4GjMPrJhjIBHUL0AX9E4oWdgJRCSFkPKKEWzQabTQBikMOhI\n" | ||
| "W4VvBMaHEBuECE5OEyrzDRiAO354I4F4JbBfxMOY8NIW0uWD6THWm2KkCzoZRIPW\n" | ||
| "yZL6dN+mK6cEH+YvbNuy5ZQGNjGG43tyiXdOCAc4AI9POeTtjdMpbbpR2VY4Ad/E\n" | ||
| "oTEiS3gNnN7WIAdgMhCJxjzvPwKszV3f7pwuTHzFMsuHLKr6JeaVUYfbi4DxxC8Z\n" | ||
| "k6PF6dLlLf3ngTSLBJyaXP1BhKMvz0TaMK3F0y2OGwHM9J8np2zWjTlNVEzffQZx\n" | ||
| "SWMOQManlJGs60xYx9KCPJMZZsMCAwEAAaMYMBYwFAYDVR0RBA0wC4IJbG9jYWxo\n" | ||
| "b3N0MA0GCSqGSIb3DQEBBQUAA4IBAQC0LrmbcNKgO+D50d/wOc+vhi9K04EZh8bg\n" | ||
| "WYAK1kLOT4eShbzqWGV/1EggY4muQ6ypSELCLuSsg88kVtFQIeRilA6bHFqQSj6t\n" | ||
| "sqgh2cWsMwyllCtmX6Maf3CLb2ZdoJlqUwdiBdrbIbuyeAZj3QweCtLKGSQzGDyI\n" | ||
| "KH7G8nC5d0IoRPiCMB6RnMMKsrhviuCdWbAFHop7Ff36JaOJ8iRa2sSf2OXE8j/5\n" | ||
| "obCXCUvYHf4Zw27JcM2AnnQI9VJLnYxis83TysC5s2Z7t0OYNS9kFmtXQbUNlmpS\n" | ||
| "doQ/Eu47vWX7S0TXeGziGtbAOKxbHE0BGGPDOAB/jGW/JVbeTiXY\n" | ||
| "-----END CERTIFICATE-----\n"; | ||
| #endif | ||
| } // namespace | ||
| class FlightClient::FlightClientImpl { | ||
| public: | ||
| Status Connect(const Location& location, const FlightClientOptions& options) { | ||
|
|
@@ -845,18 +878,49 @@ class FlightClient::FlightClientImpl { | |
| if (scheme == kSchemeGrpc || scheme == kSchemeGrpcTcp || scheme == kSchemeGrpcTls) { | ||
| grpc_uri << location.uri_->host() << ":" << location.uri_->port_text(); | ||
|
|
||
| if (scheme == "grpc+tls") { | ||
| grpc::SslCredentialsOptions ssl_options; | ||
| if (!options.tls_root_certs.empty()) { | ||
| ssl_options.pem_root_certs = options.tls_root_certs; | ||
| } | ||
| if (!options.cert_chain.empty()) { | ||
| ssl_options.pem_cert_chain = options.cert_chain; | ||
| } | ||
| if (!options.private_key.empty()) { | ||
| ssl_options.pem_private_key = options.private_key; | ||
| if (scheme == kSchemeGrpcTls) { | ||
| if (options.disable_server_verification) { | ||
| #if !defined(GRPC_NAMESPACE_FOR_TLS_CREDENTIALS_OPTIONS) | ||
| return Status::NotImplemented( | ||
| "Using encryption with server verification disabled is unsupported. " | ||
| "Please use a release of Arrow Flight built with gRPC 1.27 or higher."); | ||
| #else | ||
| namespace ge = GRPC_NAMESPACE_FOR_TLS_CREDENTIALS_OPTIONS; | ||
|
|
||
| // A callback to supply to TlsCredentialsOptions that accepts any server | ||
| // arguments. | ||
| struct NoOpTlsAuthorizationCheck | ||
| : public ge::TlsServerAuthorizationCheckInterface { | ||
| int Schedule(ge::TlsServerAuthorizationCheckArg* arg) override { | ||
| arg->set_success(1); | ||
| arg->set_status(GRPC_STATUS_OK); | ||
| return 0; | ||
| } | ||
| }; | ||
|
|
||
| noop_auth_check_ = std::make_shared<ge::TlsServerAuthorizationCheckConfig>( | ||
| std::make_shared<NoOpTlsAuthorizationCheck>()); | ||
| auto materials_config = std::make_shared<ge::TlsKeyMaterialsConfig>(); | ||
| materials_config->set_pem_root_certs(BLANK_ROOT_PEM); | ||
| ge::TlsCredentialsOptions tls_options( | ||
|
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. So gRPC has both
Member
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. Yes, but they aren't interchangeable. One works against TlsCredentials and one works against SslCredentials. TlsCredentials is a newer, currently experimental API that can do everything SslCredentials can do and more, such as do certificate reloading and supplying custom callbacks for cert verification. |
||
| GRPC_SSL_DONT_REQUEST_CLIENT_CERTIFICATE, | ||
| GRPC_TLS_SKIP_ALL_SERVER_VERIFICATION, materials_config, | ||
| std::shared_ptr<ge::TlsCredentialReloadConfig>(), noop_auth_check_); | ||
| creds = ge::TlsCredentials(tls_options); | ||
| #endif | ||
| } else { | ||
| grpc::SslCredentialsOptions ssl_options; | ||
| if (!options.tls_root_certs.empty()) { | ||
| ssl_options.pem_root_certs = options.tls_root_certs; | ||
| } | ||
| if (!options.cert_chain.empty()) { | ||
| ssl_options.pem_cert_chain = options.cert_chain; | ||
| } | ||
| if (!options.private_key.empty()) { | ||
| ssl_options.pem_private_key = options.private_key; | ||
| } | ||
| creds = grpc::SslCredentials(ssl_options); | ||
| } | ||
| creds = grpc::SslCredentials(ssl_options); | ||
| } else { | ||
| creds = grpc::InsecureChannelCredentials(); | ||
| } | ||
|
|
@@ -1101,6 +1165,15 @@ class FlightClient::FlightClientImpl { | |
| private: | ||
| std::unique_ptr<pb::FlightService::Stub> stub_; | ||
| std::shared_ptr<ClientAuthHandler> auth_handler_; | ||
| #if defined(GRPC_NAMESPACE_FOR_TLS_CREDENTIALS_OPTIONS) | ||
| // Scope the TlsServerAuthorizationCheckConfig to be at the class instance level, since | ||
| // it gets created during Connect() and needs to persist to DoAction() calls. gRPC does | ||
| // not correctly increase the reference count of this object: | ||
| // https://github.com/grpc/grpc/issues/22287 | ||
| std::shared_ptr< | ||
| GRPC_NAMESPACE_FOR_TLS_CREDENTIALS_OPTIONS::TlsServerAuthorizationCheckConfig> | ||
| noop_auth_check_; | ||
| #endif | ||
| int64_t write_size_limit_bytes_; | ||
| }; | ||
|
|
||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -90,6 +90,8 @@ class ARROW_FLIGHT_EXPORT FlightWriteSizeStatusDetail : public arrow::StatusDeta | |
|
|
||
| class ARROW_FLIGHT_EXPORT FlightClientOptions { | ||
| public: | ||
| FlightClientOptions(); | ||
|
Contributor
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. there shouldn't be two ways of getting the default values. If there needs to be another constructor that takes credentials, then use the static factory pattern.
Member
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. The default constructor was already there prior to this patch, it was just being implicitly defined instead of explicitly. I agree in principle that the Defaults() method should be used, however the constructor has already been public and I'm not sure it's worth breaking existing application code. We're not really consistent about this internally either.
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. Given there's already code using the default constructor, I think we can remove it separately: https://issues.apache.org/jira/browse/ARROW-10250 |
||
|
|
||
| /// \brief Root certificates to use for validating server | ||
| /// certificates. | ||
| std::string tls_root_certs; | ||
|
|
@@ -108,10 +110,14 @@ class ARROW_FLIGHT_EXPORT FlightClientOptions { | |
| /// positive. When enabled, FlightStreamWriter.Write* may yield a | ||
| /// IOError with error detail FlightWriteSizeStatusDetail. | ||
| int64_t write_size_limit_bytes; | ||
|
|
||
| /// \brief Generic connection options, passed to the underlying | ||
| /// transport; interpretation is implementation-dependent. | ||
| std::vector<std::pair<std::string, util::variant<int, std::string>>> generic_options; | ||
|
|
||
| /// \brief Use TLS without validating the server certificate. Use with caution. | ||
| bool disable_server_verification; | ||
|
|
||
| /// \brief Get default options. | ||
| static FlightClientOptions Defaults(); | ||
jduo marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
| }; | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,36 @@ | ||
| // 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. | ||
|
|
||
| // Dummy file for checking if TlsCredentialsOptions exists in | ||
| // the grpc_impl::experimental namespace. gRPC versions 1.27-1.31 | ||
| // put it here. This is for supporting disabling server | ||
| // validation when using TLS. | ||
|
|
||
| #include <grpc/grpc_security_constants.h> | ||
| #include <grpcpp/grpcpp.h> | ||
| #include <grpcpp/security/tls_credentials_options.h> | ||
|
|
||
| static grpc_tls_server_verification_option check( | ||
| const grpc_impl::experimental::TlsCredentialsOptions* options) { | ||
| grpc_tls_server_verification_option server_opt = options->server_verification_option(); | ||
| return server_opt; | ||
| } | ||
|
|
||
| int main(int argc, const char** argv) { | ||
| grpc_tls_server_verification_option opt = check(nullptr); | ||
| return 0; | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,36 @@ | ||
| // 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. | ||
|
|
||
| // Dummy file for checking if TlsCredentialsOptions exists in | ||
| // the grpc::experimental namespace. gRPC versions 1.32 and higher | ||
| // put it here. This is for supporting disabling server | ||
| // validation when using TLS. | ||
|
|
||
| #include <grpc/grpc_security_constants.h> | ||
| #include <grpcpp/grpcpp.h> | ||
| #include <grpcpp/security/tls_credentials_options.h> | ||
|
|
||
| static grpc_tls_server_verification_option check( | ||
| const grpc::experimental::TlsCredentialsOptions* options) { | ||
| grpc_tls_server_verification_option server_opt = options->server_verification_option(); | ||
| return server_opt; | ||
| } | ||
|
|
||
| int main(int argc, const char** argv) { | ||
| grpc_tls_server_verification_option opt = check(nullptr); | ||
| return 0; | ||
| } |
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 doesn't work with
-Werror=SOMETHING: #8419