Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add TLS certs verification for Splunk HEC exporter #3204

Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 11 additions & 0 deletions exporter/splunkhecexporter/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,9 @@ The following configuration options can also be configured:
- `disable_compression` (default: false): Whether to disable gzip compression over HTTP.
- `timeout` (default: 10s): HTTP timeout when sending data.
- `insecure_skip_verify` (default: false): Whether to skip checking the certificate of the HEC endpoint when sending data over HTTPS.
- `ca_file` (no default) Path to the CA cert to verify the server being connected to.
- `cert_file` (no default) Path to the TLS cert to use for client connections when TLS client auth is required.
- `key_file` (no default) Path to the TLS key to use for TLS required connections.
- `max_content_length_logs` (default: 2097152): Maximum log data size in bytes per HTTP post limited to 2097152 bytes (2 MiB).

In addition, this exporter offers queued retry which is enabled by default.
Expand Down Expand Up @@ -51,6 +54,14 @@ exporters:
timeout: 10s
# Whether to skip checking the certificate of the HEC endpoint when sending data over HTTPS. Defaults to false.
insecure_skip_verify: false
# Whether to skip checking the certificate of the HEC endpoint when sending data over HTTPS. Defaults to false.
insecure: false
# Path to the CA cert to verify the server being connected to. Should only be used if `insecure` is set to false.
ca_file: /certs/ExampleCA.crt
# Path to the TLS cert to use for client connections when TLS client auth is required. Should only be used if `insecure` is set to false.
cert_file: /certs/HECclient.crt
# Path to the TLS key to use for TLS required connections. Should only be used if `insecure` is set to false.
key_file: /certs/HECclient.key
```

The full list of settings exposed for this exporter are documented [here](config.go)
Expand Down
7 changes: 4 additions & 3 deletions exporter/splunkhecexporter/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ import (
"path"

"go.opentelemetry.io/collector/config"
"go.opentelemetry.io/collector/config/configtls"
"go.opentelemetry.io/collector/exporter/exporterhelper"
)

Expand Down Expand Up @@ -59,11 +60,11 @@ type Config struct {
// Disable GZip compression. Defaults to false.
DisableCompression bool `mapstructure:"disable_compression"`

// insecure_skip_verify skips checking the certificate of the HEC endpoint when sending data over HTTPS. Defaults to false.
InsecureSkipVerify bool `mapstructure:"insecure_skip_verify"`

// Maximum log data size in bytes per HTTP post. Defaults to the backend limit of 2097152 bytes (2MiB).
MaxContentLengthLogs uint `mapstructure:"max_content_length_logs"`

// TLSSetting struct exposes TLS client configuration.
TLSSetting configtls.TLSClientSetting `mapstructure:",squash"`
}

func (cfg *Config) getOptionsFromConfig() (*exporterOptions, error) {
Expand Down
10 changes: 10 additions & 0 deletions exporter/splunkhecexporter/config_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ import (
"go.opentelemetry.io/collector/component/componenttest"
"go.opentelemetry.io/collector/config"
"go.opentelemetry.io/collector/config/configtest"
"go.opentelemetry.io/collector/config/configtls"
"go.opentelemetry.io/collector/exporter/exporterhelper"
"go.uber.org/zap"
)
Expand Down Expand Up @@ -79,6 +80,15 @@ func TestLoadConfig(t *testing.T) {
NumConsumers: 2,
QueueSize: 10,
},
TLSSetting: configtls.TLSClientSetting{
TLSSetting: configtls.TLSSetting{
CAFile: "",
CertFile: "",
KeyFile: "",
},
Insecure: true,
InsecureSkipVerify: false,
},
}
assert.Equal(t, &expectedCfg, e1)

Expand Down
18 changes: 11 additions & 7 deletions exporter/splunkhecexporter/exporter.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,6 @@ package splunkhecexporter
import (
"compress/gzip"
"context"
"crypto/tls"
"errors"
"fmt"
"net"
Expand Down Expand Up @@ -68,7 +67,10 @@ func createExporter(
fmt.Errorf("failed to process %q config: %v", config.Name(), err)
}

client := buildClient(options, config, logger)
client, err := buildClient(options, config, logger)
if err != nil {
return nil, err
}

return &splunkExporter{
pushMetricsData: client.pushMetricsData,
Expand All @@ -79,7 +81,11 @@ func createExporter(
}, nil
}

func buildClient(options *exporterOptions, config *Config, logger *zap.Logger) *client {
func buildClient(options *exporterOptions, config *Config, logger *zap.Logger) (*client, error) {
tlsCfg, err := config.TLSSetting.LoadTLSConfig()
if err != nil {
return nil, fmt.Errorf("could not retrieve TLS config for Splunk HEC Exporter: %w", err)
}
return &client{
url: options.url,
client: &http.Client{
Expand All @@ -94,9 +100,7 @@ func buildClient(options *exporterOptions, config *Config, logger *zap.Logger) *
MaxIdleConnsPerHost: int(config.MaxConnections),
IdleConnTimeout: idleConnTimeout,
TLSHandshakeTimeout: tlsHandshakeTimeout,
TLSClientConfig: &tls.Config{
InsecureSkipVerify: config.InsecureSkipVerify,
},
TLSClientConfig: tlsCfg,
},
},
logger: logger,
Expand All @@ -110,5 +114,5 @@ func buildClient(options *exporterOptions, config *Config, logger *zap.Logger) *
"Authorization": splunk.HECTokenHeader + " " + config.Token,
},
config: config,
}
}, nil
}
25 changes: 23 additions & 2 deletions exporter/splunkhecexporter/exporter_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ import (
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
"go.opentelemetry.io/collector/component/componenttest"
"go.opentelemetry.io/collector/config/configtls"
"go.opentelemetry.io/collector/consumer/pdata"
"go.opentelemetry.io/collector/exporter/exporterhelper"
"go.opentelemetry.io/collector/testutil/metricstestutil"
Expand All @@ -56,6 +57,24 @@ func TestNew(t *testing.T) {
got, err = createExporter(config, zap.NewNop())
assert.NoError(t, err)
require.NotNil(t, got)

config = &Config{
Token: "someToken",
Endpoint: "https://example.com:8088",
TimeoutSettings: exporterhelper.TimeoutSettings{Timeout: 1 * time.Second},
TLSSetting: configtls.TLSClientSetting{
TLSSetting: configtls.TLSSetting{
CAFile: "file-not-found",
CertFile: "file-not-found",
KeyFile: "file-not-found",
},
Insecure: false,
InsecureSkipVerify: false,
},
}
got, err = createExporter(config, zap.NewNop())
assert.Error(t, err)
require.Nil(t, got)
}

func TestConsumeMetricsData(t *testing.T) {
Expand Down Expand Up @@ -147,7 +166,8 @@ func TestConsumeMetricsData(t *testing.T) {
config.Token = "1234"
config.Index = "test_index"

sender := buildClient(options, config, zap.NewNop())
sender, err := buildClient(options, config, zap.NewNop())
assert.NoError(t, err)

md := internaldata.OCToMetrics(tt.md)
err = sender.pushMetricsData(context.Background(), md)
Expand Down Expand Up @@ -292,7 +312,8 @@ func TestConsumeLogsData(t *testing.T) {
config.Token = "1234"
config.Index = "test_index"

sender := buildClient(options, config, zap.NewNop())
sender, err := buildClient(options, config, zap.NewNop())
assert.NoError(t, err)

err = sender.pushLogData(context.Background(), tt.ld)
if tt.wantErr {
Expand Down
5 changes: 5 additions & 0 deletions exporter/splunkhecexporter/testdata/config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,11 @@ exporters:
source: "otel"
sourcetype: "otel"
index: "metrics"
insecure_skip_verify: false
insecure: true
ca_file: ""
cert_file: ""
key_file: ""
timeout: 10s
sending_queue:
enabled: true
Expand Down
2 changes: 0 additions & 2 deletions receiver/splunkhecreceiver/receiver_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -581,7 +581,6 @@ func Test_Logs_splunkhecReceiver_IndexSourceTypePassthrough(t *testing.T) {
Token: "ignored",
SourceType: "defaultsourcetype",
Index: "defaultindex",
InsecureSkipVerify: true,
DisableCompression: true,
Endpoint: endServer.URL,
}
Expand Down Expand Up @@ -680,7 +679,6 @@ func Test_Metrics_splunkhecReceiver_IndexSourceTypePassthrough(t *testing.T) {
Token: "ignored",
SourceType: "defaultsourcetype",
Index: "defaultindex",
InsecureSkipVerify: true,
DisableCompression: true,
Endpoint: endServer.URL,
}
Expand Down