Skip to content

Commit 741c472

Browse files
authored
config: add support for certificate configuration (#6376)
Part of #6351 --------- Signed-off-by: Alex Boten <[email protected]>
1 parent 0c0b385 commit 741c472

12 files changed

+311
-1
lines changed

.golangci.yml

+6
Original file line numberDiff line numberDiff line change
@@ -70,6 +70,12 @@ issues:
7070
- gosec
7171
- perfsprint
7272
- usestdlibvars
73+
# Ignoring gosec G402: TLS MinVersion too low
74+
# as the https://pkg.go.dev/crypto/tls#Config handles MinVersion default well.
75+
- path: config/*.go
76+
text: "G402: TLS MinVersion too low."
77+
linters:
78+
- gosec
7379
include:
7480
# revive exported should have comment or be unexported.
7581
- EXC0012

CHANGELOG.md

+1
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ This project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.htm
1616
This module provides an OpenTelemetry logging bridge for `github.com/go-logr/logr`. (#6386)
1717
- Added SNS instrumentation in `go.opentelemetry.io/contrib/instrumentation/github.com/aws/aws-sdk-go-v2/otelaws`. (#6388)
1818
- Use a `sync.Pool` for metric options in `go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp`. (#6394)
19+
- Added support for configuring `Certificate` field when configuring OTLP exporters in `go.opentelemetry.io/contrib/config`. (#6376)
1920

2021
### Changed
2122

config/go.mod

+1-1
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ require (
2222
go.opentelemetry.io/otel/sdk/log v0.8.0
2323
go.opentelemetry.io/otel/sdk/metric v1.32.0
2424
go.opentelemetry.io/otel/trace v1.32.0
25+
google.golang.org/grpc v1.68.1
2526
gopkg.in/yaml.v3 v3.0.1
2627
)
2728

@@ -47,6 +48,5 @@ require (
4748
golang.org/x/text v0.21.0 // indirect
4849
google.golang.org/genproto/googleapis/api v0.0.0-20241209162323-e6fa225c2576 // indirect
4950
google.golang.org/genproto/googleapis/rpc v0.0.0-20241209162323-e6fa225c2576 // indirect
50-
google.golang.org/grpc v1.68.1 // indirect
5151
google.golang.org/protobuf v1.35.2 // indirect
5252
)

config/testdata/bad_cert.crt

+1
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
This is intentionally not a PEM formatted cert file.

config/testdata/ca.crt

+20
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
-----BEGIN CERTIFICATE-----
2+
MIIDNjCCAh4CCQC0I5IQT7eziDANBgkqhkiG9w0BAQsFADBdMQswCQYDVQQGEwJB
3+
VTESMBAGA1UECAwJQXVzdHJhbGlhMQ8wDQYDVQQHDAZTeWRuZXkxEjAQBgNVBAoM
4+
CU15T3JnTmFtZTEVMBMGA1UEAwwMTXlDb21tb25OYW1lMB4XDTIyMDgwMzA0MTky
5+
MVoXDTMyMDczMTA0MTkyMVowXTELMAkGA1UEBhMCQVUxEjAQBgNVBAgMCUF1c3Ry
6+
YWxpYTEPMA0GA1UEBwwGU3lkbmV5MRIwEAYDVQQKDAlNeU9yZ05hbWUxFTATBgNV
7+
BAMMDE15Q29tbW9uTmFtZTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEB
8+
AMhGP0dy3zvkdx9zI+/XVjPOWlER0OUp7Sgzidc3nLOk42+bH4ofIVNtOFVqlNKi
9+
O1bImu238VdBhd6R5IZZ1ZdIMcCeDgSJYu2X9wA3m4PKz8IdXo5ly2OHghhmCvqG
10+
WxgqDj5wPXiczQwuf1EcDMtRWbXJ6Z/XH1U68R/kRdNLkiZ2LwtjoQpis5XYckLL
11+
CrdF+AL6GeDIe0Mh9QGs26Vux+2kvaOGNUWRPE6Wt4GkqyKqmzYfR9HbflJ4xHT2
12+
I+jE1lg+jMBeom7z8Z90RE4GGcHjO+Vens/88r5EAjTnFj1Kb5gL2deSHY1m/++R
13+
Z/kRyg+zQJyw4fAzlAA4+VkCAwEAATANBgkqhkiG9w0BAQsFAAOCAQEAM3gRdTKX
14+
eGwGYVmmKqA2vTxeigQYLHml7OSopcWj2wJfxfp49HXPRuvgpQn9iubxO3Zmhd83
15+
2X1E+T0A8oy5CfxgpAhHb3lY0jm3TjKXm6m+dSODwL3uND8tX+SqR8sRTFxPvPuo
16+
pmvhdTZoRI3EzIiHLTgCuSU25JNP/vrVoKk0JvCkDYTU/WcVfj0v95DTMoWR4JGz
17+
mtBwrgD0EM2XRw5ZMc7sMPli1gqmCbCQUrDZ+rPB78WDCBILBd8Cz75qYTUp98BY
18+
akJyBckdJHAdyEQYDKa9HpmpexOO7IhSXCTEN1DEBgpZgEi/lBDRG/b0OzenUUgt
19+
LUABtWt3pNQ9HA==
20+
-----END CERTIFICATE-----

config/v0.3.0/config.go

+20
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,10 @@ package config // import "go.opentelemetry.io/contrib/config/v0.3.0"
55

66
import (
77
"context"
8+
"crypto/tls"
9+
"crypto/x509"
810
"errors"
11+
"os"
912

1013
"gopkg.in/yaml.v3"
1114

@@ -155,3 +158,20 @@ func toStringMap(pairs []NameStringValuePair) map[string]string {
155158
}
156159
return output
157160
}
161+
162+
// createTLSConfig creates a tls.Config from a raw certificate bytes
163+
// to verify a server certificate.
164+
func createTLSConfig(certFile string) (*tls.Config, error) {
165+
b, err := os.ReadFile(certFile)
166+
if err != nil {
167+
return nil, err
168+
}
169+
cp := x509.NewCertPool()
170+
if ok := cp.AppendCertsFromPEM(b); !ok {
171+
return nil, errors.New("failed to append certificate to the cert pool")
172+
}
173+
174+
return &tls.Config{
175+
RootCAs: cp,
176+
}, nil
177+
}

config/v0.3.0/log.go

+18
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,8 @@ import (
1010
"net/url"
1111
"time"
1212

13+
"google.golang.org/grpc/credentials"
14+
1315
"go.opentelemetry.io/otel/exporters/otlp/otlplog/otlploggrpc"
1416
"go.opentelemetry.io/otel/exporters/otlp/otlplog/otlploghttp"
1517
"go.opentelemetry.io/otel/exporters/stdout/stdoutlog"
@@ -154,6 +156,14 @@ func otlpHTTPLogExporter(ctx context.Context, otlpConfig *OTLP) (sdklog.Exporter
154156
opts = append(opts, otlploghttp.WithHeaders(toStringMap(otlpConfig.Headers)))
155157
}
156158

159+
if otlpConfig.Certificate != nil {
160+
creds, err := createTLSConfig(*otlpConfig.Certificate)
161+
if err != nil {
162+
return nil, fmt.Errorf("could not create client tls credentials: %w", err)
163+
}
164+
opts = append(opts, otlploghttp.WithTLSClientConfig(creds))
165+
}
166+
157167
return otlploghttp.New(ctx, opts...)
158168
}
159169

@@ -196,5 +206,13 @@ func otlpGRPCLogExporter(ctx context.Context, otlpConfig *OTLP) (sdklog.Exporter
196206
opts = append(opts, otlploggrpc.WithHeaders(toStringMap(otlpConfig.Headers)))
197207
}
198208

209+
if otlpConfig.Certificate != nil {
210+
creds, err := credentials.NewClientTLSFromFile(*otlpConfig.Certificate, "")
211+
if err != nil {
212+
return nil, fmt.Errorf("could not create client tls credentials: %w", err)
213+
}
214+
opts = append(opts, otlploggrpc.WithTLSCredentials(creds))
215+
}
216+
199217
return otlploggrpc.New(ctx, opts...)
200218
}

config/v0.3.0/log_test.go

+70
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,9 @@ package config
66
import (
77
"context"
88
"errors"
9+
"fmt"
910
"net/url"
11+
"path/filepath"
1012
"reflect"
1113
"testing"
1214

@@ -221,6 +223,40 @@ func TestLogProcessor(t *testing.T) {
221223
},
222224
wantProcessor: sdklog.NewBatchProcessor(otlpGRPCExporter),
223225
},
226+
{
227+
name: "batch/otlp-grpc-good-ca-certificate",
228+
processor: LogRecordProcessor{
229+
Batch: &BatchLogRecordProcessor{
230+
Exporter: LogRecordExporter{
231+
OTLP: &OTLP{
232+
Protocol: ptr("grpc"),
233+
Endpoint: ptr("localhost:4317"),
234+
Compression: ptr("gzip"),
235+
Timeout: ptr(1000),
236+
Certificate: ptr(filepath.Join("..", "testdata", "ca.crt")),
237+
},
238+
},
239+
},
240+
},
241+
wantProcessor: sdklog.NewBatchProcessor(otlpGRPCExporter),
242+
},
243+
{
244+
name: "batch/otlp-grpc-bad-ca-certificate",
245+
processor: LogRecordProcessor{
246+
Batch: &BatchLogRecordProcessor{
247+
Exporter: LogRecordExporter{
248+
OTLP: &OTLP{
249+
Protocol: ptr("grpc"),
250+
Endpoint: ptr("localhost:4317"),
251+
Compression: ptr("gzip"),
252+
Timeout: ptr(1000),
253+
Certificate: ptr(filepath.Join("..", "testdata", "bad_cert.crt")),
254+
},
255+
},
256+
},
257+
},
258+
wantErr: fmt.Errorf("could not create client tls credentials: %w", errors.New("credentials: failed to append certificates")),
259+
},
224260
{
225261
name: "batch/otlp-grpc-exporter-no-scheme",
226262
processor: LogRecordProcessor{
@@ -313,6 +349,40 @@ func TestLogProcessor(t *testing.T) {
313349
},
314350
wantProcessor: sdklog.NewBatchProcessor(otlpHTTPExporter),
315351
},
352+
{
353+
name: "batch/otlp-http-good-ca-certificate",
354+
processor: LogRecordProcessor{
355+
Batch: &BatchLogRecordProcessor{
356+
Exporter: LogRecordExporter{
357+
OTLP: &OTLP{
358+
Protocol: ptr("http/protobuf"),
359+
Endpoint: ptr("localhost:4317"),
360+
Compression: ptr("gzip"),
361+
Timeout: ptr(1000),
362+
Certificate: ptr(filepath.Join("..", "testdata", "ca.crt")),
363+
},
364+
},
365+
},
366+
},
367+
wantProcessor: sdklog.NewBatchProcessor(otlpHTTPExporter),
368+
},
369+
{
370+
name: "batch/otlp-http-bad-ca-certificate",
371+
processor: LogRecordProcessor{
372+
Batch: &BatchLogRecordProcessor{
373+
Exporter: LogRecordExporter{
374+
OTLP: &OTLP{
375+
Protocol: ptr("http/protobuf"),
376+
Endpoint: ptr("localhost:4317"),
377+
Compression: ptr("gzip"),
378+
Timeout: ptr(1000),
379+
Certificate: ptr(filepath.Join("..", "testdata", "bad_cert.crt")),
380+
},
381+
},
382+
},
383+
},
384+
wantErr: fmt.Errorf("could not create client tls credentials: %w", errors.New("failed to append certificate to the cert pool")),
385+
},
316386
{
317387
name: "batch/otlp-http-exporter-with-path",
318388
processor: LogRecordProcessor{

config/v0.3.0/metric.go

+17
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ import (
1717

1818
"github.com/prometheus/client_golang/prometheus"
1919
"github.com/prometheus/client_golang/prometheus/promhttp"
20+
"google.golang.org/grpc/credentials"
2021

2122
"go.opentelemetry.io/otel"
2223
"go.opentelemetry.io/otel/attribute"
@@ -181,6 +182,14 @@ func otlpHTTPMetricExporter(ctx context.Context, otlpConfig *OTLPMetric) (sdkmet
181182
}
182183
}
183184

185+
if otlpConfig.Certificate != nil {
186+
creds, err := createTLSConfig(*otlpConfig.Certificate)
187+
if err != nil {
188+
return nil, fmt.Errorf("could not create client tls credentials: %w", err)
189+
}
190+
opts = append(opts, otlpmetrichttp.WithTLSClientConfig(creds))
191+
}
192+
184193
return otlpmetrichttp.New(ctx, opts...)
185194
}
186195

@@ -236,6 +245,14 @@ func otlpGRPCMetricExporter(ctx context.Context, otlpConfig *OTLPMetric) (sdkmet
236245
}
237246
}
238247

248+
if otlpConfig.Certificate != nil {
249+
creds, err := credentials.NewClientTLSFromFile(*otlpConfig.Certificate, "")
250+
if err != nil {
251+
return nil, fmt.Errorf("could not create client tls credentials: %w", err)
252+
}
253+
opts = append(opts, otlpmetricgrpc.WithTLSCredentials(creds))
254+
}
255+
239256
return otlpmetricgrpc.New(ctx, opts...)
240257
}
241258

config/v0.3.0/metric_test.go

+69
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ import (
88
"errors"
99
"fmt"
1010
"net/url"
11+
"path/filepath"
1112
"reflect"
1213
"testing"
1314
"time"
@@ -215,6 +216,40 @@ func TestReader(t *testing.T) {
215216
},
216217
wantReader: sdkmetric.NewPeriodicReader(otlpGRPCExporter),
217218
},
219+
{
220+
name: "periodic/otlp-grpc-good-ca-certificate",
221+
reader: MetricReader{
222+
Periodic: &PeriodicMetricReader{
223+
Exporter: PushMetricExporter{
224+
OTLP: &OTLPMetric{
225+
Protocol: ptr("grpc"),
226+
Endpoint: ptr("https://localhost:4317"),
227+
Compression: ptr("gzip"),
228+
Timeout: ptr(1000),
229+
Certificate: ptr(filepath.Join("..", "testdata", "ca.crt")),
230+
},
231+
},
232+
},
233+
},
234+
wantReader: sdkmetric.NewPeriodicReader(otlpGRPCExporter),
235+
},
236+
{
237+
name: "periodic/otlp-grpc-bad-ca-certificate",
238+
reader: MetricReader{
239+
Periodic: &PeriodicMetricReader{
240+
Exporter: PushMetricExporter{
241+
OTLP: &OTLPMetric{
242+
Protocol: ptr("grpc"),
243+
Endpoint: ptr("https://localhost:4317"),
244+
Compression: ptr("gzip"),
245+
Timeout: ptr(1000),
246+
Certificate: ptr(filepath.Join("..", "testdata", "bad_cert.crt")),
247+
},
248+
},
249+
},
250+
},
251+
wantErr: fmt.Errorf("could not create client tls credentials: %w", errors.New("credentials: failed to append certificates")),
252+
},
218253
{
219254
name: "periodic/otlp-grpc-exporter-no-endpoint",
220255
reader: MetricReader{
@@ -408,6 +443,40 @@ func TestReader(t *testing.T) {
408443
},
409444
wantReader: sdkmetric.NewPeriodicReader(otlpHTTPExporter),
410445
},
446+
{
447+
name: "periodic/otlp-http-good-ca-certificate",
448+
reader: MetricReader{
449+
Periodic: &PeriodicMetricReader{
450+
Exporter: PushMetricExporter{
451+
OTLP: &OTLPMetric{
452+
Protocol: ptr("http/protobuf"),
453+
Endpoint: ptr("https://localhost:4317"),
454+
Compression: ptr("gzip"),
455+
Timeout: ptr(1000),
456+
Certificate: ptr(filepath.Join("..", "testdata", "ca.crt")),
457+
},
458+
},
459+
},
460+
},
461+
wantReader: sdkmetric.NewPeriodicReader(otlpHTTPExporter),
462+
},
463+
{
464+
name: "periodic/otlp-http-bad-ca-certificate",
465+
reader: MetricReader{
466+
Periodic: &PeriodicMetricReader{
467+
Exporter: PushMetricExporter{
468+
OTLP: &OTLPMetric{
469+
Protocol: ptr("http/protobuf"),
470+
Endpoint: ptr("https://localhost:4317"),
471+
Compression: ptr("gzip"),
472+
Timeout: ptr(1000),
473+
Certificate: ptr(filepath.Join("..", "testdata", "bad_cert.crt")),
474+
},
475+
},
476+
},
477+
},
478+
wantErr: fmt.Errorf("could not create client tls credentials: %w", errors.New("failed to append certificate to the cert pool")),
479+
},
411480
{
412481
name: "periodic/otlp-http-exporter-with-path",
413482
reader: MetricReader{

config/v0.3.0/trace.go

+18
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,8 @@ import (
1010
"net/url"
1111
"time"
1212

13+
"google.golang.org/grpc/credentials"
14+
1315
"go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc"
1416
"go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp"
1517
"go.opentelemetry.io/otel/exporters/stdout/stdouttrace"
@@ -127,6 +129,14 @@ func otlpGRPCSpanExporter(ctx context.Context, otlpConfig *OTLP) (sdktrace.SpanE
127129
opts = append(opts, otlptracegrpc.WithHeaders(toStringMap(otlpConfig.Headers)))
128130
}
129131

132+
if otlpConfig.Certificate != nil {
133+
creds, err := credentials.NewClientTLSFromFile(*otlpConfig.Certificate, "")
134+
if err != nil {
135+
return nil, fmt.Errorf("could not create client tls credentials: %w", err)
136+
}
137+
opts = append(opts, otlptracegrpc.WithTLSCredentials(creds))
138+
}
139+
130140
return otlptracegrpc.New(ctx, opts...)
131141
}
132142

@@ -164,6 +174,14 @@ func otlpHTTPSpanExporter(ctx context.Context, otlpConfig *OTLP) (sdktrace.SpanE
164174
opts = append(opts, otlptracehttp.WithHeaders(toStringMap(otlpConfig.Headers)))
165175
}
166176

177+
if otlpConfig.Certificate != nil {
178+
creds, err := createTLSConfig(*otlpConfig.Certificate)
179+
if err != nil {
180+
return nil, fmt.Errorf("could not create client tls credentials: %w", err)
181+
}
182+
opts = append(opts, otlptracehttp.WithTLSClientConfig(creds))
183+
}
184+
167185
return otlptracehttp.New(ctx, opts...)
168186
}
169187

0 commit comments

Comments
 (0)