feat(common.tls): Implement minimum TLS version for clients (#11493)
This commit is contained in:
parent
b07e94b662
commit
e96bbe83c5
|
|
@ -1,6 +1,10 @@
|
||||||
<!-- markdownlint-disable MD024 -->
|
<!-- markdownlint-disable MD024 -->
|
||||||
# Changelog
|
# Changelog
|
||||||
|
|
||||||
|
### BREAKING CHANGES
|
||||||
|
|
||||||
|
- [#11493](https://github.com/influxdata/telegraf/pull/11493) `common.tls` Set default minimum TLS version to v1.2 for security reasons on both server and client connections. This is a change from the previous defaults (TLS v1.0) on the server configuration and might break clients relying on older TLS versions. You can manually revert to older versions on a per-plugin basis using the `tls_min_version` option in the plugins required.
|
||||||
|
|
||||||
## v1.23.3 [2022-07-25]
|
## v1.23.3 [2022-07-25]
|
||||||
|
|
||||||
### Bugfixes
|
### Bugfixes
|
||||||
|
|
|
||||||
|
|
@ -10,12 +10,15 @@ import (
|
||||||
"github.com/influxdata/telegraf/internal/choice"
|
"github.com/influxdata/telegraf/internal/choice"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
const TLSMinVersionDefault = tls.VersionTLS12
|
||||||
|
|
||||||
// ClientConfig represents the standard client TLS config.
|
// ClientConfig represents the standard client TLS config.
|
||||||
type ClientConfig struct {
|
type ClientConfig struct {
|
||||||
TLSCA string `toml:"tls_ca"`
|
TLSCA string `toml:"tls_ca"`
|
||||||
TLSCert string `toml:"tls_cert"`
|
TLSCert string `toml:"tls_cert"`
|
||||||
TLSKey string `toml:"tls_key"`
|
TLSKey string `toml:"tls_key"`
|
||||||
TLSKeyPwd string `toml:"tls_key_pwd"`
|
TLSKeyPwd string `toml:"tls_key_pwd"`
|
||||||
|
TLSMinVersion string `toml:"tls_min_version"`
|
||||||
InsecureSkipVerify bool `toml:"insecure_skip_verify"`
|
InsecureSkipVerify bool `toml:"insecure_skip_verify"`
|
||||||
ServerName string `toml:"tls_server_name"`
|
ServerName string `toml:"tls_server_name"`
|
||||||
|
|
||||||
|
|
@ -81,6 +84,19 @@ func (c *ClientConfig) TLSConfig() (*tls.Config, error) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Explicitly and consistently set the minimal accepted version using the
|
||||||
|
// defined default. We use this setting for both clients and servers
|
||||||
|
// instead of relying on Golang's default that is different for clients
|
||||||
|
// and servers and might change over time.
|
||||||
|
tlsConfig.MinVersion = TLSMinVersionDefault
|
||||||
|
if c.TLSMinVersion != "" {
|
||||||
|
version, err := ParseTLSVersion(c.TLSMinVersion)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("could not parse tls min version %q: %w", c.TLSMinVersion, err)
|
||||||
|
}
|
||||||
|
tlsConfig.MinVersion = version
|
||||||
|
}
|
||||||
|
|
||||||
if c.ServerName != "" {
|
if c.ServerName != "" {
|
||||||
tlsConfig.ServerName = c.ServerName
|
tlsConfig.ServerName = c.ServerName
|
||||||
}
|
}
|
||||||
|
|
@ -131,6 +147,11 @@ func (c *ServerConfig) TLSConfig() (*tls.Config, error) {
|
||||||
tlsConfig.MaxVersion = version
|
tlsConfig.MaxVersion = version
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Explicitly and consistently set the minimal accepted version using the
|
||||||
|
// defined default. We use this setting for both clients and servers
|
||||||
|
// instead of relying on Golang's default that is different for clients
|
||||||
|
// and servers and might change over time.
|
||||||
|
tlsConfig.MinVersion = TLSMinVersionDefault
|
||||||
if c.TLSMinVersion != "" {
|
if c.TLSMinVersion != "" {
|
||||||
version, err := ParseTLSVersion(c.TLSMinVersion)
|
version, err := ParseTLSVersion(c.TLSMinVersion)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,7 @@
|
||||||
package tls_test
|
package tls_test
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
cryptotls "crypto/tls"
|
||||||
"net/http"
|
"net/http"
|
||||||
"net/http/httptest"
|
"net/http/httptest"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
@ -350,6 +351,141 @@ func TestConnect(t *testing.T) {
|
||||||
require.Equal(t, 200, resp.StatusCode)
|
require.Equal(t, 200, resp.StatusCode)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestConnectClientMinTLSVersion(t *testing.T) {
|
||||||
|
serverConfig := tls.ServerConfig{
|
||||||
|
TLSCert: pki.ServerCertPath(),
|
||||||
|
TLSKey: pki.ServerKeyPath(),
|
||||||
|
TLSAllowedCACerts: []string{pki.CACertPath()},
|
||||||
|
TLSAllowedDNSNames: []string{"localhost", "127.0.0.1"},
|
||||||
|
}
|
||||||
|
|
||||||
|
tests := []struct {
|
||||||
|
name string
|
||||||
|
cfg tls.ClientConfig
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
name: "TLS version default",
|
||||||
|
cfg: tls.ClientConfig{
|
||||||
|
TLSCA: pki.CACertPath(),
|
||||||
|
TLSCert: pki.ClientCertPath(),
|
||||||
|
TLSKey: pki.ClientKeyPath(),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "TLS version 1.0",
|
||||||
|
cfg: tls.ClientConfig{
|
||||||
|
TLSCA: pki.CACertPath(),
|
||||||
|
TLSCert: pki.ClientCertPath(),
|
||||||
|
TLSKey: pki.ClientKeyPath(),
|
||||||
|
TLSMinVersion: "TLS10",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "TLS version 1.1",
|
||||||
|
cfg: tls.ClientConfig{
|
||||||
|
TLSCA: pki.CACertPath(),
|
||||||
|
TLSCert: pki.ClientCertPath(),
|
||||||
|
TLSKey: pki.ClientKeyPath(),
|
||||||
|
TLSMinVersion: "TLS11",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "TLS version 1.2",
|
||||||
|
cfg: tls.ClientConfig{
|
||||||
|
TLSCA: pki.CACertPath(),
|
||||||
|
TLSCert: pki.ClientCertPath(),
|
||||||
|
TLSKey: pki.ClientKeyPath(),
|
||||||
|
TLSMinVersion: "TLS12",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "TLS version 1.3",
|
||||||
|
cfg: tls.ClientConfig{
|
||||||
|
TLSCA: pki.CACertPath(),
|
||||||
|
TLSCert: pki.ClientCertPath(),
|
||||||
|
TLSKey: pki.ClientKeyPath(),
|
||||||
|
TLSMinVersion: "TLS13",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
tlsVersions := []uint16{
|
||||||
|
cryptotls.VersionTLS10,
|
||||||
|
cryptotls.VersionTLS11,
|
||||||
|
cryptotls.VersionTLS12,
|
||||||
|
cryptotls.VersionTLS13,
|
||||||
|
}
|
||||||
|
|
||||||
|
tlsVersionNames := []string{
|
||||||
|
"TLS 1.0",
|
||||||
|
"TLS 1.1",
|
||||||
|
"TLS 1.2",
|
||||||
|
"TLS 1.3",
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, tt := range tests {
|
||||||
|
clientTLSConfig, err := tt.cfg.TLSConfig()
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
client := http.Client{
|
||||||
|
Transport: &http.Transport{
|
||||||
|
TLSClientConfig: clientTLSConfig,
|
||||||
|
},
|
||||||
|
Timeout: 1 * time.Second,
|
||||||
|
}
|
||||||
|
|
||||||
|
clientMinVersion := clientTLSConfig.MinVersion
|
||||||
|
if tt.cfg.TLSMinVersion == "" {
|
||||||
|
clientMinVersion = tls.TLSMinVersionDefault
|
||||||
|
}
|
||||||
|
|
||||||
|
for i, serverTLSMaxVersion := range tlsVersions {
|
||||||
|
serverVersionName := tlsVersionNames[i]
|
||||||
|
t.Run(tt.name+" vs "+serverVersionName, func(t *testing.T) {
|
||||||
|
// Constrain the server's maximum TLS version
|
||||||
|
serverTLSConfig, err := serverConfig.TLSConfig()
|
||||||
|
require.NoError(t, err)
|
||||||
|
serverTLSConfig.MinVersion = cryptotls.VersionTLS10
|
||||||
|
serverTLSConfig.MaxVersion = serverTLSMaxVersion
|
||||||
|
|
||||||
|
// Start the server
|
||||||
|
ts := httptest.NewUnstartedServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||||
|
w.WriteHeader(http.StatusOK)
|
||||||
|
}))
|
||||||
|
ts.TLS = serverTLSConfig
|
||||||
|
ts.StartTLS()
|
||||||
|
|
||||||
|
// Do the connection and cleanup
|
||||||
|
resp, err := client.Get(ts.URL)
|
||||||
|
ts.Close()
|
||||||
|
|
||||||
|
// Things should fail if the currently tested "serverTLSMaxVersion"
|
||||||
|
// is below the client minimum version.
|
||||||
|
if serverTLSMaxVersion < clientMinVersion {
|
||||||
|
require.ErrorContains(t, err, "tls: protocol version not supported")
|
||||||
|
} else {
|
||||||
|
require.NoErrorf(t, err, "server=%v client=%v", serverTLSMaxVersion, clientMinVersion)
|
||||||
|
require.Equal(t, 200, resp.StatusCode)
|
||||||
|
resp.Body.Close()
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestConnectClientInvalidMinTLSVersion(t *testing.T) {
|
||||||
|
clientConfig := tls.ClientConfig{
|
||||||
|
TLSCA: pki.CACertPath(),
|
||||||
|
TLSCert: pki.ClientCertPath(),
|
||||||
|
TLSKey: pki.ClientKeyPath(),
|
||||||
|
TLSMinVersion: "garbage",
|
||||||
|
}
|
||||||
|
|
||||||
|
_, err := clientConfig.TLSConfig()
|
||||||
|
expected := `could not parse tls min version "garbage": unsupported version "garbage" (available: TLS10,TLS11,TLS12,TLS13)`
|
||||||
|
require.EqualError(t, err, expected)
|
||||||
|
}
|
||||||
|
|
||||||
func TestConnectWrongDNS(t *testing.T) {
|
func TestConnectWrongDNS(t *testing.T) {
|
||||||
clientConfig := tls.ClientConfig{
|
clientConfig := tls.ClientConfig{
|
||||||
TLSCA: pki.CACertPath(),
|
TLSCA: pki.CACertPath(),
|
||||||
|
|
|
||||||
|
|
@ -2,6 +2,8 @@ package tls
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"sort"
|
||||||
|
"strings"
|
||||||
)
|
)
|
||||||
|
|
||||||
// ParseCiphers returns a `[]uint16` by received `[]string` key that represents ciphers from crypto/tls.
|
// ParseCiphers returns a `[]uint16` by received `[]string` key that represents ciphers from crypto/tls.
|
||||||
|
|
@ -26,5 +28,11 @@ func ParseTLSVersion(version string) (uint16, error) {
|
||||||
if v, ok := tlsVersionMap[version]; ok {
|
if v, ok := tlsVersionMap[version]; ok {
|
||||||
return v, nil
|
return v, nil
|
||||||
}
|
}
|
||||||
return 0, fmt.Errorf("unsupported version %q", version)
|
|
||||||
|
var available []string
|
||||||
|
for n := range tlsVersionMap {
|
||||||
|
available = append(available, n)
|
||||||
|
}
|
||||||
|
sort.Strings(available)
|
||||||
|
return 0, fmt.Errorf("unsupported version %q (available: %s)", version, strings.Join(available, ","))
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -32,6 +32,9 @@ It has been optimized to support gNMI telemetry as produced by Cisco IOS XR
|
||||||
## enable client-side TLS and define CA to authenticate the device
|
## enable client-side TLS and define CA to authenticate the device
|
||||||
# enable_tls = true
|
# enable_tls = true
|
||||||
# tls_ca = "/etc/telegraf/ca.pem"
|
# tls_ca = "/etc/telegraf/ca.pem"
|
||||||
|
## Minimal TLS version to accept by the client
|
||||||
|
# tls_min_version = "TLS12"
|
||||||
|
## Use TLS but skip chain & host verification
|
||||||
# insecure_skip_verify = true
|
# insecure_skip_verify = true
|
||||||
|
|
||||||
## define client-side TLS certificate & key to authenticate to the device
|
## define client-side TLS certificate & key to authenticate to the device
|
||||||
|
|
|
||||||
|
|
@ -16,6 +16,9 @@
|
||||||
## enable client-side TLS and define CA to authenticate the device
|
## enable client-side TLS and define CA to authenticate the device
|
||||||
# enable_tls = true
|
# enable_tls = true
|
||||||
# tls_ca = "/etc/telegraf/ca.pem"
|
# tls_ca = "/etc/telegraf/ca.pem"
|
||||||
|
## Minimal TLS version to accept by the client
|
||||||
|
# tls_min_version = "TLS12"
|
||||||
|
## Use TLS but skip chain & host verification
|
||||||
# insecure_skip_verify = true
|
# insecure_skip_verify = true
|
||||||
|
|
||||||
## define client-side TLS certificate & key to authenticate to the device
|
## define client-side TLS certificate & key to authenticate to the device
|
||||||
|
|
|
||||||
|
|
@ -50,6 +50,8 @@ configuration.
|
||||||
# tls_ca = "/etc/telegraf/ca.pem"
|
# tls_ca = "/etc/telegraf/ca.pem"
|
||||||
# tls_cert = "/etc/telegraf/cert.pem"
|
# tls_cert = "/etc/telegraf/cert.pem"
|
||||||
# tls_key = "/etc/telegraf/key.pem"
|
# tls_key = "/etc/telegraf/key.pem"
|
||||||
|
## Minimal TLS version to accept by the client
|
||||||
|
# tls_min_version = "TLS12"
|
||||||
## Use TLS but skip chain & host verification
|
## Use TLS but skip chain & host verification
|
||||||
# insecure_skip_verify = false
|
# insecure_skip_verify = false
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -39,6 +39,8 @@
|
||||||
# tls_ca = "/etc/telegraf/ca.pem"
|
# tls_ca = "/etc/telegraf/ca.pem"
|
||||||
# tls_cert = "/etc/telegraf/cert.pem"
|
# tls_cert = "/etc/telegraf/cert.pem"
|
||||||
# tls_key = "/etc/telegraf/key.pem"
|
# tls_key = "/etc/telegraf/key.pem"
|
||||||
|
## Minimal TLS version to accept by the client
|
||||||
|
# tls_min_version = "TLS12"
|
||||||
## Use TLS but skip chain & host verification
|
## Use TLS but skip chain & host verification
|
||||||
# insecure_skip_verify = false
|
# insecure_skip_verify = false
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -49,6 +49,9 @@ InfluxDB it is recommended to use [`influxdb_listener`][influxdb_listener] or
|
||||||
# tls_cert = "/etc/telegraf/cert.pem"
|
# tls_cert = "/etc/telegraf/cert.pem"
|
||||||
# tls_key = "/etc/telegraf/key.pem"
|
# tls_key = "/etc/telegraf/key.pem"
|
||||||
|
|
||||||
|
## Minimal TLS version accepted by the server
|
||||||
|
# tls_min_version = "TLS12"
|
||||||
|
|
||||||
## Optional username and password to accept for HTTP basic authentication.
|
## Optional username and password to accept for HTTP basic authentication.
|
||||||
## You probably want to make sure you have TLS configured above for this.
|
## You probably want to make sure you have TLS configured above for this.
|
||||||
# basic_username = "foobar"
|
# basic_username = "foobar"
|
||||||
|
|
@ -71,6 +74,8 @@ InfluxDB it is recommended to use [`influxdb_listener`][influxdb_listener] or
|
||||||
Metrics are collected from the part of the request specified by the
|
Metrics are collected from the part of the request specified by the
|
||||||
`data_source` param and are parsed depending on the value of `data_format`.
|
`data_source` param and are parsed depending on the value of `data_format`.
|
||||||
|
|
||||||
|
## Example Output
|
||||||
|
|
||||||
## Troubleshooting
|
## Troubleshooting
|
||||||
|
|
||||||
Send Line Protocol:
|
Send Line Protocol:
|
||||||
|
|
|
||||||
|
|
@ -33,6 +33,9 @@
|
||||||
# tls_cert = "/etc/telegraf/cert.pem"
|
# tls_cert = "/etc/telegraf/cert.pem"
|
||||||
# tls_key = "/etc/telegraf/key.pem"
|
# tls_key = "/etc/telegraf/key.pem"
|
||||||
|
|
||||||
|
## Minimal TLS version accepted by the server
|
||||||
|
# tls_min_version = "TLS12"
|
||||||
|
|
||||||
## Optional username and password to accept for HTTP basic authentication.
|
## Optional username and password to accept for HTTP basic authentication.
|
||||||
## You probably want to make sure you have TLS configured above for this.
|
## You probably want to make sure you have TLS configured above for this.
|
||||||
# basic_username = "foobar"
|
# basic_username = "foobar"
|
||||||
|
|
|
||||||
|
|
@ -50,6 +50,8 @@ from listed sensors using Junos Telemetry Interface. Refer to
|
||||||
# tls_ca = "/etc/telegraf/ca.pem"
|
# tls_ca = "/etc/telegraf/ca.pem"
|
||||||
# tls_cert = "/etc/telegraf/cert.pem"
|
# tls_cert = "/etc/telegraf/cert.pem"
|
||||||
# tls_key = "/etc/telegraf/key.pem"
|
# tls_key = "/etc/telegraf/key.pem"
|
||||||
|
## Minimal TLS version to accept by the client
|
||||||
|
# tls_min_version = "TLS12"
|
||||||
## Use TLS but skip chain & host verification
|
## Use TLS but skip chain & host verification
|
||||||
# insecure_skip_verify = false
|
# insecure_skip_verify = false
|
||||||
|
|
||||||
|
|
@ -65,3 +67,7 @@ from listed sensors using Junos Telemetry Interface. Refer to
|
||||||
|
|
||||||
- All measurements are tagged appropriately using the identifier information
|
- All measurements are tagged appropriately using the identifier information
|
||||||
in incoming data
|
in incoming data
|
||||||
|
|
||||||
|
## Example Output
|
||||||
|
|
||||||
|
## Metrics
|
||||||
|
|
|
||||||
|
|
@ -38,6 +38,8 @@
|
||||||
# tls_ca = "/etc/telegraf/ca.pem"
|
# tls_ca = "/etc/telegraf/ca.pem"
|
||||||
# tls_cert = "/etc/telegraf/cert.pem"
|
# tls_cert = "/etc/telegraf/cert.pem"
|
||||||
# tls_key = "/etc/telegraf/key.pem"
|
# tls_key = "/etc/telegraf/key.pem"
|
||||||
|
## Minimal TLS version to accept by the client
|
||||||
|
# tls_min_version = "TLS12"
|
||||||
## Use TLS but skip chain & host verification
|
## Use TLS but skip chain & host verification
|
||||||
# insecure_skip_verify = false
|
# insecure_skip_verify = false
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue