You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@pegasus.apache.org by la...@apache.org on 2023/02/28 02:58:22 UTC

[incubator-pegasus] branch master updated: feat(security): Use Apache Ranger for access control(1/n) (#1360)

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

laiyingchun pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/incubator-pegasus.git


The following commit(s) were added to refs/heads/master by this push:
     new cd01040d8 feat(security): Use Apache Ranger for access control(1/n) (#1360)
cd01040d8 is described below

commit cd01040d86b250d1183b943147ef0a551ec8e248
Author: WHBANG <38...@users.noreply.github.com>
AuthorDate: Tue Feb 28 10:58:16 2023 +0800

    feat(security): Use Apache Ranger for access control(1/n) (#1360)
---
 src/runtime/CMakeLists.txt                       |  2 +
 src/runtime/ranger/CMakeLists.txt                | 30 +++++++++
 src/runtime/ranger/ranger_resource_policy.cpp    | 82 +++++++++++++++++++++++
 src/runtime/ranger/ranger_resource_policy.h      | 85 ++++++++++++++++++++++++
 src/runtime/test/ranger_resource_policy_test.cpp | 80 ++++++++++++++++++++++
 5 files changed, 279 insertions(+)

diff --git a/src/runtime/CMakeLists.txt b/src/runtime/CMakeLists.txt
index 736cfa22d..d5757717a 100644
--- a/src/runtime/CMakeLists.txt
+++ b/src/runtime/CMakeLists.txt
@@ -26,9 +26,11 @@ add_subdirectory(test)
 add_subdirectory(rpc)
 add_subdirectory(task)
 add_subdirectory(security)
+add_subdirectory(ranger)
 
 # TODO(zlw) remove perf_counter from dsn_runtime after the refactor by WuTao
 add_library(dsn_runtime STATIC
+        $<TARGET_OBJECTS:dsn_ranger>
         $<TARGET_OBJECTS:dsn.security>
         $<TARGET_OBJECTS:dsn.rpc>
         $<TARGET_OBJECTS:dsn.task>
diff --git a/src/runtime/ranger/CMakeLists.txt b/src/runtime/ranger/CMakeLists.txt
new file mode 100644
index 000000000..3c3e441a4
--- /dev/null
+++ b/src/runtime/ranger/CMakeLists.txt
@@ -0,0 +1,30 @@
+# 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.
+
+set(MY_PROJ_NAME dsn_ranger)
+
+# Search mode for source files under CURRENT project directory?
+# "GLOB_RECURSE" for recursive search
+# "GLOB" for non-recursive search
+set(MY_SRC_SEARCH_MODE "GLOB")
+
+set(MY_PROJ_LIBS "")
+
+# Extra files that will be installed
+set(MY_BINPLACES "")
+
+dsn_add_object()
diff --git a/src/runtime/ranger/ranger_resource_policy.cpp b/src/runtime/ranger/ranger_resource_policy.cpp
new file mode 100644
index 000000000..220c07bab
--- /dev/null
+++ b/src/runtime/ranger/ranger_resource_policy.cpp
@@ -0,0 +1,82 @@
+// 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 "ranger_resource_policy.h"
+
+namespace dsn {
+namespace ranger {
+
+/*extern*/ access_type operator|(access_type lhs, access_type rhs)
+{
+    using act = std::underlying_type<access_type>::type;
+    return access_type(static_cast<act>(lhs) | static_cast<act>(rhs));
+}
+
+/*extern*/ access_type operator&(access_type lhs, access_type rhs)
+{
+    using act = std::underlying_type<access_type>::type;
+    return access_type(static_cast<act>(lhs) & static_cast<act>(rhs));
+}
+
+bool policy_item::match(const access_type &ac_type, const std::string &user_name) const
+{
+    return static_cast<bool>(access_types & ac_type) && users.count(user_name) != 0;
+}
+
+bool acl_policies::allowed(const access_type &ac_type, const std::string &user_name) const
+{
+    // 1. Check if it is not allowed.
+    for (const auto &deny_policy : deny_policies) {
+        // 1.1. In 'deny_policies'.
+        if (!deny_policy.match(ac_type, user_name)) {
+            continue;
+        }
+        bool in_deny_policies_exclude = false;
+        for (const auto &deny_policy_exclude : deny_policies_exclude) {
+            if (deny_policy_exclude.match(ac_type, user_name)) {
+                in_deny_policies_exclude = true;
+                break;
+            }
+        }
+        // 1.2. Not in any 'deny_policies_exclude', it's not allowed.
+        if (!in_deny_policies_exclude) {
+            return false;
+        }
+    }
+
+    // 2. Check if it is allowed.
+    for (const auto &allow_policy : allow_policies) {
+        // 2.1. In 'allow_policies'.
+        if (!allow_policy.match(ac_type, user_name)) {
+            continue;
+        }
+        for (const auto &allow_policy_exclude : allow_policies_exclude) {
+            // 2.2. In some 'allow_policies_exclude', it's not allowed.
+            if (allow_policy_exclude.match(ac_type, user_name)) {
+                return false;
+            }
+        }
+        // 2.3. Not in any 'allow_policies_exclude', it's allowed.
+        return true;
+    }
+
+    // 3. Otherwise, it's not allowed.
+    return false;
+}
+
+} // namespace ranger
+} // namespace dsn
diff --git a/src/runtime/ranger/ranger_resource_policy.h b/src/runtime/ranger/ranger_resource_policy.h
new file mode 100644
index 000000000..1708e5f72
--- /dev/null
+++ b/src/runtime/ranger/ranger_resource_policy.h
@@ -0,0 +1,85 @@
+// 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 <map>
+#include <string>
+#include <unordered_set>
+#include <vector>
+
+#include <rapidjson/document.h>
+
+#include "common/json_helper.h"
+#include "utils/fmt_logging.h"
+
+namespace dsn {
+namespace ranger {
+
+// ACL type defined in Range service for RPC matching policy
+enum class access_type : uint8_t
+{
+    KRead = 1,
+    KWrite = 1 << 1,
+    KCreate = 1 << 2,
+    KDrop = 1 << 3,
+    KList = 1 << 4,
+    KMetadata = 1 << 5,
+    KControl = 1 << 6
+};
+
+extern access_type operator|(access_type lhs, access_type rhs);
+
+extern access_type operator&(access_type lhs, access_type rhs);
+
+// Ranger policy data structure
+struct policy_item
+{
+    access_type access_types;
+    std::unordered_set<std::string> users;
+
+    // Check if the 'acl_type' - 'user_name' pair is matched to the policy.
+    // Return true if it is matched, otherwise return false.
+    // TODO(wanghao): add benchmark test
+    bool match(const access_type &ac_type, const std::string &user_name) const;
+};
+
+// Data structure of policies with different priorities
+struct acl_policies
+{
+    // policy priority: deny_policies_exclude > deny_policies > allow_policies_exclude >
+    // allow_policies
+    std::vector<policy_item> allow_policies;
+    std::vector<policy_item> allow_policies_exclude;
+    std::vector<policy_item> deny_policies;
+    std::vector<policy_item> deny_policies_exclude;
+
+    // Check whether the 'user_name' is allowed to access the resource by type of 'ac_type'.
+    bool allowed(const access_type &ac_type, const std::string &user_name) const;
+};
+
+// A policy data structure definition of ranger resources
+struct ranger_resource_policy
+{
+    std::string name;
+    std::unordered_set<std::string> database_names;
+    std::unordered_set<std::string> table_names;
+    acl_policies policies;
+};
+
+} // namespace ranger
+} // namespace dsn
diff --git a/src/runtime/test/ranger_resource_policy_test.cpp b/src/runtime/test/ranger_resource_policy_test.cpp
new file mode 100644
index 000000000..7e7efcc73
--- /dev/null
+++ b/src/runtime/test/ranger_resource_policy_test.cpp
@@ -0,0 +1,80 @@
+// 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 <gtest/gtest.h>
+
+#include "runtime/ranger/ranger_resource_policy.h"
+
+namespace dsn {
+namespace ranger {
+
+TEST(ranger_resource_policy_test, policy_item_match)
+{
+    policy_item item = {access_type::KRead | access_type::KWrite | access_type::KCreate,
+                        {"user1", "user2"}};
+    struct test_case
+    {
+        access_type ac_type;
+        std::string user_name;
+        bool expected_result;
+    } tests[] = {{access_type::KRead, "", false},
+                 {access_type::KRead, "user", false},
+                 {access_type::KRead, "user1", true},
+                 {access_type::KWrite, "user1", true},
+                 {access_type::KCreate, "user1", true},
+                 {access_type::KDrop, "user1", false},
+                 {access_type::KList, "user1", false},
+                 {access_type::KMetadata, "user1", false},
+                 {access_type::KControl, "user1", false},
+                 {access_type::KWrite, "user2", true}};
+    for (const auto &test : tests) {
+        auto actual_result = item.match(test.ac_type, test.user_name);
+        EXPECT_EQ(test.expected_result, actual_result);
+    }
+}
+
+TEST(ranger_resource_policy_test, acl_policies_allowed)
+{
+    acl_policies policy;
+    policy.allow_policies = {{access_type::KRead | access_type::KWrite | access_type::KCreate,
+                              {"user1", "user2", "user3", "user4"}}};
+    policy.allow_policies_exclude = {{access_type::KWrite | access_type::KCreate, {"user2"}}};
+    policy.deny_policies = {{access_type::KRead | access_type::KWrite, {"user3", "user4"}}};
+    policy.deny_policies_exclude = {{access_type::KRead, {"user4"}}};
+    struct test_case
+    {
+        access_type ac_type;
+        std::string user_name;
+        bool expected_result;
+    } tests[] = {{access_type::KRead, "user", false},      {access_type::KRead, "user1", true},
+                 {access_type::KWrite, "user1", true},     {access_type::KCreate, "user1", true},
+                 {access_type::KDrop, "user1", false},     {access_type::KList, "user1", false},
+                 {access_type::KMetadata, "user1", false}, {access_type::KControl, "user1", false},
+                 {access_type::KRead, "user2", true},      {access_type::KWrite, "user2", false},
+                 {access_type::KCreate, "user2", false},   {access_type::KDrop, "user2", false},
+                 {access_type::KList, "user2", false},     {access_type::KMetadata, "user2", false},
+                 {access_type::KControl, "user2", false},  {access_type::KRead, "user3", false},
+                 {access_type::KCreate, "user3", true},    {access_type::KList, "user3", false},
+                 {access_type::KRead, "user4", true},      {access_type::KWrite, "user4", false},
+                 {access_type::KCreate, "user4", true},    {access_type::KList, "user4", false}};
+    for (const auto &test : tests) {
+        auto actual_result = policy.allowed(test.ac_type, test.user_name);
+        EXPECT_EQ(test.expected_result, actual_result);
+    }
+}
+} // namespace ranger
+} // namespace dsn


---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscribe@pegasus.apache.org
For additional commands, e-mail: commits-help@pegasus.apache.org