mirror of
https://github.com/netdata/netdata.git
synced 2025-04-02 20:48:06 +00:00
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
This commit is contained in:
parent
d95912af08
commit
2f7962c9e1
14 changed files with 399 additions and 37 deletions
1
.gitignore
vendored
1
.gitignore
vendored
|
@ -166,6 +166,7 @@ callgrind.out.*
|
|||
gmon.out
|
||||
gmon.txt
|
||||
sitespeed-result/
|
||||
tests/acls/acl.sh
|
||||
tests/urls/request.sh
|
||||
|
||||
# tests and temp files
|
||||
|
|
|
@ -117,6 +117,103 @@ inline int pluginsd_split_words(char *str, char **words, int max_words) {
|
|||
return quoted_strings_splitter(str, words, max_words, pluginsd_space);
|
||||
}
|
||||
|
||||
#ifdef ENABLE_HTTPS
|
||||
/**
|
||||
* Update Buffer
|
||||
*
|
||||
* Update the temporary buffer used to parse data received from slave
|
||||
*
|
||||
* @param output is a pointer to the vector where I will store the data
|
||||
* @param ssl is the connection pointer with the server
|
||||
*
|
||||
* @return it returns the total of bytes read on success and a negative number otherwise
|
||||
*/
|
||||
int pluginsd_update_buffer(char *output, SSL *ssl) {
|
||||
ERR_clear_error();
|
||||
int bytesleft = SSL_read(ssl, output, PLUGINSD_LINE_MAX_SSL_READ);
|
||||
if(bytesleft <= 0) {
|
||||
int sslerrno = SSL_get_error(ssl, bytesleft);
|
||||
switch(sslerrno) {
|
||||
case SSL_ERROR_WANT_READ:
|
||||
case SSL_ERROR_WANT_WRITE:
|
||||
{
|
||||
break;
|
||||
}
|
||||
default:
|
||||
{
|
||||
u_long err;
|
||||
char buf[256];
|
||||
int counter = 0;
|
||||
while ((err = ERR_get_error()) != 0) {
|
||||
ERR_error_string_n(err, buf, sizeof(buf));
|
||||
info("%d SSL Handshake error (%s) on socket %d ", counter++, ERR_error_string((long)SSL_get_error(ssl, bytesleft), NULL), SSL_get_fd(ssl));
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
} else {
|
||||
output[bytesleft] = '\0';
|
||||
}
|
||||
|
||||
return bytesleft;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get from Buffer
|
||||
*
|
||||
* Get data to process from buffer
|
||||
*
|
||||
* @param output is the output vector that will be used to parse the string.
|
||||
* @param bytesread the amount of bytes read in the previous iteration.
|
||||
* @param input the input vector where there are data to process
|
||||
* @param ssl a pointer to the connection with the server
|
||||
* @param src the first address of the input, because sometime will be necessary to restart the addr with it.
|
||||
*
|
||||
* @return It returns a pointer for the next iteration on success and NULL otherwise.
|
||||
*/
|
||||
char * pluginsd_get_from_buffer(char *output, int *bytesread, char *input, SSL *ssl, char *src) {
|
||||
int copying = 1;
|
||||
char *endbuffer;
|
||||
size_t length;
|
||||
while(copying) {
|
||||
if(*bytesread > 0) {
|
||||
endbuffer = strchr(input, '\n');
|
||||
if(endbuffer) {
|
||||
copying = 0;
|
||||
endbuffer++; //Advance due the fact I wanna copy '\n'
|
||||
length = endbuffer - input;
|
||||
*bytesread -= length;
|
||||
|
||||
memcpy(output, input, length);
|
||||
output += length;
|
||||
*output = '\0';
|
||||
input += length;
|
||||
}else {
|
||||
length = strlen(input);
|
||||
memcpy(output, input, length);
|
||||
output += length;
|
||||
input = src;
|
||||
|
||||
*bytesread = pluginsd_update_buffer(input, ssl);
|
||||
if(*bytesread <= 0) {
|
||||
input = NULL;
|
||||
copying = 0;
|
||||
}
|
||||
}
|
||||
}else {
|
||||
//reduce sample of bytes read, print the length
|
||||
*bytesread = pluginsd_update_buffer(input, ssl);
|
||||
if(*bytesread <= 0) {
|
||||
input = NULL;
|
||||
copying = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return input;
|
||||
}
|
||||
#endif
|
||||
|
||||
inline size_t pluginsd_process(RRDHOST *host, struct plugind *cd, FILE *fp, int trust_durations) {
|
||||
int enabled = cd->enabled;
|
||||
|
||||
|
@ -149,10 +246,43 @@ inline size_t pluginsd_process(RRDHOST *host, struct plugind *cd, FILE *fp, int
|
|||
goto cleanup;
|
||||
}
|
||||
|
||||
#ifdef ENABLE_HTTPS
|
||||
int bytesleft = 0;
|
||||
char tmpbuffer[PLUGINSD_LINE_MAX];
|
||||
char *readfrom;
|
||||
#endif
|
||||
while(!ferror(fp)) {
|
||||
if(unlikely(netdata_exit)) break;
|
||||
|
||||
char *r = fgets(line, PLUGINSD_LINE_MAX, fp);
|
||||
char *r;
|
||||
#ifdef ENABLE_HTTPS
|
||||
int normalread = 1;
|
||||
if(netdata_srv_ctx) {
|
||||
if(host->ssl.conn && !host->ssl.flags) {
|
||||
if(!bytesleft) {
|
||||
r = line;
|
||||
readfrom = tmpbuffer;
|
||||
bytesleft = pluginsd_update_buffer(readfrom, host->ssl.conn);
|
||||
if(bytesleft <= 0) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
readfrom = pluginsd_get_from_buffer(line, &bytesleft, readfrom, host->ssl.conn, tmpbuffer);
|
||||
if(!readfrom) {
|
||||
r = NULL;
|
||||
}
|
||||
|
||||
normalread = 0;
|
||||
}
|
||||
}
|
||||
|
||||
if(normalread) {
|
||||
r = fgets(line, PLUGINSD_LINE_MAX, fp);
|
||||
}
|
||||
#else
|
||||
r = fgets(line, PLUGINSD_LINE_MAX, fp);
|
||||
#endif
|
||||
if(unlikely(!r)) {
|
||||
if(feof(fp))
|
||||
error("read failed: end of file");
|
||||
|
|
|
@ -31,6 +31,7 @@
|
|||
#define PLUGINSD_KEYWORD_VARIABLE "VARIABLE"
|
||||
|
||||
#define PLUGINSD_LINE_MAX 1024
|
||||
#define PLUGINSD_LINE_MAX_SSL_READ 512
|
||||
#define PLUGINSD_MAX_WORDS 20
|
||||
|
||||
#define PLUGINSD_MAX_DIRECTORIES 20
|
||||
|
|
|
@ -7,8 +7,6 @@ SSL_CTX *netdata_client_ctx=NULL;
|
|||
SSL_CTX *netdata_srv_ctx=NULL;
|
||||
const char *security_key=NULL;
|
||||
const char *security_cert=NULL;
|
||||
int netdata_use_ssl_on_stream = NETDATA_SSL_OPTIONAL;
|
||||
int netdata_use_ssl_on_http = NETDATA_SSL_FORCE; //We force SSL due safety reasons
|
||||
int netdata_validate_server = NETDATA_SSL_VALID_CERTIFICATE;
|
||||
|
||||
/**
|
||||
|
@ -176,6 +174,9 @@ void security_start_ssl(int selector) {
|
|||
}
|
||||
case NETDATA_SSL_CONTEXT_STREAMING: {
|
||||
netdata_client_ctx = security_initialize_openssl_client();
|
||||
//This is necessary for the stream, because it is working sometimes with nonblock socket.
|
||||
//It returns the bitmask afte to change, there is not any description of errors in the documentation
|
||||
SSL_CTX_set_mode(netdata_client_ctx, SSL_MODE_ENABLE_PARTIAL_WRITE |SSL_MODE_ACCEPT_MOVING_WRITE_BUFFER |SSL_MODE_AUTO_RETRY);
|
||||
break;
|
||||
}
|
||||
case NETDATA_SSL_CONTEXT_OPENTSDB: {
|
||||
|
@ -206,6 +207,17 @@ void security_clean_openssl() {
|
|||
#endif
|
||||
}
|
||||
|
||||
/**
|
||||
* Process accept
|
||||
*
|
||||
* Process the SSL handshake with the client case it is necessary.
|
||||
*
|
||||
* @param ssl is a pointer for the SSL structure
|
||||
* @param msg is a copy of the first 8 bytes of the initial message received
|
||||
*
|
||||
* @return it returns 0 case it performs the handshake, 8 case it is clean connection
|
||||
* and another integer power of 2 otherwise.
|
||||
*/
|
||||
int security_process_accept(SSL *ssl,int msg) {
|
||||
int sock = SSL_get_fd(ssl);
|
||||
int test;
|
||||
|
@ -250,7 +262,7 @@ int security_process_accept(SSL *ssl,int msg) {
|
|||
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);
|
||||
}
|
||||
|
||||
return 0;
|
||||
return NETDATA_SSL_HANDSHAKE_COMPLETE;
|
||||
}
|
||||
|
||||
int security_test_certificate(SSL *ssl) {
|
||||
|
|
|
@ -25,7 +25,7 @@
|
|||
|
||||
struct netdata_ssl{
|
||||
SSL *conn; //SSL connection
|
||||
int flags;
|
||||
int flags; //The flags for SSL connection
|
||||
};
|
||||
|
||||
extern SSL_CTX *netdata_opentsdb_ctx;
|
||||
|
@ -33,8 +33,6 @@ extern SSL_CTX *netdata_client_ctx;
|
|||
extern SSL_CTX *netdata_srv_ctx;
|
||||
extern const char *security_key;
|
||||
extern const char *security_cert;
|
||||
extern int netdata_use_ssl_on_stream;
|
||||
extern int netdata_use_ssl_on_http;
|
||||
extern int netdata_validate_server;
|
||||
|
||||
void security_openssl_library();
|
||||
|
|
|
@ -301,39 +301,47 @@ void listen_sockets_close(LISTEN_SOCKETS *sockets) {
|
|||
sockets->failed = 0;
|
||||
}
|
||||
|
||||
WEB_CLIENT_ACL socket_ssl_acl(char *ssl) {
|
||||
/*
|
||||
* SSL ACL
|
||||
*
|
||||
* Search the SSL acl and apply it case it is set.
|
||||
*
|
||||
* @param acl is the acl given by the user.
|
||||
*/
|
||||
WEB_CLIENT_ACL socket_ssl_acl(char *acl) {
|
||||
char *ssl = strchr(acl,'^');
|
||||
if(ssl) {
|
||||
//Due the format of the SSL command it is always the last command,
|
||||
//we finish it here to avoid problems with the ACLs
|
||||
*ssl = '\0';
|
||||
#ifdef ENABLE_HTTPS
|
||||
if (!strcmp(ssl,"optional")) {
|
||||
netdata_use_ssl_on_http = NETDATA_SSL_OPTIONAL;
|
||||
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;
|
||||
}
|
||||
else if (!strcmp(ssl,"force")) {
|
||||
netdata_use_ssl_on_stream = NETDATA_SSL_FORCE;
|
||||
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;
|
||||
}
|
||||
ssl++;
|
||||
if (!strncmp("SSL=",ssl,4)) {
|
||||
ssl += 4;
|
||||
if (!strcmp(ssl,"optional")) {
|
||||
return WEB_CLIENT_ACL_SSL_OPTIONAL;
|
||||
}
|
||||
else if (!strcmp(ssl,"force")) {
|
||||
return WEB_CLIENT_ACL_SSL_FORCE;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
return WEB_CLIENT_ACL_NONE;
|
||||
}
|
||||
|
||||
WEB_CLIENT_ACL read_acl(char *st) {
|
||||
char *ssl = strchr(st,'^');
|
||||
if (ssl) {
|
||||
ssl++;
|
||||
if (!strncmp("SSL=",ssl,4)) {
|
||||
ssl += 4;
|
||||
}
|
||||
socket_ssl_acl(ssl);
|
||||
}
|
||||
WEB_CLIENT_ACL ret = socket_ssl_acl(st);
|
||||
|
||||
if (!strcmp(st,"dashboard")) return WEB_CLIENT_ACL_DASHBOARD;
|
||||
if (!strcmp(st,"registry")) return WEB_CLIENT_ACL_REGISTRY;
|
||||
if (!strcmp(st,"badges")) return WEB_CLIENT_ACL_BADGE;
|
||||
if (!strcmp(st,"management")) return WEB_CLIENT_ACL_MGMT;
|
||||
if (!strcmp(st,"streaming")) return WEB_CLIENT_ACL_STREAMING;
|
||||
if (!strcmp(st,"netdata.conf")) return WEB_CLIENT_ACL_NETDATACONF;
|
||||
if (!strcmp(st,"dashboard")) ret |= WEB_CLIENT_ACL_DASHBOARD;
|
||||
if (!strcmp(st,"registry")) ret |= WEB_CLIENT_ACL_REGISTRY;
|
||||
if (!strcmp(st,"badges")) ret |= WEB_CLIENT_ACL_BADGE;
|
||||
if (!strcmp(st,"management")) ret |= WEB_CLIENT_ACL_MGMT;
|
||||
if (!strcmp(st,"streaming")) ret |= WEB_CLIENT_ACL_STREAMING;
|
||||
if (!strcmp(st,"netdata.conf")) ret |= WEB_CLIENT_ACL_NETDATACONF;
|
||||
|
||||
return socket_ssl_acl(st);
|
||||
return ret;
|
||||
}
|
||||
|
||||
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,
|
|||
error("LISTENER: Cannot create unix socket '%s'", path);
|
||||
sockets->failed++;
|
||||
} else {
|
||||
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;
|
||||
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;
|
||||
listen_sockets_add(sockets, fd, AF_UNIX, socktype, protocol_str, path, 0, acl_flags);
|
||||
added++;
|
||||
}
|
||||
|
@ -425,7 +433,13 @@ static inline int bind_to_this(LISTEN_SOCKETS *sockets, const char *definition,
|
|||
}
|
||||
acl_flags |= read_acl(portconfig);
|
||||
} else {
|
||||
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;
|
||||
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;
|
||||
}
|
||||
|
||||
//Case the user does not set the option SSL in the "bind to", but he has
|
||||
//the certificates, I must redirect, so I am assuming here the default option
|
||||
if(!(acl_flags & WEB_CLIENT_ACL_SSL_OPTIONAL) && !(acl_flags & WEB_CLIENT_ACL_SSL_FORCE)) {
|
||||
acl_flags |= WEB_CLIENT_ACL_SSL_DEFAULT;
|
||||
}
|
||||
|
||||
uint32_t scope_id = 0;
|
||||
|
|
|
@ -17,7 +17,10 @@ typedef enum web_client_acl {
|
|||
WEB_CLIENT_ACL_BADGE = 1 << 2,
|
||||
WEB_CLIENT_ACL_MGMT = 1 << 3,
|
||||
WEB_CLIENT_ACL_STREAMING = 1 << 4,
|
||||
WEB_CLIENT_ACL_NETDATACONF = 1 << 5
|
||||
WEB_CLIENT_ACL_NETDATACONF = 1 << 5,
|
||||
WEB_CLIENT_ACL_SSL_OPTIONAL = 1 << 6,
|
||||
WEB_CLIENT_ACL_SSL_FORCE = 1 << 7,
|
||||
WEB_CLIENT_ACL_SSL_DEFAULT = 1 << 8
|
||||
} WEB_CLIENT_ACL;
|
||||
|
||||
#define web_client_can_access_dashboard(w) ((w)->acl & WEB_CLIENT_ACL_DASHBOARD)
|
||||
|
@ -26,6 +29,9 @@ typedef enum web_client_acl {
|
|||
#define web_client_can_access_mgmt(w) ((w)->acl & WEB_CLIENT_ACL_MGMT)
|
||||
#define web_client_can_access_stream(w) ((w)->acl & WEB_CLIENT_ACL_STREAMING)
|
||||
#define web_client_can_access_netdataconf(w) ((w)->acl & WEB_CLIENT_ACL_NETDATACONF)
|
||||
#define web_client_is_using_ssl_optional(w) ((w)->port_acl & WEB_CLIENT_ACL_SSL_OPTIONAL)
|
||||
#define web_client_is_using_ssl_force(w) ((w)->port_acl & WEB_CLIENT_ACL_SSL_FORCE)
|
||||
#define web_client_is_using_ssl_default(w) ((w)->port_acl & WEB_CLIENT_ACL_SSL_DEFAULT)
|
||||
|
||||
typedef struct listen_sockets {
|
||||
struct config *config; // the config file to use
|
||||
|
|
|
@ -48,6 +48,7 @@ unsigned int default_rrdpush_enabled = 0;
|
|||
char *default_rrdpush_destination = NULL;
|
||||
char *default_rrdpush_api_key = NULL;
|
||||
char *default_rrdpush_send_charts_matching = NULL;
|
||||
int netdata_use_ssl_on_stream = NETDATA_SSL_OPTIONAL;
|
||||
|
||||
static void load_stream_conf() {
|
||||
errno = 0;
|
||||
|
@ -801,7 +802,17 @@ void *rrdpush_sender_thread(void *ptr) {
|
|||
rrdpush_buffer_lock(host);
|
||||
|
||||
debug(D_STREAM, "STREAM: Sending data, starting from %zu, size %zu...", begin, buffer_strlen(host->rrdpush_sender_buffer));
|
||||
ssize_t ret = send(host->rrdpush_sender_socket, &host->rrdpush_sender_buffer->buffer[begin], buffer_strlen(host->rrdpush_sender_buffer) - begin, MSG_DONTWAIT);
|
||||
ssize_t ret;
|
||||
#ifdef ENABLE_HTTPS
|
||||
SSL *conn = host->ssl.conn ;
|
||||
if(conn && !host->ssl.flags) {
|
||||
ret = SSL_write(conn,&host->rrdpush_sender_buffer->buffer[begin], buffer_strlen(host->rrdpush_sender_buffer) - begin);
|
||||
} else {
|
||||
ret = send(host->rrdpush_sender_socket, &host->rrdpush_sender_buffer->buffer[begin], buffer_strlen(host->rrdpush_sender_buffer) - begin, MSG_DONTWAIT);
|
||||
}
|
||||
#else
|
||||
ret = send(host->rrdpush_sender_socket, &host->rrdpush_sender_buffer->buffer[begin], buffer_strlen(host->rrdpush_sender_buffer) - begin, MSG_DONTWAIT);
|
||||
#endif
|
||||
if (unlikely(ret == -1)) {
|
||||
if (errno != EAGAIN && errno != EINTR && errno != EWOULDBLOCK) {
|
||||
debug(D_STREAM, "STREAM: Send failed - closing socket...");
|
||||
|
@ -1059,6 +1070,8 @@ static int rrdpush_receive(int fd
|
|||
|
||||
info("STREAM %s [receive from [%s]:%s]: initializing communication...", host->hostname, client_ip, client_port);
|
||||
#ifdef ENABLE_HTTPS
|
||||
host->ssl.conn = ssl->conn;
|
||||
host->ssl.flags = ssl->flags;
|
||||
if(send_timeout(ssl,fd, START_STREAMING_PROMPT, strlen(START_STREAMING_PROMPT), 0, 60) != strlen(START_STREAMING_PROMPT)) {
|
||||
#else
|
||||
if(send_timeout(fd, START_STREAMING_PROMPT, strlen(START_STREAMING_PROMPT), 0, 60) != strlen(START_STREAMING_PROMPT)) {
|
||||
|
|
|
@ -5,7 +5,11 @@ MAINTAINERCLEANFILES = $(srcdir)/Makefile.in
|
|||
|
||||
CLEANFILES = \
|
||||
health_mgmtapi/health-cmdapi-test.sh \
|
||||
<<<<<<< HEAD
|
||||
acls/acl.sh \
|
||||
=======
|
||||
urls/request.sh \
|
||||
>>>>>>> 63a4cadd346df71255d2350128eebcf317e81d0f
|
||||
$(NULL)
|
||||
|
||||
include $(top_srcdir)/build/subst.inc
|
||||
|
@ -23,11 +27,13 @@ dist_noinst_DATA = \
|
|||
node.d/fronius.process.spec.js \
|
||||
node.d/fronius.validation.spec.js \
|
||||
health_mgmtapi/health-cmdapi-test.sh.in \
|
||||
acls/acl.sh.in \
|
||||
urls/request.sh.in \
|
||||
$(NULL)
|
||||
|
||||
dist_plugins_SCRIPTS = \
|
||||
health_mgmtapi/health-cmdapi-test.sh \
|
||||
acls/acl.sh \
|
||||
urls/request.sh \
|
||||
$(NULL)
|
||||
|
||||
|
|
119
tests/acls/acl.sh.in
Normal file
119
tests/acls/acl.sh.in
Normal file
|
@ -0,0 +1,119 @@
|
|||
#!/bin/bash -x
|
||||
# SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
BASICURL="http://127.0.0.1"
|
||||
BASICURLS="https://127.0.0.1"
|
||||
|
||||
NETDATA_VARLIB_DIR="/var/lib/netdata"
|
||||
RED='\033[0;31m'
|
||||
GREEN='\033[0;32m'
|
||||
YELLOW='\033[0;43m'
|
||||
|
||||
#change the previous acl file and with a new
|
||||
#and store it on a new file
|
||||
change_file(){
|
||||
sed "s/$1/$2/g" netdata.cfg > "$4"
|
||||
}
|
||||
|
||||
change_ssl_file(){
|
||||
KEYROW="ssl key = $3/key.pem"
|
||||
CERTROW="ssl certificate = $3/cert.pem"
|
||||
sed "s@ssl key =@$KEYROW@g" netdata.ssl.cfg > tmp
|
||||
sed "s@ssl certificate =@$CERTROW@g" tmp > tmp2
|
||||
sed "s/$1/$2/g" tmp2 > "$4"
|
||||
}
|
||||
|
||||
run_acl_tests() {
|
||||
#Give a time for netdata start properly
|
||||
sleep 2
|
||||
|
||||
curl -v -k --tls-max 1.2 --create-dirs -o index.html "$2" 2> log_index.txt
|
||||
curl -v -k --tls-max 1.2 --create-dirs -o netdata.txt "$2/netdata.conf" 2> log_nc.txt
|
||||
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
|
||||
curl -v -k --tls-max 1.2 --create-dirs -o info.txt "$2/api/v1/info" 2> log_info.txt
|
||||
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
|
||||
|
||||
TOT=$(grep -c "HTTP/1.1 301" log_*.txt | cut -d: -f2| grep -c 1)
|
||||
if [ "$TOT" -ne "$4" ]; then
|
||||
echo -e "${RED}I got a wrong number of redirects($TOT) when SSL is activated, It was expected $4"
|
||||
rm log_* netdata.conf.test* netdata.txt health.csv index.html badge.csv tmp* key.pem cert.pem info.txt
|
||||
killall netdata
|
||||
exit 1
|
||||
elif [ "$TOT" -eq "$4" ] && [ "$4" -ne "0" ]; then
|
||||
echo -e "${YELLOW}I got the correct number of redirects($4) when SSL is activated and I try to access with HTTP."
|
||||
return
|
||||
fi
|
||||
|
||||
TOT=$(grep -c "HTTP/1.1 200 OK" log_* | cut -d: -f2| grep -c 1)
|
||||
if [ "$TOT" -ne "$3" ]; then
|
||||
echo -e "${RED}I got a wrong number of \"200 OK\" from the queries, it was expected $3."
|
||||
killall netdata
|
||||
rm log_* netdata.conf.test* netdata.txt health.csv index.html badge.csv tmp* key.pem cert.pem info.txt
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo -e "${GREEN}ACLs were applied correctly"
|
||||
}
|
||||
|
||||
CONF=$(grep "bind" netdata.cfg)
|
||||
MUSER=$(grep run netdata.cfg | cut -d= -f2|sed 's/^[ \t]*//')
|
||||
|
||||
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
|
||||
chown "$MUSER" key.pem cert.pem
|
||||
CWD=$(pwd)
|
||||
|
||||
if [ -f "${NETDATA_VARLIB_DIR}/netdata.api.key" ] ;then
|
||||
read -r TOKEN < "${NETDATA_VARLIB_DIR}/netdata.api.key"
|
||||
else
|
||||
TOKEN="NULL"
|
||||
fi
|
||||
|
||||
change_file "$CONF" " bind to = *" "$CWD" "netdata.conf.test0"
|
||||
netdata -c "netdata.conf.test0"
|
||||
run_acl_tests $TOKEN "$BASICURL:19999" 5 0
|
||||
killall netdata
|
||||
|
||||
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"
|
||||
netdata -c "netdata.conf.test1"
|
||||
run_acl_tests $TOKEN "$BASICURL:19999" 5 5
|
||||
run_acl_tests $TOKEN "$BASICURLS:19999" 5 0
|
||||
|
||||
run_acl_tests $TOKEN "$BASICURL:20000" 4 5
|
||||
run_acl_tests $TOKEN "$BASICURLS:20000" 4 0
|
||||
|
||||
run_acl_tests $TOKEN "$BASICURL:20001" 4 0
|
||||
run_acl_tests $TOKEN "$BASICURLS:20001" 4 0
|
||||
|
||||
run_acl_tests $TOKEN "$BASICURL:20002" 3 5
|
||||
run_acl_tests $TOKEN "$BASICURLS:20002" 3 0
|
||||
killall netdata
|
||||
|
||||
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"
|
||||
netdata -c "netdata.conf.test2"
|
||||
run_acl_tests $TOKEN "$BASICURL:19999" 5 5
|
||||
run_acl_tests $TOKEN "$BASICURLS:19999" 5 0
|
||||
|
||||
run_acl_tests $TOKEN "$BASICURL:20000" 4 5
|
||||
run_acl_tests $TOKEN "$BASICURLS:20000" 4 0
|
||||
|
||||
run_acl_tests $TOKEN "$BASICURL:20001" 4 5
|
||||
run_acl_tests $TOKEN "$BASICURLS:20001" 4 0
|
||||
|
||||
run_acl_tests $TOKEN "$BASICURL:20002" 3 5
|
||||
run_acl_tests $TOKEN "$BASICURLS:20002" 3 0
|
||||
killall netdata
|
||||
|
||||
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"
|
||||
netdata -c "netdata.conf.test3"
|
||||
run_acl_tests $TOKEN "$BASICURL:19999" 5 5
|
||||
run_acl_tests $TOKEN "$BASICURLS:19999" 5 0
|
||||
|
||||
run_acl_tests $TOKEN "$BASICURL:20000" 4 0
|
||||
run_acl_tests $TOKEN "$BASICURLS:20000" 4 0
|
||||
|
||||
run_acl_tests $TOKEN "$BASICURL:20001" 4 5
|
||||
run_acl_tests $TOKEN "$BASICURLS:20001" 4 0
|
||||
killall netdata
|
||||
|
||||
rm log_* netdata.conf.test* netdata.txt health.csv index.html badge.csv tmp* key.pem cert.pem info.txt
|
||||
echo "All the tests were successful"
|
20
tests/acls/netdata.cfg
Normal file
20
tests/acls/netdata.cfg
Normal file
|
@ -0,0 +1,20 @@
|
|||
# netdata configuration
|
||||
#
|
||||
# You can download the latest version of this file, using:
|
||||
#
|
||||
# wget -O /etc/netdata/netdata.conf http://localhost:19999/netdata.conf
|
||||
# or
|
||||
# curl -o /etc/netdata/netdata.conf http://localhost:19999/netdata.conf
|
||||
#
|
||||
# You can uncomment and change any of the options below.
|
||||
# The value shown in the commented settings, is the default value.
|
||||
#
|
||||
|
||||
[global]
|
||||
run as user = netdata
|
||||
|
||||
# the default database size - 1 hour
|
||||
history = 3600
|
||||
|
||||
# by default do not expose the netdata port
|
||||
bind to = localhost
|
24
tests/acls/netdata.ssl.cfg
Normal file
24
tests/acls/netdata.ssl.cfg
Normal file
|
@ -0,0 +1,24 @@
|
|||
# netdata configuration
|
||||
#
|
||||
# You can download the latest version of this file, using:
|
||||
#
|
||||
# wget -O /etc/netdata/netdata.conf http://localhost:19999/netdata.conf
|
||||
# or
|
||||
# curl -o /etc/netdata/netdata.conf http://localhost:19999/netdata.conf
|
||||
#
|
||||
# You can uncomment and change any of the options below.
|
||||
# The value shown in the commented settings, is the default value.
|
||||
#
|
||||
|
||||
[global]
|
||||
run as user = netdata
|
||||
|
||||
# the default database size - 1 hour
|
||||
history = 3600
|
||||
|
||||
# by default do not expose the netdata port
|
||||
bind to = localhost
|
||||
|
||||
[web]
|
||||
ssl key =
|
||||
ssl certificate =
|
|
@ -112,6 +112,20 @@ Example:
|
|||
|
||||
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.
|
||||
|
||||
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:
|
||||
|
||||
```
|
||||
[web]
|
||||
bind to = *=dashboard|registry|badges|management|streaming|netdata.conf^SSL=force *:20000=netdata.conf^SSL=optional *:20001=dashboard|registry
|
||||
```
|
||||
|
||||
Netdata will:
|
||||
|
||||
- Force all HTTP requests to the default port to be redirected to HTTPS (same port).
|
||||
- Refuse unencrypted streaming connections from slaves on the default port.
|
||||
- Allow both HTTP and HTTPS requests to port 20000 for netdata.conf
|
||||
- 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.
|
||||
|
||||
#### TLS/SSL errors
|
||||
|
||||
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.
|
||||
|
|
|
@ -835,7 +835,11 @@ static inline char *web_client_valid_method(struct web_client *w, char *s) {
|
|||
s = &s[7];
|
||||
|
||||
#ifdef ENABLE_HTTPS
|
||||
if ( (w->ssl.flags) && (netdata_use_ssl_on_stream & NETDATA_SSL_FORCE)){
|
||||
if (w->ssl.flags && web_client_is_using_ssl_force(w)){
|
||||
w->header_parse_tries = 0;
|
||||
w->header_parse_last_size = 0;
|
||||
web_client_disable_wait_receive(w);
|
||||
|
||||
char hostname[256];
|
||||
char *copyme = strstr(s,"hostname=");
|
||||
if ( copyme ){
|
||||
|
@ -1065,7 +1069,7 @@ static inline HTTP_VALIDATION http_request_validate(struct web_client *w) {
|
|||
}
|
||||
#ifdef ENABLE_HTTPS
|
||||
if ( (!web_client_check_unix(w)) && (netdata_srv_ctx) ) {
|
||||
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)) ) {
|
||||
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)) ) {
|
||||
w->header_parse_tries = 0;
|
||||
w->header_parse_last_size = 0;
|
||||
web_client_disable_wait_receive(w);
|
||||
|
|
Loading…
Add table
Reference in a new issue