This is an automated email from the ASF dual-hosted git repository.

abukor pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/kudu.git

commit 592ba3c5f7abfba43ee5ef1b339a4743006b6e3b
Author: Attila Bukor <[email protected]>
AuthorDate: Tue Jul 27 15:00:26 2021 +0200

    KUDU-1921 Add ability to require auth/encryption to C++ client
    
    Kudu servers support requiring authentication and encryption to be
    enabled, and clients prefer connecting in a secure way, but if a server
    doesn't support authentication and/or encryption, the client will
    silently connect insecurely, which can lead to a downgrade attack.
    
    With this patch, clients can require authentication and encryption to be
    set using the client API, where if such an attack is attempted, the
    client will fail to connect to the cluster.
    
    Change-Id: Ia3e800eb7c4e2f8787f0adf1f040d47358d29320
    Reviewed-on: http://gerrit.cloudera.org:8080/17731
    Tested-by: Kudu Jenkins
    Reviewed-by: Alexey Serbin <[email protected]>
---
 src/kudu/client/client.cc                    | 19 +++++++
 src/kudu/client/client.h                     | 42 ++++++++++++++++
 src/kudu/client/client_builder-internal.cc   | 11 ++--
 src/kudu/client/client_builder-internal.h    |  2 +
 src/kudu/integration-tests/security-itest.cc | 75 +++++++++++++++++++++++++++-
 src/kudu/rpc/client_negotiation.cc           |  4 +-
 src/kudu/rpc/client_negotiation.h            |  2 +
 src/kudu/rpc/messenger.cc                    |  2 +
 src/kudu/rpc/messenger.h                     |  8 +++
 src/kudu/rpc/negotiation-test.cc             | 20 +++++---
 src/kudu/rpc/negotiation.cc                  | 10 +++-
 src/kudu/rpc/negotiation.h                   |  1 +
 src/kudu/rpc/reactor.cc                      |  7 ++-
 src/kudu/rpc/server_negotiation.cc           |  6 ++-
 src/kudu/rpc/server_negotiation.h            |  2 +
 15 files changed, 192 insertions(+), 19 deletions(-)

diff --git a/src/kudu/client/client.cc b/src/kudu/client/client.cc
index 8c57302..d05aaa8 100644
--- a/src/kudu/client/client.cc
+++ b/src/kudu/client/client.cc
@@ -325,6 +325,16 @@ KuduClientBuilder& 
KuduClientBuilder::sasl_protocol_name(const string& sasl_prot
   return *this;
 }
 
+KuduClientBuilder& KuduClientBuilder::encryption_policy(EncryptionPolicy 
encryption_policy) {
+  data_->encryption_policy_ = encryption_policy;
+  return *this;
+}
+
+KuduClientBuilder& KuduClientBuilder::require_authentication(bool 
require_authentication) {
+  data_->require_authentication_ = require_authentication;
+  return *this;
+}
+
 namespace {
 Status ImportAuthnCreds(const string& authn_creds,
                         Messenger* messenger,
@@ -371,6 +381,15 @@ Status KuduClientBuilder::Build(shared_ptr<KuduClient>* 
client) {
   if (!data_->sasl_protocol_name_.empty()) {
     builder.set_sasl_proto_name(data_->sasl_protocol_name_);
   }
+  if (data_->require_authentication_) {
+    builder.set_rpc_authentication("required");
+  }
+  if (data_->encryption_policy_ != OPTIONAL) {
+    builder.set_rpc_encryption("required");
+    if (data_->encryption_policy_ == REQUIRED) {
+      builder.set_rpc_loopback_encryption(true);
+    }
+  }
   std::shared_ptr<Messenger> messenger;
   RETURN_NOT_OK(builder.Build(&messenger));
   UserCredentials user_credentials;
diff --git a/src/kudu/client/client.h b/src/kudu/client/client.h
index 3ff9141..853d0a1 100644
--- a/src/kudu/client/client.h
+++ b/src/kudu/client/client.h
@@ -230,6 +230,18 @@ class KUDU_EXPORT KuduClientBuilder {
   KuduClientBuilder();
   ~KuduClientBuilder();
 
+  /// Policy for on-the-wire encryption
+  enum EncryptionPolicy {
+    OPTIONAL,        ///< Optional, it uses encrypted connection if the server 
supports
+                     ///< it, but it can connect to insecure servers too.
+
+    REQUIRED_REMOTE, ///< Only connects to remote servers that support 
encryption, fails
+                     ///< otherwise. It can connect to insecure servers only 
locally.
+
+    REQUIRED         ///< Only connects to any server, including on the 
loopback interface,
+                     ///< that support encryption, fails otherwise.
+  };
+
   /// Clear the set of master addresses.
   ///
   /// @return Reference to the updated object.
@@ -319,6 +331,36 @@ class KUDU_EXPORT KuduClientBuilder {
   /// @return Reference to the updated object.
   KuduClientBuilder& sasl_protocol_name(const std::string& sasl_protocol_name);
 
+  /// Require authentication for the connection to a remote server.
+  ///
+  /// If it's set to true, the client will require mutual authentication 
between
+  /// the server and the client. If the server doesn't support authentication,
+  /// or it's disabled, the client will fail to connect.
+  ///
+  /// @param [in] require_authentication
+  ///   Whether to require authentication.
+  /// @return Reference to the updated object.
+  KuduClientBuilder& require_authentication(bool require_authentication);
+
+  /// Require encryption for the connection to a remote server.
+  ///
+  /// If it's set to REQUIRED_REMOTE or REQUIRED, the client will
+  /// require encrypting the traffic between the server and the client.
+  /// If the server doesn't support encryption, or if it's disabled, the
+  /// client will fail to connect.
+  ///
+  /// Loopback connections are encrypted only if 'encryption_policy' is
+  /// set to REQUIRED, or if it's required by the server.
+  ///
+  /// The default value is OPTIONAL, which allows connecting to servers without
+  /// encryption as well, but it will still attempt to use it if the server
+  /// supports it.
+  ///
+  /// @param [in] encryption_policy
+  ///   Which encryption policy to use.
+  /// @return Reference to the updated object.
+  KuduClientBuilder& encryption_policy(EncryptionPolicy encryption_policy);
+
   /// Create a client object.
   ///
   /// @note KuduClients objects are shared amongst multiple threads and,
diff --git a/src/kudu/client/client_builder-internal.cc 
b/src/kudu/client/client_builder-internal.cc
index 7d0d496..b3c027c 100644
--- a/src/kudu/client/client_builder-internal.cc
+++ b/src/kudu/client/client_builder-internal.cc
@@ -25,11 +25,12 @@ namespace client {
 KuduClientBuilder::Data::Data()
     : default_admin_operation_timeout_(MonoDelta::FromSeconds(30)),
       default_rpc_timeout_(MonoDelta::FromSeconds(10)),
-      replica_visibility_(internal::ReplicaController::Visibility::VOTERS) {
-}
+      replica_visibility_(internal::ReplicaController::Visibility::VOTERS),
+      require_authentication_(false),
+      encryption_policy_(EncryptionPolicy::OPTIONAL) {
+  }
 
-KuduClientBuilder::Data::~Data() {
-}
+  KuduClientBuilder::Data::~Data() {}
 
-} // namespace client
+}  // namespace client
 } // namespace kudu
diff --git a/src/kudu/client/client_builder-internal.h 
b/src/kudu/client/client_builder-internal.h
index f097b3e..8da30b4 100644
--- a/src/kudu/client/client_builder-internal.h
+++ b/src/kudu/client/client_builder-internal.h
@@ -43,6 +43,8 @@ class KuduClientBuilder::Data {
   internal::ReplicaController::Visibility replica_visibility_;
   boost::optional<int> num_reactors_;
   std::string sasl_protocol_name_;
+  bool require_authentication_;
+  EncryptionPolicy encryption_policy_;
 
   DISALLOW_COPY_AND_ASSIGN(Data);
 };
diff --git a/src/kudu/integration-tests/security-itest.cc 
b/src/kudu/integration-tests/security-itest.cc
index c2d6bd2..60646aa 100644
--- a/src/kudu/integration-tests/security-itest.cc
+++ b/src/kudu/integration-tests/security-itest.cc
@@ -25,6 +25,7 @@
 #include <memory>
 #include <ostream>
 #include <string>
+#include <tuple>
 #include <vector>
 
 #include <gflags/gflags_declare.h>
@@ -87,7 +88,9 @@ using kudu::client::sp::shared_ptr;
 using kudu::cluster::ExternalMiniCluster;
 using kudu::cluster::ExternalMiniClusterOptions;
 using kudu::rpc::Messenger;
+using std::get;
 using std::string;
+using std::tuple;
 using std::unique_ptr;
 using std::vector;
 using strings::Substitute;
@@ -639,6 +642,76 @@ TEST_F(SecurityITest, TestMismatchingPrincipals) {
   ASSERT_TRUE(s.IsTimedOut());
 }
 
+TEST_F(SecurityITest, TestRequireAuthenticationInsecureCluster) {
+  cluster_opts_.enable_kerberos = false;
+  ASSERT_OK(StartCluster());
+
+  shared_ptr<KuduClient> client;
+  KuduClientBuilder b;
+  b.require_authentication(true);
+  Status s = cluster_->CreateClient(&b, &client);
+  ASSERT_TRUE(s.IsNotAuthorized());
+  ASSERT_STR_CONTAINS(s.ToString(),
+                      "client requires authentication, but server does not 
have Kerberos enabled");
+}
+
+TEST_F(SecurityITest, TestRequireEncryptionInsecureCluster) {
+  cluster_opts_.enable_kerberos = false;
+  cluster_opts_.extra_master_flags.emplace_back("--rpc_encryption=disabled");
+  cluster_opts_.extra_tserver_flags.emplace_back("--rpc_encryption=disabled");
+  
cluster_opts_.extra_master_flags.emplace_back("--rpc_authentication=disabled");
+  
cluster_opts_.extra_tserver_flags.emplace_back("--rpc_authentication=disabled");
+  ASSERT_OK(StartCluster());
+
+  shared_ptr<KuduClient> client;
+  KuduClientBuilder b;
+  b.encryption_policy(client::KuduClientBuilder::REQUIRED);
+  Status s = cluster_->CreateClient(&b, &client);
+  ASSERT_TRUE(s.IsNotAuthorized());
+  ASSERT_STR_CONTAINS(s.ToString(), "server does not support required TLS 
encryption");
+}
+
+TEST_F(SecurityITest, TestRequireAuthenticationSecureCluster) {
+  ASSERT_OK(StartCluster());
+
+  shared_ptr<KuduClient> client;
+  KuduClientBuilder b;
+  b.require_authentication(true);
+  ASSERT_OK(cluster_->CreateClient(&b, &client));
+  SmokeTestCluster(client, /* transactional */ false);
+}
+
+class EncryptionPolicyTest :
+    public SecurityITest,
+    public ::testing::WithParamInterface<tuple<
+        KuduClientBuilder::EncryptionPolicy, bool>> {
+};
+
+INSTANTIATE_TEST_SUITE_P(,
+    EncryptionPolicyTest,
+    ::testing::Combine(
+        ::testing::Values(
+            KuduClientBuilder::EncryptionPolicy::OPTIONAL,
+            KuduClientBuilder::EncryptionPolicy::REQUIRED,
+            KuduClientBuilder::EncryptionPolicy::REQUIRED_REMOTE),
+        ::testing::Values(true, false)));
+
+TEST_P(EncryptionPolicyTest, TestEncryptionPolicy) {
+  const auto& params = GetParam();
+  if (!get<1>(params)) {
+    cluster_opts_.enable_kerberos = false;
+    
cluster_opts_.extra_master_flags.emplace_back("--rpc_authentication=disabled");
+    
cluster_opts_.extra_tserver_flags.emplace_back("--rpc_authentication=disabled");
+  }
+  ASSERT_OK(StartCluster());
+
+  shared_ptr<KuduClient> client;
+  KuduClientBuilder b;
+  b.encryption_policy(get<0>(params));
+  ASSERT_OK(cluster_->CreateClient(&b, &client));
+  SmokeTestCluster(client, /* transactional */ false);
+}
+
 Status AssignIPToClient(bool external) {
   // If the test does not require an external IP address
   // assign loopback IP to FLAGS_local_ip_for_outbound_sockets.
@@ -924,4 +997,4 @@ TEST_P(ConnectToFollowerMasterTest, 
AuthnTokenVerifierHaveKeys) {
   }
 }
 
-} // namespace kudu
+}  // namespace kudu
diff --git a/src/kudu/rpc/client_negotiation.cc 
b/src/kudu/rpc/client_negotiation.cc
index 7c3992b..9557ff3 100644
--- a/src/kudu/rpc/client_negotiation.cc
+++ b/src/kudu/rpc/client_negotiation.cc
@@ -119,6 +119,7 @@ ClientNegotiation::ClientNegotiation(unique_ptr<Socket> 
socket,
                                      const security::TlsContext* tls_context,
                                      boost::optional<security::SignedTokenPB> 
authn_token,
                                      RpcEncryption encryption,
+                                     bool encrypt_loopback,
                                      std::string sasl_proto_name)
     : socket_(std::move(socket)),
       helper_(SaslHelper::CLIENT),
@@ -126,6 +127,7 @@ ClientNegotiation::ClientNegotiation(unique_ptr<Socket> 
socket,
       tls_handshake_(security::TlsHandshakeType::CLIENT),
       encryption_(encryption),
       tls_negotiated_(false),
+      encrypt_loopback_(encrypt_loopback),
       authn_token_(std::move(authn_token)),
       psecret_(nullptr, std::free),
       negotiated_authn_(AuthenticationType::INVALID),
@@ -324,7 +326,7 @@ Status ClientNegotiation::SendNegotiate() {
     client_features_.insert(TLS);
     // If the remote peer is local, then we allow using TLS for authentication
     // without encryption or integrity.
-    if (socket_->IsLoopbackConnection() && 
!FLAGS_rpc_encrypt_loopback_connections) {
+    if (socket_->IsLoopbackConnection() && !encrypt_loopback_) {
       client_features_.insert(TLS_AUTHENTICATION_ONLY);
     }
   }
diff --git a/src/kudu/rpc/client_negotiation.h 
b/src/kudu/rpc/client_negotiation.h
index e9f0c7d..4d3e6d5 100644
--- a/src/kudu/rpc/client_negotiation.h
+++ b/src/kudu/rpc/client_negotiation.h
@@ -66,6 +66,7 @@ class ClientNegotiation {
                     const security::TlsContext* tls_context,
                     boost::optional<security::SignedTokenPB> authn_token,
                     security::RpcEncryption encryption,
+                    bool encrypt_loopback,
                     std::string sasl_proto_name);
 
   // Enable PLAIN authentication.
@@ -229,6 +230,7 @@ class ClientNegotiation {
   security::TlsHandshake tls_handshake_;
   const security::RpcEncryption encryption_;
   bool tls_negotiated_;
+  bool encrypt_loopback_;
 
   // TSK state.
   boost::optional<security::SignedTokenPB> authn_token_;
diff --git a/src/kudu/rpc/messenger.cc b/src/kudu/rpc/messenger.cc
index 87a7bae..a517a6f 100644
--- a/src/kudu/rpc/messenger.cc
+++ b/src/kudu/rpc/messenger.cc
@@ -76,6 +76,7 @@ MessengerBuilder::MessengerBuilder(string name)
       sasl_proto_name_("kudu"),
       rpc_authentication_("optional"),
       rpc_encryption_("optional"),
+      rpc_loopback_encryption_(false),
       rpc_tls_ciphers_(kudu::security::SecurityDefaults::kDefaultTlsCiphers),
       
rpc_tls_ciphersuites_(kudu::security::SecurityDefaults::kDefaultTlsCipherSuites),
       
rpc_tls_min_protocol_(kudu::security::SecurityDefaults::kDefaultTlsMinVersion),
@@ -98,6 +99,7 @@ Status MessengerBuilder::Build(shared_ptr<Messenger>* msgr) {
   RETURN_NOT_OK(ParseTriState("--rpc_encryption",
                               rpc_encryption_,
                               &new_msgr->encryption_));
+  new_msgr->loopback_encryption_ = rpc_loopback_encryption_;
   RETURN_NOT_OK(new_msgr->Init());
   if (new_msgr->encryption_ != RpcEncryption::DISABLED && enable_inbound_tls_) 
{
     auto* tls_context = new_msgr->mutable_tls_context();
diff --git a/src/kudu/rpc/messenger.h b/src/kudu/rpc/messenger.h
index 983d959..4c99f6f 100644
--- a/src/kudu/rpc/messenger.h
+++ b/src/kudu/rpc/messenger.h
@@ -160,6 +160,11 @@ class MessengerBuilder {
     return *this;
   }
 
+  MessengerBuilder& set_rpc_loopback_encryption(bool rpc_loopback_encryption) {
+    rpc_loopback_encryption_ = rpc_loopback_encryption;
+    return *this;
+  }
+
   // Set TLSv1.2 and earlier cipher suite preferences to use for TLS-secured 
RPC
   // connections. Uses the OpenSSL cipher preference list format. Under the
   // hood, SSL_CTX_set_cipher_list() is eventually being called with
@@ -261,6 +266,7 @@ class MessengerBuilder {
   std::string sasl_proto_name_;
   std::string rpc_authentication_;
   std::string rpc_encryption_;
+  bool rpc_loopback_encryption_;
   std::string rpc_tls_ciphers_;       // pre-TLSv1.3 cipher suites
   std::string rpc_tls_ciphersuites_;  // TLSv1.3-related cipher suites
   std::string rpc_tls_min_protocol_;
@@ -381,6 +387,7 @@ class Messenger {
 
   security::RpcAuthentication authentication() const { return authentication_; 
}
   security::RpcEncryption encryption() const { return encryption_; }
+  bool loopback_encryption() const { return loopback_encryption_; }
 
   ThreadPool* negotiation_pool(Connection::Direction dir);
 
@@ -473,6 +480,7 @@ class Messenger {
   // reused by different clients.
   security::RpcAuthentication authentication_;
   security::RpcEncryption encryption_;
+  bool loopback_encryption_;
 
   // Pools which are listening on behalf of this messenger.
   // Note that the user may have called Shutdown() on one of these
diff --git a/src/kudu/rpc/negotiation-test.cc b/src/kudu/rpc/negotiation-test.cc
index 3983ff0..e0a8321 100644
--- a/src/kudu/rpc/negotiation-test.cc
+++ b/src/kudu/rpc/negotiation-test.cc
@@ -252,11 +252,13 @@ TEST_P(TestNegotiation, TestNegotiation) {
                                        &client_tls_context,
                                        authn_token,
                                        desc.client.encryption,
+                                       desc.rpc_encrypt_loopback,
                                        "kudu");
   ServerNegotiation server_negotiation(std::move(server_socket),
                                        &server_tls_context,
                                        &token_verifier,
                                        desc.server.encryption,
+                                       desc.rpc_encrypt_loopback,
                                        "kudu");
 
   // Set client and server SASL mechanisms.
@@ -1034,7 +1036,8 @@ static void RunGSSAPINegotiationServer(unique_ptr<Socket> 
socket,
   CHECK_OK(tls_context.Init());
   TokenVerifier token_verifier;
   ServerNegotiation server_negotiation(std::move(socket), &tls_context,
-                                       &token_verifier, 
RpcEncryption::OPTIONAL, "kudu");
+                                       &token_verifier, 
RpcEncryption::OPTIONAL,
+                                       /* encrypt_loopback */ false, "kudu");
   server_negotiation.set_server_fqdn("127.0.0.1");
   CHECK_OK(server_negotiation.EnableGSSAPI());
   post_check(server_negotiation.Negotiate());
@@ -1047,7 +1050,8 @@ static void RunGSSAPINegotiationClient(unique_ptr<Socket> 
conn,
   TlsContext tls_context;
   CHECK_OK(tls_context.Init());
   ClientNegotiation client_negotiation(std::move(conn), &tls_context,
-                                       boost::none, RpcEncryption::OPTIONAL, 
"kudu");
+                                       boost::none, RpcEncryption::OPTIONAL,
+                                       /* encrypt_loopback */ false, "kudu");
   client_negotiation.set_server_fqdn("127.0.0.1");
   CHECK_OK(client_negotiation.EnableGSSAPI());
   post_check(client_negotiation.Negotiate());
@@ -1210,7 +1214,8 @@ static void RunTimeoutExpectingServer(unique_ptr<Socket> 
socket) {
   CHECK_OK(tls_context.Init());
   TokenVerifier token_verifier;
   ServerNegotiation server_negotiation(std::move(socket), &tls_context,
-                                       &token_verifier, 
RpcEncryption::OPTIONAL, "kudu");
+                                       &token_verifier, 
RpcEncryption::OPTIONAL,
+                                       /* encrypt_loopback */ false, "kudu");
   CHECK_OK(server_negotiation.EnablePlain());
   Status s = server_negotiation.Negotiate();
   ASSERT_TRUE(s.IsNetworkError()) << "Expected client to time out and close 
the connection. Got: "
@@ -1221,7 +1226,8 @@ static void 
RunTimeoutNegotiationClient(unique_ptr<Socket> sock) {
   TlsContext tls_context;
   CHECK_OK(tls_context.Init());
   ClientNegotiation client_negotiation(std::move(sock), &tls_context,
-                                       boost::none, RpcEncryption::OPTIONAL, 
"kudu");
+                                       boost::none, RpcEncryption::OPTIONAL,
+                                       /* encrypt_loopback */ false, "kudu");
   CHECK_OK(client_negotiation.EnablePlain("test", "test"));
   MonoTime deadline = MonoTime::Now() - MonoDelta::FromMilliseconds(100L);
   client_negotiation.set_deadline(deadline);
@@ -1242,7 +1248,8 @@ static void 
RunTimeoutNegotiationServer(unique_ptr<Socket> socket) {
   CHECK_OK(tls_context.Init());
   TokenVerifier token_verifier;
   ServerNegotiation server_negotiation(std::move(socket), &tls_context,
-                                       &token_verifier, 
RpcEncryption::OPTIONAL, "kudu");
+                                       &token_verifier, 
RpcEncryption::OPTIONAL,
+                                       /* encrypt_loopback */ false, "kudu");
   CHECK_OK(server_negotiation.EnablePlain());
   MonoTime deadline = MonoTime::Now() - MonoDelta::FromMilliseconds(100L);
   server_negotiation.set_deadline(deadline);
@@ -1255,7 +1262,8 @@ static void RunTimeoutExpectingClient(unique_ptr<Socket> 
socket) {
   TlsContext tls_context;
   CHECK_OK(tls_context.Init());
   ClientNegotiation client_negotiation(std::move(socket), &tls_context,
-                                       boost::none, RpcEncryption::OPTIONAL, 
"kudu");
+                                       boost::none, RpcEncryption::OPTIONAL,
+                                       /* encrypt_loopback */ false, "kudu");
   CHECK_OK(client_negotiation.EnablePlain("test", "test"));
   Status s = client_negotiation.Negotiate();
   ASSERT_TRUE(s.IsNetworkError()) << "Expected server to time out and close 
the connection. Got: "
diff --git a/src/kudu/rpc/negotiation.cc b/src/kudu/rpc/negotiation.cc
index 71c23f7..e429b4c 100644
--- a/src/kudu/rpc/negotiation.cc
+++ b/src/kudu/rpc/negotiation.cc
@@ -166,6 +166,7 @@ static Status DisableSocketTimeouts(Socket* socket) {
 static Status DoClientNegotiation(Connection* conn,
                                   RpcAuthentication authentication,
                                   RpcEncryption encryption,
+                                  bool encrypt_loopback,
                                   MonoTime deadline,
                                   unique_ptr<ErrorStatusPB>* rpc_error) {
   const auto* messenger = conn->reactor_thread()->reactor()->messenger();
@@ -176,6 +177,7 @@ static Status DoClientNegotiation(Connection* conn,
                                        &messenger->tls_context(),
                                        authn_token,
                                        encryption,
+                                       encrypt_loopback,
                                        messenger->sasl_proto_name());
 
   
client_negotiation.set_server_fqdn(conn->outbound_connection_id().hostname());
@@ -236,6 +238,7 @@ static Status DoClientNegotiation(Connection* conn,
 static Status DoServerNegotiation(Connection* conn,
                                   RpcAuthentication authentication,
                                   RpcEncryption encryption,
+                                  bool encrypt_loopback,
                                   const MonoTime& deadline) {
   const auto* messenger = conn->reactor_thread()->reactor()->messenger();
   if (authentication == RpcAuthentication::REQUIRED &&
@@ -257,6 +260,7 @@ static Status DoServerNegotiation(Connection* conn,
                                        &messenger->tls_context(),
                                        &messenger->token_verifier(),
                                        encryption,
+                                       encrypt_loopback,
                                        messenger->sasl_proto_name());
 
   if (authentication != RpcAuthentication::DISABLED && 
!messenger->keytab_file().empty()) {
@@ -286,13 +290,15 @@ static Status DoServerNegotiation(Connection* conn,
 void Negotiation::RunNegotiation(const scoped_refptr<Connection>& conn,
                                  RpcAuthentication authentication,
                                  RpcEncryption encryption,
+                                 bool loopback_encryption,
                                  MonoTime deadline) {
   Status s;
   unique_ptr<ErrorStatusPB> rpc_error;
+  bool encrypt_loopback = FLAGS_rpc_encrypt_loopback_connections || 
loopback_encryption;
   if (conn->direction() == Connection::SERVER) {
-    s = DoServerNegotiation(conn.get(), authentication, encryption, deadline);
+    s = DoServerNegotiation(conn.get(), authentication, encryption, 
encrypt_loopback, deadline);
   } else {
-    s = DoClientNegotiation(conn.get(), authentication, encryption, deadline,
+    s = DoClientNegotiation(conn.get(), authentication, encryption, 
encrypt_loopback, deadline,
                             &rpc_error);
   }
 
diff --git a/src/kudu/rpc/negotiation.h b/src/kudu/rpc/negotiation.h
index 9f06c64..8f48e71 100644
--- a/src/kudu/rpc/negotiation.h
+++ b/src/kudu/rpc/negotiation.h
@@ -47,6 +47,7 @@ class Negotiation {
   static void RunNegotiation(const scoped_refptr<Connection>& conn,
                              security::RpcAuthentication authentication,
                              security::RpcEncryption encryption,
+                             bool loopback_encryption,
                              MonoTime deadline);
  private:
   DISALLOW_IMPLICIT_CONSTRUCTORS(Negotiation);
diff --git a/src/kudu/rpc/reactor.cc b/src/kudu/rpc/reactor.cc
index 771b9f8..4f276ea 100644
--- a/src/kudu/rpc/reactor.cc
+++ b/src/kudu/rpc/reactor.cc
@@ -609,10 +609,13 @@ Status ReactorThread::StartConnectionNegotiation(const 
scoped_refptr<Connection>
   TRACE("Submitting negotiation task for $0", conn->ToString());
   auto authentication = reactor()->messenger()->authentication();
   auto encryption = reactor()->messenger()->encryption();
+  auto loopback_encryption = reactor()->messenger()->loopback_encryption();
   ThreadPool* negotiation_pool =
       reactor()->messenger()->negotiation_pool(conn->direction());
-  RETURN_NOT_OK(negotiation_pool->Submit([conn, authentication, encryption, 
deadline]() {
-        Negotiation::RunNegotiation(conn, authentication, encryption, 
deadline);
+  RETURN_NOT_OK(negotiation_pool->Submit([conn, authentication, encryption, 
loopback_encryption,
+                                          deadline]() {
+        Negotiation::RunNegotiation(conn, authentication, encryption, 
loopback_encryption,
+                                    deadline);
       }));
   return Status::OK();
 }
diff --git a/src/kudu/rpc/server_negotiation.cc 
b/src/kudu/rpc/server_negotiation.cc
index 5cf8c42..0f373e5 100644
--- a/src/kudu/rpc/server_negotiation.cc
+++ b/src/kudu/rpc/server_negotiation.cc
@@ -156,6 +156,7 @@ ServerNegotiation::ServerNegotiation(unique_ptr<Socket> 
socket,
                                      const security::TlsContext* tls_context,
                                      const security::TokenVerifier* 
token_verifier,
                                      RpcEncryption encryption,
+                                     bool encrypt_loopback,
                                      std::string sasl_proto_name)
     : socket_(std::move(socket)),
       helper_(SaslHelper::SERVER),
@@ -163,6 +164,7 @@ ServerNegotiation::ServerNegotiation(unique_ptr<Socket> 
socket,
       tls_handshake_(security::TlsHandshakeType::SERVER),
       encryption_(encryption),
       tls_negotiated_(false),
+      encrypt_loopback_(encrypt_loopback),
       token_verifier_(token_verifier),
       negotiated_authn_(AuthenticationType::INVALID),
       negotiated_mech_(SaslMechanism::INVALID),
@@ -304,7 +306,7 @@ Status ServerNegotiation::PreflightCheckGSSAPI(const 
std::string& sasl_proto_nam
   // We aren't going to actually send/receive any messages, but
   // this makes it easier to reuse the initialization code.
   ServerNegotiation server(
-      nullptr, nullptr, nullptr, RpcEncryption::OPTIONAL, sasl_proto_name);
+      nullptr, nullptr, nullptr, RpcEncryption::OPTIONAL, false, 
sasl_proto_name);
   Status s = server.EnableGSSAPI();
   if (!s.ok()) {
     return Status::RuntimeError(s.message());
@@ -542,7 +544,7 @@ Status ServerNegotiation::HandleNegotiate(const 
NegotiatePB& request) {
     server_features_.insert(TLS);
     // If the remote peer is local, then we allow using TLS for authentication
     // without encryption or integrity.
-    if (socket_->IsLoopbackConnection() && 
!FLAGS_rpc_encrypt_loopback_connections) {
+    if (socket_->IsLoopbackConnection() && !encrypt_loopback_) {
       server_features_.insert(TLS_AUTHENTICATION_ONLY);
     }
   }
diff --git a/src/kudu/rpc/server_negotiation.h 
b/src/kudu/rpc/server_negotiation.h
index 021f55d..6f22798 100644
--- a/src/kudu/rpc/server_negotiation.h
+++ b/src/kudu/rpc/server_negotiation.h
@@ -66,6 +66,7 @@ class ServerNegotiation {
                     const security::TlsContext* tls_context,
                     const security::TokenVerifier* token_verifier,
                     security::RpcEncryption encryption,
+                    bool encrypt_loopback,
                     std::string sasl_proto_name);
 
   // Enable PLAIN authentication.
@@ -229,6 +230,7 @@ class ServerNegotiation {
   security::TlsHandshake tls_handshake_;
   const security::RpcEncryption encryption_;
   bool tls_negotiated_;
+  bool encrypt_loopback_;
 
   // TSK state.
   const security::TokenVerifier* token_verifier_;

Reply via email to