mirror of
https://git.haproxy.org/git/haproxy.git/
synced 2025-09-25 07:41:36 +02:00
[MEDIUM] add access restrictions to the stats socket
The stats socket can now run at 3 different levels : - user - operator (default one) - admin These levels are used to restrict access to some information and commands. Only the admin can clear all stats. A user cannot clear anything nor access sensible data such as sessions or errors.
This commit is contained in:
parent
2f6bf2b82c
commit
6162db2a81
@ -476,13 +476,25 @@ pidfile <pidfile>
|
|||||||
starting the process. See also "daemon".
|
starting the process. See also "daemon".
|
||||||
|
|
||||||
stats socket <path> [{uid | user} <uid>] [{gid | group} <gid>] [mode <mode>]
|
stats socket <path> [{uid | user} <uid>] [{gid | group} <gid>] [mode <mode>]
|
||||||
|
[level <level>]
|
||||||
|
|
||||||
Creates a UNIX socket in stream mode at location <path>. Any previously
|
Creates a UNIX socket in stream mode at location <path>. Any previously
|
||||||
existing socket will be backed up then replaced. Connections to this socket
|
existing socket will be backed up then replaced. Connections to this socket
|
||||||
will get a CSV-formated output of the process statistics in response to the
|
will return various statictics outputs and even allow some commands to be
|
||||||
"show stat" command followed by a line feed, more general process information
|
issued. Please consult section 9.2 "Unix Socket commands" for more details.
|
||||||
in response to the "show info" command followed by a line feed, and a
|
|
||||||
complete list of all existing sessions in response to the "show sess" command
|
An optional "level" parameter can be specified to restrict the nature of
|
||||||
followed by a line feed.
|
the commands that can be issued on the socket :
|
||||||
|
- "user" is the least privileged level ; only non-sensitive stats can be
|
||||||
|
read, and no change is allowed. It would make sense on systems where it
|
||||||
|
is not easy to restrict access to the socket.
|
||||||
|
|
||||||
|
- "operator" is the default level and fits most common uses. All data can
|
||||||
|
be read, and only non-sensible changes are permitted (eg: clear max
|
||||||
|
counters).
|
||||||
|
|
||||||
|
- "admin" should be used with care, as everything is permitted (eg: clear
|
||||||
|
all counters).
|
||||||
|
|
||||||
On platforms which support it, it is possible to restrict access to this
|
On platforms which support it, it is possible to restrict access to this
|
||||||
socket by specifying numerical IDs after "uid" and "gid", or valid user and
|
socket by specifying numerical IDs after "uid" and "gid", or valid user and
|
||||||
@ -6753,7 +6765,9 @@ quit
|
|||||||
show errors [<iid>]
|
show errors [<iid>]
|
||||||
Dump last known request and response errors collected by frontends and
|
Dump last known request and response errors collected by frontends and
|
||||||
backends. If <iid> is specified, the limit the dump to errors concerning
|
backends. If <iid> is specified, the limit the dump to errors concerning
|
||||||
either frontend or backend whose ID is <iid>.
|
either frontend or backend whose ID is <iid>. This command is restricted
|
||||||
|
and can only be issued on sockets configured for levels "operator" or
|
||||||
|
"admin".
|
||||||
|
|
||||||
The errors which may be collected are the last request and response errors
|
The errors which may be collected are the last request and response errors
|
||||||
caused by protocol violations, often due to invalid characters in header
|
caused by protocol violations, often due to invalid characters in header
|
||||||
@ -6806,7 +6820,9 @@ show info
|
|||||||
|
|
||||||
show sess
|
show sess
|
||||||
Dump all known sessions. Avoid doing this on slow connections as this can
|
Dump all known sessions. Avoid doing this on slow connections as this can
|
||||||
be huge.
|
be huge. This command is restricted and can only be issued on sockets
|
||||||
|
configured for levels "operator" or "admin".
|
||||||
|
|
||||||
|
|
||||||
show stat [<iid> <type> <sid>]
|
show stat [<iid> <type> <sid>]
|
||||||
Dump statistics in the CSV format. By passing <id>, <type> and <sid>, it is
|
Dump statistics in the CSV format. By passing <id>, <type> and <sid>, it is
|
||||||
@ -6846,11 +6862,14 @@ clear counters
|
|||||||
Clear the max values of the statistics counters in each proxy (frontend &
|
Clear the max values of the statistics counters in each proxy (frontend &
|
||||||
backend) and in each server. The cumulated counters are not affected. This
|
backend) and in each server. The cumulated counters are not affected. This
|
||||||
can be used to get clean counters after an incident, without having to
|
can be used to get clean counters after an incident, without having to
|
||||||
restart nor to clear traffic counters.
|
restart nor to clear traffic counters. This command is restricted and can
|
||||||
|
only be issued on sockets configured for levels "operator" or "admin".
|
||||||
|
|
||||||
clear counters all
|
clear counters all
|
||||||
Clear all statistics counters in each proxy (frontend & backend) and in each
|
Clear all statistics counters in each proxy (frontend & backend) and in each
|
||||||
server. This has the same effect as restarting.
|
server. This has the same effect as restarting. This command is restricted
|
||||||
|
and can only be issued on sockets configured for level "admin".
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Local variables:
|
* Local variables:
|
||||||
|
@ -54,6 +54,11 @@
|
|||||||
/* platform-specific options */
|
/* platform-specific options */
|
||||||
#define GTUNE_USE_SPLICE (1<<5)
|
#define GTUNE_USE_SPLICE (1<<5)
|
||||||
|
|
||||||
|
/* Access level for a stats socket */
|
||||||
|
#define ACCESS_LVL_NONE 0
|
||||||
|
#define ACCESS_LVL_USER 1
|
||||||
|
#define ACCESS_LVL_OPER 2
|
||||||
|
#define ACCESS_LVL_ADMIN 3
|
||||||
|
|
||||||
/* FIXME : this will have to be redefined correctly */
|
/* FIXME : this will have to be redefined correctly */
|
||||||
struct global {
|
struct global {
|
||||||
|
@ -101,6 +101,7 @@ struct listener {
|
|||||||
uid_t uid; /* -1 to leave unchanged */
|
uid_t uid; /* -1 to leave unchanged */
|
||||||
gid_t gid; /* -1 to leave unchanged */
|
gid_t gid; /* -1 to leave unchanged */
|
||||||
mode_t mode; /* 0 to leave unchanged */
|
mode_t mode; /* 0 to leave unchanged */
|
||||||
|
int level; /* access level (ACCESS_LVL_*) */
|
||||||
} ux;
|
} ux;
|
||||||
} perm;
|
} perm;
|
||||||
char *interface; /* interface name or NULL */
|
char *interface; /* interface name or NULL */
|
||||||
|
@ -69,6 +69,15 @@ const struct chunk stats_sock_usage = {
|
|||||||
.len = sizeof(stats_sock_usage_msg)-1
|
.len = sizeof(stats_sock_usage_msg)-1
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const char stats_permission_denied_msg[] =
|
||||||
|
"Permission denied\n"
|
||||||
|
"";
|
||||||
|
|
||||||
|
const struct chunk stats_permission_denied = {
|
||||||
|
.str = (char *)&stats_permission_denied_msg,
|
||||||
|
.len = sizeof(stats_permission_denied_msg)-1
|
||||||
|
};
|
||||||
|
|
||||||
/* This function parses a "stats" statement in the "global" section. It returns
|
/* This function parses a "stats" statement in the "global" section. It returns
|
||||||
* -1 if there is any error, otherwise zero. If it returns -1, it may write an
|
* -1 if there is any error, otherwise zero. If it returns -1, it may write an
|
||||||
* error message into ther <err> buffer, for at most <errlen> bytes, trailing
|
* error message into ther <err> buffer, for at most <errlen> bytes, trailing
|
||||||
@ -129,6 +138,7 @@ static int stats_parse_global(char **args, int section_type, struct proxy *curpx
|
|||||||
global.stats_sock.analysers = 0;
|
global.stats_sock.analysers = 0;
|
||||||
global.stats_sock.nice = -64; /* we want to boost priority for local stats */
|
global.stats_sock.nice = -64; /* we want to boost priority for local stats */
|
||||||
global.stats_sock.private = global.stats_fe; /* must point to the frontend */
|
global.stats_sock.private = global.stats_fe; /* must point to the frontend */
|
||||||
|
global.stats_sock.perm.ux.level = ACCESS_LVL_OPER; /* default access level */
|
||||||
|
|
||||||
global.stats_fe->timeout.client = MS_TO_TICKS(10000); /* default timeout of 10 seconds */
|
global.stats_fe->timeout.client = MS_TO_TICKS(10000); /* default timeout of 10 seconds */
|
||||||
global.stats_sock.timeout = &global.stats_fe->timeout.client;
|
global.stats_sock.timeout = &global.stats_fe->timeout.client;
|
||||||
@ -172,8 +182,21 @@ static int stats_parse_global(char **args, int section_type, struct proxy *curpx
|
|||||||
global.stats_sock.perm.ux.gid = group->gr_gid;
|
global.stats_sock.perm.ux.gid = group->gr_gid;
|
||||||
cur_arg += 2;
|
cur_arg += 2;
|
||||||
}
|
}
|
||||||
|
else if (!strcmp(args[cur_arg], "level")) {
|
||||||
|
if (!strcmp(args[cur_arg+1], "user"))
|
||||||
|
global.stats_sock.perm.ux.level = ACCESS_LVL_USER;
|
||||||
|
else if (!strcmp(args[cur_arg+1], "operator"))
|
||||||
|
global.stats_sock.perm.ux.level = ACCESS_LVL_OPER;
|
||||||
|
else if (!strcmp(args[cur_arg+1], "admin"))
|
||||||
|
global.stats_sock.perm.ux.level = ACCESS_LVL_ADMIN;
|
||||||
|
else {
|
||||||
|
snprintf(err, errlen, "'stats socket level' only supports 'user', 'operator', and 'admin'");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
cur_arg += 2;
|
||||||
|
}
|
||||||
else {
|
else {
|
||||||
snprintf(err, errlen, "'stats socket' only supports 'user', 'uid', 'group', 'gid', and 'mode'");
|
snprintf(err, errlen, "'stats socket' only supports 'user', 'uid', 'group', 'gid', 'level', and 'mode'");
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -289,9 +312,17 @@ int stats_sock_parse_request(struct stream_interface *si, char *line)
|
|||||||
}
|
}
|
||||||
else if (strcmp(args[1], "sess") == 0) {
|
else if (strcmp(args[1], "sess") == 0) {
|
||||||
s->data_state = DATA_ST_INIT;
|
s->data_state = DATA_ST_INIT;
|
||||||
|
if (s->listener->perm.ux.level < ACCESS_LVL_OPER) {
|
||||||
|
buffer_feed(si->ib, stats_permission_denied.str, stats_permission_denied.len);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
si->st0 = STAT_CLI_O_SESS; // stats_dump_sess_to_buffer
|
si->st0 = STAT_CLI_O_SESS; // stats_dump_sess_to_buffer
|
||||||
}
|
}
|
||||||
else if (strcmp(args[1], "errors") == 0) {
|
else if (strcmp(args[1], "errors") == 0) {
|
||||||
|
if (s->listener->perm.ux.level < ACCESS_LVL_OPER) {
|
||||||
|
buffer_feed(si->ib, stats_permission_denied.str, stats_permission_denied.len);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
if (*args[2])
|
if (*args[2])
|
||||||
s->data_ctx.errors.iid = atoi(args[2]);
|
s->data_ctx.errors.iid = atoi(args[2]);
|
||||||
else
|
else
|
||||||
@ -314,6 +345,13 @@ int stats_sock_parse_request(struct stream_interface *si, char *line)
|
|||||||
if (strcmp(args[2], "all") == 0)
|
if (strcmp(args[2], "all") == 0)
|
||||||
clrall = 1;
|
clrall = 1;
|
||||||
|
|
||||||
|
/* check permissions */
|
||||||
|
if (s->listener->perm.ux.level < ACCESS_LVL_OPER ||
|
||||||
|
(clrall && s->listener->perm.ux.level < ACCESS_LVL_ADMIN)) {
|
||||||
|
buffer_feed(si->ib, stats_permission_denied.str, stats_permission_denied.len);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
for (px = proxy; px; px = px->next) {
|
for (px = proxy; px; px = px->next) {
|
||||||
if (clrall)
|
if (clrall)
|
||||||
memset(&px->counters, 0, sizeof(px->counters));
|
memset(&px->counters, 0, sizeof(px->counters));
|
||||||
|
Loading…
x
Reference in New Issue
Block a user