detect the system ca bundle at runtime (#19622)
* detect the system ca bundle at runtime * minor fix * fix for older libcurl versions * added X509_get_default_cert_file() * added validation for the certificates * moved ssl/curl code to separate file; now it configured both libcurl and openssl; added defaults to libcurl static install * run the new code only in netdata static builds * auto to check * disable runtime ssl checks
Costa Tsaousis committed
Feb 12, 2025 at 14:28 UTC
3e15a013d04f6394ad8c69e43325c923537eec8b
10 files changed
+112
-6
CMakeLists.txt
+2
@@ -1182,6 +1182,8 @@ set(DAEMON_FILES
1182
src/daemon/pulse/pulse-db-dbengine-retention.h
1183
src/daemon/pulse/pulse-parents.c
1184
src/daemon/pulse/pulse-parents.h
1185
+ src/daemon/config/netdata-conf-ssl.c
1186
+ src/daemon/config/netdata-conf-ssl.h
1187
)
1188
1189
set(H2O_FILES
packaging/makeself/install-or-update.sh
+1
-1
@@ -27,7 +27,7 @@ fi
27
28
STARTIT=1
29
REINSTALL_OPTIONS=""
30
-NETDATA_CERT_MODE="${NETDATA_CERT_MODE:-auto}"
30
+NETDATA_CERT_MODE="${NETDATA_CERT_MODE:-check}"
31
NETDATA_CERT_TEST_URL="${NETDATA_CERT_TEST_URL:-https://app.netdata.cloud}"
32
RELEASE_CHANNEL="nightly"
33
packaging/makeself/jobs/50-curl.install.sh
+2
@@ -57,6 +57,8 @@ if [ "${CACHE_HIT:-0}" -eq 0 ]; then
57
--enable-cookies \
58
--with-ca-fallback \
59
--with-openssl \
60
+ --with-ca-bundle=/opt/netdata/etc/ssl/certs/ca-certificates.crt \
61
+ --with-ca-path=/opt/netdata/etc/ssl/certs \
62
--disable-dependency-tracking
63
64
# Curl autoconf does not honour the curl_LDFLAGS environment variable
packaging/makeself/jobs/70-netdata-git.install.sh
+2
-2
@@ -7,9 +7,9 @@
7
cd "${NETDATA_SOURCE_PATH}" || exit 1
8
9
if [ "${NETDATA_BUILD_WITH_DEBUG}" -eq 0 ]; then
10
- export CFLAGS="${TUNING_FLAGS} -ffunction-sections -fdata-sections -static -O2 -funroll-loops -I/openssl-static/include -I/libnetfilter-acct-static/include/libnetfilter_acct -I/curl-local/include/curl -I/usr/include/libmnl -pipe"
10
+ export CFLAGS="${TUNING_FLAGS} -ffunction-sections -fdata-sections -static -O2 -funroll-loops -DNETDATA_STATIC_BUILD=1 -I/openssl-static/include -I/libnetfilter-acct-static/include/libnetfilter_acct -I/curl-local/include/curl -I/usr/include/libmnl -pipe"
11
else
12
- export CFLAGS="${TUNING_FLAGS} -static -O1 -pipe -ggdb -Wall -Wextra -Wformat-signedness -DNETDATA_INTERNAL_CHECKS=1 -I/openssl-static/include -I/libnetfilter-acct-static/include/libnetfilter_acct -I/curl-local/include/curl -I/usr/include/libmnl"
12
+ export CFLAGS="${TUNING_FLAGS} -static -O1 -pipe -ggdb -Wall -Wextra -Wformat-signedness -DNETDATA_STATIC_BUILD=1 -DNETDATA_INTERNAL_CHECKS=1 -I/openssl-static/include -I/libnetfilter-acct-static/include/libnetfilter_acct -I/curl-local/include/curl -I/usr/include/libmnl"
13
fi
14
15
export LDFLAGS="-Wl,--gc-sections -static -L/openssl-static/lib64 -L/libnetfilter-acct-static/lib -lnetfilter_acct -L/usr/lib -lmnl -L/usr/lib -lzstd -L/curl-local/lib"
src/daemon/config/netdata-conf-ssl.c
new
+93
@@ -0,0 +1,93 @@
1
+// SPDX-License-Identifier: GPL-3.0-or-later
2
+
3
+#include "daemon/common.h"
4
+#include "netdata-conf-ssl.h"
5
+#include <curl/curl.h>
6
+
7
+static bool is_ca_bundle_valid(const char *ca_path) {
8
+ if (!ca_path || !*ca_path)
9
+ return false;
10
+
11
+ FILE *fp = fopen(ca_path, "r");
12
+ if (!fp)
13
+ return false;
14
+
15
+ ERR_clear_error();
16
+
17
+ int valid_certs = 0;
18
+ X509 *cert = NULL;
19
+ while ((cert = PEM_read_X509(fp, NULL, NULL, NULL)) != NULL) {
20
+ ASN1_TIME *not_after = X509_get_notAfter(cert);
21
+ int day, sec;
22
+
23
+ if (ASN1_TIME_diff(&day, &sec, NULL, not_after) == 1) {
24
+ if (day > 0 || (day == 0 && sec > 0)) {
25
+ valid_certs++;
26
+
27
+ // we found 1 valid, stop reading the file
28
+ X509_free(cert);
29
+ break;
30
+ }
31
+ }
32
+
33
+ X509_free(cert);
34
+ }
35
+
36
+ fclose(fp);
37
+
38
+ ERR_clear_error();
39
+ return valid_certs > 0;
40
+}
41
+
42
+const char *detect_libcurl_default_ca() {
43
+#if LIBCURL_VERSION_NUM >= 0x074600 // 7.70.0 (CURLVERSION_SEVENTH)
44
+ curl_version_info_data *info = curl_version_info(CURLVERSION_NOW);
45
+ if (info) {
46
+ // Check built-in CA bundle
47
+ if (info->cainfo &&
48
+ access(info->cainfo, R_OK) == 0 &&
49
+ is_ca_bundle_valid(info->cainfo))
50
+ return info->cainfo;
51
+ }
52
+#endif
53
+ return NULL;
54
+}
55
+
56
+static const char *detect_ca_path(void) {
57
+ static const char *paths[] = {
58
+ "/etc/ssl/certs/ca-certificates.crt", // Debian, Ubuntu, Arch
59
+ "/etc/pki/tls/certs/ca-bundle.crt", // RHEL, CentOS, Fedora
60
+ "/etc/ssl/ca-bundle.pem", // OpenSUSE
61
+ "/etc/ssl/cert.pem", // Alpine
62
+ "/opt/netdata/etc/ssl/certs/ca-certificates.crt", // Netdata static build
63
+ "/opt/netdata/share/ssl/certs/ca-certificates.crt", // Netdata static build - fallback
64
+ NULL
65
+ };
66
+
67
+ for (int i = 0; paths[i] != NULL; i++) {
68
+ if (access(paths[i], R_OK) == 0 &&
69
+ is_ca_bundle_valid(paths[i]))
70
+ return paths[i];
71
+ }
72
+
73
+ return NULL;
74
+}
75
+
76
+void netdata_conf_ssl(void) {
77
+ netdata_ssl_initialize_openssl();
78
+
79
+#if 0
80
+ const char *p = getenv("CURL_CA_BUNDLE");
81
+ if(!p || !*p) p = getenv("SSL_CERT_FILE");
82
+ if(!p || !*p) {
83
+ p = X509_get_default_cert_file();
84
+ if(!p || !*p || !is_ca_bundle_valid(p))
85
+ p = NULL;
86
+ }
87
+ if(!p || !*p) p = detect_libcurl_default_ca();
88
+ if(!p || !*p) p = detect_ca_path();
89
+ setenv("CURL_CA_BUNDLE", inicfg_get(&netdata_config, CONFIG_SECTION_ENV_VARS, "CURL_CA_BUNDLE", p ? p : ""), 1);
90
+ setenv("SSL_CERT_FILE", inicfg_get(&netdata_config, CONFIG_SECTION_ENV_VARS, "SSL_CERT_FILE", p ? p : ""), 1);
91
+#endif
92
+
93
+}
src/daemon/config/netdata-conf-ssl.h
new
+8
@@ -0,0 +1,8 @@
1
+// SPDX-License-Identifier: GPL-3.0-or-later
2
+
3
+#ifndef NETDATA_NETDATA_CONF_SSL_H
4
+#define NETDATA_NETDATA_CONF_SSL_H
5
+
6
+void netdata_conf_ssl(void);
7
+
8
+#endif //NETDATA_NETDATA_CONF_SSL_H
src/daemon/config/netdata-conf-web.c
-2
@@ -159,7 +159,5 @@ void netdata_conf_web_security_init(void) {
159
160
tls_version = inicfg_get(&netdata_config, CONFIG_SECTION_WEB, "tls version", "1.3");
161
tls_ciphers = inicfg_get(&netdata_config, CONFIG_SECTION_WEB, "tls ciphers", "none");
162
-
163
- netdata_ssl_initialize_openssl();
162
}
163
src/daemon/config/netdata-conf.h
+1
@@ -16,5 +16,6 @@ bool netdata_conf_load(char *filename, char overwrite_used, const char **user);
16
#include "netdata-conf-logs.h"
17
#include "netdata-conf-web.h"
18
#include "netdata-conf-cloud.h"
19
+#include "netdata-conf-ssl.h"
20
21
#endif //NETDATA_DAEMON_NETDATA_CONF_H
src/daemon/environment.c
+2
-1
@@ -81,7 +81,8 @@ void set_environment_for_plugins_and_scripts(void) {
81
freez((char *)default_port);
82
83
// set the path we need
84
- char path[4096], *p = getenv("PATH");
84
+ char path[4096];
85
+ const char *p = getenv("PATH");
86
if (!p) p = "/bin:/usr/bin";
87
snprintfz(path, sizeof(path), "%s:%s", p, "/sbin:/usr/sbin:/usr/local/bin:/usr/local/sbin");
88
setenv("PATH", inicfg_get(&netdata_config, CONFIG_SECTION_ENV_VARS, "PATH", path), 1);
src/daemon/main.c
+1
@@ -762,6 +762,7 @@ int netdata_main(int argc, char **argv) {
762
// ----------------------------------------------------------------------------------------------------------------
763
// global configuration
764
765
+ netdata_conf_ssl();
766
netdata_conf_section_global();
767
768
// Get execution path before switching user to avoid permission issues