From 0ab0bd36c6ad0ba6694a35b448a8c777c427d314 Mon Sep 17 00:00:00 2001 From: Alex Boten <223565+codeboten@users.noreply.github.com> Date: Wed, 27 Nov 2024 10:23:53 -0800 Subject: [PATCH 1/9] config: add support for certificate configuration Fixes https://github.com/open-telemetry/opentelemetry-go-contrib/issues/6351 Signed-off-by: Alex Boten <223565+codeboten@users.noreply.github.com> --- config/testdata/bad_cert.crt | 1 + config/testdata/ca.crt | 20 ++++++++++++++++++++ config/v0.3.0/log.go | 8 ++++++++ config/v0.3.0/log_test.go | 36 ++++++++++++++++++++++++++++++++++++ config/v0.3.0/metric.go | 8 ++++++++ config/v0.3.0/metric_test.go | 35 +++++++++++++++++++++++++++++++++++ config/v0.3.0/trace.go | 9 +++++++++ config/v0.3.0/trace_test.go | 36 ++++++++++++++++++++++++++++++++++++ 8 files changed, 153 insertions(+) create mode 100644 config/testdata/bad_cert.crt create mode 100644 config/testdata/ca.crt diff --git a/config/testdata/bad_cert.crt b/config/testdata/bad_cert.crt new file mode 100644 index 00000000000..dbbd2b8576f --- /dev/null +++ b/config/testdata/bad_cert.crt @@ -0,0 +1 @@ +This is intentionally not a PEM formatted cert file. diff --git a/config/testdata/ca.crt b/config/testdata/ca.crt new file mode 100644 index 00000000000..2272f84e64d --- /dev/null +++ b/config/testdata/ca.crt @@ -0,0 +1,20 @@ +-----BEGIN CERTIFICATE----- +MIIDNjCCAh4CCQC0I5IQT7eziDANBgkqhkiG9w0BAQsFADBdMQswCQYDVQQGEwJB +VTESMBAGA1UECAwJQXVzdHJhbGlhMQ8wDQYDVQQHDAZTeWRuZXkxEjAQBgNVBAoM +CU15T3JnTmFtZTEVMBMGA1UEAwwMTXlDb21tb25OYW1lMB4XDTIyMDgwMzA0MTky +MVoXDTMyMDczMTA0MTkyMVowXTELMAkGA1UEBhMCQVUxEjAQBgNVBAgMCUF1c3Ry +YWxpYTEPMA0GA1UEBwwGU3lkbmV5MRIwEAYDVQQKDAlNeU9yZ05hbWUxFTATBgNV +BAMMDE15Q29tbW9uTmFtZTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEB +AMhGP0dy3zvkdx9zI+/XVjPOWlER0OUp7Sgzidc3nLOk42+bH4ofIVNtOFVqlNKi +O1bImu238VdBhd6R5IZZ1ZdIMcCeDgSJYu2X9wA3m4PKz8IdXo5ly2OHghhmCvqG +WxgqDj5wPXiczQwuf1EcDMtRWbXJ6Z/XH1U68R/kRdNLkiZ2LwtjoQpis5XYckLL +CrdF+AL6GeDIe0Mh9QGs26Vux+2kvaOGNUWRPE6Wt4GkqyKqmzYfR9HbflJ4xHT2 +I+jE1lg+jMBeom7z8Z90RE4GGcHjO+Vens/88r5EAjTnFj1Kb5gL2deSHY1m/++R +Z/kRyg+zQJyw4fAzlAA4+VkCAwEAATANBgkqhkiG9w0BAQsFAAOCAQEAM3gRdTKX +eGwGYVmmKqA2vTxeigQYLHml7OSopcWj2wJfxfp49HXPRuvgpQn9iubxO3Zmhd83 +2X1E+T0A8oy5CfxgpAhHb3lY0jm3TjKXm6m+dSODwL3uND8tX+SqR8sRTFxPvPuo +pmvhdTZoRI3EzIiHLTgCuSU25JNP/vrVoKk0JvCkDYTU/WcVfj0v95DTMoWR4JGz +mtBwrgD0EM2XRw5ZMc7sMPli1gqmCbCQUrDZ+rPB78WDCBILBd8Cz75qYTUp98BY +akJyBckdJHAdyEQYDKa9HpmpexOO7IhSXCTEN1DEBgpZgEi/lBDRG/b0OzenUUgt +LUABtWt3pNQ9HA== +-----END CERTIFICATE----- diff --git a/config/v0.3.0/log.go b/config/v0.3.0/log.go index 40ad54dbfd1..30ed897fe06 100644 --- a/config/v0.3.0/log.go +++ b/config/v0.3.0/log.go @@ -17,6 +17,7 @@ import ( "go.opentelemetry.io/otel/log/noop" sdklog "go.opentelemetry.io/otel/sdk/log" "go.opentelemetry.io/otel/sdk/resource" + "google.golang.org/grpc/credentials" ) func loggerProvider(cfg configOptions, res *resource.Resource) (log.LoggerProvider, shutdownFunc, error) { @@ -178,6 +179,13 @@ func otlpGRPCLogExporter(ctx context.Context, otlpConfig *OTLP) (sdklog.Exporter if u.Scheme == "http" { opts = append(opts, otlploggrpc.WithInsecure()) } + if otlpConfig.Certificate != nil { + creds, err := credentials.NewClientTLSFromFile(*otlpConfig.Certificate, "") + if err != nil { + return nil, fmt.Errorf("could not create client tls credentials: %w", err) + } + opts = append(opts, otlploggrpc.WithTLSCredentials(creds)) + } } if otlpConfig.Compression != nil { switch *otlpConfig.Compression { diff --git a/config/v0.3.0/log_test.go b/config/v0.3.0/log_test.go index f04d521eb50..aaf46a4f906 100644 --- a/config/v0.3.0/log_test.go +++ b/config/v0.3.0/log_test.go @@ -6,7 +6,9 @@ package config import ( "context" "errors" + "fmt" "net/url" + "path/filepath" "reflect" "testing" @@ -221,6 +223,40 @@ func TestLogProcessor(t *testing.T) { }, wantProcessor: sdklog.NewBatchProcessor(otlpGRPCExporter), }, + { + name: "batch/otlp-grpc-good-ca-certificate", + processor: LogRecordProcessor{ + Batch: &BatchLogRecordProcessor{ + Exporter: LogRecordExporter{ + OTLP: &OTLP{ + Protocol: ptr("grpc"), + Endpoint: ptr("localhost:4317"), + Compression: ptr("gzip"), + Timeout: ptr(1000), + Certificate: ptr(filepath.Join("testdata", "ca.crt")), + }, + }, + }, + }, + wantProcessor: sdklog.NewBatchProcessor(otlpGRPCExporter), + }, + { + name: "batch/otlp-grpc-bad-ca-certificate", + processor: LogRecordProcessor{ + Batch: &BatchLogRecordProcessor{ + Exporter: LogRecordExporter{ + OTLP: &OTLP{ + Protocol: ptr("grpc"), + Endpoint: ptr("localhost:4317"), + Compression: ptr("gzip"), + Timeout: ptr(1000), + Certificate: ptr(filepath.Join("testdata", "bad_cert.crt")), + }, + }, + }, + }, + wantErr: fmt.Errorf("could not create client tls credentials: %w", errors.New("credentials: failed to append certificates")), + }, { name: "batch/otlp-grpc-exporter-no-scheme", processor: LogRecordProcessor{ diff --git a/config/v0.3.0/metric.go b/config/v0.3.0/metric.go index c551a5b91fe..444550f2ab7 100644 --- a/config/v0.3.0/metric.go +++ b/config/v0.3.0/metric.go @@ -17,6 +17,7 @@ import ( "github.com/prometheus/client_golang/prometheus" "github.com/prometheus/client_golang/prometheus/promhttp" + "google.golang.org/grpc/credentials" "go.opentelemetry.io/otel" "go.opentelemetry.io/otel/attribute" @@ -205,6 +206,13 @@ func otlpGRPCMetricExporter(ctx context.Context, otlpConfig *OTLPMetric) (sdkmet if u.Scheme == "http" { opts = append(opts, otlpmetricgrpc.WithInsecure()) } + if otlpConfig.Certificate != nil { + creds, err := credentials.NewClientTLSFromFile(*otlpConfig.Certificate, "") + if err != nil { + return nil, fmt.Errorf("could not create client tls credentials: %w", err) + } + opts = append(opts, otlpmetricgrpc.WithTLSCredentials(creds)) + } } if otlpConfig.Compression != nil { diff --git a/config/v0.3.0/metric_test.go b/config/v0.3.0/metric_test.go index b6c6d095fa8..87fa3c0277d 100644 --- a/config/v0.3.0/metric_test.go +++ b/config/v0.3.0/metric_test.go @@ -8,6 +8,7 @@ import ( "errors" "fmt" "net/url" + "path/filepath" "reflect" "testing" "time" @@ -215,6 +216,40 @@ func TestReader(t *testing.T) { }, wantReader: sdkmetric.NewPeriodicReader(otlpGRPCExporter), }, + { + name: "periodic/otlp-grpc-good-ca-certificate", + reader: MetricReader{ + Periodic: &PeriodicMetricReader{ + Exporter: PushMetricExporter{ + OTLP: &OTLPMetric{ + Protocol: ptr("grpc"), + Endpoint: ptr("https://localhost:4317"), + Compression: ptr("gzip"), + Timeout: ptr(1000), + Certificate: ptr(filepath.Join("testdata", "ca.crt")), + }, + }, + }, + }, + wantReader: sdkmetric.NewPeriodicReader(otlpGRPCExporter), + }, + { + name: "periodic/otlp-grpc-bad-ca-certificate", + reader: MetricReader{ + Periodic: &PeriodicMetricReader{ + Exporter: PushMetricExporter{ + OTLP: &OTLPMetric{ + Protocol: ptr("grpc"), + Endpoint: ptr("https://localhost:4317"), + Compression: ptr("gzip"), + Timeout: ptr(1000), + Certificate: ptr(filepath.Join("testdata", "bad_cert.crt")), + }, + }, + }, + }, + wantErr: fmt.Errorf("could not create client tls credentials: %w", errors.New("credentials: failed to append certificates")), + }, { name: "periodic/otlp-grpc-exporter-no-endpoint", reader: MetricReader{ diff --git a/config/v0.3.0/trace.go b/config/v0.3.0/trace.go index f1e6552cde3..e07b3922eef 100644 --- a/config/v0.3.0/trace.go +++ b/config/v0.3.0/trace.go @@ -17,6 +17,7 @@ import ( sdktrace "go.opentelemetry.io/otel/sdk/trace" "go.opentelemetry.io/otel/trace" "go.opentelemetry.io/otel/trace/noop" + "google.golang.org/grpc/credentials" ) func tracerProvider(cfg configOptions, res *resource.Resource) (trace.TracerProvider, shutdownFunc, error) { @@ -108,6 +109,14 @@ func otlpGRPCSpanExporter(ctx context.Context, otlpConfig *OTLP) (sdktrace.SpanE if u.Scheme == "http" { opts = append(opts, otlptracegrpc.WithInsecure()) } + + if otlpConfig.Certificate != nil { + creds, err := credentials.NewClientTLSFromFile(*otlpConfig.Certificate, "") + if err != nil { + return nil, fmt.Errorf("could not create client tls credentials: %w", err) + } + opts = append(opts, otlptracegrpc.WithTLSCredentials(creds)) + } } if otlpConfig.Compression != nil { diff --git a/config/v0.3.0/trace_test.go b/config/v0.3.0/trace_test.go index fb6e9b14cdc..80c3a91ac41 100644 --- a/config/v0.3.0/trace_test.go +++ b/config/v0.3.0/trace_test.go @@ -6,7 +6,9 @@ package config import ( "context" "errors" + "fmt" "net/url" + "path/filepath" "reflect" "testing" @@ -261,6 +263,40 @@ func TestSpanProcessor(t *testing.T) { }, wantProcessor: sdktrace.NewBatchSpanProcessor(otlpGRPCExporter), }, + { + name: "batch/otlp-grpc-good-ca-certificate", + processor: SpanProcessor{ + Batch: &BatchSpanProcessor{ + Exporter: SpanExporter{ + OTLP: &OTLP{ + Protocol: ptr("grpc"), + Endpoint: ptr("localhost:4317"), + Compression: ptr("gzip"), + Timeout: ptr(1000), + Certificate: ptr(filepath.Join("testdata", "ca.crt")), + }, + }, + }, + }, + wantProcessor: sdktrace.NewBatchProcessor(otlpGRPCExporter), + }, + { + name: "batch/otlp-grpc-bad-ca-certificate", + processor: SpanProcessor{ + Batch: &BatchSpanProcessor{ + Exporter: SpanExporter{ + OTLP: &OTLP{ + Protocol: ptr("grpc"), + Endpoint: ptr("localhost:4317"), + Compression: ptr("gzip"), + Timeout: ptr(1000), + Certificate: ptr(filepath.Join("testdata", "bad_cert.crt")), + }, + }, + }, + }, + wantErr: fmt.Errorf("could not create client tls credentials: %w", errors.New("credentials: failed to append certificates")), + }, { name: "batch/otlp-grpc-exporter-no-scheme", processor: SpanProcessor{ From 9208392774510d06645cc9aaba3f01c43f6a75a1 Mon Sep 17 00:00:00 2001 From: Alex Boten <223565+codeboten@users.noreply.github.com> Date: Wed, 27 Nov 2024 10:27:13 -0800 Subject: [PATCH 2/9] fix typo Signed-off-by: Alex Boten <223565+codeboten@users.noreply.github.com> --- config/v0.3.0/trace_test.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/config/v0.3.0/trace_test.go b/config/v0.3.0/trace_test.go index 80c3a91ac41..c57ea90250c 100644 --- a/config/v0.3.0/trace_test.go +++ b/config/v0.3.0/trace_test.go @@ -278,7 +278,7 @@ func TestSpanProcessor(t *testing.T) { }, }, }, - wantProcessor: sdktrace.NewBatchProcessor(otlpGRPCExporter), + wantProcessor: sdktrace.NewBatchSpanProcessor(otlpGRPCExporter), }, { name: "batch/otlp-grpc-bad-ca-certificate", From 3c4c6b820cb7ccaa5ae4164b4d03584e4dc4ac38 Mon Sep 17 00:00:00 2001 From: Alex Boten <223565+codeboten@users.noreply.github.com> Date: Wed, 27 Nov 2024 10:30:57 -0800 Subject: [PATCH 3/9] tidy Signed-off-by: Alex Boten <223565+codeboten@users.noreply.github.com> --- config/go.mod | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/config/go.mod b/config/go.mod index 1412a25e94c..f9b705ec6f1 100644 --- a/config/go.mod +++ b/config/go.mod @@ -22,6 +22,7 @@ require ( go.opentelemetry.io/otel/sdk/log v0.8.0 go.opentelemetry.io/otel/sdk/metric v1.32.0 go.opentelemetry.io/otel/trace v1.32.0 + google.golang.org/grpc v1.68.1 gopkg.in/yaml.v3 v3.0.1 ) @@ -47,6 +48,5 @@ require ( golang.org/x/text v0.21.0 // indirect google.golang.org/genproto/googleapis/api v0.0.0-20241209162323-e6fa225c2576 // indirect google.golang.org/genproto/googleapis/rpc v0.0.0-20241209162323-e6fa225c2576 // indirect - google.golang.org/grpc v1.68.1 // indirect google.golang.org/protobuf v1.35.2 // indirect ) From ff94ddd951f7983c5dabee5dda26e1b4ad035f73 Mon Sep 17 00:00:00 2001 From: Alex Boten <223565+codeboten@users.noreply.github.com> Date: Wed, 27 Nov 2024 10:33:45 -0800 Subject: [PATCH 4/9] more tidying Signed-off-by: Alex Boten <223565+codeboten@users.noreply.github.com> --- config/v0.3.0/log.go | 3 ++- config/v0.3.0/trace.go | 3 ++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/config/v0.3.0/log.go b/config/v0.3.0/log.go index 30ed897fe06..a8b48b9fdaf 100644 --- a/config/v0.3.0/log.go +++ b/config/v0.3.0/log.go @@ -10,6 +10,8 @@ import ( "net/url" "time" + "google.golang.org/grpc/credentials" + "go.opentelemetry.io/otel/exporters/otlp/otlplog/otlploggrpc" "go.opentelemetry.io/otel/exporters/otlp/otlplog/otlploghttp" "go.opentelemetry.io/otel/exporters/stdout/stdoutlog" @@ -17,7 +19,6 @@ import ( "go.opentelemetry.io/otel/log/noop" sdklog "go.opentelemetry.io/otel/sdk/log" "go.opentelemetry.io/otel/sdk/resource" - "google.golang.org/grpc/credentials" ) func loggerProvider(cfg configOptions, res *resource.Resource) (log.LoggerProvider, shutdownFunc, error) { diff --git a/config/v0.3.0/trace.go b/config/v0.3.0/trace.go index e07b3922eef..6f56345170a 100644 --- a/config/v0.3.0/trace.go +++ b/config/v0.3.0/trace.go @@ -10,6 +10,8 @@ import ( "net/url" "time" + "google.golang.org/grpc/credentials" + "go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc" "go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp" "go.opentelemetry.io/otel/exporters/stdout/stdouttrace" @@ -17,7 +19,6 @@ import ( sdktrace "go.opentelemetry.io/otel/sdk/trace" "go.opentelemetry.io/otel/trace" "go.opentelemetry.io/otel/trace/noop" - "google.golang.org/grpc/credentials" ) func tracerProvider(cfg configOptions, res *resource.Resource) (trace.TracerProvider, shutdownFunc, error) { From d12d08c208b12ebc1362d9470dda6fec4140c1a3 Mon Sep 17 00:00:00 2001 From: Alex Boten <223565+codeboten@users.noreply.github.com> Date: Wed, 27 Nov 2024 14:20:43 -0800 Subject: [PATCH 5/9] add support for http export as well Signed-off-by: Alex Boten <223565+codeboten@users.noreply.github.com> --- config/v0.3.0/config.go | 20 ++++++++++++++++++++ config/v0.3.0/log.go | 23 ++++++++++++++++------- config/v0.3.0/log_test.go | 34 ++++++++++++++++++++++++++++++++++ config/v0.3.0/metric.go | 23 ++++++++++++++++------- config/v0.3.0/metric_test.go | 34 ++++++++++++++++++++++++++++++++++ config/v0.3.0/trace.go | 24 ++++++++++++++++-------- config/v0.3.0/trace_test.go | 34 ++++++++++++++++++++++++++++++++++ 7 files changed, 170 insertions(+), 22 deletions(-) diff --git a/config/v0.3.0/config.go b/config/v0.3.0/config.go index 44030d4f612..b54c60479c2 100644 --- a/config/v0.3.0/config.go +++ b/config/v0.3.0/config.go @@ -5,7 +5,10 @@ package config // import "go.opentelemetry.io/contrib/config/v0.3.0" import ( "context" + "crypto/tls" + "crypto/x509" "errors" + "os" "gopkg.in/yaml.v3" @@ -155,3 +158,20 @@ func toStringMap(pairs []NameStringValuePair) map[string]string { } return output } + +// createTLSConfig creates a tls.Config from a raw certificate bytes +// to verify a server certificate. +func createTLSConfig(certFile string) (*tls.Config, error) { + b, err := os.ReadFile(certFile) + if err != nil { + return nil, err + } + cp := x509.NewCertPool() + if ok := cp.AppendCertsFromPEM(b); !ok { + return nil, errors.New("failed to append certificate to the cert pool") + } + + return &tls.Config{ + RootCAs: cp, + }, nil +} diff --git a/config/v0.3.0/log.go b/config/v0.3.0/log.go index a8b48b9fdaf..42b1b209207 100644 --- a/config/v0.3.0/log.go +++ b/config/v0.3.0/log.go @@ -156,6 +156,14 @@ func otlpHTTPLogExporter(ctx context.Context, otlpConfig *OTLP) (sdklog.Exporter opts = append(opts, otlploghttp.WithHeaders(toStringMap(otlpConfig.Headers))) } + if otlpConfig.Certificate != nil { + creds, err := createTLSConfig(*otlpConfig.Certificate) + if err != nil { + return nil, fmt.Errorf("could not create client tls credentials: %w", err) + } + opts = append(opts, otlploghttp.WithTLSClientConfig(creds)) + } + return otlploghttp.New(ctx, opts...) } @@ -180,13 +188,6 @@ func otlpGRPCLogExporter(ctx context.Context, otlpConfig *OTLP) (sdklog.Exporter if u.Scheme == "http" { opts = append(opts, otlploggrpc.WithInsecure()) } - if otlpConfig.Certificate != nil { - creds, err := credentials.NewClientTLSFromFile(*otlpConfig.Certificate, "") - if err != nil { - return nil, fmt.Errorf("could not create client tls credentials: %w", err) - } - opts = append(opts, otlploggrpc.WithTLSCredentials(creds)) - } } if otlpConfig.Compression != nil { switch *otlpConfig.Compression { @@ -205,5 +206,13 @@ func otlpGRPCLogExporter(ctx context.Context, otlpConfig *OTLP) (sdklog.Exporter opts = append(opts, otlploggrpc.WithHeaders(toStringMap(otlpConfig.Headers))) } + if otlpConfig.Certificate != nil { + creds, err := credentials.NewClientTLSFromFile(*otlpConfig.Certificate, "") + if err != nil { + return nil, fmt.Errorf("could not create client tls credentials: %w", err) + } + opts = append(opts, otlploggrpc.WithTLSCredentials(creds)) + } + return otlploggrpc.New(ctx, opts...) } diff --git a/config/v0.3.0/log_test.go b/config/v0.3.0/log_test.go index aaf46a4f906..2774d7c0818 100644 --- a/config/v0.3.0/log_test.go +++ b/config/v0.3.0/log_test.go @@ -349,6 +349,40 @@ func TestLogProcessor(t *testing.T) { }, wantProcessor: sdklog.NewBatchProcessor(otlpHTTPExporter), }, + { + name: "batch/otlp-http-good-ca-certificate", + processor: LogRecordProcessor{ + Batch: &BatchLogRecordProcessor{ + Exporter: LogRecordExporter{ + OTLP: &OTLP{ + Protocol: ptr("http/protobuf"), + Endpoint: ptr("localhost:4317"), + Compression: ptr("gzip"), + Timeout: ptr(1000), + Certificate: ptr(filepath.Join("testdata", "ca.crt")), + }, + }, + }, + }, + wantProcessor: sdklog.NewBatchProcessor(otlpHTTPExporter), + }, + { + name: "batch/otlp-http-bad-ca-certificate", + processor: LogRecordProcessor{ + Batch: &BatchLogRecordProcessor{ + Exporter: LogRecordExporter{ + OTLP: &OTLP{ + Protocol: ptr("http/protobuf"), + Endpoint: ptr("localhost:4317"), + Compression: ptr("gzip"), + Timeout: ptr(1000), + Certificate: ptr(filepath.Join("testdata", "bad_cert.crt")), + }, + }, + }, + }, + wantErr: fmt.Errorf("could not create client tls credentials: %w", errors.New("failed to append certificate to the cert pool")), + }, { name: "batch/otlp-http-exporter-with-path", processor: LogRecordProcessor{ diff --git a/config/v0.3.0/metric.go b/config/v0.3.0/metric.go index 444550f2ab7..e88c02349c9 100644 --- a/config/v0.3.0/metric.go +++ b/config/v0.3.0/metric.go @@ -182,6 +182,14 @@ func otlpHTTPMetricExporter(ctx context.Context, otlpConfig *OTLPMetric) (sdkmet } } + if otlpConfig.Certificate != nil { + creds, err := createTLSConfig(*otlpConfig.Certificate) + if err != nil { + return nil, fmt.Errorf("could not create client tls credentials: %w", err) + } + opts = append(opts, otlpmetrichttp.WithTLSClientConfig(creds)) + } + return otlpmetrichttp.New(ctx, opts...) } @@ -206,13 +214,6 @@ func otlpGRPCMetricExporter(ctx context.Context, otlpConfig *OTLPMetric) (sdkmet if u.Scheme == "http" { opts = append(opts, otlpmetricgrpc.WithInsecure()) } - if otlpConfig.Certificate != nil { - creds, err := credentials.NewClientTLSFromFile(*otlpConfig.Certificate, "") - if err != nil { - return nil, fmt.Errorf("could not create client tls credentials: %w", err) - } - opts = append(opts, otlpmetricgrpc.WithTLSCredentials(creds)) - } } if otlpConfig.Compression != nil { @@ -244,6 +245,14 @@ func otlpGRPCMetricExporter(ctx context.Context, otlpConfig *OTLPMetric) (sdkmet } } + if otlpConfig.Certificate != nil { + creds, err := credentials.NewClientTLSFromFile(*otlpConfig.Certificate, "") + if err != nil { + return nil, fmt.Errorf("could not create client tls credentials: %w", err) + } + opts = append(opts, otlpmetricgrpc.WithTLSCredentials(creds)) + } + return otlpmetricgrpc.New(ctx, opts...) } diff --git a/config/v0.3.0/metric_test.go b/config/v0.3.0/metric_test.go index 87fa3c0277d..4384af9ea04 100644 --- a/config/v0.3.0/metric_test.go +++ b/config/v0.3.0/metric_test.go @@ -443,6 +443,40 @@ func TestReader(t *testing.T) { }, wantReader: sdkmetric.NewPeriodicReader(otlpHTTPExporter), }, + { + name: "periodic/otlp-http-good-ca-certificate", + reader: MetricReader{ + Periodic: &PeriodicMetricReader{ + Exporter: PushMetricExporter{ + OTLP: &OTLPMetric{ + Protocol: ptr("http/protobuf"), + Endpoint: ptr("https://localhost:4317"), + Compression: ptr("gzip"), + Timeout: ptr(1000), + Certificate: ptr(filepath.Join("testdata", "ca.crt")), + }, + }, + }, + }, + wantReader: sdkmetric.NewPeriodicReader(otlpHTTPExporter), + }, + { + name: "periodic/otlp-http-bad-ca-certificate", + reader: MetricReader{ + Periodic: &PeriodicMetricReader{ + Exporter: PushMetricExporter{ + OTLP: &OTLPMetric{ + Protocol: ptr("http/protobuf"), + Endpoint: ptr("https://localhost:4317"), + Compression: ptr("gzip"), + Timeout: ptr(1000), + Certificate: ptr(filepath.Join("testdata", "bad_cert.crt")), + }, + }, + }, + }, + wantErr: fmt.Errorf("could not create client tls credentials: %w", errors.New("failed to append certificate to the cert pool")), + }, { name: "periodic/otlp-http-exporter-with-path", reader: MetricReader{ diff --git a/config/v0.3.0/trace.go b/config/v0.3.0/trace.go index 6f56345170a..10d2473912f 100644 --- a/config/v0.3.0/trace.go +++ b/config/v0.3.0/trace.go @@ -110,14 +110,6 @@ func otlpGRPCSpanExporter(ctx context.Context, otlpConfig *OTLP) (sdktrace.SpanE if u.Scheme == "http" { opts = append(opts, otlptracegrpc.WithInsecure()) } - - if otlpConfig.Certificate != nil { - creds, err := credentials.NewClientTLSFromFile(*otlpConfig.Certificate, "") - if err != nil { - return nil, fmt.Errorf("could not create client tls credentials: %w", err) - } - opts = append(opts, otlptracegrpc.WithTLSCredentials(creds)) - } } if otlpConfig.Compression != nil { @@ -137,6 +129,14 @@ func otlpGRPCSpanExporter(ctx context.Context, otlpConfig *OTLP) (sdktrace.SpanE opts = append(opts, otlptracegrpc.WithHeaders(toStringMap(otlpConfig.Headers))) } + if otlpConfig.Certificate != nil { + creds, err := credentials.NewClientTLSFromFile(*otlpConfig.Certificate, "") + if err != nil { + return nil, fmt.Errorf("could not create client tls credentials: %w", err) + } + opts = append(opts, otlptracegrpc.WithTLSCredentials(creds)) + } + return otlptracegrpc.New(ctx, opts...) } @@ -174,6 +174,14 @@ func otlpHTTPSpanExporter(ctx context.Context, otlpConfig *OTLP) (sdktrace.SpanE opts = append(opts, otlptracehttp.WithHeaders(toStringMap(otlpConfig.Headers))) } + if otlpConfig.Certificate != nil { + creds, err := createTLSConfig(*otlpConfig.Certificate) + if err != nil { + return nil, fmt.Errorf("could not create client tls credentials: %w", err) + } + opts = append(opts, otlptracehttp.WithTLSClientConfig(creds)) + } + return otlptracehttp.New(ctx, opts...) } diff --git a/config/v0.3.0/trace_test.go b/config/v0.3.0/trace_test.go index c57ea90250c..32f6b4c70b5 100644 --- a/config/v0.3.0/trace_test.go +++ b/config/v0.3.0/trace_test.go @@ -389,6 +389,40 @@ func TestSpanProcessor(t *testing.T) { }, wantProcessor: sdktrace.NewBatchSpanProcessor(otlpHTTPExporter), }, + { + name: "batch/otlp-http-good-ca-certificate", + processor: SpanProcessor{ + Batch: &BatchSpanProcessor{ + Exporter: SpanExporter{ + OTLP: &OTLP{ + Protocol: ptr("http/protobuf"), + Endpoint: ptr("localhost:4317"), + Compression: ptr("gzip"), + Timeout: ptr(1000), + Certificate: ptr(filepath.Join("testdata", "ca.crt")), + }, + }, + }, + }, + wantProcessor: sdktrace.NewBatchSpanProcessor(otlpHTTPExporter), + }, + { + name: "batch/otlp-http-bad-ca-certificate", + processor: SpanProcessor{ + Batch: &BatchSpanProcessor{ + Exporter: SpanExporter{ + OTLP: &OTLP{ + Protocol: ptr("http/protobuf"), + Endpoint: ptr("localhost:4317"), + Compression: ptr("gzip"), + Timeout: ptr(1000), + Certificate: ptr(filepath.Join("testdata", "bad_cert.crt")), + }, + }, + }, + }, + wantErr: fmt.Errorf("could not create client tls credentials: %w", errors.New("failed to append certificate to the cert pool")), + }, { name: "batch/otlp-http-exporter-with-path", processor: SpanProcessor{ From 4408e3a556e272eaca536cb519b6203d65b04144 Mon Sep 17 00:00:00 2001 From: Alex Boten <223565+codeboten@users.noreply.github.com> Date: Wed, 27 Nov 2024 14:21:16 -0800 Subject: [PATCH 6/9] update changelog Signed-off-by: Alex Boten <223565+codeboten@users.noreply.github.com> --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 7a27860223f..d25a7a084ac 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -15,6 +15,7 @@ This project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.htm - The `go.opentelemetry.io/contrib/bridges/otellogr` module. This module provides an OpenTelemetry logging bridge for `github.com/go-logr/logr`. (#6386) - Added SNS instrumentation in `go.opentelemetry.io/contrib/instrumentation/github.com/aws/aws-sdk-go-v2/otelaws`. (#6388) +- Added support for configuring `Certificate` field when configuring OTLP exporters in `go.opentelemetry.io/contrib/config`. (#6376) ### Changed From a6549fd9c8b6ff6ace848e32aa55c962b0fcfb3c Mon Sep 17 00:00:00 2001 From: Alex Boten <223565+codeboten@users.noreply.github.com> Date: Wed, 27 Nov 2024 14:30:20 -0800 Subject: [PATCH 7/9] add ignore to G402 as per the otel-go repo Signed-off-by: Alex Boten <223565+codeboten@users.noreply.github.com> --- .golangci.yml | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/.golangci.yml b/.golangci.yml index a86971538da..13e41d8d2a9 100644 --- a/.golangci.yml +++ b/.golangci.yml @@ -70,6 +70,11 @@ issues: - gosec - perfsprint - usestdlibvars + # Ignoring gosec G402: TLS MinVersion too low + # as the https://pkg.go.dev/crypto/tls#Config handles MinVersion default well. + - text: "G402: TLS MinVersion too low." + linters: + - gosec include: # revive exported should have comment or be unexported. - EXC0012 From 2cdf0ca596200ed807fdf08de84711e37cb71f1b Mon Sep 17 00:00:00 2001 From: Alex Boten <223565+codeboten@users.noreply.github.com> Date: Tue, 3 Dec 2024 13:16:35 -0800 Subject: [PATCH 8/9] restrict linter config to config/*.go Signed-off-by: Alex Boten <223565+codeboten@users.noreply.github.com> --- .golangci.yml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.golangci.yml b/.golangci.yml index 13e41d8d2a9..a1edee29a6c 100644 --- a/.golangci.yml +++ b/.golangci.yml @@ -72,7 +72,8 @@ issues: - usestdlibvars # Ignoring gosec G402: TLS MinVersion too low # as the https://pkg.go.dev/crypto/tls#Config handles MinVersion default well. - - text: "G402: TLS MinVersion too low." + - path: config/*.go + text: "G402: TLS MinVersion too low." linters: - gosec include: From f2dfd61f11af7361164c08be9ffe4e65aa60d0bb Mon Sep 17 00:00:00 2001 From: Alex Boten <223565+codeboten@users.noreply.github.com> Date: Tue, 10 Dec 2024 12:15:38 -0800 Subject: [PATCH 9/9] fix test path Signed-off-by: Alex Boten <223565+codeboten@users.noreply.github.com> --- config/v0.3.0/log_test.go | 8 ++++---- config/v0.3.0/metric_test.go | 8 ++++---- config/v0.3.0/trace_test.go | 8 ++++---- 3 files changed, 12 insertions(+), 12 deletions(-) diff --git a/config/v0.3.0/log_test.go b/config/v0.3.0/log_test.go index 2774d7c0818..7d96fee647d 100644 --- a/config/v0.3.0/log_test.go +++ b/config/v0.3.0/log_test.go @@ -233,7 +233,7 @@ func TestLogProcessor(t *testing.T) { Endpoint: ptr("localhost:4317"), Compression: ptr("gzip"), Timeout: ptr(1000), - Certificate: ptr(filepath.Join("testdata", "ca.crt")), + Certificate: ptr(filepath.Join("..", "testdata", "ca.crt")), }, }, }, @@ -250,7 +250,7 @@ func TestLogProcessor(t *testing.T) { Endpoint: ptr("localhost:4317"), Compression: ptr("gzip"), Timeout: ptr(1000), - Certificate: ptr(filepath.Join("testdata", "bad_cert.crt")), + Certificate: ptr(filepath.Join("..", "testdata", "bad_cert.crt")), }, }, }, @@ -359,7 +359,7 @@ func TestLogProcessor(t *testing.T) { Endpoint: ptr("localhost:4317"), Compression: ptr("gzip"), Timeout: ptr(1000), - Certificate: ptr(filepath.Join("testdata", "ca.crt")), + Certificate: ptr(filepath.Join("..", "testdata", "ca.crt")), }, }, }, @@ -376,7 +376,7 @@ func TestLogProcessor(t *testing.T) { Endpoint: ptr("localhost:4317"), Compression: ptr("gzip"), Timeout: ptr(1000), - Certificate: ptr(filepath.Join("testdata", "bad_cert.crt")), + Certificate: ptr(filepath.Join("..", "testdata", "bad_cert.crt")), }, }, }, diff --git a/config/v0.3.0/metric_test.go b/config/v0.3.0/metric_test.go index 4384af9ea04..aa01665831f 100644 --- a/config/v0.3.0/metric_test.go +++ b/config/v0.3.0/metric_test.go @@ -226,7 +226,7 @@ func TestReader(t *testing.T) { Endpoint: ptr("https://localhost:4317"), Compression: ptr("gzip"), Timeout: ptr(1000), - Certificate: ptr(filepath.Join("testdata", "ca.crt")), + Certificate: ptr(filepath.Join("..", "testdata", "ca.crt")), }, }, }, @@ -243,7 +243,7 @@ func TestReader(t *testing.T) { Endpoint: ptr("https://localhost:4317"), Compression: ptr("gzip"), Timeout: ptr(1000), - Certificate: ptr(filepath.Join("testdata", "bad_cert.crt")), + Certificate: ptr(filepath.Join("..", "testdata", "bad_cert.crt")), }, }, }, @@ -453,7 +453,7 @@ func TestReader(t *testing.T) { Endpoint: ptr("https://localhost:4317"), Compression: ptr("gzip"), Timeout: ptr(1000), - Certificate: ptr(filepath.Join("testdata", "ca.crt")), + Certificate: ptr(filepath.Join("..", "testdata", "ca.crt")), }, }, }, @@ -470,7 +470,7 @@ func TestReader(t *testing.T) { Endpoint: ptr("https://localhost:4317"), Compression: ptr("gzip"), Timeout: ptr(1000), - Certificate: ptr(filepath.Join("testdata", "bad_cert.crt")), + Certificate: ptr(filepath.Join("..", "testdata", "bad_cert.crt")), }, }, }, diff --git a/config/v0.3.0/trace_test.go b/config/v0.3.0/trace_test.go index 32f6b4c70b5..8e0ef27a479 100644 --- a/config/v0.3.0/trace_test.go +++ b/config/v0.3.0/trace_test.go @@ -273,7 +273,7 @@ func TestSpanProcessor(t *testing.T) { Endpoint: ptr("localhost:4317"), Compression: ptr("gzip"), Timeout: ptr(1000), - Certificate: ptr(filepath.Join("testdata", "ca.crt")), + Certificate: ptr(filepath.Join("..", "testdata", "ca.crt")), }, }, }, @@ -290,7 +290,7 @@ func TestSpanProcessor(t *testing.T) { Endpoint: ptr("localhost:4317"), Compression: ptr("gzip"), Timeout: ptr(1000), - Certificate: ptr(filepath.Join("testdata", "bad_cert.crt")), + Certificate: ptr(filepath.Join("..", "testdata", "bad_cert.crt")), }, }, }, @@ -399,7 +399,7 @@ func TestSpanProcessor(t *testing.T) { Endpoint: ptr("localhost:4317"), Compression: ptr("gzip"), Timeout: ptr(1000), - Certificate: ptr(filepath.Join("testdata", "ca.crt")), + Certificate: ptr(filepath.Join("..", "testdata", "ca.crt")), }, }, }, @@ -416,7 +416,7 @@ func TestSpanProcessor(t *testing.T) { Endpoint: ptr("localhost:4317"), Compression: ptr("gzip"), Timeout: ptr(1000), - Certificate: ptr(filepath.Join("testdata", "bad_cert.crt")), + Certificate: ptr(filepath.Join("..", "testdata", "bad_cert.crt")), }, }, },