diff --git a/CHANGELOG.md b/CHANGELOG.md index 2268800c4..e4d3de69c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -22,6 +22,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - github.com/aws/aws-sdk-go [PR 395](https://github.com/observIQ/stanza/pull/395) - golang.org/x/text [PR 386](https://github.com/observIQ/stanza/pull/386) - ARM64 Container Image: [PR 381](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/drop_output.md b/docs/operators/drop_output.md new file mode 100644 index 000000000..93feeafdb --- /dev/null +++ b/docs/operators/drop_output.md @@ -0,0 +1,37 @@ +## `drop_output` operator + +The `drop_output` operator does nothing. Useful for discarding entries while troubleshooting Stanza during development. + +### Configuration Fields + +Operator `drop_output` does not have configuration + +### Example Configurations + +Configuration +```yaml +pipeline: +- type: stdin +- type: drop_output +``` + +Send a message: +```bash +echo "hello world" | ./stanza -c ./config.yaml +``` + +There will be no output: +```json +{"level":"info","timestamp":"2021-08-20T20:09:55.057-0400","message":"Starting stanza agent"} +{"level":"info","timestamp":"2021-08-20T20:09:55.057-0400","message":"Stanza agent started"} +{"level":"info","timestamp":"2021-08-20T20:09:55.057-0400","message":"Stdin has been closed","operator_id":"$.stdin","operator_type":"stdin"} +``` + +Compare with `stdout` output operator: +```json +{"level":"info","timestamp":"2021-08-20T20:09:28.314-0400","message":"Starting stanza agent"} +{"level":"info","timestamp":"2021-08-20T20:09:28.314-0400","message":"Stanza agent started"} +{"timestamp":"2021-08-20T20:09:28.314776719-04:00","severity":0,"record":"hello world"} +{"level":"info","timestamp":"2021-08-20T20:09:28.314-0400","message":"Stdin has been closed","operator_id":"$.stdin","operator_type":"stdin"} +``` + 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{ diff --git a/scripts/unix-install.sh b/scripts/unix-install.sh index fb1792b2c..454289e51 100755 --- a/scripts/unix-install.sh +++ b/scripts/unix-install.sh @@ -934,7 +934,7 @@ Environment=PATH=/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin WorkingDirectory=$agent_home ExecStart=$agent_binary --log_file $agent_log --database $agent_database SuccessExitStatus=143 -TimeoutSec=0 +TimeoutSec=120 StandardOutput=null Restart=on-failure RestartSec=5s