@cryptotaxi247 / netdata-1 / commits / 2f7962c9e

Fix parsing SSL ACL along with others (#6468)

* sslstream: ACL parser It was noticed in the issue 6457 that the some ACLs were not parsing correctly when they were along SSL acl, this commit fixes this' * sslstream: remove comments This commit removes the comments that were present while I was testing the code * sslstream: Tests This commit adds ACL tests to check the Netdata response to them * sslstream: Tests Fix the extension to upload the files * sslstream: more tests In this commit I am bringing more tests, including the ssl tests' * sslstream: leading space Remove leading space from variable that was creating problem with shellcheck * sslstream: glob Remove special character from script * sslstream: Makefile The Makefile diretives were pointed to wrong files * sslstream: Missing stream encrypt This commit solves the problem of the stream not be encrypted, but it is not the final solution, because the parser made is incomplete. * sslstream: Finish encrypt channel This commit brings the step that I was missing, the complete encryptation in the communication between Master and Slave * sslstream: Fix argument in script After the latest tests, it was verified that two arguments given to a function inside the script were not correct, with this PR I am fixing this! * sslstream: Fix argument in info Instead to call a function to deliver an integer I was passing a size_t value. Only cmake showed this, but not in my clion! :/ * sslstream: Fix redirect When we were having different SSL configuration, the system were not applying the option for all * sslstream: Update documentation Our documentation was not clear about the rules according our code so I am updating the text to explain for the users * sslstream: Adjust script With this last commit, I am adjusting the tests to avoid false positive * sslstream: Missing elif The previous commit had a missing elif in the shell script * sslstream: Split ports Before this commit Netdata was having SSL as a global option, now it has as a real ACL. * sslstream: reduce context The stream variable will not be affected in the master side, it is only necessary on the slave side, so I am reducing the context of it * sslstream: Force SSL When the user has certificate and he does not set any SSL flag, it is necessary to append the SSL=force flag * sslstream: Default flag It is necessary to have a default flag when the SSL flags are not SET * sslstream: remove comments Remove comments from the scrip * sslstream: moving flag It is better the flag to be set inside socket instead everytime there is a new connection * sslstream: documentation Fix a sentence in the web/server/README.md

thiagoftsm committed Jul 25, 2019 at 16:43 UTC 2f7962c9e154dcce1684f2275387c9b6ac4d0b4c
14 files changed +399 -37
.gitignore
+1
@@ -166,6 +166,7 @@ callgrind.out.*
166 gmon.out
167 gmon.txt
168 sitespeed-result/
169 +tests/acls/acl.sh
170 tests/urls/request.sh
171
172 # tests and temp files
collectors/plugins.d/plugins_d.c
+131 -1
@@ -117,6 +117,103 @@ inline int pluginsd_split_words(char *str, char **words, int max_words) {
117 return quoted_strings_splitter(str, words, max_words, pluginsd_space);
118 }
119
120 +#ifdef ENABLE_HTTPS
121 +/**
122 + * Update Buffer
123 + *
124 + * Update the temporary buffer used to parse data received from slave
125 + *
126 + * @param output is a pointer to the vector where I will store the data
127 + * @param ssl is the connection pointer with the server
128 + *
129 + * @return it returns the total of bytes read on success and a negative number otherwise
130 + */
131 +int pluginsd_update_buffer(char *output, SSL *ssl) {
132 + ERR_clear_error();
133 + int bytesleft = SSL_read(ssl, output, PLUGINSD_LINE_MAX_SSL_READ);
134 + if(bytesleft <= 0) {
135 + int sslerrno = SSL_get_error(ssl, bytesleft);
136 + switch(sslerrno) {
137 + case SSL_ERROR_WANT_READ:
138 + case SSL_ERROR_WANT_WRITE:
139 + {
140 + break;
141 + }
142 + default:
143 + {
144 + u_long err;
145 + char buf[256];
146 + int counter = 0;
147 + while ((err = ERR_get_error()) != 0) {
148 + ERR_error_string_n(err, buf, sizeof(buf));
149 + info("%d SSL Handshake error (%s) on socket %d ", counter++, ERR_error_string((long)SSL_get_error(ssl, bytesleft), NULL), SSL_get_fd(ssl));
150 + }
151 + }
152 +
153 + }
154 + } else {
155 + output[bytesleft] = '\0';
156 + }
157 +
158 + return bytesleft;
159 +}
160 +
161 +/**
162 + * Get from Buffer
163 + *
164 + * Get data to process from buffer
165 + *
166 + * @param output is the output vector that will be used to parse the string.
167 + * @param bytesread the amount of bytes read in the previous iteration.
168 + * @param input the input vector where there are data to process
169 + * @param ssl a pointer to the connection with the server
170 + * @param src the first address of the input, because sometime will be necessary to restart the addr with it.
171 + *
172 + * @return It returns a pointer for the next iteration on success and NULL otherwise.
173 + */
174 +char * pluginsd_get_from_buffer(char *output, int *bytesread, char *input, SSL *ssl, char *src) {
175 + int copying = 1;
176 + char *endbuffer;
177 + size_t length;
178 + while(copying) {
179 + if(*bytesread > 0) {
180 + endbuffer = strchr(input, '\n');
181 + if(endbuffer) {
182 + copying = 0;
183 + endbuffer++; //Advance due the fact I wanna copy '\n'
184 + length = endbuffer - input;
185 + *bytesread -= length;
186 +
187 + memcpy(output, input, length);
188 + output += length;
189 + *output = '\0';
190 + input += length;
191 + }else {
192 + length = strlen(input);
193 + memcpy(output, input, length);
194 + output += length;
195 + input = src;
196 +
197 + *bytesread = pluginsd_update_buffer(input, ssl);
198 + if(*bytesread <= 0) {
199 + input = NULL;
200 + copying = 0;
201 + }
202 + }
203 + }else {
204 + //reduce sample of bytes read, print the length
205 + *bytesread = pluginsd_update_buffer(input, ssl);
206 + if(*bytesread <= 0) {
207 + input = NULL;
208 + copying = 0;
209 + }
210 + }
211 + }
212 +
213 + return input;
214 +}
215 +#endif
216 +
217 inline size_t pluginsd_process(RRDHOST *host, struct plugind *cd, FILE *fp, int trust_durations) {
218 int enabled = cd->enabled;
219
@@ -149,10 +246,43 @@ inline size_t pluginsd_process(RRDHOST *host, struct plugind *cd, FILE *fp, int
246 goto cleanup;
247 }
248
249 +#ifdef ENABLE_HTTPS
250 + int bytesleft = 0;
251 + char tmpbuffer[PLUGINSD_LINE_MAX];
252 + char *readfrom;
253 +#endif
254 while(!ferror(fp)) {
255 if(unlikely(netdata_exit)) break;
256
155 - char *r = fgets(line, PLUGINSD_LINE_MAX, fp);
257 + char *r;
258 +#ifdef ENABLE_HTTPS
259 + int normalread = 1;
260 + if(netdata_srv_ctx) {
261 + if(host->ssl.conn && !host->ssl.flags) {
262 + if(!bytesleft) {
263 + r = line;
264 + readfrom = tmpbuffer;
265 + bytesleft = pluginsd_update_buffer(readfrom, host->ssl.conn);
266 + if(bytesleft <= 0) {
267 + break;
268 + }
269 + }
270 +
271 + readfrom = pluginsd_get_from_buffer(line, &bytesleft, readfrom, host->ssl.conn, tmpbuffer);
272 + if(!readfrom) {
273 + r = NULL;
274 + }
275 +
276 + normalread = 0;
277 + }
278 + }
279 +
280 + if(normalread) {
281 + r = fgets(line, PLUGINSD_LINE_MAX, fp);
282 + }
283 +#else
284 + r = fgets(line, PLUGINSD_LINE_MAX, fp);
285 +#endif
286 if(unlikely(!r)) {
287 if(feof(fp))
288 error("read failed: end of file");
collectors/plugins.d/plugins_d.h
+1
@@ -31,6 +31,7 @@
31 #define PLUGINSD_KEYWORD_VARIABLE "VARIABLE"
32
33 #define PLUGINSD_LINE_MAX 1024
34 +#define PLUGINSD_LINE_MAX_SSL_READ 512
35 #define PLUGINSD_MAX_WORDS 20
36
37 #define PLUGINSD_MAX_DIRECTORIES 20
libnetdata/socket/security.c
+15 -3
@@ -7,8 +7,6 @@ SSL_CTX *netdata_client_ctx=NULL;
7 SSL_CTX *netdata_srv_ctx=NULL;
8 const char *security_key=NULL;
9 const char *security_cert=NULL;
10 -int netdata_use_ssl_on_stream = NETDATA_SSL_OPTIONAL;
11 -int netdata_use_ssl_on_http = NETDATA_SSL_FORCE; //We force SSL due safety reasons
10 int netdata_validate_server = NETDATA_SSL_VALID_CERTIFICATE;
11
12 /**
@@ -176,6 +174,9 @@ void security_start_ssl(int selector) {
174 }
175 case NETDATA_SSL_CONTEXT_STREAMING: {
176 netdata_client_ctx = security_initialize_openssl_client();
177 + //This is necessary for the stream, because it is working sometimes with nonblock socket.
178 + //It returns the bitmask afte to change, there is not any description of errors in the documentation
179 + SSL_CTX_set_mode(netdata_client_ctx, SSL_MODE_ENABLE_PARTIAL_WRITE |SSL_MODE_ACCEPT_MOVING_WRITE_BUFFER |SSL_MODE_AUTO_RETRY);
180 break;
181 }
182 case NETDATA_SSL_CONTEXT_OPENTSDB: {
@@ -206,6 +207,17 @@ void security_clean_openssl() {
207 #endif
208 }
209
210 +/**
211 + * Process accept
212 + *
213 + * Process the SSL handshake with the client case it is necessary.
214 + *
215 + * @param ssl is a pointer for the SSL structure
216 + * @param msg is a copy of the first 8 bytes of the initial message received
217 + *
218 + * @return it returns 0 case it performs the handshake, 8 case it is clean connection
219 + * and another integer power of 2 otherwise.
220 + */
221 int security_process_accept(SSL *ssl,int msg) {
222 int sock = SSL_get_fd(ssl);
223 int test;
@@ -250,7 +262,7 @@ int security_process_accept(SSL *ssl,int msg) {
262 debug(D_WEB_CLIENT_ACCESS,"SSL Handshake finished %s errno %d on socket fd %d", ERR_error_string((long)SSL_get_error(ssl, test), NULL), errno, sock);
263 }
264
253 - return 0;
265 + return NETDATA_SSL_HANDSHAKE_COMPLETE;
266 }
267
268 int security_test_certificate(SSL *ssl) {
libnetdata/socket/security.h
+1 -3
@@ -25,7 +25,7 @@
25
26 struct netdata_ssl{
27 SSL *conn; //SSL connection
28 - int flags;
28 + int flags; //The flags for SSL connection
29 };
30
31 extern SSL_CTX *netdata_opentsdb_ctx;
@@ -33,8 +33,6 @@ extern SSL_CTX *netdata_client_ctx;
33 extern SSL_CTX *netdata_srv_ctx;
34 extern const char *security_key;
35 extern const char *security_cert;
36 -extern int netdata_use_ssl_on_stream;
37 -extern int netdata_use_ssl_on_http;
36 extern int netdata_validate_server;
37
38 void security_openssl_library();
libnetdata/socket/socket.c
+40 -26
@@ -301,39 +301,47 @@ void listen_sockets_close(LISTEN_SOCKETS *sockets) {
301 sockets->failed = 0;
302 }
303
304 -WEB_CLIENT_ACL socket_ssl_acl(char *ssl) {
304 +/*
305 + * SSL ACL
306 + *
307 + * Search the SSL acl and apply it case it is set.
308 + *
309 + * @param acl is the acl given by the user.
310 + */
311 +WEB_CLIENT_ACL socket_ssl_acl(char *acl) {
312 + char *ssl = strchr(acl,'^');
313 + if(ssl) {
314 + //Due the format of the SSL command it is always the last command,
315 + //we finish it here to avoid problems with the ACLs
316 + *ssl = '\0';
317 #ifdef ENABLE_HTTPS
306 - if (!strcmp(ssl,"optional")) {
307 - netdata_use_ssl_on_http = NETDATA_SSL_OPTIONAL;
308 - return WEB_CLIENT_ACL_DASHBOARD | WEB_CLIENT_ACL_REGISTRY | WEB_CLIENT_ACL_BADGE | WEB_CLIENT_ACL_MGMT | WEB_CLIENT_ACL_NETDATACONF | WEB_CLIENT_ACL_STREAMING;
309 - }
310 - else if (!strcmp(ssl,"force")) {
311 - netdata_use_ssl_on_stream = NETDATA_SSL_FORCE;
312 - return WEB_CLIENT_ACL_DASHBOARD | WEB_CLIENT_ACL_REGISTRY | WEB_CLIENT_ACL_BADGE | WEB_CLIENT_ACL_MGMT | WEB_CLIENT_ACL_NETDATACONF | WEB_CLIENT_ACL_STREAMING;
313 - }
318 + ssl++;
319 + if (!strncmp("SSL=",ssl,4)) {
320 + ssl += 4;
321 + if (!strcmp(ssl,"optional")) {
322 + return WEB_CLIENT_ACL_SSL_OPTIONAL;
323 + }
324 + else if (!strcmp(ssl,"force")) {
325 + return WEB_CLIENT_ACL_SSL_FORCE;
326 + }
327 + }
328 #endif
329 + }
330
331 return WEB_CLIENT_ACL_NONE;
332 }
333
334 WEB_CLIENT_ACL read_acl(char *st) {
320 - char *ssl = strchr(st,'^');
321 - if (ssl) {
322 - ssl++;
323 - if (!strncmp("SSL=",ssl,4)) {
324 - ssl += 4;
325 - }
326 - socket_ssl_acl(ssl);
327 - }
335 + WEB_CLIENT_ACL ret = socket_ssl_acl(st);
336
329 - if (!strcmp(st,"dashboard")) return WEB_CLIENT_ACL_DASHBOARD;
330 - if (!strcmp(st,"registry")) return WEB_CLIENT_ACL_REGISTRY;
331 - if (!strcmp(st,"badges")) return WEB_CLIENT_ACL_BADGE;
332 - if (!strcmp(st,"management")) return WEB_CLIENT_ACL_MGMT;
333 - if (!strcmp(st,"streaming")) return WEB_CLIENT_ACL_STREAMING;
334 - if (!strcmp(st,"netdata.conf")) return WEB_CLIENT_ACL_NETDATACONF;
337 + if (!strcmp(st,"dashboard")) ret |= WEB_CLIENT_ACL_DASHBOARD;
338 + if (!strcmp(st,"registry")) ret |= WEB_CLIENT_ACL_REGISTRY;
339 + if (!strcmp(st,"badges")) ret |= WEB_CLIENT_ACL_BADGE;
340 + if (!strcmp(st,"management")) ret |= WEB_CLIENT_ACL_MGMT;
341 + if (!strcmp(st,"streaming")) ret |= WEB_CLIENT_ACL_STREAMING;
342 + if (!strcmp(st,"netdata.conf")) ret |= WEB_CLIENT_ACL_NETDATACONF;
343
336 - return socket_ssl_acl(st);
344 + return ret;
345 }
346
347 static inline int bind_to_this(LISTEN_SOCKETS *sockets, const char *definition, uint16_t default_port, int listen_backlog) {
@@ -375,7 +383,7 @@ static inline int bind_to_this(LISTEN_SOCKETS *sockets, const char *definition,
383 error("LISTENER: Cannot create unix socket '%s'", path);
384 sockets->failed++;
385 } else {
378 - acl_flags = WEB_CLIENT_ACL_DASHBOARD | WEB_CLIENT_ACL_REGISTRY | WEB_CLIENT_ACL_BADGE | WEB_CLIENT_ACL_MGMT | WEB_CLIENT_ACL_NETDATACONF | WEB_CLIENT_ACL_STREAMING;
386 + acl_flags = WEB_CLIENT_ACL_DASHBOARD | WEB_CLIENT_ACL_REGISTRY | WEB_CLIENT_ACL_BADGE | WEB_CLIENT_ACL_MGMT | WEB_CLIENT_ACL_NETDATACONF | WEB_CLIENT_ACL_STREAMING | WEB_CLIENT_ACL_SSL_DEFAULT;
387 listen_sockets_add(sockets, fd, AF_UNIX, socktype, protocol_str, path, 0, acl_flags);
388 added++;
389 }
@@ -425,7 +433,13 @@ static inline int bind_to_this(LISTEN_SOCKETS *sockets, const char *definition,
433 }
434 acl_flags |= read_acl(portconfig);
435 } else {
428 - acl_flags = WEB_CLIENT_ACL_DASHBOARD | WEB_CLIENT_ACL_REGISTRY | WEB_CLIENT_ACL_BADGE | WEB_CLIENT_ACL_MGMT | WEB_CLIENT_ACL_NETDATACONF | WEB_CLIENT_ACL_STREAMING;
436 + acl_flags = WEB_CLIENT_ACL_DASHBOARD | WEB_CLIENT_ACL_REGISTRY | WEB_CLIENT_ACL_BADGE | WEB_CLIENT_ACL_MGMT | WEB_CLIENT_ACL_NETDATACONF | WEB_CLIENT_ACL_STREAMING | WEB_CLIENT_ACL_SSL_DEFAULT;
437 + }
438 +
439 + //Case the user does not set the option SSL in the "bind to", but he has
440 + //the certificates, I must redirect, so I am assuming here the default option
441 + if(!(acl_flags & WEB_CLIENT_ACL_SSL_OPTIONAL) && !(acl_flags & WEB_CLIENT_ACL_SSL_FORCE)) {
442 + acl_flags |= WEB_CLIENT_ACL_SSL_DEFAULT;
443 }
444
445 uint32_t scope_id = 0;
libnetdata/socket/socket.h
+7 -1
@@ -17,7 +17,10 @@ typedef enum web_client_acl {
17 WEB_CLIENT_ACL_BADGE = 1 << 2,
18 WEB_CLIENT_ACL_MGMT = 1 << 3,
19 WEB_CLIENT_ACL_STREAMING = 1 << 4,
20 - WEB_CLIENT_ACL_NETDATACONF = 1 << 5
20 + WEB_CLIENT_ACL_NETDATACONF = 1 << 5,
21 + WEB_CLIENT_ACL_SSL_OPTIONAL = 1 << 6,
22 + WEB_CLIENT_ACL_SSL_FORCE = 1 << 7,
23 + WEB_CLIENT_ACL_SSL_DEFAULT = 1 << 8
24 } WEB_CLIENT_ACL;
25
26 #define web_client_can_access_dashboard(w) ((w)->acl & WEB_CLIENT_ACL_DASHBOARD)
@@ -26,6 +29,9 @@ typedef enum web_client_acl {
29 #define web_client_can_access_mgmt(w) ((w)->acl & WEB_CLIENT_ACL_MGMT)
30 #define web_client_can_access_stream(w) ((w)->acl & WEB_CLIENT_ACL_STREAMING)
31 #define web_client_can_access_netdataconf(w) ((w)->acl & WEB_CLIENT_ACL_NETDATACONF)
32 +#define web_client_is_using_ssl_optional(w) ((w)->port_acl & WEB_CLIENT_ACL_SSL_OPTIONAL)
33 +#define web_client_is_using_ssl_force(w) ((w)->port_acl & WEB_CLIENT_ACL_SSL_FORCE)
34 +#define web_client_is_using_ssl_default(w) ((w)->port_acl & WEB_CLIENT_ACL_SSL_DEFAULT)
35
36 typedef struct listen_sockets {
37 struct config *config; // the config file to use
streaming/rrdpush.c
+14 -1
@@ -48,6 +48,7 @@ unsigned int default_rrdpush_enabled = 0;
48 char *default_rrdpush_destination = NULL;
49 char *default_rrdpush_api_key = NULL;
50 char *default_rrdpush_send_charts_matching = NULL;
51 +int netdata_use_ssl_on_stream = NETDATA_SSL_OPTIONAL;
52
53 static void load_stream_conf() {
54 errno = 0;
@@ -801,7 +802,17 @@ void *rrdpush_sender_thread(void *ptr) {
802 rrdpush_buffer_lock(host);
803
804 debug(D_STREAM, "STREAM: Sending data, starting from %zu, size %zu...", begin, buffer_strlen(host->rrdpush_sender_buffer));
804 - ssize_t ret = send(host->rrdpush_sender_socket, &host->rrdpush_sender_buffer->buffer[begin], buffer_strlen(host->rrdpush_sender_buffer) - begin, MSG_DONTWAIT);
805 + ssize_t ret;
806 +#ifdef ENABLE_HTTPS
807 + SSL *conn = host->ssl.conn ;
808 + if(conn && !host->ssl.flags) {
809 + ret = SSL_write(conn,&host->rrdpush_sender_buffer->buffer[begin], buffer_strlen(host->rrdpush_sender_buffer) - begin);
810 + } else {
811 + ret = send(host->rrdpush_sender_socket, &host->rrdpush_sender_buffer->buffer[begin], buffer_strlen(host->rrdpush_sender_buffer) - begin, MSG_DONTWAIT);
812 + }
813 +#else
814 + ret = send(host->rrdpush_sender_socket, &host->rrdpush_sender_buffer->buffer[begin], buffer_strlen(host->rrdpush_sender_buffer) - begin, MSG_DONTWAIT);
815 +#endif
816 if (unlikely(ret == -1)) {
817 if (errno != EAGAIN && errno != EINTR && errno != EWOULDBLOCK) {
818 debug(D_STREAM, "STREAM: Send failed - closing socket...");
@@ -1059,6 +1070,8 @@ static int rrdpush_receive(int fd
1070
1071 info("STREAM %s [receive from [%s]:%s]: initializing communication...", host->hostname, client_ip, client_port);
1072 #ifdef ENABLE_HTTPS
1073 + host->ssl.conn = ssl->conn;
1074 + host->ssl.flags = ssl->flags;
1075 if(send_timeout(ssl,fd, START_STREAMING_PROMPT, strlen(START_STREAMING_PROMPT), 0, 60) != strlen(START_STREAMING_PROMPT)) {
1076 #else
1077 if(send_timeout(fd, START_STREAMING_PROMPT, strlen(START_STREAMING_PROMPT), 0, 60) != strlen(START_STREAMING_PROMPT)) {
tests/Makefile.am
+6
@@ -5,7 +5,11 @@ MAINTAINERCLEANFILES = $(srcdir)/Makefile.in
5
6 CLEANFILES = \
7 health_mgmtapi/health-cmdapi-test.sh \
8 +<<<<<<< HEAD
9 + acls/acl.sh \
10 +=======
11 urls/request.sh \
12 +>>>>>>> 63a4cadd346df71255d2350128eebcf317e81d0f
13 $(NULL)
14
15 include $(top_srcdir)/build/subst.inc
@@ -23,11 +27,13 @@ dist_noinst_DATA = \
27 node.d/fronius.process.spec.js \
28 node.d/fronius.validation.spec.js \
29 health_mgmtapi/health-cmdapi-test.sh.in \
30 + acls/acl.sh.in \
31 urls/request.sh.in \
32 $(NULL)
33
34 dist_plugins_SCRIPTS = \
35 health_mgmtapi/health-cmdapi-test.sh \
36 + acls/acl.sh \
37 urls/request.sh \
38 $(NULL)
39
tests/acls/acl.sh.in new
+119
@@ -0,0 +1,119 @@
1 +#!/bin/bash -x
2 +# SPDX-License-Identifier: GPL-3.0-or-later
3 +
4 +BASICURL="http://127.0.0.1"
5 +BASICURLS="https://127.0.0.1"
6 +
7 +NETDATA_VARLIB_DIR="/var/lib/netdata"
8 +RED='\033[0;31m'
9 +GREEN='\033[0;32m'
10 +YELLOW='\033[0;43m'
11 +
12 +#change the previous acl file and with a new
13 +#and store it on a new file
14 +change_file(){
15 + sed "s/$1/$2/g" netdata.cfg > "$4"
16 +}
17 +
18 +change_ssl_file(){
19 + KEYROW="ssl key = $3/key.pem"
20 + CERTROW="ssl certificate = $3/cert.pem"
21 + sed "s@ssl key =@$KEYROW@g" netdata.ssl.cfg > tmp
22 + sed "s@ssl certificate =@$CERTROW@g" tmp > tmp2
23 + sed "s/$1/$2/g" tmp2 > "$4"
24 +}
25 +
26 +run_acl_tests() {
27 + #Give a time for netdata start properly
28 + sleep 2
29 +
30 + curl -v -k --tls-max 1.2 --create-dirs -o index.html "$2" 2> log_index.txt
31 + curl -v -k --tls-max 1.2 --create-dirs -o netdata.txt "$2/netdata.conf" 2> log_nc.txt
32 + curl -v -k --tls-max 1.2 --create-dirs -o badge.csv "$2/api/v1/badge.svg?chart=cpu.cpu0_interrupts" 2> log_badge.txt
33 + curl -v -k --tls-max 1.2 --create-dirs -o info.txt "$2/api/v1/info" 2> log_info.txt
34 + curl -H "X-Auth-Token: $1" -v -k --tls-max 1.2 --create-dirs -o health.csv "$2/api/v1/manage/health?cmd=LIST" 2> log_health.txt
35 +
36 + TOT=$(grep -c "HTTP/1.1 301" log_*.txt | cut -d: -f2| grep -c 1)
37 + if [ "$TOT" -ne "$4" ]; then
38 + echo -e "${RED}I got a wrong number of redirects($TOT) when SSL is activated, It was expected $4"
39 + rm log_* netdata.conf.test* netdata.txt health.csv index.html badge.csv tmp* key.pem cert.pem info.txt
40 + killall netdata
41 + exit 1
42 + elif [ "$TOT" -eq "$4" ] && [ "$4" -ne "0" ]; then
43 + echo -e "${YELLOW}I got the correct number of redirects($4) when SSL is activated and I try to access with HTTP."
44 + return
45 + fi
46 +
47 + TOT=$(grep -c "HTTP/1.1 200 OK" log_* | cut -d: -f2| grep -c 1)
48 + if [ "$TOT" -ne "$3" ]; then
49 + echo -e "${RED}I got a wrong number of \"200 OK\" from the queries, it was expected $3."
50 + killall netdata
51 + rm log_* netdata.conf.test* netdata.txt health.csv index.html badge.csv tmp* key.pem cert.pem info.txt
52 + exit 1
53 + fi
54 +
55 + echo -e "${GREEN}ACLs were applied correctly"
56 +}
57 +
58 +CONF=$(grep "bind" netdata.cfg)
59 +MUSER=$(grep run netdata.cfg | cut -d= -f2|sed 's/^[ \t]*//')
60 +
61 +openssl req -new -newkey rsa:2048 -days 365 -nodes -x509 -sha512 -subj "/C=US/ST=Denied/L=Somewhere/O=Dis/CN=www.example.com" -keyout key.pem -out cert.pem
62 +chown "$MUSER" key.pem cert.pem
63 +CWD=$(pwd)
64 +
65 +if [ -f "${NETDATA_VARLIB_DIR}/netdata.api.key" ] ;then
66 + read -r TOKEN < "${NETDATA_VARLIB_DIR}/netdata.api.key"
67 +else
68 + TOKEN="NULL"
69 +fi
70 +
71 +change_file "$CONF" " bind to = *" "$CWD" "netdata.conf.test0"
72 +netdata -c "netdata.conf.test0"
73 +run_acl_tests $TOKEN "$BASICURL:19999" 5 0
74 +killall netdata
75 +
76 +change_ssl_file "$CONF" " bind to = *=dashboard|registry|badges|management|netdata.conf *:20000=dashboard|registry|badges|management *:20001=dashboard|registry|netdata.conf^SSL=optional *:20002=dashboard|registry" "$CWD" "netdata.conf.test1"
77 +netdata -c "netdata.conf.test1"
78 +run_acl_tests $TOKEN "$BASICURL:19999" 5 5
79 +run_acl_tests $TOKEN "$BASICURLS:19999" 5 0
80 +
81 +run_acl_tests $TOKEN "$BASICURL:20000" 4 5
82 +run_acl_tests $TOKEN "$BASICURLS:20000" 4 0
83 +
84 +run_acl_tests $TOKEN "$BASICURL:20001" 4 0
85 +run_acl_tests $TOKEN "$BASICURLS:20001" 4 0
86 +
87 +run_acl_tests $TOKEN "$BASICURL:20002" 3 5
88 +run_acl_tests $TOKEN "$BASICURLS:20002" 3 0
89 +killall netdata
90 +
91 +change_ssl_file "$CONF" " bind to = *=dashboard|registry|badges|management|netdata.conf *:20000=dashboard|registry|badges|management *:20001=dashboard|registry|netdata.conf^SSL=force *:20002=dashboard|registry" "$CWD" "netdata.conf.test2"
92 +netdata -c "netdata.conf.test2"
93 +run_acl_tests $TOKEN "$BASICURL:19999" 5 5
94 +run_acl_tests $TOKEN "$BASICURLS:19999" 5 0
95 +
96 +run_acl_tests $TOKEN "$BASICURL:20000" 4 5
97 +run_acl_tests $TOKEN "$BASICURLS:20000" 4 0
98 +
99 +run_acl_tests $TOKEN "$BASICURL:20001" 4 5
100 +run_acl_tests $TOKEN "$BASICURLS:20001" 4 0
101 +
102 +run_acl_tests $TOKEN "$BASICURL:20002" 3 5
103 +run_acl_tests $TOKEN "$BASICURLS:20002" 3 0
104 +killall netdata
105 +
106 +change_ssl_file "$CONF" " bind to = *=dashboard|registry|badges|management|netdata.conf *:20000=dashboard|registry|badges|management^SSL=optional *:20001=dashboard|registry|netdata.conf^SSL=force" "$CWD" "netdata.conf.test3"
107 +netdata -c "netdata.conf.test3"
108 +run_acl_tests $TOKEN "$BASICURL:19999" 5 5
109 +run_acl_tests $TOKEN "$BASICURLS:19999" 5 0
110 +
111 +run_acl_tests $TOKEN "$BASICURL:20000" 4 0
112 +run_acl_tests $TOKEN "$BASICURLS:20000" 4 0
113 +
114 +run_acl_tests $TOKEN "$BASICURL:20001" 4 5
115 +run_acl_tests $TOKEN "$BASICURLS:20001" 4 0
116 +killall netdata
117 +
118 +rm log_* netdata.conf.test* netdata.txt health.csv index.html badge.csv tmp* key.pem cert.pem info.txt
119 +echo "All the tests were successful"
tests/acls/netdata.cfg new
+20
@@ -0,0 +1,20 @@
1 +# netdata configuration
2 +#
3 +# You can download the latest version of this file, using:
4 +#
5 +# wget -O /etc/netdata/netdata.conf http://localhost:19999/netdata.conf
6 +# or
7 +# curl -o /etc/netdata/netdata.conf http://localhost:19999/netdata.conf
8 +#
9 +# You can uncomment and change any of the options below.
10 +# The value shown in the commented settings, is the default value.
11 +#
12 +
13 +[global]
14 + run as user = netdata
15 +
16 + # the default database size - 1 hour
17 + history = 3600
18 +
19 + # by default do not expose the netdata port
20 + bind to = localhost
tests/acls/netdata.ssl.cfg new
+24
@@ -0,0 +1,24 @@
1 +# netdata configuration
2 +#
3 +# You can download the latest version of this file, using:
4 +#
5 +# wget -O /etc/netdata/netdata.conf http://localhost:19999/netdata.conf
6 +# or
7 +# curl -o /etc/netdata/netdata.conf http://localhost:19999/netdata.conf
8 +#
9 +# You can uncomment and change any of the options below.
10 +# The value shown in the commented settings, is the default value.
11 +#
12 +
13 +[global]
14 + run as user = netdata
15 +
16 + # the default database size - 1 hour
17 + history = 3600
18 +
19 + # by default do not expose the netdata port
20 + bind to = localhost
21 +
22 +[web]
23 + ssl key =
24 + ssl certificate =
web/server/README.md
+14
@@ -112,6 +112,20 @@ Example:
112
113 For information how to configure the slaves to use TLS, check [securing the communication](../../streaming#securing-streaming-communications) in the streaming documentation. There you will find additional details on the expected behavior for client and server nodes, when their respective TLS options are enabled.
114
115 +When we define the use of SSL in a Netdata agent for different ports, Netdata will apply the behavior specified on each port. For example, using the configuration line below:
116 +
117 +```
118 +[web]
119 + bind to = *=dashboard|registry|badges|management|streaming|netdata.conf^SSL=force *:20000=netdata.conf^SSL=optional *:20001=dashboard|registry
120 +```
121 +
122 +Netdata will:
123 +
124 +- Force all HTTP requests to the default port to be redirected to HTTPS (same port).
125 +- Refuse unencrypted streaming connections from slaves on the default port.
126 +- Allow both HTTP and HTTPS requests to port 20000 for netdata.conf
127 +- Force HTTP requests to port 20001 to be redirected to HTTPS (same port). Only allow requests for the dashboard, the read API and the registry on port 20001.
128 +
129 #### TLS/SSL errors
130
131 When you start using Netdata with TLS, you may find errors in the Netdata log, which is stored at `/var/log/netdata/error.log` by default.
web/server/web_client.c
+6 -2
@@ -835,7 +835,11 @@ static inline char *web_client_valid_method(struct web_client *w, char *s) {
835 s = &s[7];
836
837 #ifdef ENABLE_HTTPS
838 - if ( (w->ssl.flags) && (netdata_use_ssl_on_stream & NETDATA_SSL_FORCE)){
838 + if (w->ssl.flags && web_client_is_using_ssl_force(w)){
839 + w->header_parse_tries = 0;
840 + w->header_parse_last_size = 0;
841 + web_client_disable_wait_receive(w);
842 +
843 char hostname[256];
844 char *copyme = strstr(s,"hostname=");
845 if ( copyme ){
@@ -1065,7 +1069,7 @@ static inline HTTP_VALIDATION http_request_validate(struct web_client *w) {
1069 }
1070 #ifdef ENABLE_HTTPS
1071 if ( (!web_client_check_unix(w)) && (netdata_srv_ctx) ) {
1068 - if ((w->ssl.conn) && ((w->ssl.flags & NETDATA_SSL_NO_HANDSHAKE) && (netdata_use_ssl_on_http & NETDATA_SSL_FORCE) && (w->mode != WEB_CLIENT_MODE_STREAM)) ) {
1072 + if ((w->ssl.conn) && ((w->ssl.flags & NETDATA_SSL_NO_HANDSHAKE) && (web_client_is_using_ssl_force(w) || web_client_is_using_ssl_default(w)) && (w->mode != WEB_CLIENT_MODE_STREAM)) ) {
1073 w->header_parse_tries = 0;
1074 w->header_parse_last_size = 0;
1075 web_client_disable_wait_receive(w);