Skip to content

Commit

Permalink
Return TLS creds failure as error and simplify secure-tracing setup.
Browse files Browse the repository at this point in the history
  • Loading branch information
Juliaj committed Jan 5, 2024
1 parent 7ee198b commit bd24163
Show file tree
Hide file tree
Showing 11 changed files with 98 additions and 60 deletions.
27 changes: 27 additions & 0 deletions .chloggen/juliaj_telemetrygen-tls-mtls-support.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
# Use this changelog template to create an entry for release notes.

# One of 'breaking', 'deprecation', 'new_component', 'enhancement', 'bug_fix'
change_type: enhancement

# The name of the component, or a single word describing the area of concern, (e.g. filelogreceiver)
component: cmd/telemetrygen

# A brief description of the change. Surround your text with quotes ("") if it needs to start with a backtick (`).
note: This updates telemetrygen with TLS/mTLS options to test the security of telemetry ingestion services and infrastructure for secure communication. To illustrate the usage, a new example, secure-tracing is added to examples collection.

# Mandatory: One or more tracking issues related to the change. You can use the PR number here if no issue exists.
issues: []

# (Optional) One or more lines of additional information to render under the primary note.
# These lines will be padded with 2 spaces and then inserted directly into the document.
# Use pipe (|) for multiline entries.
subtext:

# If your change doesn't affect end users or the exported elements of any package,
# you should instead start your pull request title with [chore] or use the "Skip Changelog" label.
# Optional: The change log or logs in which this entry should be included.
# e.g. '[user]' or '[user, api]'
# Include 'user' if the change is relevant to end users.
# Include 'api' if there is a change to a library API.
# Default: '[user]'
change_logs: []
1 change: 1 addition & 0 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -318,6 +318,7 @@ otel-from-lib:
$(MAKE) for-all CMD="$(GOCMD) mod edit -dropreplace go.opentelemetry.io/collector"

.PHONY: build-examples
build-examples:
docker-compose -f examples/demo/docker-compose.yaml build
cd examples/secure-tracing/certs && $(MAKE) clean && $(MAKE) all && docker-compose -f ../docker-compose.yaml build
docker-compose -f exporter/splunkhecexporter/example/docker-compose.yml build
Expand Down
2 changes: 1 addition & 1 deletion cmd/telemetrygen/internal/common/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -139,7 +139,7 @@ func (c *Config) CommonFlags(fs *pflag.FlagSet) {
"Flag may be repeated to set multiple attributes (e.g --telemetry-attributes \"key1=\\\"value1\\\"\" --telemetry-attributes \"key2=\\\"value2\\\"\")")

// TLS CA configuration
fs.StringVar(&c.CaFile, "ca-cert", "", "Trusted Certificate Authority to verify collector receiver certificate")
fs.StringVar(&c.CaFile, "ca-cert", "", "Trusted Certificate Authority to verify server certificate")

// mTLS configuration
fs.BoolVar(&c.ClientAuth.Enabled, "mtls", false, "Whether to require client authentication for mTLS")
Expand Down
7 changes: 3 additions & 4 deletions cmd/telemetrygen/internal/common/tls_utils.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@ import (
"crypto/tls"
"crypto/x509"
"errors"
"fmt"
"os"

"google.golang.org/grpc/credentials"
Expand Down Expand Up @@ -40,7 +39,7 @@ func GetTLSCredentialsForGRPCExporter(caFile string, cAuth ClientAuth) (credenti
RootCAs: pool,
})

//Configuration for mTLS
// Configuration for mTLS
if cAuth.Enabled {
keypair, err := tls.LoadX509KeyPair(cAuth.ClientCertFile, cAuth.ClientKeyFile)
if err != nil {
Expand All @@ -64,8 +63,8 @@ func GetTLSCredentialsForHTTPExporter(caFile string, cAuth ClientAuth) (*tls.Con
tlsCfg := tls.Config{
RootCAs: pool,
}
//Configuration for mTLS

// Configuration for mTLS
if cAuth.Enabled {
keypair, err := tls.LoadX509KeyPair(cAuth.ClientCertFile, cAuth.ClientKeyFile)
if err != nil {
Expand Down
22 changes: 9 additions & 13 deletions cmd/telemetrygen/internal/logs/exporter.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,6 @@ import (
"fmt"
"io"
"net/http"
"os"

"go.opentelemetry.io/collector/pdata/plog"
"go.opentelemetry.io/collector/pdata/plog/plogotlp"
Expand All @@ -32,17 +31,15 @@ func newExporter(ctx context.Context, cfg *Config) (exporter, error) {
client: http.DefaultClient,
cfg: cfg,
}, nil
} else {
creds, err := common.GetTLSCredentialsForHTTPExporter(cfg.CaFile, cfg.ClientAuth)
if err != nil {
fmt.Printf("Failed to get TLS crendentials: %w, exiting.\n", err)
os.Exit(1)
}
return &httpClientExporter{
client: &http.Client{Transport: &http.Transport{TLSClientConfig: creds}},
cfg: cfg,
}, nil
}
creds, err := common.GetTLSCredentialsForHTTPExporter(cfg.CaFile, cfg.ClientAuth)
if err != nil {
return nil, fmt.Errorf("failed to get TLS crendentials: %w", err)
}
return &httpClientExporter{
client: &http.Client{Transport: &http.Transport{TLSClientConfig: creds}},
cfg: cfg,
}, nil
}

// Exporter with GRPC
Expand All @@ -56,8 +53,7 @@ func newExporter(ctx context.Context, cfg *Config) (exporter, error) {
} else {
creds, err := common.GetTLSCredentialsForGRPCExporter(cfg.CaFile, cfg.ClientAuth)
if err != nil {
fmt.Printf("Failed to get TLS crendentials: %w, exiting.\n", err)
os.Exit(1)
return nil, fmt.Errorf("failed to get TLS crendentials: %w", err)
}
clientConn, err = grpc.DialContext(ctx, cfg.Endpoint(), grpc.WithTransportCredentials(creds))
if err != nil {
Expand Down
22 changes: 8 additions & 14 deletions cmd/telemetrygen/internal/metrics/exporter.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@ package metrics

import (
"fmt"
"os"

"go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetricgrpc"
"go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetrichttp"
Expand All @@ -16,7 +15,7 @@ import (

// grpcExporterOptions creates the configuration options for a gRPC-based OTLP metric exporter.
// It configures the exporter with the provided endpoint, connection security settings, and headers.
func grpcExporterOptions(cfg *Config) []otlpmetricgrpc.Option {
func grpcExporterOptions(cfg *Config) ([]otlpmetricgrpc.Option, error) {
grpcExpOpt := []otlpmetricgrpc.Option{
otlpmetricgrpc.WithEndpoint(cfg.Endpoint()),
otlpmetricgrpc.WithDialOption(
Expand All @@ -29,24 +28,21 @@ func grpcExporterOptions(cfg *Config) []otlpmetricgrpc.Option {
} else {
credentials, err := common.GetTLSCredentialsForGRPCExporter(cfg.CaFile, cfg.ClientAuth)
if err != nil {
fmt.Printf("Failed to get TLS crendentials: %w, exiting.\n", err)
os.Exit(1)
} else {
grpcExpOpt = append(grpcExpOpt, otlpmetricgrpc.WithTLSCredentials(credentials))
fmt.Printf("successfully added grpc option for TLS\n")
return nil, fmt.Errorf("failed to get TLS credentials: %w", err)
}
grpcExpOpt = append(grpcExpOpt, otlpmetricgrpc.WithTLSCredentials(credentials))
}

if len(cfg.Headers) > 0 {
grpcExpOpt = append(grpcExpOpt, otlpmetricgrpc.WithHeaders(cfg.Headers))
}

return grpcExpOpt
return grpcExpOpt, nil
}

// httpExporterOptions creates the configuration options for an HTTP-based OTLP metric exporter.
// It configures the exporter with the provided endpoint, URL path, connection security settings, and headers.
func httpExporterOptions(cfg *Config) []otlpmetrichttp.Option {
func httpExporterOptions(cfg *Config) ([]otlpmetrichttp.Option, error) {
httpExpOpt := []otlpmetrichttp.Option{
otlpmetrichttp.WithEndpoint(cfg.Endpoint()),
otlpmetrichttp.WithURLPath(cfg.HTTPPath),
Expand All @@ -57,16 +53,14 @@ func httpExporterOptions(cfg *Config) []otlpmetrichttp.Option {
} else {
tlsCfg, err := common.GetTLSCredentialsForHTTPExporter(cfg.CaFile, cfg.ClientAuth)
if err != nil {
fmt.Printf("Failed to get TLS configuration: %w, exiting.\n", err)
os.Exit(1)
} else {
httpExpOpt = append(httpExpOpt, otlpmetrichttp.WithTLSClientConfig(tlsCfg))
return nil, fmt.Errorf("failed to get TLS credentials: %w", err)
}
httpExpOpt = append(httpExpOpt, otlpmetrichttp.WithTLSClientConfig(tlsCfg))
}

if len(cfg.Headers) > 0 {
httpExpOpt = append(httpExpOpt, otlpmetrichttp.WithHeaders(cfg.Headers))
}

return httpExpOpt
return httpExpOpt, nil
}
22 changes: 20 additions & 2 deletions cmd/telemetrygen/internal/metrics/metrics.go
Original file line number Diff line number Diff line change
Expand Up @@ -32,11 +32,29 @@ func Start(cfg *Config) error {
expFunc := func() (sdkmetric.Exporter, error) {
var exp sdkmetric.Exporter
if cfg.UseHTTP {
var exporterOpts []otlpmetrichttp.Option

logger.Info("starting HTTP exporter")
exp, err = otlpmetrichttp.New(context.Background(), httpExporterOptions(cfg)...)
exporterOpts, err = httpExporterOptions(cfg)
if err != nil {
return nil, err
}
exp, err = otlpmetrichttp.New(context.Background(), exporterOpts...)
if err != nil {
return nil, fmt.Errorf("failed to obtain OTLP HTTP exporter: %w", err)
}
} else {
var exporterOpts []otlpmetricgrpc.Option

logger.Info("starting gRPC exporter")
exp, err = otlpmetricgrpc.New(context.Background(), grpcExporterOptions(cfg)...)
exporterOpts, err = grpcExporterOptions(cfg)
if err != nil {
return nil, err
}
exp, err = otlpmetricgrpc.New(context.Background(), exporterOpts...)
if err != nil {
return nil, fmt.Errorf("failed to obtain OTLP gRPC exporter: %w", err)
}
}
return exp, err
}
Expand Down
21 changes: 8 additions & 13 deletions cmd/telemetrygen/internal/traces/exporter.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@ package traces

import (
"fmt"
"os"

"go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc"
"go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp"
Expand All @@ -16,7 +15,7 @@ import (

// grpcExporterOptions creates the configuration options for a gRPC-based OTLP trace exporter.
// It configures the exporter with the provided endpoint, connection security settings, and headers.
func grpcExporterOptions(cfg *Config) []otlptracegrpc.Option {
func grpcExporterOptions(cfg *Config) ([]otlptracegrpc.Option, error) {
grpcExpOpt := []otlptracegrpc.Option{
otlptracegrpc.WithEndpoint(cfg.Endpoint()),
otlptracegrpc.WithDialOption(
Expand All @@ -29,23 +28,21 @@ func grpcExporterOptions(cfg *Config) []otlptracegrpc.Option {
} else {
credentials, err := common.GetTLSCredentialsForGRPCExporter(cfg.CaFile, cfg.ClientAuth)
if err != nil {
fmt.Printf("Failed to get TLS crendentials: %w, exiting.\n", err)
os.Exit(1)
} else {
grpcExpOpt = append(grpcExpOpt, otlptracegrpc.WithTLSCredentials(credentials))
return nil, fmt.Errorf("failed to get TLS credentials: %w", err)
}
grpcExpOpt = append(grpcExpOpt, otlptracegrpc.WithTLSCredentials(credentials))
}

if len(cfg.Headers) > 0 {
grpcExpOpt = append(grpcExpOpt, otlptracegrpc.WithHeaders(cfg.Headers))
}

return grpcExpOpt
return grpcExpOpt, nil
}

// httpExporterOptions creates the configuration options for an HTTP-based OTLP trace exporter.
// It configures the exporter with the provided endpoint, URL path, connection security settings, and headers.
func httpExporterOptions(cfg *Config) []otlptracehttp.Option {
func httpExporterOptions(cfg *Config) ([]otlptracehttp.Option, error) {
httpExpOpt := []otlptracehttp.Option{
otlptracehttp.WithEndpoint(cfg.Endpoint()),
otlptracehttp.WithURLPath(cfg.HTTPPath),
Expand All @@ -56,16 +53,14 @@ func httpExporterOptions(cfg *Config) []otlptracehttp.Option {
} else {
tlsCfg, err := common.GetTLSCredentialsForHTTPExporter(cfg.CaFile, cfg.ClientAuth)
if err != nil {
fmt.Printf("Failed to get TLS configuration: %w, exiting.\n", err)
os.Exit(1)
} else {
httpExpOpt = append(httpExpOpt, otlptracehttp.WithTLSClientConfig(tlsCfg))
return nil, fmt.Errorf("failed to get TLS credentials: %w", err)
}
httpExpOpt = append(httpExpOpt, otlptracehttp.WithTLSClientConfig(tlsCfg))
}

if len(cfg.Headers) > 0 {
httpExpOpt = append(httpExpOpt, otlptracehttp.WithHeaders(cfg.Headers))
}

return httpExpOpt
return httpExpOpt, nil
}
25 changes: 20 additions & 5 deletions cmd/telemetrygen/internal/traces/traces.go
Original file line number Diff line number Diff line change
Expand Up @@ -34,16 +34,31 @@ func Start(cfg *Config) error {

var exp *otlptrace.Exporter
if cfg.UseHTTP {
var exporterOpts []otlptracehttp.Option

logger.Info("starting HTTP exporter")
exp, err = otlptracehttp.New(context.Background(), httpExporterOptions(cfg)...)
exporterOpts, err = httpExporterOptions(cfg)
if err != nil {
return err
}
exp, err = otlptracehttp.New(context.Background(), exporterOpts...)
if err != nil {
return fmt.Errorf("failed to obtain OTLP HTTP exporter: %w", err)
}
} else {
var exporterOpts []otlptracegrpc.Option

logger.Info("starting gRPC exporter")
exp, err = otlptracegrpc.New(context.Background(), grpcExporterOptions(cfg)...)
exporterOpts, err = grpcExporterOptions(cfg)
if err != nil {
return err
}
exp, err = otlptracegrpc.New(context.Background(), exporterOpts...)
if err != nil {
return fmt.Errorf("failed to obtain OTLP gRPC exporter: %w", err)
}
}

if err != nil {
return fmt.Errorf("failed to obtain OTLP exporter: %w", err)
}
defer func() {
logger.Info("stopping the exporter")
if tempError := exp.Shutdown(context.Background()); tempError != nil {
Expand Down
2 changes: 1 addition & 1 deletion examples/secure-tracing/docker-compose.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ services:
- ./certs/ca.crt:/etc/ca.crt
- ./envoy/edge.yaml:/etc/edge.yaml
otel-collector:
image: otel/opentelemetry-collector:0.85.0
image: otel/opentelemetry-collector:0.91.0
command: ["--config=/etc/otel-collector-config.yaml"]
volumes:
- ./certs/otel-collector.crt:/etc/otel-collector.crt
Expand Down
7 changes: 0 additions & 7 deletions examples/secure-tracing/otel-collector-config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -18,16 +18,9 @@ exporters:
verbosity: detailed

service:
telemetry:
logs:
level: "debug"
metrics:
address: ":8888"

pipelines:
traces:
receivers: [otlp]
processors: [batch]
exporters: [logging]

extensions: [health_check]

0 comments on commit bd24163

Please sign in to comment.