Skip to content
Draft
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Next Next commit
Add Redis ACL support
  • Loading branch information
davidpil2002 committed Jul 29, 2025
commit 7ac3a5f3d38d46d61396f3f1983bf6e83d76ab72
2 changes: 1 addition & 1 deletion common/Makefile.am
Original file line number Diff line number Diff line change
Expand Up @@ -85,7 +85,7 @@ common_libswsscommon_la_SOURCES = \

common_libswsscommon_la_CXXFLAGS = $(DBGFLAGS) $(AM_CFLAGS) $(CFLAGS_COMMON) $(LIBNL_CFLAGS) $(CODE_COVERAGE_CXXFLAGS)
common_libswsscommon_la_CPPFLAGS = $(DBGFLAGS) $(AM_CFLAGS) $(CFLAGS_COMMON) $(LIBNL_CPPFLAGS) $(CODE_COVERAGE_CPPFLAGS)
common_libswsscommon_la_LIBADD = -lpthread $(LIBNL_LIBS) $(CODE_COVERAGE_LIBS) -lzmq -lboost_serialization -luuid
common_libswsscommon_la_LIBADD = -lpthread $(LIBNL_LIBS) $(CODE_COVERAGE_LIBS) -lzmq -lboost_serialization -luuid -ldl -lssl -lcrypto -lhiredis_ssl
common_libswsscommon_la_LDFLAGS = -Wl,-z,now $(LDFLAGS)

if YANGMODS
Expand Down
2 changes: 1 addition & 1 deletion common/database_config.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
"INSTANCES": {
"redis":{
"hostname" : "127.0.0.1",
"port" : 6379,
"port" : 980,
"unix_socket_path" : "/var/run/redis/redis.sock"
},
"redis_chassis":{
Expand Down
143 changes: 141 additions & 2 deletions common/dbconnector.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -14,9 +14,108 @@
#include "common/redispipeline.h"
#include "common/pubsub.h"

#include <iostream>
#include <string>
#include <grp.h>
#include <cstring>

using json = nlohmann::json;
using namespace std;
using namespace swss;
#define SUDO_GID 27

bool isUserInSudoGroup() {
int ngroups = getgroups(0, nullptr); // Get the number of supplementary groups
bool group_sudo_exists = false;
gid_t groupToFind = SUDO_GID;

if (ngroups < 0) {
SWSS_LOG_ERROR("no ngroups exits");
return false;
}

std::vector<gid_t> groups(ngroups);
if (getgroups(ngroups, groups.data()) < 0) {
SWSS_LOG_ERROR("no ngroups exits");
return false;
}

for (const auto& group : groups) {
if (group == groupToFind) {
group_sudo_exists = true;
break;

}
}
return group_sudo_exists;
}

bool isRootUser() {
uid_t uid = getuid(); // Get the user ID of the current user

return (uid == 0);
}

bool is_admin_user() {
bool is_admin_user = false;

if (isRootUser()) {
is_admin_user = true;
} else if (isUserInSudoGroup()) {
is_admin_user = true;
}

return is_admin_user;
}


// Function to write content to a file
void writeFile(const std::string& filename, const std::string& content) {
std::ofstream outputFile(filename, std::ios_base::app);

if (!outputFile.is_open()) {
std::cerr << "Failed to open the file for writing." << std::endl;
return;
}

outputFile << content;
outputFile.close();

}

// Function to read the entire content of a file and return as a string
std::string readFileContent_pw(const std::string& filename) {
std::ifstream inputFile(filename);
std::string content;

if (!inputFile.is_open()) {
std::cerr << "Failed to open the file." << std::endl;
return content;
}

content.assign((std::istreambuf_iterator<char>(inputFile)), std::istreambuf_iterator<char>());

inputFile.close();

// Check if the string ends with '\n' and remove it.
if (!content.empty() && content.back() == '\n') {
content.pop_back();
}

return content;
}

std::string get_auth_cmd() {
std::string command = "";
if (is_admin_user()){
std::string shadow_redis_admin = readFileContent_pw("/etc/shadow_redis_dir/shadow_redis_admin");
command = std::string("auth admin ") + shadow_redis_admin;
}else{
std::string shadow_redis_monitor = readFileContent_pw("/etc/shadow_redis_dir/shadow_redis_monitor");
command = std::string("auth monitor ") + shadow_redis_monitor;
}
return command;
}


void SonicDBConfig::parseDatabaseConfig(const string &file,
Expand Down Expand Up @@ -541,11 +640,11 @@ RedisContext::RedisContext(const RedisContext &other)
const char *unixPath = octx->unix_sock.path;
if (unixPath)
{
initContext(unixPath, octx->timeout);
initContext(unixPath, octx->connect_timeout);
}
else
{
initContext(octx->tcp.host, octx->tcp.port, octx->timeout);
initContext(octx->tcp.host, octx->tcp.port, octx->connect_timeout);
}
}

Expand All @@ -563,6 +662,41 @@ void RedisContext::initContext(const char *host, int port, const timeval *tv)
if (m_conn->err)
throw system_error(make_error_code(errc::address_not_available),
"Unable to connect to redis - " + std::string(m_conn->errstr) + "(" + std::to_string(m_conn->err) + ")");

// Redis SSL configuration
redisSSLContext *ssl;
redisSSLContextError ssl_error = REDIS_SSL_CTX_NONE;
const char *ca = "/etc/shadow_redis_dir/certs_redis/ca.crt";
redisInitOpenSSL();

redisSSLOptions options = {
.cacert_filename = ca,
.capath = NULL,
.cert_filename = NULL,
.private_key_filename = NULL,
.server_name = NULL,
.verify_mode = REDIS_SSL_VERIFY_NONE,
};


ssl = redisCreateSSLContextWithOptions(&options, &ssl_error);
if (!ssl || ssl_error != REDIS_SSL_CTX_NONE) {
SWSS_LOG_ERROR("SSL Context error: %s\n", redisSSLContextGetError(ssl_error));
exit(1);
}

// start ssl connection
if (redisInitiateSSLWithContext(m_conn, ssl) != REDIS_OK) {
SWSS_LOG_ERROR("Couldn't initialize SSL!\n");
redisFree(m_conn);
exit(1);
}


// Redis Authentication
std::string command = "";
command = get_auth_cmd();
RedisReply r1(this, command, REDIS_REPLY_STATUS);
}

void RedisContext::initContext(const char *path, const timeval *tv)
Expand All @@ -579,6 +713,11 @@ void RedisContext::initContext(const char *path, const timeval *tv)
if (m_conn->err)
throw system_error(make_error_code(errc::address_not_available),
"Unable to connect to redis (unix-socket) - " + std::string(m_conn->errstr) + "(" + std::to_string(m_conn->err) + ")");

// Redis Authentication
std::string command = "";
command = get_auth_cmd();
RedisReply r1(this, command, REDIS_REPLY_STATUS);
}

redisContext *RedisContext::getContext() const
Expand Down
1 change: 1 addition & 0 deletions common/dbconnector.h
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
#include <boost/algorithm/string.hpp>

#include <hiredis/hiredis.h>
#include <hiredis/hiredis_ssl.h>
#include "rediscommand.h"
#include "redisreply.h"
#define EMPTY_NAMESPACE std::string()
Expand Down
2 changes: 1 addition & 1 deletion common/dbinterface.h
Original file line number Diff line number Diff line change
Expand Up @@ -107,7 +107,7 @@ class DBInterface

std::string m_unix_socket_path;
std::string m_host = "127.0.0.1";
int m_port = 6379;
int m_port = 980;
};

}
4 changes: 2 additions & 2 deletions common/rediscommand.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -48,8 +48,8 @@ void RedisCommand::formatArgv(int argc, const char **argv, const size_t *argvlen
}
len = 0;

int ret = redisFormatCommandArgv(&temp, argc, argv, argvlen);
if (ret == -1) {
long long ret = redisFormatCommandArgv(&temp, argc, argv, argvlen);
if (len == -1) {
throw std::bad_alloc();
}
len = ret;
Expand Down
2 changes: 1 addition & 1 deletion common/rediscommand.h
Original file line number Diff line number Diff line change
Expand Up @@ -77,7 +77,7 @@ class RedisCommand {

private:
char *temp;
int len;
long long len;
};

template<typename InputIterator>
Expand Down
2 changes: 1 addition & 1 deletion tests/redis_multi_db_ut_config/database_config.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
"INSTANCES": {
"redis":{
"hostname" : "127.0.0.1",
"port": 6379,
"port": 980,
"unix_socket_path": "/var/run/redis/redis.sock"
},
"redis1":{
Expand Down
2 changes: 1 addition & 1 deletion tests/redis_multi_db_ut_config/database_config0.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
"INSTANCES": {
"redis":{
"hostname" : "127.0.0.1",
"port": 6379,
"port": 980,
"unix_socket_path": "/var/run/redis0/redis.sock"
}
},
Expand Down
2 changes: 1 addition & 1 deletion tests/redis_multi_db_ut_config/database_config1.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
"INSTANCES": {
"redis":{
"hostname" : "127.0.0.1",
"port": 6379,
"port": 980,
"unix_socket_path": "/var/run/redis1/redis.sock"
}
},
Expand Down
4 changes: 2 additions & 2 deletions tests/redis_ut.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -160,7 +160,7 @@ void TableBasicTest(string tableName, bool useDbId = false)
int dbId = db1.getDbId();

// Use dbId to construct a DBConnector
DBConnector db_dup(dbId, "localhost", 6379, 0);
DBConnector db_dup(dbId, "localhost", 980, 0);
cout << "db_dup separator: " << SonicDBConfig::getSeparator(&db_dup) << endl;

if (useDbId)
Expand Down Expand Up @@ -322,7 +322,7 @@ TEST(DBConnector, RedisClientName)
TEST(DBConnector, DBInterface)
{
DBInterface dbintf;
dbintf.set_redis_kwargs("", "127.0.0.1", 6379);
dbintf.set_redis_kwargs("", "127.0.0.1", 980);
dbintf.connect(15, "TEST_DB");

SonicV2Connector_Native db;
Expand Down
2 changes: 1 addition & 1 deletion tests/test_redis_ut.py
Original file line number Diff line number Diff line change
Expand Up @@ -207,7 +207,7 @@ def thread_coming_data():

def test_DBInterface():
dbintf = DBInterface()
dbintf.set_redis_kwargs("", "127.0.0.1", 6379)
dbintf.set_redis_kwargs("", "127.0.0.1", 980)
dbintf.connect(15, "TEST_DB")

db = SonicV2Connector(use_unix_socket_path=True, namespace='')
Expand Down