@cryptotaxi247 / netdata-1 / commits / 842ada7cd

implemented API authentication

Costa Tsaousis (ktsaou) committed Feb 22, 2017 at 03:40 UTC 842ada7cd5bcf8d018df718efc629571ba2103fa
8 files changed +182 -29
conf.d/Makefile.am
+1
@@ -4,6 +4,7 @@
4 MAINTAINERCLEANFILES= $(srcdir)/Makefile.in
5
6 dist_config_DATA = \
7 + aggregated_hosts.conf \
8 apps_groups.conf \
9 charts.d.conf \
10 fping.conf \
conf.d/aggregated_hosts.conf new
+75
@@ -0,0 +1,75 @@
1 +# netdata configuration for aggregating data from remote hosts
2 +#
3 +# 1. You need an API key: API_KEY_GENERATED_BY_UUIDGEN
4 +#
5 +# You can generate one with the command: uuidgen
6 +# You can add many API key sections, for different API keys
7 +#
8 +# 2. All options below are used in this order:
9 +#
10 +# a) MACHINE_GUID (settings for each machine)
11 +# b) API_KEY (settings for the API key)
12 +# c) this netdata defaults (as in netdata.conf)
13 +#
14 +# You can combine the above (the more specific will be used).
15 +#
16 +# 3. At the remote host that will be sending metrics, you need
17 +# to add in netdata.conf, the following:
18 +#
19 +# [global]
20 +# central netdata to send all data = 10.11.12.1:19999
21 +# central netdata api key = API_KEY_GENERATED_BY_UUIDGEN
22 +#
23 +# Of course, the same API_KEY_GENERATED_BY_UUIDGEN key must
24 +# given there (the remote host) and here (the central netdata).
25 +#
26 +# -----------------------------------------------------------------------------
27 +
28 +[API_KEY_GENERATED_BY_UUIDGEN]
29 + # You can disable the API key, by setting this to: no
30 + # The default (for unknown API keys) is also: no
31 +# enabled = yes
32 +
33 + # The default history in entries, for all hosts using this API key.
34 + # You can also set it per host below.
35 + # If you don't set it here, the history size of the central netdata
36 + # will be used
37 +# default history = 3600
38 +
39 + # The default memory mode to be used for all hosts using this API key.
40 + # You can also set it per host below.
41 + # If you don't set it here, the memory mode of the central netdata
42 + # will be used
43 +# default memory mode = save
44 +
45 + # Shall we enable health monitoring for the hosts using this API key?
46 + # 3 values:
47 + # yes enable alarms
48 + # no do not enable alarms
49 + # auto enable alarms, only when the host is streaming metrics
50 + # You can also set it per host, below.
51 + # The default is the same as the central netdata
52 +# health enabled by default = auto
53 +
54 +
55 +# -----------------------------------------------------------------------------
56 +# Each netdata has a unique GUID - generated the first time netdata starts.
57 +# You can find it at /var/lib/netdata/registry/netdata.public.unique.id
58 +# The host sending data will have one. If it is static and you can find it,
59 +# you can give settings for each specific host here.
60 +
61 +[MACHINE_GUID]
62 + # This can be used to stop receiving data
63 + # THIS IS NOT A SECURITY MECHANISM - AN ATTACKER CAN SET ANY OTHER GUID.
64 + # Use only the API key for security.
65 +# enabled = yes
66 +
67 + # The number of entries in the database
68 +# history = 3600
69 +
70 + # The memory mode of the database
71 +# memory mode = save
72 +
73 + # Health / alarms control
74 +# health enabled = yes
75 +
src/main.c
+5 -1
@@ -844,8 +844,12 @@ int main(int argc, char **argv) {
844 // --------------------------------------------------------------------
845 // create the listening sockets
846
847 - if(!check_config && !central_netdata_to_push_data)
847 + if(!check_config && !central_netdata_to_push_data) {
848 + char filename[FILENAME_MAX + 1];
849 + snprintfz(filename, FILENAME_MAX, "%s/aggregated_hosts.conf", netdata_configured_config_dir);
850 + appconfig_load(&stream_config, filename, 0);
851 create_listen_sockets();
852 + }
853 }
854
855 // initialize the log files
src/plugins_d.c
+3 -3
@@ -96,7 +96,7 @@ inline size_t pluginsd_process(RRDHOST *host, struct plugind *cd, FILE *fp, int
96 char line[PLUGINSD_LINE_MAX + 1];
97
98 char *words[MAX_WORDS] = { NULL };
99 - uint32_t HOST_HASH = simple_hash("HOST");
99 + /* uint32_t HOST_HASH = simple_hash("HOST"); */
100 uint32_t BEGIN_HASH = simple_hash("BEGIN");
101 uint32_t END_HASH = simple_hash("END");
102 uint32_t FLUSH_HASH = simple_hash("FLUSH");
@@ -205,7 +205,7 @@ inline size_t pluginsd_process(RRDHOST *host, struct plugind *cd, FILE *fp, int
205
206 count++;
207 }
208 - else if(likely(hash == HOST_HASH && !strcmp(s, "HOST"))) {
208 +/* else if(likely(hash == HOST_HASH && !strcmp(s, "HOST"))) {
209 char *guid = words[1];
210 char *hostname = words[2];
211
@@ -221,7 +221,7 @@ inline size_t pluginsd_process(RRDHOST *host, struct plugind *cd, FILE *fp, int
221 }
222
223 host = rrdhost_find_or_create(hostname, guid);
224 - }
224 + } */
225 else if(likely(hash == FLUSH_HASH && !strcmp(s, "FLUSH"))) {
226 debug(D_PLUGINSD, "PLUGINSD: '%s' is requesting a FLUSH", cd->fullfilename);
227 st = NULL;
src/rrd.h
+1 -1
@@ -406,7 +406,7 @@ extern pthread_rwlock_t rrd_rwlock;
406 extern void rrd_init(char *hostname);
407
408 extern RRDHOST *rrdhost_find(const char *guid, uint32_t hash);
409 -extern RRDHOST *rrdhost_find_or_create(const char *hostname, const char *guid);
409 +extern RRDHOST *rrdhost_find_or_create(const char *hostname, const char *guid, int update_every, int history, RRD_MEMORY_MODE mode, int health_enabled);
410
411 #ifdef NETDATA_INTERNAL_CHECKS
412 extern void rrdhost_check_wrlock_int(RRDHOST *host, const char *file, const char *function, const unsigned long line);
src/rrdhost.c
+23 -9
@@ -176,18 +176,32 @@ RRDHOST *rrdhost_create(const char *hostname,
176 return host;
177 }
178
179 -RRDHOST *rrdhost_find_or_create(const char *hostname, const char *guid) {
179 +RRDHOST *rrdhost_find_or_create(const char *hostname, const char *guid, int update_every, int history, RRD_MEMORY_MODE mode, int health_enabled) {
180 debug(D_RRDHOST, "Searching for host '%s' with guid '%s'", hostname, guid);
181
182 RRDHOST *host = rrdhost_find(guid, 0);
183 - if(!host)
184 - host = rrdhost_create(hostname,
185 - guid,
186 - default_rrd_update_every,
187 - default_rrd_history_entries,
188 - default_rrd_memory_mode,
189 - default_health_enabled
190 - );
183 + if(!host) {
184 + host = rrdhost_create(hostname, guid, update_every, history, mode, health_enabled);
185 + }
186 + else {
187 + host->health_enabled = health_enabled;
188 +
189 + if(strcmp(host->hostname, hostname)) {
190 + char *t = host->hostname;
191 + char *n = strdupz(hostname);
192 + host->hostname = n;
193 + freez(t);
194 + }
195 +
196 + if(host->rrd_update_every != update_every)
197 + error("Host '%s' has an update frequency of %d seconds, but the wanted one is %d seconds.", host->hostname, host->rrd_update_every, update_every);
198 +
199 + if(host->rrd_history_entries != history)
200 + error("Host '%s' has history of %d entries, but the wanted one is %d entries.", host->hostname, host->rrd_history_entries, history);
201 +
202 + if(host->rrd_memory_mode != mode)
203 + error("Host '%s' has memory mode '%s', but the wanted one is '%s'.", host->hostname, rrd_memory_mode_name(host->rrd_memory_mode), rrd_memory_mode_name(mode));
204 + }
205
206 return host;
207 }
src/rrdpush.c
+10 -10
@@ -7,7 +7,6 @@ int rrdpush_pipe[2];
7
8 static BUFFER *rrdpush_buffer = NULL;
9 static pthread_mutex_t rrdpush_mutex = PTHREAD_MUTEX_INITIALIZER;
10 -static volatile RRDHOST *last_host = NULL;
10 static volatile int rrdpush_connected = 0;
11
12 static inline void rrdpush_lock() {
@@ -99,8 +98,6 @@ static void reset_all_charts(void) {
98 rrdhost_unlock(host);
99 }
100 rrd_unlock();
102 -
103 - last_host = NULL;
101 }
102
103 void rrdset_done_push(RRDSET *st) {
@@ -123,11 +120,6 @@ void rrdset_done_push(RRDSET *st) {
120 }
121 error_shown = 0;
122
126 - if(st->rrdhost != last_host) {
127 - buffer_sprintf(rrdpush_buffer, "HOST '%s' '%s'\n", st->rrdhost->machine_guid, st->rrdhost->hostname);
128 - last_host = st->rrdhost;
129 - }
130 -
123 rrdset_rdlock(st);
124 if(need_to_send_chart_definition(st))
125 send_chart_definition(st);
@@ -149,7 +141,6 @@ static inline void rrdpush_flush(void) {
141
142 buffer_flush(rrdpush_buffer);
143 reset_all_charts();
152 - last_host = NULL;
144 rrdpush_unlock();
145 }
146
@@ -209,7 +200,16 @@ void *central_netdata_push_thread(void *ptr) {
200 info("STREAM: initializing communication to central netdata at: %s", central_netdata_to_push_data);
201
202 char http[1000 + 1];
212 - snprintfz(http, 1000, "GET /stream?key=%s HTTP/1.1\r\nUser-Agent: netdata-push-service/%s\r\nAccept: */*\r\n\r\n", config_get("global", "central netdata api key", ""), program_version);
203 + snprintfz(http, 1000, "GET /stream?key=%s&hostname=%s&machine_guid=%s&update_every=%d HTTP/1.1\r\n"
204 + "User-Agent: netdata-push-service/%s\r\n"
205 + "Accept: */*\r\n\r\n"
206 + , config_get("global", "central netdata api key", "")
207 + , localhost->hostname
208 + , localhost->machine_guid
209 + , default_rrd_update_every
210 + , program_version
211 + );
212 +
213 if(send_timeout(sock, http, strlen(http), 0, 60) == -1) {
214 close(sock);
215 sock = -1;
src/web_client.c
+64 -5
@@ -1668,13 +1668,18 @@ int web_client_api_old_data_request(RRDHOST *host, struct web_client *w, char *u
1668 }
1669
1670 int validate_stream_api_key(const char *key) {
1671 + if(appconfig_get(&stream_config, key, "enabled", 0))
1672 + return 1;
1673 +
1674 return 0;
1675 }
1676
1677 int web_client_stream_request(RRDHOST *host, struct web_client *w, char *url) {
1675 - info("STREAM request from client '%s:%s', starting as host '%s'", w->client_ip, w->client_port, host->hostname);
1676 -
1677 - char *key = NULL;
1678 + char *key = NULL, *hostname = NULL, *machine_guid = NULL;
1679 + int update_every = default_rrd_update_every;
1680 + int history = default_rrd_history_entries;
1681 + RRD_MEMORY_MODE mode = default_rrd_memory_mode;
1682 + int health_enabled = default_health_enabled;
1683
1684 while(url) {
1685 char *value = mystrsep(&url, "?&");
@@ -1686,6 +1691,12 @@ int web_client_stream_request(RRDHOST *host, struct web_client *w, char *url) {
1691
1692 if(!strcmp(name, "key"))
1693 key = value;
1694 + else if(!strcmp(name, "hostname"))
1695 + hostname = value;
1696 + else if(!strcmp(name, "machine_guid"))
1697 + machine_guid = value;
1698 + else if(!strcmp(name, "update_every"))
1699 + update_every = (int)strtoul(value, NULL, 0);
1700 }
1701
1702 if(!key || !*key) {
@@ -1695,6 +1706,20 @@ int web_client_stream_request(RRDHOST *host, struct web_client *w, char *url) {
1706 return 401;
1707 }
1708
1709 + if(!hostname || !*hostname) {
1710 + error("STREAM [%s]:%s: request without a hostname. Forbidding access.", w->client_ip, w->client_port);
1711 + buffer_flush(w->response.data);
1712 + buffer_sprintf(w->response.data, "You need to send a hostname too.");
1713 + return 400;
1714 + }
1715 +
1716 + if(!machine_guid || !*machine_guid) {
1717 + error("STREAM [%s]:%s: request without a machine GUID. Forbidding access.", w->client_ip, w->client_port);
1718 + buffer_flush(w->response.data);
1719 + buffer_sprintf(w->response.data, "You need to send a machine GUID too.");
1720 + return 400;
1721 + }
1722 +
1723 if(!validate_stream_api_key(key)) {
1724 error("STREAM [%s]:%s: API key '%s' is not allowed. Forbidding access.", w->client_ip, w->client_port, key);
1725 buffer_flush(w->response.data);
@@ -1702,6 +1727,38 @@ int web_client_stream_request(RRDHOST *host, struct web_client *w, char *url) {
1727 return 401;
1728 }
1729
1730 + if(!appconfig_get_boolean(&stream_config, machine_guid, "enabled", 1)) {
1731 + error("STREAM [%s]:%s: machine GUID '%s' is not allowed. Forbidding access.", w->client_ip, w->client_port, machine_guid);
1732 + buffer_flush(w->response.data);
1733 + buffer_sprintf(w->response.data, "Your machine guide is not permitted access.");
1734 + return 404;
1735 + }
1736 +
1737 + // update_every = (int)appconfig_get_number(&stream_config, key, "default update every", update_every);
1738 + update_every = (int)appconfig_get_number(&stream_config, machine_guid, "update every", update_every);
1739 + if(update_every < 0) update_every = 1;
1740 +
1741 + history = (int)appconfig_get_number(&stream_config, key, "default history", history);
1742 + history = (int)appconfig_get_number(&stream_config, machine_guid, "history", history);
1743 + if(history < 5) history = 5;
1744 +
1745 + mode = rrd_memory_mode_id(appconfig_get(&stream_config, key, "default memory mode", rrd_memory_mode_name(mode)));
1746 + mode = rrd_memory_mode_id(appconfig_get(&stream_config, machine_guid, "memory mode", rrd_memory_mode_name(mode)));
1747 +
1748 + health_enabled = appconfig_get_boolean_ondemand(&stream_config, key, "health enabled by default", health_enabled);
1749 + health_enabled = appconfig_get_boolean_ondemand(&stream_config, machine_guid, "health enabled", health_enabled);
1750 +
1751 + host = rrdhost_find_or_create(hostname, machine_guid, update_every, history, mode, health_enabled?1:0);
1752 +
1753 + info("STREAM request from client '%s:%s' for host '%s' with machine_guid '%s': update every = %d, history = %d, memory mode = %s, health %s",
1754 + w->client_ip, w->client_port,
1755 + hostname, machine_guid,
1756 + update_every,
1757 + history,
1758 + rrd_memory_mode_name(mode),
1759 + (health_enabled == CONFIG_BOOLEAN_NO)?"disabled":((health_enabled == CONFIG_BOOLEAN_YES)?"enabled":"auto")
1760 + );
1761 +
1762 struct plugind cd = {
1763 .enabled = 1,
1764 .update_every = default_rrd_update_every,
@@ -1750,9 +1807,11 @@ int web_client_stream_request(RRDHOST *host, struct web_client *w, char *url) {
1807 }
1808
1809 // call the plugins.d processor to receive the metrics
1753 - info("STREAM [%s]:%s: connecting client to plugins.d.", w->client_ip, w->client_port);
1810 + info("STREAM [%s]:%s: connecting client to plugins.d on host '%s' with machine GUID '%s'.", w->client_ip, w->client_port, host->hostname, host->machine_guid);
1811 size_t count = pluginsd_process(host, &cd, fp, 1);
1755 - error("STREAM [%s]:%s: client disconnected.", w->client_ip, w->client_port);
1812 + error("STREAM [%s]:%s: client disconnected (host '%s', machine GUID '%s').", w->client_ip, w->client_port, host->hostname, host->machine_guid);
1813 + if(health_enabled == CONFIG_BOOLEAN_AUTO)
1814 + host->health_enabled = 0;
1815
1816 // close all sockets, to let the socket worker we are done
1817 fclose(fp);