This is an automated email from the ASF dual-hosted git repository.
alexey pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/kudu.git
The following commit(s) were added to refs/heads/master by this push:
new 6b2077e48 [rpc] clean up JWT-related client-side negotiation code
6b2077e48 is described below
commit 6b2077e48e1e96cf6520db09ddd8c2d3ca97334d
Author: Alexey Serbin <[email protected]>
AuthorDate: Wed Jun 14 19:10:30 2023 -0700
[rpc] clean up JWT-related client-side negotiation code
Since now there is an API to add a trusted TLS certificate into the
chain of trusted certificates of a Kudu C++ client application, the
test-only flag --jwt_client_require_trusted_tls_cert is no longer
needed. This patch removes the flag along with corresponding
test scenario. Correspondingly, the client now verifies the server's
TLS certificate during TLS handshake since there isn't a case when
a client would send out its JWT to a server it doesn't trust once
the --jwt_client_require_trusted_tls_cert test-only flag is removed.
This patch also adds an extra logging about a connection negotiation
condition when the client has a JWT, but it doesn't trust the server's
TLS certificate.
In addition, I took the liberty of removing a few TODOs related to
KUDU-1921 since the referred functionality has already been implemented.
Change-Id: I85574ed05396fcf3740d9d068afa524cf125f5ff
Reviewed-on: http://gerrit.cloudera.org:8080/20076
Reviewed-by: Attila Bukor <[email protected]>
Tested-by: Kudu Jenkins
---
src/kudu/integration-tests/security-itest.cc | 23 ------------
src/kudu/rpc/client_negotiation.cc | 53 ++++++++++++++--------------
2 files changed, 27 insertions(+), 49 deletions(-)
diff --git a/src/kudu/integration-tests/security-itest.cc
b/src/kudu/integration-tests/security-itest.cc
index fdf54619f..7cb2bde4a 100644
--- a/src/kudu/integration-tests/security-itest.cc
+++ b/src/kudu/integration-tests/security-itest.cc
@@ -84,7 +84,6 @@
#include "kudu/util/test_macros.h"
#include "kudu/util/test_util.h"
-DECLARE_bool(jwt_client_require_trusted_tls_cert);
DECLARE_string(local_ip_for_outbound_sockets);
using kudu::client::KuduClient;
@@ -644,28 +643,6 @@ TEST_F(SecurityITest, TestJwtMiniCluster) {
ASSERT_STR_CONTAINS(s.ToString(),
"client requires authentication, but server does not have");
}
- {
- SCOPED_TRACE("Valid JWT with relaxed requirements for server's TLS cert");
- KuduClientBuilder cb;
- for (auto i = 0; i < cluster_->num_masters(); ++i) {
-
cb.add_master_server_addr(cluster_->master(i)->bound_rpc_addr().ToString());
- }
- cb.jwt(cluster_->oidc()->CreateJwt(kValidAccount, kSubject, true));
- cb.require_authentication(true);
-
- // If not adding the CA certificate that Kudu RPC server certificates are
- // signed with, in simplified test scenarios it's possible to relax the
- // requirements at the client side of the Kudu RPC connection negotiation
- // protocol. With --jwt_client_require_trusted_tls_cert=false, the client
- // does not verify the server's TLS certificate before sending its JWT
- // to the server for authentication.
- FLAGS_jwt_client_require_trusted_tls_cert = false;
-
- shared_ptr<KuduClient> client;
- ASSERT_OK(cb.Build(&client));
- vector<string> tables;
- ASSERT_OK(client->ListTables(&tables));
- }
}
TEST_F(SecurityITest, TestJwtMiniClusterWithInvalidCert) {
diff --git a/src/kudu/rpc/client_negotiation.cc
b/src/kudu/rpc/client_negotiation.cc
index feb3bec86..42c23f099 100644
--- a/src/kudu/rpc/client_negotiation.cc
+++ b/src/kudu/rpc/client_negotiation.cc
@@ -33,7 +33,6 @@
#include <glog/logging.h>
#include "kudu/gutil/basictypes.h"
-#include "kudu/gutil/macros.h"
#include "kudu/gutil/map-util.h"
#include "kudu/gutil/stl_util.h"
#include "kudu/gutil/strings/join.h"
@@ -51,7 +50,6 @@
#include "kudu/security/token.pb.h"
#include "kudu/util/debug/leakcheck_disabler.h"
#include "kudu/util/faststring.h"
-#include "kudu/util/flag_tags.h"
#include "kudu/util/net/sockaddr.h"
#include "kudu/util/net/socket.h"
#include "kudu/util/slice.h"
@@ -64,16 +62,6 @@
#pragma GCC diagnostic ignored "-Wdeprecated-declarations"
#endif // #if defined(__APPLE__)
-DEFINE_bool(jwt_client_require_trusted_tls_cert, true,
- "When this flag is set to 'false', a Kudu client is willing "
- "to send its JSON Web Token over TLS connections to authenticate "
- "to a Kudu server whose TLS certificate is not trusted "
- "by the client. "
- "NOTE: this is used for test purposes only; don't use in any other
"
- "use case due to security implications");
-TAG_FLAG(jwt_client_require_trusted_tls_cert, hidden);
-TAG_FLAG(jwt_client_require_trusted_tls_cert, unsafe);
-
DECLARE_bool(rpc_encrypt_loopback_connections);
using kudu::security::RpcEncryption;
@@ -202,14 +190,12 @@ Status
ClientNegotiation::Negotiate(unique_ptr<ErrorStatusPB>* rpc_error) {
}
// Step 3: if both ends support TLS, do a TLS handshake.
- // TODO(KUDU-1921): allow the client to require TLS.
if (encryption_ != RpcEncryption::DISABLED &&
ContainsKey(server_features_, TLS)) {
RETURN_NOT_OK(tls_context_->InitiateHandshake(&tls_handshake_));
- if (negotiated_authn_ == AuthenticationType::SASL ||
- negotiated_authn_ == AuthenticationType::JWT) {
- // When using SASL or JWT authentication, verifying the server's
certificate is
+ if (negotiated_authn_ == AuthenticationType::SASL) {
+ // When using SASL authentication, verifying the server's certificate is
// not necessary. This allows the client to still use TLS encryption for
// connections to servers which only have a self-signed certificate.
tls_handshake_.set_verification_mode(security::TlsVerificationMode::VERIFY_NONE);
@@ -366,14 +352,31 @@ Status ClientNegotiation::SendNegotiate() {
// reliably on clients?
msg.add_authn_types()->mutable_token();
}
- if (jwt_ && (tls_context_->has_trusted_cert() ||
- PREDICT_FALSE(!FLAGS_jwt_client_require_trusted_tls_cert))) {
- // The client isn't sending its JWT to servers whose authenticity it cannot
- // verify, otherwise its authn credentials might be stolen by an impostor.
- // So, even if the client has a JWT to use, it does not advertise that
- // it's capable of JWT-based authentication when it doesn't trust the
- // server's TLS certificate.
- msg.add_authn_types()->mutable_jwt();
+ if (jwt_) {
+ if (tls_context_->has_trusted_cert()) {
+ msg.add_authn_types()->mutable_jwt();
+ } else {
+ // The client isn't sending its JWT to a server whose authenticity
+ // it cannot verify, otherwise its authn credentials might be stolen
+ // by an impostor. So, even if the client has a JWT to use, it does not
+ // advertise its JWT-based authentication capability when it doesn't
trust
+ // the server's TLS certificate.
+ string server_addr_str;
+ {
+ Sockaddr server_addr;
+ if (auto s = socket_->GetPeerAddress(&server_addr); !s.ok()) {
+ LOG(WARNING) << "could not deduce server's address from socket info";
+ } else {
+ server_addr_str = server_addr.ToString();
+ }
+ }
+ const string& server_info = server_addr_str.empty()
+ ? "server" : Substitute("server at $0", server_addr_str);
+ LOG(WARNING) << Substitute(
+ "the client has a JWT but it isn't advertising its JWT-based authn "
+ "capability since it doesn't trust the certificate of the $0",
+ server_info);
+ }
}
if (PREDICT_FALSE(msg.authn_types().empty())) {
@@ -464,8 +467,6 @@ Status ClientNegotiation::HandleNegotiate(const
NegotiatePB& response) {
// The preference list in order of most to least preferred:
// * GSSAPI
// * PLAIN
- //
- // TODO(KUDU-1921): allow the client to require authentication.
if (ContainsKey(client_mechs, SaslMechanism::GSSAPI) &&
ContainsKey(server_mechs, SaslMechanism::GSSAPI)) {
// Check that the client has local Kerberos credentials, and if not fall