Added authentication failure and access denied metrics (#11288)

Added authentication failure and access denied metrics
This commit is contained in:
aradz44 2022-10-07 20:19:34 +03:00 committed by GitHub
parent 210ad2e4db
commit 8e19415343
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 114 additions and 0 deletions

View File

@ -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;

View File

@ -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 */

View File

@ -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 */

View File

@ -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"]