From 355def333c337df8db91a809e8b102696b58bbce Mon Sep 17 00:00:00 2001 From: Kyle Loveless Date: Tue, 25 Apr 2023 13:55:57 -0400 Subject: [PATCH] Add support for client-side cert/key to gRPC exports. TODO: Add tests. I have not run or written any tests, other than verifying it worked once in my production system. --- api/CMakeLists.txt | 5 +++ .../otlp/otlp_grpc_exporter_options.h | 15 ++++++++ exporters/otlp/src/otlp_grpc_client.cc | 35 +++++++++++++------ 3 files changed, 44 insertions(+), 11 deletions(-) diff --git a/api/CMakeLists.txt b/api/CMakeLists.txt index 31863b25e3..da5deced72 100644 --- a/api/CMakeLists.txt +++ b/api/CMakeLists.txt @@ -113,6 +113,11 @@ if(WITH_OTLP_HTTP_SSL_PREVIEW) endif() endif() +if (WITH_OTLP_GRPC_MTLS_PREVIEW) + target_compile_definitions(opentelemetry_api + INTERFACE ENABLE_OTLP_GRPC_MTLS_PREVIEW) +endif() + if(WITH_METRICS_EXEMPLAR_PREVIEW) target_compile_definitions(opentelemetry_api INTERFACE ENABLE_METRICS_EXEMPLAR_PREVIEW) diff --git a/exporters/otlp/include/opentelemetry/exporters/otlp/otlp_grpc_exporter_options.h b/exporters/otlp/include/opentelemetry/exporters/otlp/otlp_grpc_exporter_options.h index f5a2b9d295..930358c3be 100644 --- a/exporters/otlp/include/opentelemetry/exporters/otlp/otlp_grpc_exporter_options.h +++ b/exporters/otlp/include/opentelemetry/exporters/otlp/otlp_grpc_exporter_options.h @@ -3,6 +3,8 @@ #pragma once +#include "absl/types/optional.h" +#include "absl/types/variant.h" #include "opentelemetry/exporters/otlp/otlp_environment.h" #include @@ -28,6 +30,19 @@ struct OtlpGrpcExporterOptions // ssl_credentials_cacert_as_string in-memory string representation of .pem file to be used for // SSL encryption. std::string ssl_credentials_cacert_as_string = GetOtlpDefaultSslCertificateString(); + +#ifdef ENABLE_OTLP_GRPC_MTLS_PREVIEW + // At most one of ssl_client_key_* should be non-empty. If use_ssl_credentials, they will + // be read to allow for mTLS. + std::string ssl_client_key_path = GetOtlpDefaultTracesSslClientKeyPath(); + std::string ssl_client_key_string = GetOtlpDefaultTracesSslClientKeyString(); + + // At most one of ssl_client_cert_* should be non-empty. If use_ssl_credentials, they will + // be read to allow for mTLS. + std::string ssl_client_cert_path = GetOtlpDefaultTracesSslClientCertificatePath(); + std::string ssl_client_cert_string = GetOtlpDefaultTracesSslClientCertificateString(); +#endif + // Timeout for grpc deadline std::chrono::system_clock::duration timeout = GetOtlpDefaultTimeout(); // Additional HTTP headers diff --git a/exporters/otlp/src/otlp_grpc_client.cc b/exporters/otlp/src/otlp_grpc_client.cc index 9250f87cc4..a14f624d51 100644 --- a/exporters/otlp/src/otlp_grpc_client.cc +++ b/exporters/otlp/src/otlp_grpc_client.cc @@ -34,6 +34,16 @@ static std::string GetFileContents(const char *fpath) finstream.close(); return contents; } + +// If the file path is non-empty, returns the contents of the file. Otherwise returns contents. +static std::string GetFileContentsOrInMemoryContents( + const std::string& file_path, const std::string& contents) { + if (!file_path.empty()) { + return GetFileContents(file_path.c_str()); + } + return contents; +} + } // namespace std::shared_ptr OtlpGrpcClient::MakeChannel(const OtlpGrpcExporterOptions &options) @@ -58,17 +68,20 @@ std::shared_ptr OtlpGrpcClient::MakeChannel(const OtlpGrpcExporte grpc::ChannelArguments grpc_arguments; grpc_arguments.SetUserAgentPrefix(options.user_agent); - if (options.use_ssl_credentials) - { - grpc::SslCredentialsOptions ssl_opts; - if (options.ssl_credentials_cacert_path.empty()) - { - ssl_opts.pem_root_certs = options.ssl_credentials_cacert_as_string; - } - else - { - ssl_opts.pem_root_certs = GetFileContents((options.ssl_credentials_cacert_path).c_str()); - } + if (options.use_ssl_credentials) { + grpc::SslCredentialsOptions ssl_opts = { + .pem_root_certs = GetFileContentsOrInMemoryContents( + options.ssl_credentials_cacert_path, + options.ssl_credentials_cacert_as_string), +#if ENABLE_OTLP_GRPC_MTLS_PREVIEW + .pem_private_key = GetFileContentsOrInMemoryContents( + options.ssl_client_key_path, + options.ssl_client_key_string), + .pem_cert_chain = GetFileContentsOrInMemoryContents( + options.ssl_client_cert_path, + options.ssl_client_cert_string) +#endif + }; channel = grpc::CreateCustomChannel(grpc_target, grpc::SslCredentials(ssl_opts), grpc_arguments); }