diff --git a/CHANGELOG.md b/CHANGELOG.md index 1ad638d29..678b0e563 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -21,6 +21,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - github.com/aws/aws-sdk-go [PR395](https://github.com/observIQ/stanza/pull/395) - golang.org/x/text [PR386](https://github.com/observIQ/stanza/pull/386) - ARM64 Container Image: [PR381](https://github.com/observIQ/stanza/pull/381) +- TCP Input: Minimum TLS version is now configurable: [PR 400](https://github.com/observIQ/stanza/pull/400) ## 1.1.8 - 2021-08-19 diff --git a/docs/operators/tcp_input.md b/docs/operators/tcp_input.md index f8e56d9a8..38c06db53 100644 --- a/docs/operators/tcp_input.md +++ b/docs/operators/tcp_input.md @@ -25,6 +25,7 @@ The `tcp_input` operator supports TLS, disabled by default. | `enable` | `false` | Boolean value to enable or disable TLS | | `certificate` | | File path for the X509 certificate chain | | `private_key` | | File path for the X509 private key | +| `min_version` | `1.0` | Minimum TLS version to accept connections from, defaults [TLS 1.0](https://pkg.go.dev/crypto/tls#Config) ### Example Configurations @@ -56,3 +57,74 @@ Generated entries: "record": "message2" } ``` + +### Example TLS Configurations + +#### Simple TLS + +Configuration: +```yaml +pipeline: +- type: tcp_input + listen_address: 0.0.0.0:5000 + tls: + enable: true + certificate: ./cert + private_key: ./key +- type: stdout +``` + +Send a log: +```bash +echo sample message | openssl s_client -connect localhost:5000 +``` + +Generated entry: +```json +{ + "timestamp": "2021-08-20T19:53:56.905051345-04:00", + "severity": 0, + "record": "sample message" +} +``` + +#### TLS 1.3 + +Configuration: +```yaml +pipeline: +- type: tcp_input + listen_address: 0.0.0.0:5000 + tls: + enable: true + certificate: ./cert + private_key: ./key + min_version: 1.3 +- type: stdout +``` + +Send a log with the `-tls1_3` flag: +```bash +echo sample message | openssl s_client -tls1_3 -connect localhost:5000 +``` + +Generated entry: +```json +{ + "timestamp": "2021-08-20T19:53:56.905051345-04:00", + "severity": 0, + "record": "sample message" +} +``` + +Try it a second time using a lower TLS version, such as `-tls1_2`, and it will fail: +```json +{ + "level":"error", + "timestamp":"2021-08-20T19:56:38.108-0400", + "message":"Scanner error", + "operator_id":"$.tcp_input", + "operator_type":"tcp_input", + "error":"tls: client offered only unsupported versions: [303 302 301]" +} +``` \ No newline at end of file diff --git a/operator/builtin/input/tcp/tcp.go b/operator/builtin/input/tcp/tcp.go index 6125ee27e..c9390fd82 100644 --- a/operator/builtin/input/tcp/tcp.go +++ b/operator/builtin/input/tcp/tcp.go @@ -59,6 +59,9 @@ type TLSConfig struct { // PrivateKey is the file path for the private key PrivateKey string `json:"private_key,omitempty" yaml:"private_key,omitempty"` + + // MinVersion is the minimum tls version + MinVersion float32 `json:"min_version,omitempty" yaml:"min_version,omitempty"` } // Build will build a tcp input operator. @@ -104,6 +107,21 @@ func (c TCPInputConfig) Build(context operator.BuildContext) ([]operator.Operato cert = c } + var tlsMinVersion uint16 + switch c.TLS.MinVersion { + case 0, 1.0: + // TLS 1.0 is the default version implemented by cypto/tls https://pkg.go.dev/crypto/tls#Config + tlsMinVersion = tls.VersionTLS10 + case 1.1: + tlsMinVersion = tls.VersionTLS11 + case 1.2: + tlsMinVersion = tls.VersionTLS12 + case 1.3: + tlsMinVersion = tls.VersionTLS13 + default: + return nil, fmt.Errorf("unsupported tls version: %f", c.TLS.MinVersion) + } + tcpInput := &TCPInput{ InputOperator: inputOperator, address: c.ListenAddress, @@ -111,6 +129,7 @@ func (c TCPInputConfig) Build(context operator.BuildContext) ([]operator.Operato addLabels: c.AddLabels, tlsEnable: c.TLS.Enable, tlsKeyPair: cert, + tlsMinVersion: tlsMinVersion, backoff: backoff.Backoff{ Min: 100 * time.Millisecond, Max: 3 * time.Second, @@ -129,6 +148,7 @@ type TCPInput struct { addLabels bool tlsEnable bool tlsKeyPair tls.Certificate + tlsMinVersion uint16 backoff backoff.Backoff listener net.Listener @@ -158,16 +178,10 @@ func (t *TCPInput) configureListener() error { return nil } - // TLS 1.0 is the package default since Go 1.2 - // https://golang.org/pkg/crypto/tls/ - // An issue has been filed to support modifyingn the minimum version - // https://github.com/observIQ/stanza/issues/349 - var tlsVersion uint16 = tls.VersionTLS10 - - // #nosec - Go defaults to TLS 1.0, and some users may require it + // #nosec - User to specify tls minimum version config := tls.Config{ Certificates: []tls.Certificate{t.tlsKeyPair}, - MinVersion: tlsVersion, + MinVersion: t.tlsMinVersion, } config.Time = func() time.Time { return time.Now() } config.Rand = rand.Reader diff --git a/operator/builtin/input/tcp/tcp_test.go b/operator/builtin/input/tcp/tcp_test.go index b9fe745de..6d3e87ec9 100644 --- a/operator/builtin/input/tcp/tcp_test.go +++ b/operator/builtin/input/tcp/tcp_test.go @@ -305,6 +305,90 @@ func TestBuild(t *testing.T) { }, false, }, + { + "tls-min-version-default", + TCPInputConfig{ + MaxBufferSize: 65536, + ListenAddress: "10.0.0.1:9000", + TLS: TLSConfig{ + Enable: false, + Certificate: "/tmp/cert", + PrivateKey: "/tmp/key", + MinVersion: 0, + }, + }, + false, + }, + { + "tls-min-version-1.0", + TCPInputConfig{ + MaxBufferSize: 65536, + ListenAddress: "10.0.0.1:9000", + TLS: TLSConfig{ + Enable: false, + Certificate: "/tmp/cert", + PrivateKey: "/tmp/key", + MinVersion: 1.0, + }, + }, + false, + }, + { + "tls-min-version-1.1", + TCPInputConfig{ + MaxBufferSize: 65536, + ListenAddress: "10.0.0.1:9000", + TLS: TLSConfig{ + Enable: false, + Certificate: "/tmp/cert", + PrivateKey: "/tmp/key", + MinVersion: 1.1, + }, + }, + false, + }, + { + "tls-min-version-1.2", + TCPInputConfig{ + MaxBufferSize: 65536, + ListenAddress: "10.0.0.1:9000", + TLS: TLSConfig{ + Enable: false, + Certificate: "/tmp/cert", + PrivateKey: "/tmp/key", + MinVersion: 1.2, + }, + }, + false, + }, + { + "tls-min-version-1.3", + TCPInputConfig{ + MaxBufferSize: 65536, + ListenAddress: "10.0.0.1:9000", + TLS: TLSConfig{ + Enable: false, + Certificate: "/tmp/cert", + PrivateKey: "/tmp/key", + MinVersion: 1.3, + }, + }, + false, + }, + { + "tls-invalid-min-version-1.4", + TCPInputConfig{ + MaxBufferSize: 65536, + ListenAddress: "10.0.0.1:9000", + TLS: TLSConfig{ + Enable: false, + Certificate: "/tmp/cert", + PrivateKey: "/tmp/key", + MinVersion: 1.4, + }, + }, + true, + }, { "tls-enabled-with-no-such-file-error", TCPInputConfig{