summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authoraradz44 <112960166+aradz44@users.noreply.github.com>2022-10-07 20:19:34 +0300
committerGitHub <noreply@github.com>2022-10-07 10:19:34 -0700
commit8e1941534388101f7e936bdf1126eda0036eb9fe (patch)
tree6462306cc6237eab8ed8cd39aa7fb375c7ef7fa7
parent210ad2e4dbed843ef91c2d291a5823d7c3a5cb66 (diff)
downloadredis-8e1941534388101f7e936bdf1126eda0036eb9fe.tar.gz
Added authentication failure and access denied metrics (#11288)
Added authentication failure and access denied metrics
-rw-r--r--src/acl.c18
-rw-r--r--src/server.c21
-rw-r--r--src/server.h10
-rw-r--r--tests/unit/acl.tcl65
4 files changed, 114 insertions, 0 deletions
diff --git a/src/acl.c b/src/acl.c
index 4b959433e..090430da2 100644
--- a/src/acl.c
+++ b/src/acl.c
@@ -2479,6 +2479,21 @@ void ACLFreeLogEntry(void *leptr) {
zfree(le);
}
+/* Update the relevant counter by the reason */
+void ACLUpdateInfoMetrics(int reason){
+ if (reason == ACL_DENIED_AUTH) {
+ server.acl_info.user_auth_failures++;
+ } else if (reason == ACL_DENIED_CMD) {
+ server.acl_info.invalid_cmd_accesses++;
+ } else if (reason == ACL_DENIED_KEY) {
+ server.acl_info.invalid_key_accesses++;
+ } else if (reason == ACL_DENIED_CHANNEL) {
+ server.acl_info.invalid_channel_accesses++;
+ } else {
+ serverPanic("Unknown ACL_DENIED encoding");
+ }
+}
+
/* Adds a new entry in the ACL log, making sure to delete the old entry
* if we reach the maximum length allowed for the log. This function attempts
* to find similar entries in the current log in order to bump the counter of
@@ -2495,6 +2510,9 @@ void ACLFreeLogEntry(void *leptr) {
* If `object` is not NULL, this functions takes over it.
*/
void addACLLogEntry(client *c, int reason, int context, int argpos, sds username, sds object) {
+ /* Update ACL info metrics */
+ ACLUpdateInfoMetrics(reason);
+
/* Create a new entry. */
struct ACLLogEntry *le = zmalloc(sizeof(*le));
le->count = 1;
diff --git a/src/server.c b/src/server.c
index d5b3ea690..cb1e0447a 100644
--- a/src/server.c
+++ b/src/server.c
@@ -2536,6 +2536,12 @@ void initServer(void) {
server.repl_good_slaves_count = 0;
server.last_sig_received = 0;
+ /* Initiate acl info struct */
+ server.acl_info.invalid_cmd_accesses = 0;
+ server.acl_info.invalid_key_accesses = 0;
+ server.acl_info.user_auth_failures = 0;
+ server.acl_info.invalid_channel_accesses = 0;
+
/* Create the timer callback, this is our way to process many background
* operations incrementally, like clients timeout, eviction of unaccessed
* expired keys and so forth. */
@@ -5167,6 +5173,20 @@ sds genRedisInfoStringCommandStats(sds info, dict *commands) {
return info;
}
+/* Writes the ACL metrics to the info */
+sds genRedisInfoStringACLStats(sds info) {
+ info = sdscatprintf(info,
+ "acl_access_denied_auth:%lld\r\n"
+ "acl_access_denied_cmd:%lld\r\n"
+ "acl_access_denied_key:%lld\r\n"
+ "acl_access_denied_channel:%lld\r\n",
+ server.acl_info.user_auth_failures,
+ server.acl_info.invalid_cmd_accesses,
+ server.acl_info.invalid_key_accesses,
+ server.acl_info.invalid_channel_accesses);
+ return info;
+}
+
sds genRedisInfoStringLatencyStats(sds info, dict *commands) {
struct redisCommand *c;
dictEntry *de;
@@ -5778,6 +5798,7 @@ sds genRedisInfoString(dict *section_dict, int all_sections, int everything) {
server.stat_io_writes_processed,
server.stat_reply_buffer_shrinks,
server.stat_reply_buffer_expands);
+ info = genRedisInfoStringACLStats(info);
}
/* Replication */
diff --git a/src/server.h b/src/server.h
index c88087164..74e4098db 100644
--- a/src/server.h
+++ b/src/server.h
@@ -1189,6 +1189,14 @@ typedef struct client {
char *buf;
} client;
+/* ACL information */
+typedef struct aclInfo {
+ long long user_auth_failures; /* Auth failure counts on user level */
+ long long invalid_cmd_accesses; /* Invalid command accesses that user doesn't have permission to */
+ long long invalid_key_accesses; /* Invalid key accesses that user doesn't have permission to */
+ long long invalid_channel_accesses; /* Invalid channel accesses that user doesn't have permission to */
+} aclInfo;
+
struct saveparam {
time_t seconds;
int changes;
@@ -1899,6 +1907,7 @@ struct redisServer {
the old "requirepass" directive for
backward compatibility with Redis <= 5. */
int acl_pubsub_default; /* Default ACL pub/sub channels flag */
+ aclInfo acl_info; /* ACL info */
/* Assert & bug reporting */
int watchdog_period; /* Software watchdog period in ms. 0 = off */
/* System hardware info */
@@ -2798,6 +2807,7 @@ void ACLFreeUserAndKillClients(user *u);
void addACLLogEntry(client *c, int reason, int context, int argpos, sds username, sds object);
const char* getAclErrorMessage(int acl_res);
void ACLUpdateDefaultUserPassword(sds password);
+sds genRedisInfoStringACLStats(sds info);
/* Sorted sets data type */
diff --git a/tests/unit/acl.tcl b/tests/unit/acl.tcl
index 0900d8e03..9160b641a 100644
--- a/tests/unit/acl.tcl
+++ b/tests/unit/acl.tcl
@@ -751,6 +751,71 @@ start_server {tags {"acl external:skip"}} {
catch {r ACL load} err
set err
} {*Redis instance is not configured to use an ACL file*}
+
+ # If there is an AUTH failure the metric increases
+ test {ACL-Metrics user AUTH failure} {
+ set current_auth_failures [s acl_access_denied_auth]
+ set current_invalid_cmd_accesses [s acl_access_denied_cmd]
+ set current_invalid_key_accesses [s acl_access_denied_key]
+ set current_invalid_channel_accesses [s acl_access_denied_channel]
+ assert_error "*WRONGPASS*" {r AUTH notrealuser 1233456}
+ assert {[s acl_access_denied_auth] eq [expr $current_auth_failures + 1]}
+ assert_error "*WRONGPASS*" {r HELLO 3 AUTH notrealuser 1233456}
+ assert {[s acl_access_denied_auth] eq [expr $current_auth_failures + 2]}
+ assert_error "*WRONGPASS*" {r HELLO 2 AUTH notrealuser 1233456}
+ assert {[s acl_access_denied_auth] eq [expr $current_auth_failures + 3]}
+ assert {[s acl_access_denied_cmd] eq $current_invalid_cmd_accesses}
+ assert {[s acl_access_denied_key] eq $current_invalid_key_accesses}
+ assert {[s acl_access_denied_channel] eq $current_invalid_channel_accesses}
+ }
+
+ # If a user try to access an unauthorized command the metric increases
+ test {ACL-Metrics invalid command accesses} {
+ set current_auth_failures [s acl_access_denied_auth]
+ set current_invalid_cmd_accesses [s acl_access_denied_cmd]
+ set current_invalid_key_accesses [s acl_access_denied_key]
+ set current_invalid_channel_accesses [s acl_access_denied_channel]
+ r ACL setuser invalidcmduser on >passwd nocommands
+ r AUTH invalidcmduser passwd
+ assert_error "*no permissions to run the * command*" {r acl list}
+ r AUTH default ""
+ assert {[s acl_access_denied_auth] eq $current_auth_failures}
+ assert {[s acl_access_denied_cmd] eq [expr $current_invalid_cmd_accesses + 1]}
+ assert {[s acl_access_denied_key] eq $current_invalid_key_accesses}
+ assert {[s acl_access_denied_channel] eq $current_invalid_channel_accesses}
+ }
+
+ # If a user try to access an unauthorized key the metric increases
+ test {ACL-Metrics invalid key accesses} {
+ set current_auth_failures [s acl_access_denied_auth]
+ set current_invalid_cmd_accesses [s acl_access_denied_cmd]
+ set current_invalid_key_accesses [s acl_access_denied_key]
+ set current_invalid_channel_accesses [s acl_access_denied_channel]
+ r ACL setuser invalidkeyuser on >passwd resetkeys allcommands
+ r AUTH invalidkeyuser passwd
+ assert_error "*no permissions to access one of the keys*" {r get x}
+ r AUTH default ""
+ assert {[s acl_access_denied_auth] eq $current_auth_failures}
+ assert {[s acl_access_denied_cmd] eq $current_invalid_cmd_accesses}
+ assert {[s acl_access_denied_key] eq [expr $current_invalid_key_accesses + 1]}
+ assert {[s acl_access_denied_channel] eq $current_invalid_channel_accesses}
+ }
+
+ # If a user try to access an unauthorized channel the metric increases
+ test {ACL-Metrics invalid channels accesses} {
+ set current_auth_failures [s acl_access_denied_auth]
+ set current_invalid_cmd_accesses [s acl_access_denied_cmd]
+ set current_invalid_key_accesses [s acl_access_denied_key]
+ set current_invalid_channel_accesses [s acl_access_denied_channel]
+ r ACL setuser invalidchanneluser on >passwd resetchannels allcommands
+ r AUTH invalidkeyuser passwd
+ assert_error "*no permissions to access one of the channels*" {r subscribe x}
+ r AUTH default ""
+ assert {[s acl_access_denied_auth] eq $current_auth_failures}
+ assert {[s acl_access_denied_cmd] eq $current_invalid_cmd_accesses}
+ assert {[s acl_access_denied_key] eq $current_invalid_key_accesses}
+ assert {[s acl_access_denied_channel] eq [expr $current_invalid_channel_accesses + 1]}
+ }
}
set server_path [tmpdir "server.acl"]