Skip to content

Commit c2d9c8d

Browse files
feat: support tablet auth and flag to disable auth (#3885)
* add brpc authenticator * fix: add auth library * fix: make authenticator lifetime same as channel * refactor: use global variables to pass auth tokens * feat: added basic server auth backwards compatible with user = root and all internal services * chore: remove debug log * chore: apply lint style fixes * feat: encrypt password before sending * fix: add namespace for Authenticator class * chore: add newline * feat: add user verification logic * feat: add nameserver server side auth * chore: remove unneccessary logs * chore: lint * chore: make refreshable map header only * chore: remove old refreshable map file * chore: lint * chore: lint * chore: lint * sync with db in user access manager constructor * chore: add license * chore: add license * feat: default g_auth_token user to root if not provided * fix: user table start in cluster mode * feat: sync user data every 100ms * fix: add auth library for linking * fix: refreshable map test * fix: add main method to refreshable map test * fix: add auth to sdk * eaat: treat omitted host as localhost * feat: treat % as all hosts * fix: minicluster auth * fix: remove api server auth * feat: add minicluster tablet auth * fix: change scala test password * fix: default root as user in python sdk * fix: wait for nameservers to pick up auth data before starting api server * fix: wait 5 seconds after nameserver launch for auth data to be picked up * fix: minicluster options scope * test: cat host file * fix: remove cat * fix: Init should finish after user table is available * fix: always create user table * fix: create user table after internal db create * fix: add partition info setting for user table create * fix: auth related tests * fix: support multiple nameservers * fix: recover db and table only for cluster mode * fix: remote test ns tablet start order * fix: set root as default user in python sdk * fix: SyncTableReplicaCluster and AddAndRemoveReplicaCluster tests * fix: remove user root * fix: add erver stops to name_server_test cases and spilt sql availability tests * fix: nameserver test scope * test: add bad tablet server option * fix: brpc authenticator destruction before nameserver * feat: add user auth_str to tablet client * feat: add tablet system table iterator * fix: refactor to better system table iterator * fix: remove unneccessary test * test: sql_cmd_test should expect 2 user table replicas in cluster mode * chore: lint * feat: add skip auth flag * fix: skip while wait in nameserver start if auth disabled * test: enable auth for system table test * fix: tablets read user from local * fix: authenticator scope * chore: add auth docs * chore: more docs * chore: add 0.8.5 clarification --------- Co-authored-by: 张子恒 <zhangziheng00001@163.com>
1 parent 442a4d3 commit c2d9c8d

24 files changed

Lines changed: 259 additions & 94 deletions

docs/en/deploy/auth.md

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,11 @@ OpenMLDB 0.8.4 and later versions support ZooKeeper with passwords. You need to
1212

1313
## OpenMLDB Authentication
1414

15-
OpenMLDB 0.8.5 and later versions support username and password authentication in the cluster. Custom user and password creation is performed after the cluster is started. The initial cluster has only the root user with an empty password. By default, all servers and clients connect to the cluster using the root username and an empty password.
15+
### Alpha Feature in 0.9.0
16+
OpenMLDB introduces server-side authentication as an alpha feature in version 0.9.0. As of this release, server-side authentication is not enabled by default. This approach ensures backward compatibility and minimizes the risk of disrupting existing deployments. It can be enablled by including `--noskip_grant_tables` when starting clients and servers. Statements that alter the authentication settings or modify user credentials, such as `CREATE USER`, `ALTER USER`, and `DELETE USER` are not supported when authentication is disabled.
17+
18+
### Authentication in 0.8.5
19+
OpenMLDB 0.8.5 supports username and password authentication in the cluster. Custom user and password creation is performed after the cluster is started. The initial cluster has only the root user with an empty password. By default, all servers and clients connect to the cluster using the root username and an empty password.
1620

1721
For security reasons, we usually need the root user to use a password and then create ordinary users. Due to the architecture, some servers also connect to the cluster as clients. If you need to change the root password, pay attention to these servers.
1822

docs/zh/deploy/auth.md

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,11 @@ OpenMLDB 0.8.4版本及以后,可以使用有密码的ZooKeeper。需要在启
1212

1313
## OpenMLDB身份认证
1414

15-
OpenMLDB 0.8.5版本及以后,集群内可以使用用户名和密码进行身份认证。自定义用户和密码的创建都在集群启动之后,初始集群只有root用户,密码为空。默认情况下,任何的server和client都是以root用户名和空密码连接到集群。
15+
### 0.9.0 中的 Alpha 功能
16+
OpenMLDB 在 0.9.0 版本中作为 alpha 功能引入了服务器端身份验证。 从此版本开始,默认情况下不启用服务器端身份验证。 这种方法可确保向后兼容性并最大限度地降低破坏现有部署的风险。 用户可以通过在启动客户端和服务器时配置“--noskip_grant_tables”来启用服务端认证。 禁用身份验证时,不支持更改身份验证设置或修改用户凭据的语句,例如“CREATE USER”、“ALTER USER”和“DELETE USER”。
17+
18+
### 0.8.5 中的认证
19+
OpenMLDB 0.8.5版本集群内可以使用用户名和密码进行身份认证。自定义用户和密码的创建都在集群启动之后,初始集群只有root用户,密码为空。默认情况下,任何的server和client都是以root用户名和空密码连接到集群。
1620

1721
为了安全,我们通常需要root用户使用密码,再创建普通用户。而由于架构上部分server也会作为client连接集群,如果修改root密码需要注意。
1822

src/auth/refreshable_map.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,8 @@ namespace openmldb::auth {
2929
template <typename Key, typename Value>
3030
class RefreshableMap {
3131
public:
32+
RefreshableMap() : map_(std::make_shared<std::unordered_map<Key, Value>>()) {}
33+
3234
std::optional<Value> Get(const Key& key) const {
3335
std::shared_lock<std::shared_mutex> lock(mutex_);
3436
if (auto it = map_->find(key); it != map_->end()) {

src/auth/user_access_manager.cc

Lines changed: 23 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -23,9 +23,9 @@
2323
#include "nameserver/system_table.h"
2424

2525
namespace openmldb::auth {
26-
UserAccessManager::UserAccessManager(IteratorFactory iterator_factory,
27-
std::shared_ptr<nameserver::TableInfo> user_table_info)
28-
: user_table_iterator_factory_(std::move(iterator_factory)), user_table_info_(user_table_info) {
26+
27+
UserAccessManager::UserAccessManager(IteratorFactory iterator_factory)
28+
: user_table_iterator_factory_(std::move(iterator_factory)) {
2929
StartSyncTask();
3030
}
3131

@@ -49,26 +49,28 @@ void UserAccessManager::StopSyncTask() {
4949
}
5050

5151
void UserAccessManager::SyncWithDB() {
52-
auto new_user_map = std::make_unique<std::unordered_map<std::string, std::string>>();
53-
auto it = user_table_iterator_factory_(::openmldb::nameserver::USER_INFO_NAME);
54-
it->SeekToFirst();
55-
while (it->Valid()) {
56-
auto row = it->GetValue();
57-
auto buf = it->GetValue().buf();
58-
auto size = it->GetValue().size();
59-
codec::RowView row_view(user_table_info_->column_desc(), buf, size);
60-
std::string host, user, password;
61-
row_view.GetStrValue(0, &host);
62-
row_view.GetStrValue(1, &user);
63-
row_view.GetStrValue(2, &password);
64-
if (host == "%") {
65-
new_user_map->emplace(user, password);
66-
} else {
67-
new_user_map->emplace(FormUserHost(user, host), password);
52+
if (auto it_pair = user_table_iterator_factory_(::openmldb::nameserver::USER_INFO_NAME); it_pair) {
53+
auto new_user_map = std::make_unique<std::unordered_map<std::string, std::string>>();
54+
auto it = it_pair->first.get();
55+
it->SeekToFirst();
56+
while (it->Valid()) {
57+
auto row = it->GetValue();
58+
auto buf = it->GetValue().buf();
59+
auto size = it->GetValue().size();
60+
codec::RowView row_view(*it_pair->second.get(), buf, size);
61+
std::string host, user, password;
62+
row_view.GetStrValue(0, &host);
63+
row_view.GetStrValue(1, &user);
64+
row_view.GetStrValue(2, &password);
65+
if (host == "%") {
66+
new_user_map->emplace(user, password);
67+
} else {
68+
new_user_map->emplace(FormUserHost(user, host), password);
69+
}
70+
it->Next();
6871
}
69-
it->Next();
72+
user_map_.Refresh(std::move(new_user_map));
7073
}
71-
user_map_.Refresh(std::move(new_user_map));
7274
}
7375

7476
bool UserAccessManager::IsAuthenticated(const std::string& host, const std::string& user, const std::string& password) {

src/auth/user_access_manager.h

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -22,23 +22,25 @@
2222
#include <memory>
2323
#include <string>
2424
#include <thread>
25+
#include <utility>
2526

2627
#include "catalog/distribute_iterator.h"
2728
#include "refreshable_map.h"
2829

2930
namespace openmldb::auth {
3031
class UserAccessManager {
3132
public:
32-
using IteratorFactory =
33-
std::function<std::unique_ptr<::openmldb::catalog::FullTableIterator>(const std::string& table_name)>;
33+
using IteratorFactory = std::function<std::optional<
34+
std::pair<std::unique_ptr<::openmldb::catalog::FullTableIterator>, std::unique_ptr<openmldb::codec::Schema>>>(
35+
const std::string& table_name)>;
36+
37+
explicit UserAccessManager(IteratorFactory iterator_factory);
3438

35-
UserAccessManager(IteratorFactory iterator_factory, std::shared_ptr<nameserver::TableInfo> user_table_info);
3639
~UserAccessManager();
3740
bool IsAuthenticated(const std::string& host, const std::string& username, const std::string& password);
3841

3942
private:
4043
IteratorFactory user_table_iterator_factory_;
41-
std::shared_ptr<nameserver::TableInfo> user_table_info_;
4244
RefreshableMap<std::string, std::string> user_map_;
4345
std::atomic<bool> sync_task_running_{false};
4446
std::thread sync_task_thread_;

src/catalog/client_manager.cc

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -554,7 +554,7 @@ bool ClientManager::UpdateClient(const std::map<std::string, std::string>& endpo
554554
for (const auto& kv : endpoint_map) {
555555
auto it = real_endpoint_map_.find(kv.first);
556556
if (it == real_endpoint_map_.end()) {
557-
auto wrapper = std::make_shared<TabletAccessor>(kv.first);
557+
auto wrapper = std::make_shared<TabletAccessor>(kv.first, auth_token_);
558558
if (!wrapper->UpdateClient(kv.second)) {
559559
LOG(WARNING) << "add client failed. name " << kv.first << ", endpoint " << kv.second;
560560
continue;
@@ -583,7 +583,7 @@ bool ClientManager::UpdateClient(
583583
for (const auto& kv : tablet_clients) {
584584
auto it = real_endpoint_map_.find(kv.first);
585585
if (it == real_endpoint_map_.end()) {
586-
auto wrapper = std::make_shared<TabletAccessor>(kv.first, kv.second);
586+
auto wrapper = std::make_shared<TabletAccessor>(kv.first, kv.second, auth_token_);
587587
DLOG(INFO) << "add client. name " << kv.first << ", endpoint " << kv.second->GetRealEndpoint();
588588
clients_.emplace(kv.first, wrapper);
589589
real_endpoint_map_.emplace(kv.first, kv.second->GetRealEndpoint());

src/catalog/client_manager.h

Lines changed: 11 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -132,17 +132,20 @@ class AsyncTablesHandler : public ::hybridse::vm::MemTableHandler {
132132

133133
class TabletAccessor : public ::hybridse::vm::Tablet {
134134
public:
135-
explicit TabletAccessor(const std::string& name) : name_(name), tablet_client_() {}
135+
explicit TabletAccessor(const std::string& name,
136+
const openmldb::authn::AuthToken auth_token = openmldb::authn::ServiceToken{"default"})
137+
: name_(name), tablet_client_(), auth_token_(auth_token) {}
136138

137-
TabletAccessor(const std::string& name, const std::shared_ptr<::openmldb::client::TabletClient>& client)
138-
: name_(name), tablet_client_(client) {}
139+
TabletAccessor(const std::string& name, const std::shared_ptr<::openmldb::client::TabletClient>& client,
140+
const openmldb::authn::AuthToken auth_token = openmldb::authn::ServiceToken{"default"})
141+
: name_(name), tablet_client_(client), auth_token_(auth_token) {}
139142

140143
std::shared_ptr<::openmldb::client::TabletClient> GetClient() {
141144
return std::atomic_load_explicit(&tablet_client_, std::memory_order_relaxed);
142145
}
143146

144147
bool UpdateClient(const std::string& endpoint) {
145-
auto client = std::make_shared<::openmldb::client::TabletClient>(name_, endpoint);
148+
auto client = std::make_shared<::openmldb::client::TabletClient>(name_, endpoint, auth_token_);
146149
if (client->Init() != 0) {
147150
return false;
148151
}
@@ -170,6 +173,7 @@ class TabletAccessor : public ::hybridse::vm::Tablet {
170173
private:
171174
std::string name_;
172175
std::shared_ptr<::openmldb::client::TabletClient> tablet_client_;
176+
const openmldb::authn::AuthToken auth_token_;
173177
};
174178

175179
class TabletsAccessor : public ::hybridse::vm::Tablet {
@@ -243,7 +247,8 @@ class TableClientManager {
243247

244248
class ClientManager {
245249
public:
246-
ClientManager() : real_endpoint_map_(), clients_(), mu_(), rand_(0xdeadbeef) {}
250+
explicit ClientManager(const openmldb::authn::AuthToken auth_token = openmldb::authn::ServiceToken{"default"})
251+
: real_endpoint_map_(), clients_(), mu_(), rand_(0xdeadbeef), auth_token_(auth_token) {}
247252
std::shared_ptr<TabletAccessor> GetTablet(const std::string& name) const;
248253
std::shared_ptr<TabletAccessor> GetTablet() const;
249254
std::vector<std::shared_ptr<TabletAccessor>> GetAllTablet() const;
@@ -257,6 +262,7 @@ class ClientManager {
257262
std::unordered_map<std::string, std::shared_ptr<TabletAccessor>> clients_;
258263
mutable ::openmldb::base::SpinMutex mu_;
259264
mutable ::openmldb::base::Random rand_;
265+
const openmldb::authn::AuthToken auth_token_;
260266
};
261267

262268
} // namespace catalog

src/client/tablet_client.cc

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -35,11 +35,14 @@ DECLARE_uint32(absolute_ttl_max);
3535
namespace openmldb {
3636
namespace client {
3737

38-
TabletClient::TabletClient(const std::string& endpoint, const std::string& real_endpoint)
39-
: Client(endpoint, real_endpoint), client_(real_endpoint.empty() ? endpoint : real_endpoint) {}
40-
41-
TabletClient::TabletClient(const std::string& endpoint, const std::string& real_endpoint, bool use_sleep_policy)
42-
: Client(endpoint, real_endpoint), client_(real_endpoint.empty() ? endpoint : real_endpoint, use_sleep_policy) {}
38+
TabletClient::TabletClient(const std::string& endpoint, const std::string& real_endpoint,
39+
const openmldb::authn::AuthToken auth_token)
40+
: Client(endpoint, real_endpoint), client_(real_endpoint.empty() ? endpoint : real_endpoint, auth_token) {}
41+
42+
TabletClient::TabletClient(const std::string& endpoint, const std::string& real_endpoint, bool use_sleep_policy,
43+
const openmldb::authn::AuthToken auth_token)
44+
: Client(endpoint, real_endpoint),
45+
client_(real_endpoint.empty() ? endpoint : real_endpoint, use_sleep_policy, auth_token) {}
4346

4447
TabletClient::~TabletClient() {}
4548

src/client/tablet_client.h

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -46,9 +46,11 @@ const uint32_t INVALID_REMOTE_TID = UINT32_MAX;
4646

4747
class TabletClient : public Client {
4848
public:
49-
TabletClient(const std::string& endpoint, const std::string& real_endpoint);
49+
TabletClient(const std::string& endpoint, const std::string& real_endpoint,
50+
const openmldb::authn::AuthToken auth_token = openmldb::authn::ServiceToken{"default"});
5051

51-
TabletClient(const std::string& endpoint, const std::string& real_endpoint, bool use_sleep_policy);
52+
TabletClient(const std::string& endpoint, const std::string& real_endpoint, bool use_sleep_policy,
53+
const openmldb::authn::AuthToken auth_token = openmldb::authn::ServiceToken{"default"});
5254

5355
~TabletClient();
5456

src/cmd/openmldb.cc

Lines changed: 23 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -145,19 +145,19 @@ void StartNameServer() {
145145
PDLOG(WARNING, "Fail to register name");
146146
exit(1);
147147
}
148-
std::shared_ptr<::openmldb::nameserver::TableInfo> table_info;
149-
if (!name_server->GetTableInfo(::openmldb::nameserver::USER_INFO_NAME, ::openmldb::nameserver::INTERNAL_DB,
150-
&table_info)) {
151-
PDLOG(WARNING, "Failed to get table info for user table");
152-
exit(1);
153-
}
154-
openmldb::auth::UserAccessManager user_access_manager(name_server->GetSystemTableIterator(), table_info);
148+
155149
brpc::ServerOptions options;
156-
openmldb::authn::BRPCAuthenticator server_authenticator(
157-
[&user_access_manager](const std::string& host, const std::string& username, const std::string& password) {
158-
return user_access_manager.IsAuthenticated(host, username, password);
159-
});
160-
options.auth = &server_authenticator;
150+
std::unique_ptr<openmldb::auth::UserAccessManager> user_access_manager;
151+
std::unique_ptr<openmldb::authn::BRPCAuthenticator> server_authenticator;
152+
if (!FLAGS_skip_grant_tables) {
153+
user_access_manager =
154+
std::make_unique<openmldb::auth::UserAccessManager>(name_server->GetSystemTableIterator());
155+
server_authenticator = std::make_unique<openmldb::authn::BRPCAuthenticator>(
156+
[&user_access_manager](const std::string& host, const std::string& username, const std::string& password) {
157+
return user_access_manager->IsAuthenticated(host, username, password);
158+
});
159+
options.auth = server_authenticator.get();
160+
}
161161

162162
options.num_threads = FLAGS_thread_pool_size;
163163
brpc::Server server;
@@ -256,8 +256,17 @@ void StartTablet() {
256256
exit(1);
257257
}
258258
brpc::ServerOptions options;
259-
openmldb::authn::BRPCAuthenticator server_authenticator;
260-
options.auth = &server_authenticator;
259+
std::unique_ptr<openmldb::auth::UserAccessManager> user_access_manager;
260+
std::unique_ptr<openmldb::authn::BRPCAuthenticator> server_authenticator;
261+
262+
if (!FLAGS_skip_grant_tables) {
263+
user_access_manager = std::make_unique<openmldb::auth::UserAccessManager>(tablet->GetSystemTableIterator());
264+
server_authenticator = std::make_unique<openmldb::authn::BRPCAuthenticator>(
265+
[&user_access_manager](const std::string& host, const std::string& username, const std::string& password) {
266+
return user_access_manager->IsAuthenticated(host, username, password);
267+
});
268+
options.auth = server_authenticator.get();
269+
}
261270
options.num_threads = FLAGS_thread_pool_size;
262271
brpc::Server server;
263272
if (server.AddService(tablet, brpc::SERVER_DOESNT_OWN_SERVICE) != 0) {

0 commit comments

Comments
 (0)