KUDU-2541: add Kerberos support to Sentry client and mini-cluster

More infrastructure work towards KUDU-428.

Change-Id: I3f7e27137135cb9b463a90b98e4aba864cece3c1
Reviewed-on: http://gerrit.cloudera.org:8080/11525
Reviewed-by: Hao Hao <hao....@cloudera.com>
Reviewed-by: Adar Dembo <a...@cloudera.com>
Tested-by: Kudu Jenkins


Project: http://git-wip-us.apache.org/repos/asf/kudu/repo
Commit: http://git-wip-us.apache.org/repos/asf/kudu/commit/ecc4998c
Tree: http://git-wip-us.apache.org/repos/asf/kudu/tree/ecc4998c
Diff: http://git-wip-us.apache.org/repos/asf/kudu/diff/ecc4998c

Branch: refs/heads/master
Commit: ecc4998cb921b97d919ce6acef2b0f623a75d653
Parents: 14f3e6f
Author: Dan Burkert <danburk...@apache.org>
Authored: Mon Sep 24 15:47:39 2018 -0700
Committer: Dan Burkert <danburk...@apache.org>
Committed: Thu Sep 27 00:34:32 2018 +0000

----------------------------------------------------------------------
 src/kudu/sentry/CMakeLists.txt        |  1 +
 src/kudu/sentry/mini_sentry.cc        | 53 +++++++++++++++++++++++++++---
 src/kudu/sentry/mini_sentry.h         | 10 ++++++
 src/kudu/sentry/sentry_client-test.cc | 41 +++++++++++++++++++----
 4 files changed, 95 insertions(+), 10 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/kudu/blob/ecc4998c/src/kudu/sentry/CMakeLists.txt
----------------------------------------------------------------------
diff --git a/src/kudu/sentry/CMakeLists.txt b/src/kudu/sentry/CMakeLists.txt
index 910117c..588bf9f 100644
--- a/src/kudu/sentry/CMakeLists.txt
+++ b/src/kudu/sentry/CMakeLists.txt
@@ -72,6 +72,7 @@ target_link_libraries(mini_sentry
 if (NOT NO_TESTS)
   SET_KUDU_TEST_LINK_LIBS(
     kudu_sentry
+    mini_kdc
     mini_sentry)
 
   ADD_KUDU_TEST(sentry_client-test)

http://git-wip-us.apache.org/repos/asf/kudu/blob/ecc4998c/src/kudu/sentry/mini_sentry.cc
----------------------------------------------------------------------
diff --git a/src/kudu/sentry/mini_sentry.cc b/src/kudu/sentry/mini_sentry.cc
index ff54ad8..f50aa5b 100644
--- a/src/kudu/sentry/mini_sentry.cc
+++ b/src/kudu/sentry/mini_sentry.cc
@@ -53,6 +53,18 @@ MiniSentry::~MiniSentry() {
   WARN_NOT_OK(Stop(), "Failed to stop MiniSentry");
 }
 
+void MiniSentry::EnableKerberos(std::string krb5_conf,
+                                std::string service_principal,
+                                std::string keytab_file) {
+  CHECK(!sentry_process_);
+  CHECK(!krb5_conf.empty());
+  CHECK(!service_principal.empty());
+  CHECK(!keytab_file.empty());
+  krb5_conf_ = std::move(krb5_conf);
+  service_principal_ = std::move(service_principal);
+  keytab_file_ = std::move(keytab_file);
+}
+
 Status MiniSentry::Start() {
   SCOPED_LOG_SLOW_EXECUTION(WARNING, kSentryStartTimeoutMs / 2, "Starting 
Sentry");
   CHECK(!sentry_process_);
@@ -76,9 +88,16 @@ Status MiniSentry::Start() {
 
   RETURN_NOT_OK(CreateSentryConfigs(tmp_dir));
 
+  // List of JVM environment options to pass to the Sentry service.
+  string java_options;
+  if (!krb5_conf_.empty()) {
+    java_options += Substitute(" -Djava.security.krb5.conf=$0", krb5_conf_);
+  }
+
   map<string, string> env_vars {
       { "JAVA_HOME", java_home },
       { "HADOOP_HOME", hadoop_home },
+      { "JAVA_TOOL_OPTIONS", java_options },
   };
 
   // Start Sentry.
@@ -145,17 +164,31 @@ Status MiniSentry::CreateSentryConfigs(const string& 
tmp_dir) const {
   //
   // - sentry.service.admin.group
   //     Set up admin groups which have unrestricted privileges in Sentry.
+  //
+  // - sentry.service.allow.connect
+  //     Set of Kerberos principals which is allowed to connect to Sentry when
+  //     the Kerberos security mode is enabled.
   static const string kFileTemplate = R"(
 <configuration>
 
   <property>
     <name>sentry.service.security.mode</name>
-    <value>none</value>
+    <value>$0</value>
+  </property>
+
+  <property>
+    <name>sentry.service.server.principal</name>
+    <value>$1</value>
+  </property>
+
+  <property>
+    <name>sentry.service.server.keytab</name>
+    <value>$2</value>
   </property>
 
   <property>
     <name>sentry.store.jdbc.url</name>
-    <value>jdbc:derby:$0/sentry;create=true</value>
+    <value>jdbc:derby:$3/sentry;create=true</value>
   </property>
 
   <property>
@@ -180,18 +213,30 @@ Status MiniSentry::CreateSentryConfigs(const string& 
tmp_dir) const {
 
   <property>
     <name>sentry.store.group.mapping.resource</name>
-    <value>$1</value>
+    <value>$4</value>
   </property>
 
   <property>
     <name>sentry.service.admin.group</name>
     <value>admin</value>
   </property>
+
+  <property>
+    <name>sentry.service.allow.connect</name>
+    <value>kudu</value>
+  </property>
+
 </configuration>
   )";
 
   string users_ini_path = JoinPathSegments(tmp_dir, "users.ini");
-  string file_contents = Substitute(kFileTemplate, tmp_dir, users_ini_path);
+  string file_contents = Substitute(
+      kFileTemplate,
+      keytab_file_.empty() ? "none" : "kerberos",
+      service_principal_,
+      keytab_file_,
+      tmp_dir,
+      users_ini_path);
   RETURN_NOT_OK(WriteStringToFile(Env::Default(),
                                   file_contents,
                                   JoinPathSegments(tmp_dir, 
"sentry-site.xml")));

http://git-wip-us.apache.org/repos/asf/kudu/blob/ecc4998c/src/kudu/sentry/mini_sentry.h
----------------------------------------------------------------------
diff --git a/src/kudu/sentry/mini_sentry.h b/src/kudu/sentry/mini_sentry.h
index bcf46aa..708ed6b 100644
--- a/src/kudu/sentry/mini_sentry.h
+++ b/src/kudu/sentry/mini_sentry.h
@@ -38,6 +38,11 @@ class MiniSentry {
 
   ~MiniSentry();
 
+  // Configures the mini Sentry service to use Kerberos.
+  void EnableKerberos(std::string krb5_conf,
+                      std::string service_principal,
+                      std::string keytab_file);
+
   // Starts the mini Sentry service.
   //
   // If the MiniSentry has already been started and stopped, it will be 
restarted
@@ -70,6 +75,11 @@ class MiniSentry {
 
   std::unique_ptr<Subprocess> sentry_process_;
   uint16_t port_ = 0;
+
+  // Kerberos configuration
+  std::string krb5_conf_;
+  std::string service_principal_;
+  std::string keytab_file_;
 };
 
 } // namespace sentry

http://git-wip-us.apache.org/repos/asf/kudu/blob/ecc4998c/src/kudu/sentry/sentry_client-test.cc
----------------------------------------------------------------------
diff --git a/src/kudu/sentry/sentry_client-test.cc 
b/src/kudu/sentry/sentry_client-test.cc
index 7e3815b..d738a4b 100644
--- a/src/kudu/sentry/sentry_client-test.cc
+++ b/src/kudu/sentry/sentry_client-test.cc
@@ -17,10 +17,13 @@
 
 #include "kudu/sentry/sentry_client.h"
 
+#include <map>
 #include <string>
 
 #include <gtest/gtest.h>
 
+#include "kudu/rpc/sasl_common.h"
+#include "kudu/security/test/mini_kdc.h"
 #include "kudu/sentry/mini_sentry.h"
 #include "kudu/sentry/sentry_policy_service_types.h"
 #include "kudu/thrift/client.h"
@@ -28,14 +31,21 @@
 #include "kudu/util/test_macros.h"
 #include "kudu/util/test_util.h"
 
+using std::string;
+
 namespace kudu {
 namespace sentry {
 
-class SentryClientTest : public KuduTest {
+class SentryClientTest : public KuduTest,
+                         public ::testing::WithParamInterface<bool> {
  public:
+  bool KerberosEnabled() const {
+    return GetParam();
+  }
 };
+INSTANTIATE_TEST_CASE_P(KerberosEnabled, SentryClientTest, ::testing::Bool());
 
-TEST_F(SentryClientTest, TestMiniSentryLifecycle) {
+TEST_P(SentryClientTest, TestMiniSentryLifecycle) {
   MiniSentry mini_sentry;
   ASSERT_OK(mini_sentry.Start());
 
@@ -50,11 +60,30 @@ TEST_F(SentryClientTest, TestMiniSentryLifecycle) {
 // test of Sentry's role handling, but instead verification that the client can
 // communicate with the Sentry service, and errors are converted to Status
 // instances.
-TEST_F(SentryClientTest, TestCreateDropRole) {
-  MiniSentry mini_sentry;
-  ASSERT_OK(mini_sentry.Start());
+TEST_P(SentryClientTest, TestCreateDropRole) {
+  MiniKdc kdc;
+  MiniSentry sentry;
+  thrift::ClientOptions sentry_client_opts;
+
+  if (KerberosEnabled()) {
+    ASSERT_OK(kdc.Start());
+
+    string spn = "sentry/127.0....@krbtest.com";
+    string ktpath;
+    ASSERT_OK(kdc.CreateServiceKeytab("sentry/127.0.0.1", &ktpath));
+
+    ASSERT_OK(rpc::SaslInit());
+    sentry.EnableKerberos(kdc.GetEnvVars()["KRB5_CONFIG"], spn, ktpath);
+
+    ASSERT_OK(kdc.CreateUserPrincipal("kudu"));
+    ASSERT_OK(kdc.Kinit("kudu"));
+    ASSERT_OK(kdc.SetKrb5Environment());
+    sentry_client_opts.enable_kerberos = true;
+    sentry_client_opts.service_principal = "sentry";
+  }
+  ASSERT_OK(sentry.Start());
 
-  SentryClient client(mini_sentry.address(), thrift::ClientOptions());
+  SentryClient client(sentry.address(), sentry_client_opts);
   ASSERT_OK(client.Start());
 
   { // Create a role

Reply via email to