From 7f0d99fd722da91ef951a2f0ddd36d59d581e342 Mon Sep 17 00:00:00 2001 From: Nikita Vakula Date: Fri, 15 Nov 2024 11:39:30 +0100 Subject: [PATCH] Support export via TLS (fix #12). (cherry picked from commit 6c1659a20ba946cdde21e9dbc52e7c740b06d968) --- src/batch_exporter.hpp | 4 ++-- src/ngx_otel_module.cpp | 45 +++++++++++++++++++++++++++++++++--- src/trace_service_client.hpp | 14 ++++++++--- 3 files changed, 55 insertions(+), 8 deletions(-) diff --git a/src/batch_exporter.hpp b/src/batch_exporter.hpp index 2432fe3..cb3e075 100644 --- a/src/batch_exporter.hpp +++ b/src/batch_exporter.hpp @@ -111,10 +111,10 @@ public: int attrSize{0}; }; - BatchExporter(StrView target, + BatchExporter(StrView target, bool ssl, const std::string& trustedCert, size_t batchSize, size_t batchCount, const std::map& resourceAttrs) : - batchSize(batchSize), client(std::string(target)) + batchSize(batchSize), client(std::string(target), ssl, trustedCert) { free.reserve(batchCount); while (batchCount-- > 0) { diff --git a/src/ngx_otel_module.cpp b/src/ngx_otel_module.cpp index f22616f..e23ef5a 100644 --- a/src/ngx_otel_module.cpp +++ b/src/ngx_otel_module.cpp @@ -6,6 +6,8 @@ #include "trace_context.hpp" #include "batch_exporter.hpp" +#include + extern ngx_module_t ngx_otel_module; namespace { @@ -26,6 +28,8 @@ struct MainConfBase { struct MainConf : MainConfBase { std::map resourceAttrs; + bool ssl; + std::string trustedCert; }; struct SpanAttr { @@ -44,6 +48,7 @@ struct LocationConf { char* setExporter(ngx_conf_t* cf, ngx_command_t* cmd, void* conf); char* addResourceAttr(ngx_conf_t* cf, ngx_command_t* cmd, void* conf); char* addSpanAttr(ngx_conf_t* cf, ngx_command_t* cmd, void* conf); +char* setTrustedCertificate(ngx_conf_t* cf, ngx_command_t* cmd, void* conf); namespace Propagation { @@ -111,6 +116,10 @@ ngx_command_t gExporterCommands[] = { 0, offsetof(MainConfBase, endpoint) }, + { ngx_string("trusted_certificate"), + NGX_CONF_TAKE1, + setTrustedCertificate }, + { ngx_string("interval"), NGX_CONF_TAKE1, ngx_conf_set_msec_slot, @@ -569,6 +578,8 @@ ngx_int_t initWorkerProcess(ngx_cycle_t* cycle) try { gExporter.reset(new BatchExporter( toStrView(mcf->endpoint), + mcf->ssl, + mcf->trustedCert, mcf->batchSize, mcf->batchCount, mcf->resourceAttrs)); @@ -671,9 +682,7 @@ char* setExporter(ngx_conf_t* cf, ngx_command_t* cmd, void* conf) } if (iremovePrefix(&mcf->endpoint, "https://")) { - ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, - "\"otel_exporter\" doesn't support \"https\" endpoints"); - return (char*)NGX_CONF_ERROR; + mcf->ssl = true; } else { iremovePrefix(&mcf->endpoint, "http://"); } @@ -702,6 +711,36 @@ char* addResourceAttr(ngx_conf_t* cf, ngx_command_t* cmd, void* conf) return NGX_CONF_OK; } +char* setTrustedCertificate(ngx_conf_t* cf, ngx_command_t* cmd, void* conf) { + auto path = ((ngx_str_t*)cf->args->elts)[1]; + auto mcf = getMainConf(cf); + + if (ngx_get_full_name(cf->pool, &cf->cycle->conf_prefix, &path) != NGX_OK) { + return (char*)NGX_CONF_ERROR; + } + + try { + std::ifstream file{(const char*)path.data, std::ios::binary}; + if (!file.is_open()) { + ngx_conf_log_error(NGX_LOG_EMERG, cf, ngx_errno, + "failed to open \"%V\"", &path); + return (char*)NGX_CONF_ERROR; + } + file.exceptions(std::ios::failbit | std::ios::badbit); + file.seekg(0, std::ios::end); + size_t size = file.tellg(); + mcf->trustedCert.resize(size); + file.seekg(0); + file.read(&mcf->trustedCert[0], mcf->trustedCert.size()); + } catch (const std::exception& e) { + ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, + "failed to read \"%V\": %s", &path, e.what()); + return (char*)NGX_CONF_ERROR; + } + + return NGX_CONF_OK; +} + void* createMainConf(ngx_conf_t* cf) { auto cln = ngx_pool_cleanup_add(cf->pool, sizeof(MainConf)); diff --git a/src/trace_service_client.hpp b/src/trace_service_client.hpp index 6871019..d248f00 100644 --- a/src/trace_service_client.hpp +++ b/src/trace_service_client.hpp @@ -17,10 +17,18 @@ public: typedef std::function ResponseCb; - TraceServiceClient(const std::string& target) + TraceServiceClient(const std::string& target, bool ssl, + const std::string& trustedCert) { - auto channel = grpc::CreateChannel( - target, grpc::InsecureChannelCredentials()); + std::shared_ptr creds; + if (ssl) { + grpc::SslCredentialsOptions options; + options.pem_root_certs = trustedCert; + creds = grpc::SslCredentials(options); + } else { + creds = grpc::InsecureChannelCredentials(); + } + auto channel = grpc::CreateChannel(target, creds); channel->GetState(true); // trigger 'connecting' state stub = TraceService::NewStub(channel);