Skip to content

Commit

Permalink
feat(Ranger): add a default database policy name for legacy table (#1507
Browse files Browse the repository at this point in the history
)

#1054

This patch adds a new conf item `legacy_table_database_mapping_policy_name`,
the legacy table (the tables which are created before Ranger ACL enabled) will be
matched to the database named `legacy_table_database_mapping_policy_name`
for ACL.

"*" can match any table, including legacy tables and tables named by new rules.
  • Loading branch information
WHBANG authored Jun 8, 2023
1 parent d216696 commit f3d1388
Show file tree
Hide file tree
Showing 3 changed files with 52 additions and 27 deletions.
56 changes: 33 additions & 23 deletions src/runtime/ranger/ranger_resource_policy_manager.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,11 @@ DSN_DEFINE_string(ranger,
ranger_service_name,
"",
"The name of the policies defined in the Ranger service.");
DSN_DEFINE_string(ranger,
legacy_table_database_mapping_policy_name,
"__default__",
"The name of the Ranger database policy matched by the legacy table(The table "
"name does not follow the naming rules of {database_name}.{table_name})");

#define RETURN_ERR_IF_MISSING_MEMBER(obj, member) \
do { \
Expand Down Expand Up @@ -241,20 +246,25 @@ bool ranger_resource_policy_manager::allowed(const int rpc_code,
break;
}

// legacy table belongs to the default database.
std::string db_name =
database_name.empty() ? FLAGS_legacy_table_database_mapping_policy_name : database_name;

// Check if it is allowed by any DATABASE policy.
utils::auto_read_lock l(_database_policies_lock);
for (const auto &policy : _database_policies_cache) {
if (!policy.policies.allowed(ac_type->second, user_name)) {
continue;
}
// Legacy tables may don't contain database section.
if (database_name.empty() && policy.database_names.count("*") != 0) {
return true;
}
if (policy.database_names.count(database_name) != 0) {
// "*" can match any table, including legacy table and new table.
if (policy.database_names.count("*") != 0 ||
policy.database_names.count(db_name) != 0) {
return true;
}
}

// The check that does not match any DATABASE policy returns false.
return false;
} while (false);

// The check that does not match any policy returns false.
Expand Down Expand Up @@ -578,9 +588,10 @@ dsn::error_code ranger_resource_policy_manager::sync_policies_to_app_envs()
LOG_AND_RETURN_NOT_OK(ERROR, list_resp.err, "list_apps failed.");
for (const auto &app : list_resp.infos) {
std::string database_name = get_database_name_from_app_name(app.app_name);
// Use "*" for table name of invalid Ranger rules to match datdabase resources.
// Use 'legacy_table_database_mapping_policy_name' for table name of invalid Ranger rules to
// match datdabase resources.
if (database_name.empty()) {
database_name = "*";
database_name = FLAGS_legacy_table_database_mapping_policy_name;
}
std::string table_name = get_table_name_from_app_name(app.app_name);

Expand All @@ -590,32 +601,31 @@ dsn::error_code ranger_resource_policy_manager::sync_policies_to_app_envs()
{dsn::replication::replica_envs::REPLICA_ACCESS_CONTROLLER_RANGER_POLICIES});
bool is_policy_matched = false;
for (const auto &policy : table_policies->second) {
if (policy.database_names.count(database_name) == 0) {
// If this table does not match any database, its Ranger policies will be cleaned up.
if (policy.database_names.count(database_name) == 0 &&
policy.database_names.count("*") == 0) {
continue;
}

// if table name does not conform to the naming rules(database_name.table_name),
// database is defined by "*" in ranger for acl matching
if (policy.table_names.count("*") != 0 || policy.table_names.count(table_name) != 0) {
is_policy_matched = true;
req->__set_op(dsn::replication::app_env_operation::type::APP_ENV_OP_SET);
req->__set_values(
{json::json_forwarder<acl_policies>::encode(policy.policies).to_string()});

dsn::replication::update_app_env_rpc rpc(std::move(req),
LPC_USE_RANGER_ACCESS_CONTROL);
_meta_svc->get_server_state()->set_app_envs(rpc);
LOG_AND_RETURN_NOT_OK(ERROR, rpc.response().err, "set_app_envs failed.");
break;
}
is_policy_matched = true;
req->__set_op(dsn::replication::app_env_operation::type::APP_ENV_OP_SET);
req->__set_values(
{json::json_forwarder<acl_policies>::encode(policy.policies).to_string()});

dsn::replication::update_app_env_rpc rpc(std::move(req), LPC_USE_RANGER_ACCESS_CONTROL);
_meta_svc->get_server_state()->set_app_envs(rpc);
_meta_svc->get_server_state()->wait_all_task();
LOG_AND_RETURN_NOT_OK(ERROR, rpc.response().err, "set_app_envs failed.");
break;
}

// There is no matched policy, clear app Ranger policy
// There is no matched policy, clear the table's Ranger policies.
if (!is_policy_matched) {
req->__set_op(dsn::replication::app_env_operation::type::APP_ENV_OP_DEL);

dsn::replication::update_app_env_rpc rpc(std::move(req), LPC_USE_RANGER_ACCESS_CONTROL);
_meta_svc->get_server_state()->del_app_envs(rpc);
_meta_svc->get_server_state()->wait_all_task();
LOG_AND_RETURN_NOT_OK(ERROR, rpc.response().err, "del_app_envs failed.");
}
}
Expand Down
5 changes: 3 additions & 2 deletions src/runtime/ranger/ranger_resource_policy_manager.h
Original file line number Diff line number Diff line change
Expand Up @@ -74,8 +74,9 @@ class ranger_resource_policy_manager
// When using Ranger for ACL, periodically pull policies from Ranger service.
void start();

// Return true if the 'user_name' is allowed to access 'app_name' via 'rpc_code'.
bool allowed(const int rpc_code, const std::string &user_name, const std::string &app_name);
// Return true if the 'user_name' is allowed to access 'database_name' via 'rpc_code'.
bool
allowed(const int rpc_code, const std::string &user_name, const std::string &database_name);

private:
// Parse Ranger ACL policies from 'data' in JSON format into 'policies'.
Expand Down
18 changes: 16 additions & 2 deletions src/runtime/test/ranger_resource_policy_manager_test.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -34,9 +34,11 @@
#include "runtime/ranger/ranger_resource_policy_manager.h"
#include "runtime/task/task_code.h"
#include "utils/blob.h"
#include "utils/flags.h"

namespace dsn {
namespace ranger {
DSN_DECLARE_string(legacy_table_database_mapping_policy_name);

TEST(ranger_resource_policy_manager_test, parse_policies_from_json_for_test)
{
Expand Down Expand Up @@ -286,8 +288,17 @@ class ranger_resource_policy_manager_function_test : public ranger_resource_poli
{{access_type::kCreate, {"user6"}}},
{},
{}}});
ranger_resource_policy fake_default_ranger_resource_policy(
{"",
{FLAGS_legacy_table_database_mapping_policy_name},
{},
{{{access_type::kCreate, {"user5", "user6"}}},
{{access_type::kCreate, {"user5"}}},
{},
{}}});
_database_policies_cache = {fake_ranger_resource_policy_1,
fake_ranger_resource_policy_2,
fake_default_ranger_resource_policy,
fake_ranger_resource_policy_3};

ranger_resource_policy fake_ranger_resource_policy_4(
Expand Down Expand Up @@ -331,9 +342,12 @@ TEST_F(ranger_resource_policy_manager_function_test, allowed)
{"RPC_CM_START_BACKUP_APP", "user3", "database2", true},
{"RPC_CM_START_BACKUP_APP", "user4", "database2", false},
{"TASK_CODE_INVALID", "user5", "", false},
// Next two case matched to the default database policy and "*" database.
{"RPC_CM_CREATE_APP", "user5", "", true},
{"RPC_CM_CREATE_APP", "user5", "database2", false},
{"RPC_CM_CREATE_APP", "user6", "", false},
{"RPC_CM_CREATE_APP", "user6", "", true},
// Next two case matched to the database policy named "*".
{"RPC_CM_CREATE_APP", "user5", "any_database_name", true},
{"RPC_CM_CREATE_APP", "user6", "any_database_name", false},
{"RPC_CM_CREATE_APP", "user6", "database2", false},
{"TASK_CODE_INVALID", "user7", "database3", false},
{"RPC_CM_LIST_NODES", "user7", "database3", true},
Expand Down

0 comments on commit f3d1388

Please sign in to comment.