Add configurable default locations for trusted CA certificates (#6549)
* sslcertificate: Trust certificate The netdata could not allow invalid certificate or certificate with invalid chain this commit fixes this! * sslcertificate: Changing name We are binging the same names used by the OpenSSL library to simplify the understand of the parameters * sslcertificate: Name changes and explicity directory This commit fix the problem with Streams and rename correctly the files in the option, it also uses stat to define the existence of a file * sslcertificate: Documentation Fix grammar for the newest section in the documentation * sslcertificate: Rename variables The old variables did not represent well what they are doing, so it was renamed
thiagoftsm committed
Jul 29, 2019 at 12:27 UTC
551617bd322e2b855ccf19375650348fda77938a
6 files changed
+129
-3
collectors/plugins.d/plugins_d.c
+1
-1
@@ -251,10 +251,10 @@ inline size_t pluginsd_process(RRDHOST *host, struct plugind *cd, FILE *fp, int
251
char tmpbuffer[PLUGINSD_LINE_MAX];
252
char *readfrom;
253
#endif
254
+ char *r = NULL;
255
while(!ferror(fp)) {
256
if(unlikely(netdata_exit)) break;
257
257
- char *r;
258
#ifdef ENABLE_HTTPS
259
int normalread = 1;
260
if(netdata_srv_ctx) {
libnetdata/socket/security.c
+56
-1
@@ -164,7 +164,7 @@ void security_start_ssl(int selector) {
164
switch (selector) {
165
case NETDATA_SSL_CONTEXT_SERVER: {
166
struct stat statbuf;
167
- if (stat(security_key,&statbuf) || stat(security_cert,&statbuf)) {
167
+ if (stat(security_key, &statbuf) || stat(security_cert, &statbuf)) {
168
info("To use encryption it is necessary to set \"ssl certificate\" and \"ssl key\" in [web] !\n");
169
return;
170
}
@@ -186,6 +186,11 @@ void security_start_ssl(int selector) {
186
}
187
}
188
189
+/**
190
+ * Clean Open SSL
191
+ *
192
+ * Clean all the allocated contexts from netdata.
193
+ */
194
void security_clean_openssl() {
195
if (netdata_srv_ctx)
196
{
@@ -265,6 +270,15 @@ int security_process_accept(SSL *ssl,int msg) {
270
return NETDATA_SSL_HANDSHAKE_COMPLETE;
271
}
272
273
+/**
274
+ * Test Certificate
275
+ *
276
+ * Check the certificate of Netdata master
277
+ *
278
+ * @param ssl is the connection structure
279
+ *
280
+ * @return It returns 0 on success and -1 otherwise
281
+ */
282
int security_test_certificate(SSL *ssl) {
283
X509* cert = SSL_get_peer_certificate(ssl);
284
int ret;
@@ -283,7 +297,48 @@ int security_test_certificate(SSL *ssl) {
297
} else {
298
ret = 0;
299
}
300
+
301
return ret;
302
}
303
304
+/**
305
+ * Location for context
306
+ *
307
+ * Case the user give us a directory with the certificates available and
308
+ * the Netdata master certificate, we use this function to validate the certificate.
309
+ *
310
+ * @param ctx the context where the path will be set.
311
+ * @param file the file with Netdata master certificate.
312
+ * @param path the directory where the certificates are stored.
313
+ *
314
+ * @return It returns 0 on success and -1 otherwise.
315
+ */
316
+int security_location_for_context(SSL_CTX *ctx, char *file, char *path) {
317
+ struct stat statbuf;
318
+ if (stat(file, &statbuf)) {
319
+ info("Netdata does not have a SSL master certificate, so it will use the default OpenSSL configuration to validate certificates!");
320
+ return 0;
321
+ }
322
+
323
+ ERR_clear_error();
324
+ u_long err;
325
+ char buf[256];
326
+ if(!SSL_CTX_load_verify_locations(ctx, file, path)) {
327
+ goto slfc;
328
+ }
329
+
330
+ if(!SSL_CTX_set_default_verify_paths(ctx)) {
331
+ goto slfc;
332
+ }
333
+
334
+ return 0;
335
+
336
+slfc:
337
+ while ((err = ERR_get_error()) != 0) {
338
+ ERR_error_string_n(err, buf, sizeof(buf));
339
+ error("Cannot set the directory for the certificates and the master SSL certificate: %s",buf);
340
+ }
341
+ return -1;
342
+}
343
+
344
#endif
libnetdata/socket/security.h
+1
@@ -34,6 +34,7 @@ extern SSL_CTX *netdata_srv_ctx;
34
extern const char *security_key;
35
extern const char *security_cert;
36
extern int netdata_validate_server;
37
+extern int security_location_for_context(SSL_CTX *ctx,char *file,char *path);
38
39
void security_openssl_library();
40
void security_clean_openssl();
streaming/README.md
+47
@@ -236,6 +236,53 @@ When TLS/SSL is enabled on the slave, the default behavior will be to not connec
236
ssl skip certificate verification = yes
237
```
238
239
+#### Trusted certificate
240
+
241
+If you've enabled [certificate verification](#certificate-verification), you might see errors from the OpenSSL library when there's a problem with checking the certificate chain (`X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT_LOCALLY`). More importantly, OpenSSL will reject self-signed certificates.
242
+
243
+Given these known issues, you have two options. If you trust your certificate, you can set the options `CApath` and `CAfile` to inform Netdata where your certificates, and the certificate trusted file, are stored.
244
+
245
+For more details about these options, you can read about [verify locations](https://www.openssl.org/docs/man1.1.1/man3/SSL_CTX_load_verify_locations.html).
246
+
247
+Before you changed your streaming configuration, you need to copy your trusted certificate to your slave system and add the certificate to OpenSSL's list.
248
+
249
+On most Linux distributions, the `update-ca-certificates` command searches inside the `/usr/share/ca-certificates` directory for certificates. You should double-check by reading the `update-ca-certificate` manual (`man update-ca-certificate`), and then change the directory in the below commands if needed.
250
+
251
+If you have `sudo` configured on your slave system, you can use that to run the following commands. If not, you'll have to log in as `root` to complete them.
252
+
253
+```
254
+# mkdir /usr/share/ca-certificates/netdata
255
+# cp master_cert.pem /usr/share/ca-certificates/netdata/master_cert.crt
256
+# chown -R netdata.netdata /usr/share/ca-certificates/netdata/
257
+```
258
+
259
+First, you create a new directory to store your certificates for Netdata. Next, you need to change the extension on your certificate from `.pem` to `.crt` so it's compatible with `update-ca-certificate`. Finally, you need to change permissions so the user that runs Netdata can access the directory where you copied in your certificate.
260
+
261
+Next, edit the file `/etc/ca-certificates.conf` and add the following line:
262
+
263
+```
264
+netdata/master_cert.crt
265
+```
266
+
267
+Now you update the list of certificates running the following, again either as `sudo` or `root`:
268
+
269
+```
270
+# update-ca-certificates
271
+```
272
+
273
+!!! note
274
+ Some Linux distributions have different methods of updating the certificate list. For more details, please read this guide on [addding trusted root certificates](https://github.com/Busindre/How-to-Add-trusted-root-certificates).
275
+
276
+Once you update your certificate list, you can set the stream parameters for Netdata to trust the master certificate. Open `stream.conf` for editing and change the following lines:
277
+
278
+```
279
+[stream]
280
+ CApath = /etc/ssl/certs/
281
+ CAfile = /etc/ssl/certs/master_cert.pem
282
+```
283
+
284
+With this configuration, the `CApath` option tells Netdata to search for trusted certificates inside `/etc/ssl/certs`. The `CAfile` option specifies the Netdata master certificate is located at `/etc/ssl/certs/master_cert.pem`. With this configuration, you can skip using the system's entire list of certificates and use Netdata's master certificate instead.
285
+
286
#### Expected behaviors
287
288
With the introduction of TLS/SSL, the master-slave communication behaves as shown in the table below, depending on the following configurations:
streaming/rrdpush.c
+8
-1
@@ -50,6 +50,8 @@ char *default_rrdpush_api_key = NULL;
50
char *default_rrdpush_send_charts_matching = NULL;
51
#ifdef ENABLE_HTTPS
52
int netdata_use_ssl_on_stream = NETDATA_SSL_OPTIONAL;
53
+char *netdata_ssl_ca_path = NULL;
54
+char *netdata_ssl_ca_file = NULL;
55
#endif
56
57
static void load_stream_conf() {
@@ -92,13 +94,17 @@ int rrdpush_init() {
94
}
95
}
96
}
97
+
98
char *invalid_certificate = appconfig_get(&stream_config, CONFIG_SECTION_STREAM, "ssl skip certificate verification", "no");
99
if ( !strcmp(invalid_certificate,"yes")){
100
if (netdata_validate_server == NETDATA_SSL_VALID_CERTIFICATE){
98
- info("The Netdata is configured to accept invalid certificate.");
101
+ info("Netdata is configured to accept invalid SSL certificate.");
102
netdata_validate_server = NETDATA_SSL_INVALID_CERTIFICATE;
103
}
104
}
105
+
106
+ netdata_ssl_ca_path = appconfig_get(&stream_config, CONFIG_SECTION_STREAM, "CApath", "/etc/ssl/certs/");
107
+ netdata_ssl_ca_file = appconfig_get(&stream_config, CONFIG_SECTION_STREAM, "CAfile", "/etc/ssl/certs/certs.pem");
108
#endif
109
110
return default_rrdpush_enabled;
@@ -655,6 +661,7 @@ void *rrdpush_sender_thread(void *ptr) {
661
#ifdef ENABLE_HTTPS
662
if (netdata_use_ssl_on_stream & NETDATA_SSL_FORCE ){
663
security_start_ssl(NETDATA_SSL_CONTEXT_STREAMING);
664
+ security_location_for_context(netdata_client_ctx, netdata_ssl_ca_file, netdata_ssl_ca_path);
665
}
666
#endif
667
streaming/stream.conf
+16
@@ -41,6 +41,22 @@
41
#
42
#ssl skip certificate verification = yes
43
44
+ # Certificate Authority Path
45
+ #
46
+ # OpenSSL has a default directory where the known certificates are stored,
47
+ # case it is necessary it is possible to change this rule using the variable
48
+ # "CApath"
49
+ #
50
+ #CApath = /etc/ssl/certs/
51
+
52
+ # Certificate Authority file
53
+ #
54
+ # When the Netdata master has certificate, that is not recognized as valid,
55
+ # we can add this certificate in the list of known certificates in CApath
56
+ # and give for Netdata as argument.
57
+ #
58
+ #CAfile = /etc/ssl/certs/cert.pem
59
+
60
# The API_KEY to use (as the sender)
61
api key =
62