From 86933ebb7fb2c1670f070bc9a7bbc1d875554d47 Mon Sep 17 00:00:00 2001 From: Bob Shannon Date: Tue, 17 Apr 2018 20:02:04 -0400 Subject: [PATCH] Add TLS support to socket_writer and socket_listener plugins (#4021) --- internal/internal.go | 51 +++++++++++++++++-- plugins/inputs/socket_listener/README.md | 7 +++ .../inputs/socket_listener/socket_listener.go | 49 +++++++++++++++--- .../socket_listener/socket_listener_test.go | 48 +++++++++++++++++ .../inputs/socket_listener/testdata/ca.pem | 31 +++++++++++ .../socket_listener/testdata/client.key | 27 ++++++++++ .../socket_listener/testdata/client.pem | 24 +++++++++ .../socket_listener/testdata/server.key | 27 ++++++++++ .../socket_listener/testdata/server.pem | 25 +++++++++ plugins/outputs/socket_writer/README.md | 7 +++ .../outputs/socket_writer/socket_writer.go | 32 ++++++++++-- 11 files changed, 314 insertions(+), 14 deletions(-) create mode 100644 plugins/inputs/socket_listener/testdata/ca.pem create mode 100644 plugins/inputs/socket_listener/testdata/client.key create mode 100644 plugins/inputs/socket_listener/testdata/client.pem create mode 100644 plugins/inputs/socket_listener/testdata/server.key create mode 100644 plugins/inputs/socket_listener/testdata/server.pem diff --git a/internal/internal.go b/internal/internal.go index aae7aa773f87e..3227832c991ec 100644 --- a/internal/internal.go +++ b/internal/internal.go @@ -112,9 +112,10 @@ func RandomString(n int) string { return string(bytes) } -// GetTLSConfig gets a tls.Config object from the given certs, key, and CA files. -// you must give the full path to the files. -// If all files are blank and InsecureSkipVerify=false, returns a nil pointer. +// GetTLSConfig gets a tls.Config object from the given certs, key, and CA files +// for use with a client. +// The full path to each file must be provided. +// Returns a nil pointer if all files are blank and InsecureSkipVerify=false. func GetTLSConfig( SSLCert, SSLKey, SSLCA string, InsecureSkipVerify bool, @@ -155,6 +156,50 @@ func GetTLSConfig( return t, nil } +// GetServerTLSConfig gets a tls.Config object from the given certs, key, and one or more CA files +// for use with a server. +// The full path to each file must be provided. +// Returns a nil pointer if all files are blank. +func GetServerTLSConfig( + TLSCert, TLSKey string, + TLSAllowedCACerts []string, +) (*tls.Config, error) { + if TLSCert == "" && TLSKey == "" && len(TLSAllowedCACerts) == 0 { + return nil, nil + } + + t := &tls.Config{} + + if len(TLSAllowedCACerts) != 0 { + caCertPool := x509.NewCertPool() + for _, cert := range TLSAllowedCACerts { + c, err := ioutil.ReadFile(cert) + if err != nil { + return nil, errors.New(fmt.Sprintf("Could not load TLS CA: %s", + err)) + } + caCertPool.AppendCertsFromPEM(c) + } + t.ClientCAs = caCertPool + t.ClientAuth = tls.RequireAndVerifyClientCert + } + + if TLSCert != "" && TLSKey != "" { + cert, err := tls.LoadX509KeyPair(TLSCert, TLSKey) + if err != nil { + return nil, errors.New(fmt.Sprintf( + "Could not load TLS client key/certificate from %s:%s: %s", + TLSKey, TLSCert, err)) + } + + t.Certificates = []tls.Certificate{cert} + } + + t.BuildNameToCertificate() + + return t, nil +} + // SnakeCase converts the given string to snake case following the Golang format: // acronyms are converted to lower-case and preceded by an underscore. func SnakeCase(in string) string { diff --git a/plugins/inputs/socket_listener/README.md b/plugins/inputs/socket_listener/README.md index 698f3aeeedf68..ff73b1fbbf8e7 100644 --- a/plugins/inputs/socket_listener/README.md +++ b/plugins/inputs/socket_listener/README.md @@ -35,6 +35,13 @@ This is a sample configuration for the plugin. ## 0 (default) is unlimited. # read_timeout = "30s" + ## Optional TLS configuration. + ## Only applies to stream sockets (e.g. TCP). + # tls_cert = "/etc/telegraf/cert.pem" + # tls_key = "/etc/telegraf/key.pem" + ## Enables client authentication if set. + # tls_allowed_cacerts = ["/etc/telegraf/clientca.pem"] + ## Maximum socket buffer size in bytes. ## For stream sockets, once the buffer fills up, the sender will start backing up. ## For datagram sockets, once the buffer fills up, metrics will start dropping. diff --git a/plugins/inputs/socket_listener/socket_listener.go b/plugins/inputs/socket_listener/socket_listener.go index 2ad6c42645f1c..011a1edb481f4 100644 --- a/plugins/inputs/socket_listener/socket_listener.go +++ b/plugins/inputs/socket_listener/socket_listener.go @@ -12,6 +12,7 @@ import ( "time" + "crypto/tls" "github.com/influxdata/telegraf" "github.com/influxdata/telegraf/internal" "github.com/influxdata/telegraf/plugins/inputs" @@ -122,9 +123,9 @@ func (ssl *streamSocketListener) read(c net.Conn) { } if err := scnr.Err(); err != nil { - if err, ok := err.(net.Error); ok && err.Timeout() { + if netErr, ok := err.(net.Error); ok && netErr.Timeout() { log.Printf("D! Timeout in plugin [input.socket_listener]: %s", err) - } else if !strings.HasSuffix(err.Error(), ": use of closed network connection") { + } else if netErr != nil && !strings.HasSuffix(err.Error(), ": use of closed network connection") { ssl.AddError(err) } } @@ -159,11 +160,14 @@ func (psl *packetSocketListener) listen() { } type SocketListener struct { - ServiceAddress string - MaxConnections int - ReadBufferSize int - ReadTimeout *internal.Duration - KeepAlivePeriod *internal.Duration + ServiceAddress string `toml:"service_address"` + MaxConnections int `toml:"max_connections"` + ReadBufferSize int `toml:"read_buffer_size"` + ReadTimeout *internal.Duration `toml:"read_timeout"` + TLSAllowedCACerts []string `toml:"tls_allowed_cacerts"` + TLSCert string `toml:"tls_cert"` + TLSKey string `toml:"tls_key"` + KeepAlivePeriod *internal.Duration `toml:"keep_alive_period"` parsers.Parser telegraf.Accumulator @@ -198,6 +202,13 @@ func (sl *SocketListener) SampleConfig() string { ## 0 (default) is unlimited. # read_timeout = "30s" + ## Optional TLS configuration. + ## Only applies to stream sockets (e.g. TCP). + # tls_cert = "/etc/telegraf/cert.pem" + # tls_key = "/etc/telegraf/key.pem" + ## Enables client authentication if set. + # tls_allowed_cacerts = ["/etc/telegraf/clientca.pem"] + ## Maximum socket buffer size in bytes. ## For stream sockets, once the buffer fills up, the sender will start backing up. ## For datagram sockets, once the buffer fills up, metrics will start dropping. @@ -242,7 +253,21 @@ func (sl *SocketListener) Start(acc telegraf.Accumulator) error { switch spl[0] { case "tcp", "tcp4", "tcp6", "unix", "unixpacket": - l, err := net.Listen(spl[0], spl[1]) + var ( + err error + l net.Listener + ) + + tlsCfg, err := internal.GetServerTLSConfig(sl.TLSCert, sl.TLSKey, sl.TLSAllowedCACerts) + if err != nil { + return nil + } + + if tlsCfg == nil { + l, err = net.Listen(spl[0], spl[1]) + } else { + l, err = tls.Listen(spl[0], spl[1], tlsCfg) + } if err != nil { return err } @@ -313,6 +338,14 @@ func (uc unixCloser) Close() error { return err } +func (uc unixCloser) Accept() (net.Conn, error) { + return uc.closer.(net.Listener).Accept() +} + +func (uc unixCloser) Addr() net.Addr { + return uc.closer.(net.Listener).Addr() +} + func init() { inputs.Add("socket_listener", func() telegraf.Input { return newSocketListener() }) } diff --git a/plugins/inputs/socket_listener/socket_listener_test.go b/plugins/inputs/socket_listener/socket_listener_test.go index 4e8335699b2f8..b647e724fcedc 100644 --- a/plugins/inputs/socket_listener/socket_listener_test.go +++ b/plugins/inputs/socket_listener/socket_listener_test.go @@ -2,12 +2,14 @@ package socket_listener import ( "bytes" + "crypto/tls" "log" "net" "os" "testing" "time" + "github.com/influxdata/telegraf/internal" "github.com/influxdata/telegraf/testutil" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" @@ -25,6 +27,52 @@ func testEmptyLog(t *testing.T) func() { } } +func TestSocketListener_tcp_tls(t *testing.T) { + defer testEmptyLog(t)() + + sl := newSocketListener() + sl.ServiceAddress = "tcp://127.0.0.1:0" + sl.TLSCert = "testdata/server.pem" + sl.TLSKey = "testdata/server.key" + sl.TLSAllowedCACerts = []string{"testdata/ca.pem"} + + acc := &testutil.Accumulator{} + err := sl.Start(acc) + require.NoError(t, err) + defer sl.Stop() + + tlsCfg, err := internal.GetTLSConfig("testdata/client.pem", "testdata/client.key", "testdata/ca.pem", true) + require.NoError(t, err) + + secureClient, err := tls.Dial("tcp", sl.Closer.(net.Listener).Addr().String(), tlsCfg) + require.NoError(t, err) + + testSocketListener(t, sl, secureClient) +} + +func TestSocketListener_unix_tls(t *testing.T) { + defer testEmptyLog(t)() + + sl := newSocketListener() + sl.ServiceAddress = "unix:///tmp/telegraf_test.sock" + sl.TLSCert = "testdata/server.pem" + sl.TLSKey = "testdata/server.key" + sl.TLSAllowedCACerts = []string{"testdata/ca.pem"} + + acc := &testutil.Accumulator{} + err := sl.Start(acc) + require.NoError(t, err) + defer sl.Stop() + + tlsCfg, err := internal.GetTLSConfig("testdata/client.pem", "testdata/client.key", "testdata/ca.pem", true) + require.NoError(t, err) + + secureClient, err := tls.Dial("unix", "/tmp/telegraf_test.sock", tlsCfg) + require.NoError(t, err) + + testSocketListener(t, sl, secureClient) +} + func TestSocketListener_tcp(t *testing.T) { defer testEmptyLog(t)() diff --git a/plugins/inputs/socket_listener/testdata/ca.pem b/plugins/inputs/socket_listener/testdata/ca.pem new file mode 100644 index 0000000000000..d3b6d9a14080c --- /dev/null +++ b/plugins/inputs/socket_listener/testdata/ca.pem @@ -0,0 +1,31 @@ +-----BEGIN CERTIFICATE----- +MIIFVTCCAz2gAwIBAgIJAOhLvwv6zUf+MA0GCSqGSIb3DQEBCwUAMEExCzAJBgNV +BAYTAlVTMQswCQYDVQQIDAJDQTEWMBQGA1UEBwwNU2FuIEZyYW5jaXNjbzENMAsG +A1UECgwEVGVzdDAeFw0xODA0MTcwNDIwNDZaFw0yMTAyMDQwNDIwNDZaMEExCzAJ +BgNVBAYTAlVTMQswCQYDVQQIDAJDQTEWMBQGA1UEBwwNU2FuIEZyYW5jaXNjbzEN +MAsGA1UECgwEVGVzdDCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAKwE +Xy814CDH03G3Fg2/XSpYZXVMzwp6oq/bUe3iLhkOpA6C4+j07AxAAa22qEPlvYkb +W7oxVJiL0ih1od2FeAxvroBTmjG54j/Syb8OeQsZaJLNp1rRmwYGBIVi284ScaIc +dn+2bfmfpSLjK3SbU5XygtwIE3gh/B7x02UJRNJmJ1faRT2CfTeg/56xnTE4bcR5 +HRrlojoN5laJngowLWAEAvWljCR8oge+ciNYB3xoK8Hgc9+WgTy95G1RBCNkaFFI +73nrcHl6dGOH9UgIqfbHJYxNEarI3o/JAr8DIBS0W4r8r4aY4JQ4LoN3bg4mLHQq +THKkVW5hyBeWe47qmlL0m4F6/+mzVi95NAWG2BQDCZJAWJNc+PbSRHi81838m7ff +O4rixd/F53LUUas8/zVca3vtv+XjOHZzIQLIy1bM4MhzpHlRcSmS9kqxxZ3S70e3 +ZIWFdM0iRrtlBbJeoHIJRDpgPRYIWdRc6XotljTTi6/lN4Bj/0NK4E3iONcDsscN +kiqEHRAWZ4ptCqdVPgYR0S096Fx6OaC3ASODE0Cjb18ylZQRsQi8TiYSihGzuoio +wJwSLdIifDbbSUkjT1384cA/HsOjFQ9xHXYa6cQnAg3TUZyG1lAMJyFWYke+rxmG +srfL/EtIzgbzmEOC5anQjA2pdgUO9Pk2SinJaMApAgMBAAGjUDBOMB0GA1UdDgQW +BBQNJctDLjj8bVKNCYANaOcboPQnmzAfBgNVHSMEGDAWgBQNJctDLjj8bVKNCYAN +aOcboPQnmzAMBgNVHRMEBTADAQH/MA0GCSqGSIb3DQEBCwUAA4ICAQATSr26Kc8g +3l2zuccoKWM57DQcgRmzSYwEOKA2jn3FWmrAdwozEIkLaTK0OXz0zh2dZxh9V3GR +w0WFCynbGNy/9s33MSi+zIWJOU/MZvt6zGE5CTcTgZ+u5IZyvSubMkPcwQi3Yvcg +AHmWzpF42kT2J5C5MfrSU65hrhPX7hT/CUoV3gN7oxFzj+/ED4kgNorO8SUUJCmq +DJNFbjgsD63EhnvAhn1AeM35GmKdl2enEKqcZsRkE4ZLpU7ibrThEm1aOQuJUtHk +gDAx49QMdQpWnxWxnfoiwpLu7ufR7ls8O9oA8ZJux/SVHEmtkOdRsuMtY5MElFZg +dANlQsdFWDko4ixaxFYzppuPNnRlqjGNnaEFJrNc2KR0Dxgmp28Yh2VyLd4r3fLT +nLVBYF8KzFchUdXYYPNBXwAf/N52jGfugDx8snLxOfzxoUZ4y64qMCpYhntGgBJ1 +Rrk2trcn3Dw19gi8p3ylbdoz/Ch1INDDrO35pd0bZpcwASc/UNU72W5v2kGL0H7o +nJzgtrqeHcoIzNBmBhHlMlnTF5GMfrYGsf5d30KyKv7UL6qJTvT641dpKpB/FFrk +y3AQbKmKRDI+aVzeOlwdy/eJAwt7FikD4bR9GZ4PBX9n9jd4u/PHZNfxtgzplqo1 +oy7kJv0cB/vRKOblmn/vPUfTFtAX7M3GkQ== +-----END CERTIFICATE----- diff --git a/plugins/inputs/socket_listener/testdata/client.key b/plugins/inputs/socket_listener/testdata/client.key new file mode 100644 index 0000000000000..285a2747825b4 --- /dev/null +++ b/plugins/inputs/socket_listener/testdata/client.key @@ -0,0 +1,27 @@ +-----BEGIN RSA PRIVATE KEY----- +MIIEpAIBAAKCAQEAmRuY+9Gg5V4e9hCd2mYek1jKeoaZijz89EPvox78XzoGdxPf +RoukUcTVS9VWN7HyJBjRA9P+KuHI9dX47skxyxH53uXZvRmGQAJBY4cE07JHvGkZ +eK1heXoWlBzYtivckha7bLBfn1ttAzcFCblUfJdzsn9XDuC4Jfn4oSaKn1o8Rzy1 +KRvyLgvsYxMA/XzhyBzVMyoUOulye7EZx4f+AwSNmNHD4OgtxxPofrrMOtXZ2tC6 +xNOexIZXbsB9dyrUW+4pWXYaadU7fl2V+arAJj+NVxV+3tmGGjmd1MiIypPx6BbP +g7xH20nJ/Y0U6V7gklZpYO1i84RbtR/kqBgi9QIDAQABAoIBAEONJJM+KyHnw/tG +246HbcgO7c7fYhDW1bgj3S/4NNsC6+VP1Dv40nftQzphFtgd37rDZDyvJL3gvlyQ +mnMoO5rgBIGuocHH6C6HkDgMUznft7zOFhnjTVVeY2XX0FmXwoqGEw1iR940ZUV8 +2fEvXrJV1AsWGeALj9PZlTPsoE6rv5sUk9Lh3wCD73m7GSg7DzBRE+6bBze8Lmwn +ZzTvmimhgPJw8LR5rRpYbDbhAJLAfgA7/yPgYEPxA/ffry6Ba4epj8tVNUNOAcOf +PURF+uuIF7RceI2PkdvoNuQyVR5oxQUPUfidfVK5ClUmnHECSgb/FFnYC+nU2vSi +IAnmC6ECgYEAyrUFHyxxuIQAiinjBxa0OQ3ynvMxDnF/+zvWe8536Y61lz9dblKb +0xvFhpOEMfiG/zFdZdWJ+xdq7VQVNMHu4USoskG8sZs5zImMTu50kuDNln7xYqVf +SUuN1U7cp7JouI1qkZAOsytPfAgZN/83hLObd07lAvL44jKYaHVeMmkCgYEAwVxZ +wKXpboHwQawA+4ubsnZ36IlOk21/+FlGJiDg/LB643BS+QhgVNxuB2gL1gOCYkhl +6BBcIhWMvZOIIo5uwnv4fQ+WfFwntU9POFViZgbZvkitQtorB7MXc/NU2BDrNYx2 +TBCiRn/9BaZ4fziW8I3Fx3xQ3rKDBXrexmrJQq0CgYEAvYGQYT12r47Qxlo0gcsL +AA/3E/y9jwgzItglQ6eZ2ULup5C4s0wNm8Zp2s+Mlf8HjgpDi9Gf5ptU/r1N+f2Y +awd6QvRMCSraVUr+Xkh1uV7rNNhGqPd75pT460OH7EtRtb+XsrAf3gcOjyEvGnfC +GpCjNl4OobwvS6ELdRTM1IkCgYAHUGX4uo3k5zdeVJJI8ZP3ITIR8retLfQsQbw8 +jvvTsx1C4ynQT7fNHfVvhEkGVGWnMBPivlOt2mDTfvQkUnzwEF5q5J8NnzLFUfWu +LNSnBVVRNFCRec0s4mJduXOZJLKw+No0sGBjCE5a21wte8eB2+sCS7qHYftAxtAM +c1eflQKBgQDGTFsMvpM8BEPTreinTllFBdjeYchcdY/Ov9DZ3mMVopjAWRD81MKM +zM1RCqwLkgv9FvF79B1FLJ1Inr8e/XIGdcrhE1a4sZdIWdqTWQ4xFrlDgxCquq66 +da09WVBRdvq2kVLAMaBViH2/GP1G4ZV9a8+JHuWKj+Arrr52Qeazjw== +-----END RSA PRIVATE KEY----- diff --git a/plugins/inputs/socket_listener/testdata/client.pem b/plugins/inputs/socket_listener/testdata/client.pem new file mode 100644 index 0000000000000..d741e6518964e --- /dev/null +++ b/plugins/inputs/socket_listener/testdata/client.pem @@ -0,0 +1,24 @@ +-----BEGIN CERTIFICATE----- +MIIEEjCCAfoCCQCmcronmMSqXTANBgkqhkiG9w0BAQsFADBBMQswCQYDVQQGEwJV +UzELMAkGA1UECAwCQ0ExFjAUBgNVBAcMDVNhbiBGcmFuY2lzY28xDTALBgNVBAoM +BFRlc3QwHhcNMTgwNDE3MDQyNDMwWhcNNDUwOTAyMDQyNDMwWjBVMQswCQYDVQQG +EwJVUzELMAkGA1UECAwCQ0ExFjAUBgNVBAcMDVNhbiBGcmFuY2lzY28xITAfBgNV +BAoMGEludGVybmV0IFdpZGdpdHMgUHR5IEx0ZDCCASIwDQYJKoZIhvcNAQEBBQAD +ggEPADCCAQoCggEBAJkbmPvRoOVeHvYQndpmHpNYynqGmYo8/PRD76Me/F86BncT +30aLpFHE1UvVVjex8iQY0QPT/irhyPXV+O7JMcsR+d7l2b0ZhkACQWOHBNOyR7xp +GXitYXl6FpQc2LYr3JIWu2ywX59bbQM3BQm5VHyXc7J/Vw7guCX5+KEmip9aPEc8 +tSkb8i4L7GMTAP184cgc1TMqFDrpcnuxGceH/gMEjZjRw+DoLccT6H66zDrV2drQ +usTTnsSGV27AfXcq1FvuKVl2GmnVO35dlfmqwCY/jVcVft7Zhho5ndTIiMqT8egW +z4O8R9tJyf2NFOle4JJWaWDtYvOEW7Uf5KgYIvUCAwEAATANBgkqhkiG9w0BAQsF +AAOCAgEACJkccOvBavtagiMQc9OLsbo0PkHv7Qk9uTm5Sg9+LjLGUsu+3WLjAAmj +YScHyGbvQzXlwpgo8JuwY0lMNoPfwGuydlJPfOBCbaoAqFp6Vpc/E49J9YovCsqa +2HJUJeuxpf6SiH1Vc1SECjzwzKo03t8ul7t7SNVqA0r9fV4I936FlJOeQ4d5U+Wv +H7c2LmAqbHi2Mwf+m+W6ziOvzp+szspcP2gJDX7hsKEtIlqmHYm2bzZ4fsCuU9xN +3quewBVQUOuParO632yaLgzpGmfzzxLmCPO84lxarJKCxjHG2Q2l30TO/wA44m+r +Wd17HpCT3PkCDG5eSNCSnYqfLm8DE1hLGfHiXxKmrgU94q4wvwVGOlcYa+CQeP9Q +ZW3Tj0Axz0Mqlg1iLLo12+Z/yocSY2nFnFntBFT4qBKNCeD0xH3PxC0HJdK66xBv +MVDE/OE2hBtTTts+vC9yjx4W8thtMSA4VCOgtt5sHjt3ZekiYYh5VZK47Bx/a0uc +8CouRdyppWyPp/cNC+PcGW3YnXpAkxe/bSY/qgfK5kmbeOf+HzvZAIwAH/d9VK0g +AoLNp46eP6U2E2lVvtc/HJ1C/gsiC/1TSIq/kBbYtuIJjhhH3u6IVet7WSD22Akv +o5gOpcoKwy8IPDRC5lJEAAVYUKt7ORo2en3OVg6I4FaQmeBFp5s= +-----END CERTIFICATE----- diff --git a/plugins/inputs/socket_listener/testdata/server.key b/plugins/inputs/socket_listener/testdata/server.key new file mode 100644 index 0000000000000..4ad8e642f6952 --- /dev/null +++ b/plugins/inputs/socket_listener/testdata/server.key @@ -0,0 +1,27 @@ +-----BEGIN RSA PRIVATE KEY----- +MIIEowIBAAKCAQEAzkEDLijGOqXNQPAqUjOz5TLuM28SENauknLtcfIyEN/N6PwZ +re5DjokxtDPp+c9yP/9qtn7+dBfdUXg2Mu7HQz8lAKniir2ZH+axkjp5LUE6vYJd +I1W8lOOc0kXDjozBetgriE0jkgc3v9oDBbLhN5waKR86jpQaNkfnI7/4U3yrlymK +yaT3uD6L1ldUJubdQ/xc1HxdmX8VewBnkK1urYyiRbju2iL9YmtSM72yWXvFsD1O +I4fP/XuiaymicBmXKL4cu6KYdfn1qeLAV3U35xG597M031WmR5o67rc63sqs+Q// +V3dbGqnFXRMkLhoOnuKK0DD28ujY1kctbNQWVQIDAQABAoIBAHFxFJy41H7BXulO +rxhTU6jGoHktqBQW4CGwkKTRf3QEhK6WqlEd8Y5eKzZgL1q1HLPSehEyPCYCUjpT +EgxlhLeZ7XI1/mIs8iG3swconimj7Pj60Nt0dqq1njWRJYQsKua0Kw1m0B+rVKBy ++qKRxondlA32HTD6iIg+eAUTuzO/KzimZcyL9hiT/g6aN9k0H5+qURi8dO7VV8fD +zvP8Y+oOGLwW2ccp+ZjFQizjTOkL4lgldr0hsGQXZJNHL94fA7jPdAxAUbnTicMJ +oXM++L3eCwIVabipGxxlqCMj9Dn8yfbQvRGzP2e76QDeROYZHX4osH6vLcZEjx9i +tJ4J+ekCgYEA82kKzkSKmFo4gZxnqAywlfZ2X2PADuMmHdqdiDFwt54orlMlKf/b +wVSvN/djLXwvFHuyzFmJeMFSHKFkYVTOsh8kPSETAIGkcJEMHD3viYn7DwjkQudY +vB/FpBWSiDT0T7qDUCzW3iMbx/JvTUSp7uO4ZuwOu6t6v3PEZwIChQ8CgYEA2Ov9 +FXHmm7sS54HgvZd6Wk8zLMLIDnyMmECjtYOasJ9c40yQHpRlXsb+Dzn/2xhMMwth +Bln2hIiJ/e+G0bzFu4x0cItRPOQeRNyz5Pal8EsATeUwcX4KRKOZaUpDkV6XV1L0 +r/HSk/wed+90B74sGoJY1qsFflOATIUVs7SIllsCgYEAwhGSB/sl9WqZet1U1+um +LyqeHlfNnREGJu9Sgm/Iyt1S2gp4qw/QCkiWmyym6nEEqHQnjj4lGR4pdaJIAkI3 +ulSR9BsWp2S10voSicHn5eUZQld4hs8lNHiwf66jce2mjJrMb3QQrHOZhsWIcDa6 +tjjhoU28QWzrJRIMGYTEtYkCgYA17NSJlDsj06mra5oXB6Ue9jlekz1wfH3nC4qn +AQRfi/5ncw0QzQs2OHnIBz8XlD69IcMI9SxXXioPuo/la+wr54q6v6d+X6c2rzb5 +YGd4CO0WcDdOv2qGDbWBezi41q8AwlqZsqAKsc5ROnG5ywjjviufkfxXnyJx41O1 +zNd3qQKBgGEy+EwUXD5iGeQxdCDnd6iVu14SoBscHO5SpIeDu3DIhnu+7gPq2VMg +Vp9j/iNVtEA3HyYCOeXc2rz9Di1wwt3YijED4birLAkC5YW6YB9rmLMfCNc1EyLh +BKAkUQN3D+XCN4pXdbKvbkOcfYRUHoD+pPBjRYH020OtPBUc6Wkl +-----END RSA PRIVATE KEY----- diff --git a/plugins/inputs/socket_listener/testdata/server.pem b/plugins/inputs/socket_listener/testdata/server.pem new file mode 100644 index 0000000000000..96cfa0b00a4ca --- /dev/null +++ b/plugins/inputs/socket_listener/testdata/server.pem @@ -0,0 +1,25 @@ +-----BEGIN CERTIFICATE----- +MIIEJjCCAg4CCQCmcronmMSqXDANBgkqhkiG9w0BAQsFADBBMQswCQYDVQQGEwJV +UzELMAkGA1UECAwCQ0ExFjAUBgNVBAcMDVNhbiBGcmFuY2lzY28xDTALBgNVBAoM +BFRlc3QwHhcNMTgwNDE3MDQyNDAwWhcNNDUwOTAyMDQyNDAwWjBpMQswCQYDVQQG +EwJVUzELMAkGA1UECAwCQ0ExFjAUBgNVBAcMDVNhbiBGcmFuY2lzY28xITAfBgNV +BAoMGEludGVybmV0IFdpZGdpdHMgUHR5IEx0ZDESMBAGA1UEAwwJMTI3LjAuMC4x +MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAzkEDLijGOqXNQPAqUjOz +5TLuM28SENauknLtcfIyEN/N6PwZre5DjokxtDPp+c9yP/9qtn7+dBfdUXg2Mu7H +Qz8lAKniir2ZH+axkjp5LUE6vYJdI1W8lOOc0kXDjozBetgriE0jkgc3v9oDBbLh +N5waKR86jpQaNkfnI7/4U3yrlymKyaT3uD6L1ldUJubdQ/xc1HxdmX8VewBnkK1u +rYyiRbju2iL9YmtSM72yWXvFsD1OI4fP/XuiaymicBmXKL4cu6KYdfn1qeLAV3U3 +5xG597M031WmR5o67rc63sqs+Q//V3dbGqnFXRMkLhoOnuKK0DD28ujY1kctbNQW +VQIDAQABMA0GCSqGSIb3DQEBCwUAA4ICAQCVgzqFrehoRAMFLMEL8avfokYtsSYc +50Yug4Es0ISo/PRWGeUnv8k1inyE3Y1iR/gbN5n/yjLXJKEflan6BuqGuukfr2eA +fRdDCyPvzQLABdxCx2n6ByQFxj92z82tizf35R2OMuHHWzTckta+7s5EvxwIiUsd +rUuXp+0ltJzlYYW9xTGFiJO9hAbRgMgZiwL8F7ayic8GmLQ1eRK/DfKDCOH3afeX +MNN5FulgjqNyhXHF33vwgIJynGDg2JEhkWjB1DkUAxll0+SMQoYyVGZVrQSGbGw1 +JhOLc8C8bTzfK3qcJDuyldvjiut+To+lpu76R0u0+sn+wxQFL1uCWuAbMJgGsJgM +ARavu2XDeae9X+e8MgJuN1FYS3tihBplPjMJD3UYRybRvHAvQh26BZ7Ch3JNSNST +AL2l5T7JKU+XaWWeo+crV+AnGIJyqyh9Su/n97PEoZoEMGH4Kcl/n/w2Jms60+5s +K0FK2OGNL42ddUfQiVL9CwYQQo70hydjsIo1x8S6+tSFLMAAysQEToSjfAA6qxDu +fgGVMuIYHo0rSkpTVsHVwru08Z5o4m+XDAK0iHalZ4knKsO0lJ+9l7vFnQHlzwt7 +JTjDhnyOKWPIANeWf3PrHPWE7kKpFVBqFBzOvWLJuxDu5NlgLo1PFahsahTqB9bz +qwUyMg/oYWnwqw== +-----END CERTIFICATE----- diff --git a/plugins/outputs/socket_writer/README.md b/plugins/outputs/socket_writer/README.md index e8b5a0174df4d..8e28c5f88ddbe 100644 --- a/plugins/outputs/socket_writer/README.md +++ b/plugins/outputs/socket_writer/README.md @@ -19,6 +19,13 @@ It can output data in any of the [supported output formats](https://github.com/i # address = "unix:///tmp/telegraf.sock" # address = "unixgram:///tmp/telegraf.sock" + ## Optional SSL Config + # ssl_ca = "/etc/telegraf/ca.pem" + # ssl_cert = "/etc/telegraf/cert.pem" + # ssl_key = "/etc/telegraf/key.pem" + ## Use SSL but skip chain & host verification + # insecure_skip_verify = false + ## Period between keep alive probes. ## Only applies to TCP sockets. ## 0 disables keep alive probes. diff --git a/plugins/outputs/socket_writer/socket_writer.go b/plugins/outputs/socket_writer/socket_writer.go index 503130c624f45..855df4a8fb905 100644 --- a/plugins/outputs/socket_writer/socket_writer.go +++ b/plugins/outputs/socket_writer/socket_writer.go @@ -6,6 +6,7 @@ import ( "net" "strings" + "crypto/tls" "github.com/influxdata/telegraf" "github.com/influxdata/telegraf/internal" "github.com/influxdata/telegraf/plugins/outputs" @@ -13,8 +14,12 @@ import ( ) type SocketWriter struct { - Address string - KeepAlivePeriod *internal.Duration + Address string + KeepAlivePeriod *internal.Duration + SSLCA string + SSLCert string + SSLKey string + InsecureSkipVerify bool serializers.Serializer @@ -39,6 +44,13 @@ func (sw *SocketWriter) SampleConfig() string { # address = "unix:///tmp/telegraf.sock" # address = "unixgram:///tmp/telegraf.sock" + ## Optional SSL Config + # ssl_ca = "/etc/telegraf/ca.pem" + # ssl_cert = "/etc/telegraf/cert.pem" + # ssl_key = "/etc/telegraf/key.pem" + ## Use SSL but skip chain & host verification + # insecure_skip_verify = false + ## Period between keep alive probes. ## Only applies to TCP sockets. ## 0 disables keep alive probes. @@ -58,12 +70,26 @@ func (sw *SocketWriter) SetSerializer(s serializers.Serializer) { } func (sw *SocketWriter) Connect() error { + var ( + c net.Conn + err error + ) + spl := strings.SplitN(sw.Address, "://", 2) if len(spl) != 2 { return fmt.Errorf("invalid address: %s", sw.Address) } - c, err := net.Dial(spl[0], spl[1]) + tlsCfg, err := internal.GetTLSConfig(sw.SSLCert, sw.SSLKey, sw.SSLCA, sw.InsecureSkipVerify) + if err != nil { + return err + } + + if tlsCfg == nil { + c, err = net.Dial(spl[0], spl[1]) + } else { + c, err = tls.Dial(spl[0], spl[1], tlsCfg) + } if err != nil { return err }