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 support to socket_writer and socket_listener plugins #4021

Merged
merged 9 commits into from
Apr 18, 2018
Merged
Show file tree
Hide file tree
Changes from 4 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
62 changes: 59 additions & 3 deletions internal/internal.go
Original file line number Diff line number Diff line change
Expand Up @@ -112,12 +112,21 @@ 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.
// Deprecated - use GetClientTLSConfig or GetServerTLSConfig instead.
func GetTLSConfig(
SSLCert, SSLKey, SSLCA string,
InsecureSkipVerify bool,
) (*tls.Config, error) {
return GetClientTLSConfig(SSLCert, SSLKey, SSLCA, InsecureSkipVerify)
}

// GetClientTLSConfig 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 GetClientTLSConfig(
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just leave this as GetTLSConfig for now.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done.

SSLCert, SSLKey, SSLCA string,
InsecureSkipVerify bool,
) (*tls.Config, error) {
if SSLCert == "" && SSLKey == "" && SSLCA == "" && !InsecureSkipVerify {
return nil, nil
Expand Down Expand Up @@ -155,6 +164,53 @@ 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(
SSLCert, SSLKey string,
SSLCA []string,
SSLClientAuth bool,
) (*tls.Config, error) {
if SSLCert == "" && SSLKey == "" && len(SSLCA) == 0 {
return nil, nil
}

t := &tls.Config{}

if len(SSLCA) != 0 {
caCertPool := x509.NewCertPool()
for _, cert := range SSLCA {
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
}

if SSLCert != "" && SSLKey != "" {
cert, err := tls.LoadX509KeyPair(SSLCert, SSLKey)
if err != nil {
return nil, errors.New(fmt.Sprintf(
"Could not load TLS client key/certificate from %s:%s: %s",
SSLKey, SSLCert, err))
}

t.Certificates = []tls.Certificate{cert}
t.BuildNameToCertificate()
}

if SSLClientAuth {
t.ClientAuth = tls.RequireAndVerifyClientCert
}

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 {
Expand Down
9 changes: 9 additions & 0 deletions plugins/inputs/socket_listener/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,15 @@ This is a sample configuration for the plugin.
## 0 (default) is unlimited.
# read_timeout = "30s"

## Optional SSL configuration.
## Only applies to stream sockets (e.g. TCP).
# ssl_cert = "/etc/telegraf/cert.pem"
# ssl_key = "/etc/telegraf/key.pem"
## Enable and require client certificate authentication.
# ssl_client_auth = false
## CAs used to verify client certificates.
# ssl_ca = ["/etc/telegraf/ca.pem"]
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We have a little bit of prior art on the server side: #3191, I would prefer if we use the same variable names, but let me know if you think that is a problem. The biggest difference is that client_auth is enabled automatically if there are cacerts specified.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Makes sense -- definitely want to stay consistent. The config now matches those variable names.


## 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.
Expand Down
30 changes: 29 additions & 1 deletion plugins/inputs/socket_listener/socket_listener.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import (

"time"

"crypto/tls"
"github.com/influxdata/telegraf"
"github.com/influxdata/telegraf/internal"
"github.com/influxdata/telegraf/plugins/inputs"
Expand Down Expand Up @@ -163,6 +164,10 @@ type SocketListener struct {
MaxConnections int
ReadBufferSize int
ReadTimeout *internal.Duration
SSLCA []string
SSLCert string
SSLKey string
SSLClientAuth bool
KeepAlivePeriod *internal.Duration

parsers.Parser
Expand Down Expand Up @@ -198,6 +203,15 @@ func (sl *SocketListener) SampleConfig() string {
## 0 (default) is unlimited.
# read_timeout = "30s"

## Optional SSL configuration.
## Only applies to stream sockets (e.g. TCP).
# ssl_cert = "/etc/telegraf/cert.pem"
# ssl_key = "/etc/telegraf/key.pem"
## Enable and require client certificate authentication.
# ssl_client_auth = false
## CAs used to verify client certificates.
# ssl_ca = ["/etc/telegraf/ca.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.
Expand Down Expand Up @@ -242,7 +256,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.SSLCert, sl.SSLKey, sl.SSLCA, sl.SSLClientAuth)
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
}
Expand Down
7 changes: 7 additions & 0 deletions plugins/outputs/socket_writer/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down
32 changes: 29 additions & 3 deletions plugins/outputs/socket_writer/socket_writer.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,15 +6,20 @@ import (
"net"
"strings"

"crypto/tls"
"github.com/influxdata/telegraf"
"github.com/influxdata/telegraf/internal"
"github.com/influxdata/telegraf/plugins/outputs"
"github.com/influxdata/telegraf/plugins/serializers"
)

type SocketWriter struct {
Address string
KeepAlivePeriod *internal.Duration
Address string
KeepAlivePeriod *internal.Duration
SSLCA string
SSLCert string
SSLKey string
InsecureSkipVerify bool

serializers.Serializer

Expand All @@ -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.
Expand All @@ -58,12 +70,26 @@ func (sw *SocketWriter) SetSerializer(s serializers.Serializer) {
}

func (sw *SocketWriter) Connect() error {
var (
c net.Conn
err error
)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: it's idiomatic go to declare variables right before they're used, not at the top of the function.
Also err doesn't need to be declared at all. It'll get declared on line 83.


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.GetClientTLSConfig(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
}
Expand Down