diff --git a/.chloggen/juliaj_telemetrygen-tls-mtls-support.yaml b/.chloggen/juliaj_telemetrygen-tls-mtls-support.yaml new file mode 100644 index 000000000000..b4cf8b44a7f6 --- /dev/null +++ b/.chloggen/juliaj_telemetrygen-tls-mtls-support.yaml @@ -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: [] diff --git a/Makefile b/Makefile index 1a07f5535b48..bdcc104c603b 100644 --- a/Makefile +++ b/Makefile @@ -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 diff --git a/cmd/telemetrygen/internal/common/config.go b/cmd/telemetrygen/internal/common/config.go index 4d5827d47320..154b2fd4a43f 100644 --- a/cmd/telemetrygen/internal/common/config.go +++ b/cmd/telemetrygen/internal/common/config.go @@ -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") diff --git a/cmd/telemetrygen/internal/common/tls_utils.go b/cmd/telemetrygen/internal/common/tls_utils.go index 4cbe8fa24c01..d9678079a188 100644 --- a/cmd/telemetrygen/internal/common/tls_utils.go +++ b/cmd/telemetrygen/internal/common/tls_utils.go @@ -7,7 +7,6 @@ import ( "crypto/tls" "crypto/x509" "errors" - "fmt" "os" "google.golang.org/grpc/credentials" @@ -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 { @@ -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 { diff --git a/cmd/telemetrygen/internal/logs/exporter.go b/cmd/telemetrygen/internal/logs/exporter.go index a0b3d82f646a..452a5668002a 100644 --- a/cmd/telemetrygen/internal/logs/exporter.go +++ b/cmd/telemetrygen/internal/logs/exporter.go @@ -9,7 +9,6 @@ import ( "fmt" "io" "net/http" - "os" "go.opentelemetry.io/collector/pdata/plog" "go.opentelemetry.io/collector/pdata/plog/plogotlp" @@ -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 @@ -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 { diff --git a/cmd/telemetrygen/internal/metrics/exporter.go b/cmd/telemetrygen/internal/metrics/exporter.go index d8b45b2a2d92..5d77caf4eae8 100644 --- a/cmd/telemetrygen/internal/metrics/exporter.go +++ b/cmd/telemetrygen/internal/metrics/exporter.go @@ -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" @@ -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( @@ -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), @@ -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 } diff --git a/cmd/telemetrygen/internal/metrics/metrics.go b/cmd/telemetrygen/internal/metrics/metrics.go index 0061d64b3695..8289287e3793 100644 --- a/cmd/telemetrygen/internal/metrics/metrics.go +++ b/cmd/telemetrygen/internal/metrics/metrics.go @@ -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 } diff --git a/cmd/telemetrygen/internal/traces/exporter.go b/cmd/telemetrygen/internal/traces/exporter.go index 8943bbea6fad..dbcf55d7ab6e 100644 --- a/cmd/telemetrygen/internal/traces/exporter.go +++ b/cmd/telemetrygen/internal/traces/exporter.go @@ -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" @@ -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( @@ -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), @@ -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 } diff --git a/cmd/telemetrygen/internal/traces/traces.go b/cmd/telemetrygen/internal/traces/traces.go index a84491a378fb..576346ad56aa 100644 --- a/cmd/telemetrygen/internal/traces/traces.go +++ b/cmd/telemetrygen/internal/traces/traces.go @@ -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 { diff --git a/examples/secure-tracing/docker-compose.yaml b/examples/secure-tracing/docker-compose.yaml index 703c05856749..a1af6c78cd53 100644 --- a/examples/secure-tracing/docker-compose.yaml +++ b/examples/secure-tracing/docker-compose.yaml @@ -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 diff --git a/examples/secure-tracing/otel-collector-config.yaml b/examples/secure-tracing/otel-collector-config.yaml index 80b52a2830a9..0fa797d33ba8 100644 --- a/examples/secure-tracing/otel-collector-config.yaml +++ b/examples/secure-tracing/otel-collector-config.yaml @@ -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]