From 208902bb4c237e6aa097ebcda656dc3e5079f900 Mon Sep 17 00:00:00 2001 From: ph Date: Fri, 4 May 2018 13:18:25 -0400 Subject: [PATCH 1/6] Reorganization and Addition: Move TLS types and config out of the outputs and support server options. When working on the TLS tcp it was a bit strange to actually import a package coming from the outputs, this commit addresses a few things: - Move the `outputs/tls.go` and `transport/tls.go` into the tlscommon under the transport folder. - Add shims to make sure we keep backward compatibility on anything that could be using theses classes. - Extract common logic code to be reusable. - Add inverse mapper for TLSVersion and tlsCiphersuite, to give a uint and get the human string. - Add a new `ServerConfig` config struct used for any tcl class and the appropriate helper to get a new `tls.Config`. *This is a light refactoring, mostly moving code and adding a few tests. Fixes: #6079 --- .../common/transport/tlscommon/ca_test.key | 51 +++ .../common/transport/tlscommon/ca_test.pem | 31 ++ libbeat/common/transport/tlscommon/config.go | 86 +++++ .../transport/tlscommon/server_config.go | 84 +++++ libbeat/common/transport/tlscommon/tls.go | 172 ++++++++++ .../common/transport/tlscommon/tls_config.go | 77 +++++ .../transport/tlscommon}/tls_test.go | 110 +++++-- libbeat/common/transport/tlscommon/types.go | 267 +++++++++++++++ libbeat/outputs/tls.go | 304 +----------------- libbeat/outputs/transport/tls.go | 180 +---------- winlogbeat/docs/fields.asciidoc | 2 +- 11 files changed, 880 insertions(+), 484 deletions(-) create mode 100644 libbeat/common/transport/tlscommon/ca_test.key create mode 100644 libbeat/common/transport/tlscommon/ca_test.pem create mode 100644 libbeat/common/transport/tlscommon/config.go create mode 100644 libbeat/common/transport/tlscommon/server_config.go create mode 100644 libbeat/common/transport/tlscommon/tls.go create mode 100644 libbeat/common/transport/tlscommon/tls_config.go rename libbeat/{outputs => common/transport/tlscommon}/tls_test.go (60%) create mode 100644 libbeat/common/transport/tlscommon/types.go diff --git a/libbeat/common/transport/tlscommon/ca_test.key b/libbeat/common/transport/tlscommon/ca_test.key new file mode 100644 index 000000000000..6b658ead57c7 --- /dev/null +++ b/libbeat/common/transport/tlscommon/ca_test.key @@ -0,0 +1,51 @@ +-----BEGIN RSA PRIVATE KEY----- +MIIJKAIBAAKCAgEAv8IiJDAIDl+roQOWe+oSq46Nyuu9R+Iis0V1i6M7zA6Qijbx +CSZ64cCFYQfKheRYQSZRstHPHSUM1gSvUih/sqZqsiNMYDbb9j7geMDvls4c7rsH +x7xImD7nCrEVWkiapGIhkW6SOtVo18Zmw89FUuDFhoRmMHcQ+7AtM4uUNPkSqKcX +vzG093SU0oNdIBdw5PzoQlvBh5DL0iRYC6y22cwJyjWTUEB5vTjOTDxiFzsovRtj +pdjzSZACXyW68b99icLzmxzLvsZ7w8tFJ8uOPQAVxwg6SmMUorURv48sBjfVfN48 +7OjH3d+51ozNJjP1MmKoN2BoE8pWq0jdhOWhDQH+pRiRjfMuL+yvcIJ2pxdOv0F3 +KBkng7qEgEUA8cqaFnawDA7O3a20SeDFWSQtN6LsFjT7EDMzNkML1pJjbGK24QFC +IOOvCJtaccuREN1OfbN1yhTz3VErbJttwO6j2KueasPHXU3qLu2FKOlsXbPy1XMu +LYZgv8Zprcbs4KhQ3/A7/RO1cakxWlRwta63mUIM2xLIMIgRSR+DSZ5dJaDNO6i4 +9eIGQXRxDb9dxA2hoCcoTv7PJKyOpNb5vyxMXJGY7H5j1jEEcqEeuI5uvuUwugQG +tsl1eFLXIeQLerOHEQoS6wMv0fHBtZOVCHu8CCrnt/ag7kn39nkwNofLovECAwEA +AQKCAgA7hRB/1wDJJVzqb2ioMbF12pucXquzwjcvGeIwY4xN/D9VB1StmGoP5GgC +BB8SjBvwrOoy7PiyfSuMyot4nuV0GD+J53bvble8CSw3jvtO/c7xMtBpaMHHr86a +/Pg5u8t0NplgwMdWx6LxRr3jDVThMq9c33+wj2SQGtEM7Mgl4SGvg53VVKJtJJyE +8w1Wxq/eA7o7zqs1XvZE1c8WYJeo5rIrN5HwGPMwjo9KDnwL5erxN60obzykmrSB +v/5UxzE6L27ZuIhtQMJttYxTm9Ucjgg0bRNav4JKNpW5tcDedTootfqHNoHDFoxi +UfXjY8E50HGSLrRfYDCinc1UUMo568Ed9vRPOBSfw9FAZy4iExifmfHJsn8Bepse +xvYQfsYJpEsKoxzTTD7yLZALJEu18+8AHgYG6jFkvIlOUUjUKHiOyU5UlFErHk/P +W2n9FZPzSTnZQ2J06Rwmj2ILZ86kXIYoL8kEJSYTCG4TQ6KX4oeJq8v4yVHf+SiD +ZiYFWLAZbZQ46lL/7+dyy3rhLErm57DgYhJL/BqLys0GZdaazh12AcDcLjSQ6Yoh +xQYOogq+6xB4k8mqMkNmln5JWdhzFGAzkhClnCToYpvPK8KTg3a0cLV7X1wLlyh9 +Nr0kGATrUr2bHzBZazhwMkSXh+JUDZhyK0ZflqySQX8lQbMooQKCAQEA5ZVySenZ +qfRNHdcdjIf/J7/vu9cDnPAqszbGpt/GeLD3yag8zTUnTh8ZjFhQ3LH4SQ/4TdmF +37PsuNIzlay1TJ2b6lf0XoDG9DgbW3PpuRSVy2QIse7p6lsyNISn6bIJR1XSr9aP +pbgiQK9svq+QN0rSWSsQEDZB9rTNC+VcMY0r4043MxGFwGauiSoARmu6yqD3y/3q +ah3bz1UTZpUbnlO6PHT2nE+pV+YVHNz/MfprEFc+Ob9vCm6oCEhQyyAnOjcFxDjV +6J2uxn8MhDjvGOsJ8OfJt9UDhVBbzJXBfOZXO7bLDbWMzTfaa7BcQRaNkOY+ZPC/ +tW62E12hhxlHfQKCAQEA1dKC+LXFmQp36Dp1IrPEvU+AFF67MnxQErKptaCcGCo0 +A/udpSC3ivja5dPxJOM+wF0Vz3601biJUhI8Sar+P+V67dLrK/uY30Aq9GNrjtTj +sDqZejqvJak+nHa+CHe8RfkMlrTs/bgTSdQ0Go4k7+pH+Vi1pVnE07PQT8n772JY +ibLrkx54EUWqhh0+/q8MHd7pdNEYGhfft54GddZG6Tnmg4/PDyLcF9+TL86sV3Hv +uV6ftGVjE/Jrer3RCvGz28iYCy+pXLtg6xt768iI0bTDL5A9EopLiONRVu7hJJf5 +nYTmvQdjbVsfm7a9o/UxG3jOkgIy5W3haCVOFt2rhQKCAQBfVXWF99No3YeAUql0 +h6yOhwc3yws3CgvRK3fGJ7o0t9fNJ01IMUBHEmb7fljlrAlb3YPQX/lVcVNlU/QT +vQnz7Kan4yoYbAUxuHKzwShWsJObR8jMilcb+A6a/FL1mfZ8Zsj8N26i9BlVHwNb +E3AhZbJ/UIB1GvK9TUqwG+fys5p74yjMzgPqZzkmwAgpNeb06W68iI3kzs1OBRfv +Sw+S6VW2cSNOuU2qsGIoACUATepTeMbgF/w2Kskf11elYY6of9ynJKq+02uWBX/f +D/1JLaCNJtL+wTebDklwZOdZxBSJOViMMs1rEjxi53MHnCPg/Zr/M3GIF5cH56OB +hB/JAoIBAQCt8/4zYoYoFJkqZ+yF1+R18yiK6eq3juUB4TIqHkj/a843c0t0XKKV +wBEtqvhi/zE9BD3LOhTaTrABAe7kK+V+jC4vL0m91YkwDx8jBYMqh03ZQEM+amG1 +bPQQDJZbgzW7Y3r3XKf1XfzrMmVVOVEZkesOEzpsFBUJ+h692uBIhyTqmZIHdWFP +A/NP+pkWT8i2wHQDYlyOVd/enQQ6d6Hm+gDsBWH5uW1/SpeO7D/PQFU75JxfAaDS +SIViLOzVT3/4jUAM0bCiTZryisCNOO7+VGX62wikfbgn3G9/HwYxZCZiHQ4uuMUN +4XVclBXCPqa959F+faV0e6lGthrKhXqVAoIBAGAVqGQrexKADcE3TKbOBAaOi8vo +9HcTraZWOBY8QSP5xQZRey3L3sNrCTmT8L8fNmvXMMBoK9Lm51EYS8vgedUvlII9 +rC19IT0TG39AdFQH4/rWfcF9eqpneItPWuCRM3UokfeqDkS+4pBEGVOhI+dNr0oJ +APXpue6CgbD9xLvNAvdn0/PgmD0tV4HO6VUbJ9W3yFE1j+m1vNHVwk36nEdaL1aC +x7DTAiMGqrcTDr7DXwOImhPLrSWkLPxmIp+GD4831cmJqSSp/Lg/6OHa5fFZEJg7 +gkY+tjXMvUbuSx4lrOW6SY9LIxi7xTcRdfnd9g6z/G7IyGvXTevXDpopASo= +-----END RSA PRIVATE KEY----- diff --git a/libbeat/common/transport/tlscommon/ca_test.pem b/libbeat/common/transport/tlscommon/ca_test.pem new file mode 100644 index 000000000000..dcc8b984b789 --- /dev/null +++ b/libbeat/common/transport/tlscommon/ca_test.pem @@ -0,0 +1,31 @@ +-----BEGIN CERTIFICATE----- +MIIFTDCCAzSgAwIBAgIRAOAMlgVxz4G+Zj/EtBTvpg4wDQYJKoZIhvcNAQENBQAw +LzELMAkGA1UEBhMCVVMxEDAOBgNVBAoTB2VsYXN0aWMxDjAMBgNVBAsTBWJlYXRz +MB4XDTE3MDUxODIwMzI1MVoXDTI3MDUxODIwMzI1MVowLzELMAkGA1UEBhMCVVMx +EDAOBgNVBAoTB2VsYXN0aWMxDjAMBgNVBAsTBWJlYXRzMIICIjANBgkqhkiG9w0B +AQEFAAOCAg8AMIICCgKCAgEAv8IiJDAIDl+roQOWe+oSq46Nyuu9R+Iis0V1i6M7 +zA6QijbxCSZ64cCFYQfKheRYQSZRstHPHSUM1gSvUih/sqZqsiNMYDbb9j7geMDv +ls4c7rsHx7xImD7nCrEVWkiapGIhkW6SOtVo18Zmw89FUuDFhoRmMHcQ+7AtM4uU +NPkSqKcXvzG093SU0oNdIBdw5PzoQlvBh5DL0iRYC6y22cwJyjWTUEB5vTjOTDxi +FzsovRtjpdjzSZACXyW68b99icLzmxzLvsZ7w8tFJ8uOPQAVxwg6SmMUorURv48s +BjfVfN487OjH3d+51ozNJjP1MmKoN2BoE8pWq0jdhOWhDQH+pRiRjfMuL+yvcIJ2 +pxdOv0F3KBkng7qEgEUA8cqaFnawDA7O3a20SeDFWSQtN6LsFjT7EDMzNkML1pJj +bGK24QFCIOOvCJtaccuREN1OfbN1yhTz3VErbJttwO6j2KueasPHXU3qLu2FKOls +XbPy1XMuLYZgv8Zprcbs4KhQ3/A7/RO1cakxWlRwta63mUIM2xLIMIgRSR+DSZ5d +JaDNO6i49eIGQXRxDb9dxA2hoCcoTv7PJKyOpNb5vyxMXJGY7H5j1jEEcqEeuI5u +vuUwugQGtsl1eFLXIeQLerOHEQoS6wMv0fHBtZOVCHu8CCrnt/ag7kn39nkwNofL +ovECAwEAAaNjMGEwDgYDVR0PAQH/BAQDAgKkMB0GA1UdJQQWMBQGCCsGAQUFBwMC +BggrBgEFBQcDATAPBgNVHRMBAf8EBTADAQH/MA4GA1UdDgQHBAUxMjM0NTAPBgNV +HREECDAGhwR/AAABMA0GCSqGSIb3DQEBDQUAA4ICAQBjeGIfFqXuwHiClMytJNZL +cRyjeZ6PJIAQtqh8Vi+XD2JiDTkwJ/g4R0FbgqE/icGkm/hsJ6BEwp8ep5eXevjS +Hb8tVbM5Uc31yyIKcJMgnfS8O0eIXi5PxgFWPcUXxrsjwHyQREqj96HImmzOm99O +MJhifWT3YP8OEMyl1KpioPaXafhc4ATEiRVZizHM9z+phyINBNghH3OaN91ZnsKJ +El7mvOLjRi7fuSxBWJntKVAZAwXK+nH+z/Ay4AZFA9HgFHo3PGpKUaLOYCIsGxAq +GP4V/WsOtEJ9rP5TR92pOvcj49T47FmwSYaRtoXHDVuoun0fdwT4DxWJdksqdWzG +ieRls2IrZIvR2FT/A/XdQG3kZ79WA/K3OAGDgxv0PCpw6ssAMvgjR03TjEXpwMmN +SNcrx1H6l8DHFHJN9f7SofO/J0hkA+fRZUFxP5R+P2BPU0hV14H9iSie/bxhSWIW +ieAh0K1SNRbffXeYUvAgrjEvG5x40TktnvjHb20lxc1F1gqB+855kfZdiJeUeizi +syq6OnCEp+RSBdK7J3scm7t6Nt3GRndJMO9hNDprogTqHxQbZ0jficntGd7Lbp+C +CBegkhOzD6cp2rGlyYI+MmvdXFaHbsUJj2tfjHQdo2YjQ1s8r2pw219LTzPvO/Dz +morZ618ezCBBqxHsDF6DCA== +-----END CERTIFICATE----- diff --git a/libbeat/common/transport/tlscommon/config.go b/libbeat/common/transport/tlscommon/config.go new file mode 100644 index 000000000000..9e89f2eea3aa --- /dev/null +++ b/libbeat/common/transport/tlscommon/config.go @@ -0,0 +1,86 @@ +package tlscommon + +import ( + "crypto/tls" + + "github.com/joeshaw/multierror" +) + +// Config defines the user configurable options in the yaml file. +type Config struct { + Enabled *bool `config:"enabled"` + VerificationMode TLSVerificationMode `config:"verification_mode"` // one of 'none', 'full' + Versions []TLSVersion `config:"supported_protocols"` + CipherSuites []tlsCipherSuite `config:"cipher_suites"` + CAs []string `config:"certificate_authorities"` + Certificate CertificateConfig `config:",inline"` + CurveTypes []tlsCurveType `config:"curve_types"` + Renegotiation tlsRenegotiationSupport `config:"renegotiation"` +} + +// LoadTLSConfig will load a certificate from config with all TLS based keys +// defined. If Certificate and CertificateKey are configured, client authentication +// will be configured. If no CAs are configured, the host CA will be used by go +// built-in TLS support. +func LoadTLSConfig(config *Config) (*TLSConfig, error) { + if !config.IsEnabled() { + return nil, nil + } + + fail := multierror.Errors{} + logFail := func(es ...error) { + for _, e := range es { + if e != nil { + fail = append(fail, e) + } + } + } + + var cipherSuites []uint16 + for _, suite := range config.CipherSuites { + cipherSuites = append(cipherSuites, uint16(suite)) + } + + var curves []tls.CurveID + for _, id := range config.CurveTypes { + curves = append(curves, tls.CurveID(id)) + } + + cert, err := LoadCertificate(&config.Certificate) + logFail(err) + + cas, errs := LoadCertificateAuthorities(config.CAs) + logFail(errs...) + + // fail, if any error occurred when loading certificate files + if err = fail.Err(); err != nil { + return nil, err + } + + var certs []tls.Certificate + if cert != nil { + certs = []tls.Certificate{*cert} + } + + // return config if no error occurred + return &TLSConfig{ + Versions: config.Versions, + Verification: config.VerificationMode, + Certificates: certs, + RootCAs: cas, + CipherSuites: cipherSuites, + CurvePreferences: curves, + Renegotiation: tls.RenegotiationSupport(config.Renegotiation), + }, nil +} + +// Validate valies the TLSConfig struct making sure certificate sure we have both a certificate and +// a key. +func (c *Config) Validate() error { + return c.Certificate.Validate() +} + +// IsEnabled returns true if the `enable` field is set to true in the yaml. +func (c *Config) IsEnabled() bool { + return c != nil && (c.Enabled == nil || *c.Enabled) +} diff --git a/libbeat/common/transport/tlscommon/server_config.go b/libbeat/common/transport/tlscommon/server_config.go new file mode 100644 index 000000000000..c63514109216 --- /dev/null +++ b/libbeat/common/transport/tlscommon/server_config.go @@ -0,0 +1,84 @@ +package tlscommon + +import ( + "crypto/tls" + + "github.com/joeshaw/multierror" +) + +// ServerConfig defines the user configurable tls options for any TCP based service. +type ServerConfig struct { + Enabled *bool `config:"enabled"` + VerificationMode TLSVerificationMode `config:"verification_mode"` // one of 'none', 'full' + Versions []TLSVersion `config:"supported_protocols"` + CipherSuites []tlsCipherSuite `config:"cipher_suites"` + CAs []string `config:"certificate_authorities"` + Certificate CertificateConfig `config:",inline"` + CurveTypes []tlsCurveType `config:"curve_types"` + ClientAuth tlsClientAuth `config:"client_authentification"` //`none`, `optional` or `required` +} + +// LoadTLSServerConfig tranforms a ServerConfig into a `tls.Config` to be used directly with golang +// network types. +func LoadTLSServerConfig(config *ServerConfig) (*TLSConfig, error) { + if !config.IsEnabled() { + return nil, nil + } + + fail := multierror.Errors{} + logFail := func(es ...error) { + for _, e := range es { + if e != nil { + fail = append(fail, e) + } + } + } + + var cipherSuites []uint16 + for _, suite := range config.CipherSuites { + cipherSuites = append(cipherSuites, uint16(suite)) + } + + var curves []tls.CurveID + for _, id := range config.CurveTypes { + curves = append(curves, tls.CurveID(id)) + } + + cert, err := LoadCertificate(&config.Certificate) + logFail(err) + + cas, errs := LoadCertificateAuthorities(config.CAs) + logFail(errs...) + + // fail, if any error occurred when loading certificate files + if err = fail.Err(); err != nil { + return nil, err + } + + var certs []tls.Certificate + if cert != nil { + certs = []tls.Certificate{*cert} + } + + // return config if no error occurred + return &TLSConfig{ + Versions: config.Versions, + Verification: config.VerificationMode, + Certificates: certs, + ClientCAs: cas, + CipherSuites: cipherSuites, + CurvePreferences: curves, + ClientAuth: tls.ClientAuthType(config.ClientAuth), + }, nil +} + +// Validate valies the TLSConfig struct making sure certificate sure we have both a certificate and +// a key. +func (c *ServerConfig) Validate() error { + return c.Certificate.Validate() +} + +// IsEnabled returns true if the `enable` field is set to true in the yaml. +func (c *ServerConfig) IsEnabled() bool { + return c != nil && (c.Enabled == nil || *c.Enabled) +} diff --git a/libbeat/common/transport/tlscommon/tls.go b/libbeat/common/transport/tlscommon/tls.go new file mode 100644 index 000000000000..d90c2500b317 --- /dev/null +++ b/libbeat/common/transport/tlscommon/tls.go @@ -0,0 +1,172 @@ +package tlscommon + +import ( + "bytes" + "crypto/tls" + "crypto/x509" + "encoding/pem" + "errors" + "fmt" + "io/ioutil" + + "github.com/elastic/beats/libbeat/logp" +) + +// LoadCertificate will load a certificate from disk and return a tls.Certificate or error +func LoadCertificate(config *CertificateConfig) (*tls.Certificate, error) { + certificate := config.Certificate + key := config.Key + + hasCertificate := certificate != "" + hasKey := key != "" + + switch { + case hasCertificate && !hasKey: + return nil, ErrCertificateNoKey + case !hasCertificate && hasKey: + return nil, ErrKeyNoCertificate + case !hasCertificate && !hasKey: + return nil, nil + } + + certPEM, err := ReadPEMFile(certificate, config.Passphrase) + if err != nil { + logp.Critical("Failed reading certificate file %v: %v", certificate, err) + return nil, fmt.Errorf("%v %v", err, certificate) + } + + keyPEM, err := ReadPEMFile(key, config.Passphrase) + if err != nil { + logp.Critical("Failed reading key file %v: %v", key, err) + return nil, fmt.Errorf("%v %v", err, key) + } + + cert, err := tls.X509KeyPair(certPEM, keyPEM) + if err != nil { + logp.Critical("Failed loading client certificate", err) + return nil, err + } + + logp.Debug("tls", "loading certificate: %v and key %v", certificate, key) + return &cert, nil +} + +// ReadPEMFile reads a PEM format file on disk and decrypt it with the privided password and +// return the raw content. +func ReadPEMFile(path, passphrase string) ([]byte, error) { + pass := []byte(passphrase) + var blocks []*pem.Block + + content, err := ioutil.ReadFile(path) + if err != nil { + return nil, err + } + + for len(content) > 0 { + var block *pem.Block + + block, content = pem.Decode(content) + if block == nil { + if len(blocks) == 0 { + return nil, errors.New("no pem file") + } + break + } + + if x509.IsEncryptedPEMBlock(block) { + var buffer []byte + var err error + if len(pass) == 0 { + err = errors.New("No passphrase available") + } else { + // Note, decrypting pem might succeed even with wrong password, but + // only noise will be stored in buffer in this case. + buffer, err = x509.DecryptPEMBlock(block, pass) + } + + if err != nil { + logp.Err("Dropping encrypted pem '%v' block read from %v. %v", + block.Type, path, err) + continue + } + + // DEK-Info contains encryption info. Remove header to mark block as + // unencrypted. + delete(block.Headers, "DEK-Info") + block.Bytes = buffer + } + blocks = append(blocks, block) + } + + if len(blocks) == 0 { + return nil, errors.New("no PEM blocks") + } + + // re-encode available, decrypted blocks + buffer := bytes.NewBuffer(nil) + for _, block := range blocks { + err := pem.Encode(buffer, block) + if err != nil { + return nil, err + } + } + return buffer.Bytes(), nil +} + +// LoadCertificateAuthorities read the slice of CAcert and return a Certpool. +func LoadCertificateAuthorities(CAs []string) (*x509.CertPool, []error) { + errors := []error{} + + if len(CAs) == 0 { + return nil, nil + } + + roots := x509.NewCertPool() + for _, path := range CAs { + pemData, err := ioutil.ReadFile(path) + if err != nil { + logp.Critical("Failed reading CA certificate: %v", err) + errors = append(errors, fmt.Errorf("%v reading %v", err, path)) + continue + } + + if ok := roots.AppendCertsFromPEM(pemData); !ok { + logp.Critical("Failed reading CA certificate: %v", err) + errors = append(errors, fmt.Errorf("%v adding %v", ErrNotACertificate, path)) + continue + } + logp.Debug("tls", "successfully loaded CA certificate: %v", path) + } + + return roots, errors +} + +func extractMinMaxVersion(versions []TLSVersion) (uint16, uint16) { + if len(versions) == 0 { + versions = TLSDefaultVersions + } + + minVersion := uint16(0xffff) + maxVersion := uint16(0) + for _, version := range versions { + v := uint16(version) + if v < minVersion { + minVersion = v + } + if v > maxVersion { + maxVersion = v + } + } + + return minVersion, maxVersion +} + +// ResolveTLSVersion takes the integer representation and return the name. +func ResolveTLSVersion(v uint16) string { + return TLSVersion(v).String() +} + +// ResolveCipherSuite takes the integer representation and return the cipher name. +func ResolveCipherSuite(cipher uint16) string { + return tlsCipherSuite(cipher).String() +} diff --git a/libbeat/common/transport/tlscommon/tls_config.go b/libbeat/common/transport/tlscommon/tls_config.go new file mode 100644 index 000000000000..e4d9bca14b8c --- /dev/null +++ b/libbeat/common/transport/tlscommon/tls_config.go @@ -0,0 +1,77 @@ +package tlscommon + +import ( + "crypto/tls" + "crypto/x509" + + "github.com/elastic/beats/libbeat/logp" +) + +// TLSConfig is the interface used to configure a tcp client or server from a `Config` +type TLSConfig struct { + + // List of allowed SSL/TLS protocol versions. Connections might be dropped + // after handshake succeeded, if TLS version in use is not listed. + Versions []TLSVersion + + // Configure SSL/TLS verification mode used during handshake. By default + // VerifyFull will be used. + Verification TLSVerificationMode + + // List of certificate chains to present to the other side of the + // connection. + Certificates []tls.Certificate + + // Set of root certificate authorities use to verify server certificates. + // If RootCAs is nil, TLS might use the system its root CA set (not supported + // on MS Windows). + RootCAs *x509.CertPool + + // Set of root certificate authorities use to verify client certificates. + // If ClientCAs is nil, TLS might use the system its root CA set (not supported + // on MS Windows). + ClientCAs *x509.CertPool + + // List of supported cipher suites. If nil, a default list provided by the + // implementation will be used. + CipherSuites []uint16 + + // Types of elliptic curves that will be used in an ECDHE handshake. If empty, + // the implementation will choose a default. + CurvePreferences []tls.CurveID + + // Renegotiation controls what types of renegotiation are supported. + // The default, never, is correct for the vast majority of applications. + Renegotiation tls.RenegotiationSupport + + // ClientAuth controls how we want to verify certificate from a client, `none`, `optional` and + // `required`, default to required. Do not affect TCP client. + ClientAuth tls.ClientAuthType +} + +// BuildModuleConfig takes the TLSConfig and tranform it into a `tls.Config`. +func (c *TLSConfig) BuildModuleConfig(host string) *tls.Config { + if c == nil { + // use default TLS settings, if config is empty. + return &tls.Config{ServerName: host} + } + + minVersion, maxVersion := extractMinMaxVersion(c.Versions) + insecure := c.Verification != VerifyFull + if insecure { + logp.Warn("SSL/TLS verifications disabled.") + } + + return &tls.Config{ + ServerName: host, + MinVersion: minVersion, + MaxVersion: maxVersion, + Certificates: c.Certificates, + RootCAs: c.RootCAs, + ClientCAs: c.ClientCAs, + InsecureSkipVerify: insecure, + CipherSuites: c.CipherSuites, + CurvePreferences: c.CurvePreferences, + ClientAuth: c.ClientAuth, + } +} diff --git a/libbeat/outputs/tls_test.go b/libbeat/common/transport/tlscommon/tls_test.go similarity index 60% rename from libbeat/outputs/tls_test.go rename to libbeat/common/transport/tlscommon/tls_test.go index 4c8ce1eae494..d629fcaecedf 100644 --- a/libbeat/outputs/tls_test.go +++ b/libbeat/common/transport/tlscommon/tls_test.go @@ -1,21 +1,21 @@ // +build !integration -package outputs +package tlscommon import ( "crypto/tls" + "fmt" "testing" "github.com/stretchr/testify/assert" "github.com/elastic/beats/libbeat/common" - "github.com/elastic/beats/libbeat/outputs/transport" ) // test TLS config loading -func load(yamlStr string) (*TLSConfig, error) { - var cfg TLSConfig +func load(yamlStr string) (*Config, error) { + var cfg Config config, err := common.NewConfigWithYAML([]byte(yamlStr), "") if err != nil { return nil, err @@ -27,7 +27,7 @@ func load(yamlStr string) (*TLSConfig, error) { return &cfg, nil } -func mustLoad(t *testing.T, yamlStr string) *TLSConfig { +func mustLoad(t *testing.T, yamlStr string) *Config { cfg, err := load(yamlStr) if err != nil { t.Fatal(err) @@ -39,7 +39,7 @@ func TestEmptyTlsConfig(t *testing.T) { cfg, err := load("") assert.Nil(t, err) - assert.Equal(t, cfg, &TLSConfig{}) + assert.Equal(t, cfg, &Config{}) } func TestLoadWithEmptyValues(t *testing.T) { @@ -56,7 +56,7 @@ func TestLoadWithEmptyValues(t *testing.T) { `) assert.Nil(t, err) - assert.Equal(t, cfg, &TLSConfig{}) + assert.Equal(t, cfg, &Config{}) } func TestNoLoadNilConfig(t *testing.T) { @@ -67,7 +67,7 @@ func TestNoLoadNilConfig(t *testing.T) { func TestNoLoadDisabledConfig(t *testing.T) { enabled := false - cfg, err := LoadTLSConfig(&TLSConfig{Enabled: &enabled}) + cfg, err := LoadTLSConfig(&Config{Enabled: &enabled}) assert.Nil(t, err) assert.Nil(t, cfg) } @@ -95,10 +95,10 @@ func TestValuesSet(t *testing.T) { assert.Equal(t, "mycert.pem", cfg.Certificate.Certificate) assert.Equal(t, "mycert.key", cfg.Certificate.Key) assert.Len(t, cfg.CAs, 2) - assert.Equal(t, transport.VerifyNone, cfg.VerificationMode) + assert.Equal(t, VerifyNone, cfg.VerificationMode) assert.Len(t, cfg.CipherSuites, 2) assert.Equal(t, - []transport.TLSVersion{transport.TLSVersion11, transport.TLSVersion12}, + []TLSVersion{TLSVersion11, TLSVersion12}, cfg.Versions) assert.Len(t, cfg.CurveTypes, 1) assert.Equal(t, @@ -107,7 +107,7 @@ func TestValuesSet(t *testing.T) { } func TestApplyEmptyConfig(t *testing.T) { - tmp, err := LoadTLSConfig(&TLSConfig{}) + tmp, err := LoadTLSConfig(&Config{}) if err != nil { t.Fatal(err) } @@ -124,9 +124,9 @@ func TestApplyEmptyConfig(t *testing.T) { func TestApplyWithConfig(t *testing.T) { tmp, err := LoadTLSConfig(mustLoad(t, ` - certificate: logstash/ca_test.pem - key: logstash/ca_test.key - certificate_authorities: [logstash/ca_test.pem] + certificate: ca_test.pem + key: ca_test.key + certificate_authorities: [ca_test.pem] verification_mode: none cipher_suites: - "ECDHE-ECDSA-AES-256-CBC-SHA" @@ -148,6 +148,46 @@ func TestApplyWithConfig(t *testing.T) { assert.Len(t, cfg.CurvePreferences, 1) } +func TestApplyWithServerConfig(t *testing.T) { + yamlStr := ` + certificate: ca_test.pem + key: ca_test.key + certificate_authorities: [ca_test.pem] + verification_mode: none + client_authentification: optional + supported_protocols: [TLSv1.1, TLSv1.2] + cipher_suites: + - "ECDHE-ECDSA-AES-256-CBC-SHA" + - "ECDHE-ECDSA-AES-256-GCM-SHA384" + curve_types: [P-384] + ` + var c ServerConfig + config, err := common.NewConfigWithYAML([]byte(yamlStr), "") + if !assert.NoError(t, err) { + return + } + + err = config.Unpack(&c) + if !assert.NoError(t, err) { + return + } + tmp, err := LoadTLSServerConfig(&c) + if !assert.NoError(t, err) { + return + } + + cfg := tmp.BuildModuleConfig("") + assert.NotNil(t, cfg) + assert.Len(t, cfg.Certificates, 1) + assert.NotNil(t, cfg.ClientCAs) + assert.Equal(t, true, cfg.InsecureSkipVerify) + assert.Len(t, cfg.CipherSuites, 2) + assert.Equal(t, int(tls.VersionTLS11), int(cfg.MinVersion)) + assert.Equal(t, int(tls.VersionTLS12), int(cfg.MaxVersion)) + assert.Len(t, cfg.CurvePreferences, 1) + assert.Equal(t, tls.VerifyClientCertIfGiven, cfg.ClientAuth) +} + func TestCertificateFails(t *testing.T) { tests := []struct { title string @@ -180,22 +220,32 @@ func TestCertificateFails(t *testing.T) { } for i, test := range tests { - t.Logf("run test (%v): %v", i, test.title) - - config, err := common.NewConfigWithYAML([]byte(test.yaml), "") - if err != nil { - t.Error(err) - continue - } - - // one must fail: validators on Unpack or transformation to *tls.Config - var tlscfg TLSConfig - if err = config.Unpack(&tlscfg); err != nil { + t.Run(fmt.Sprintf("run test (%v): %v", i, test.title), func(t *testing.T) { + config, err := common.NewConfigWithYAML([]byte(test.yaml), "") + if err != nil { + t.Error(err) + return + } + + // one must fail: validators on Unpack or transformation to *tls.Config + var tlscfg Config + if err = config.Unpack(&tlscfg); err != nil { + t.Log(err) + return + } + _, err = LoadTLSConfig(&tlscfg) t.Log(err) - continue - } - _, err = LoadTLSConfig(&tlscfg) - t.Log(err) - assert.Error(t, err) + assert.Error(t, err) + }) } } + +func TestResolveTLSVersion(t *testing.T) { + v := ResolveTLSVersion(tls.VersionTLS11) + assert.Equal(t, "TLSv1.1", v) +} + +func TestResolveCipherSuite(t *testing.T) { + c := ResolveCipherSuite(tls.TLS_RSA_WITH_AES_128_CBC_SHA) + assert.Equal(t, "RSA-AES-128-CBC-SHA", c) +} diff --git a/libbeat/common/transport/tlscommon/types.go b/libbeat/common/transport/tlscommon/types.go new file mode 100644 index 000000000000..7c2be0e9a0ec --- /dev/null +++ b/libbeat/common/transport/tlscommon/types.go @@ -0,0 +1,267 @@ +package tlscommon + +import ( + "crypto/tls" + "errors" + "fmt" +) + +var ( + // ErrNotACertificate indicates a PEM file to be loaded not being a valid + // PEM file or certificate. + ErrNotACertificate = errors.New("file is not a certificate") + + // ErrCertificateNoKey indicate a configuration error with missing key file + ErrCertificateNoKey = errors.New("key file not configured") + + // ErrKeyNoCertificate indicate a configuration error with missing certificate file + ErrKeyNoCertificate = errors.New("certificate file not configured") +) + +var tlsCipherSuites = map[string]tlsCipherSuite{ + "ECDHE-ECDSA-AES-128-CBC-SHA": tlsCipherSuite(tls.TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA), + "ECDHE-ECDSA-AES-128-GCM-SHA256": tlsCipherSuite(tls.TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256), + "ECDHE-ECDSA-AES-256-CBC-SHA": tlsCipherSuite(tls.TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA), + "ECDHE-ECDSA-AES-256-GCM-SHA384": tlsCipherSuite(tls.TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384), + "ECDHE-ECDSA-RC4-128-SHA": tlsCipherSuite(tls.TLS_ECDHE_ECDSA_WITH_RC4_128_SHA), + "ECDHE-RSA-3DES-CBC3-SHA": tlsCipherSuite(tls.TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA), + "ECDHE-RSA-AES-128-CBC-SHA": tlsCipherSuite(tls.TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA), + "ECDHE-RSA-AES-128-GCM-SHA256": tlsCipherSuite(tls.TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256), + "ECDHE-RSA-AES-256-CBC-SHA": tlsCipherSuite(tls.TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA), + "ECDHE-RSA-AES-256-GCM-SHA384": tlsCipherSuite(tls.TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384), + "ECDHE-RSA-RC4-128-SHA": tlsCipherSuite(tls.TLS_ECDHE_RSA_WITH_RC4_128_SHA), + "RSA-3DES-CBC3-SHA": tlsCipherSuite(tls.TLS_RSA_WITH_3DES_EDE_CBC_SHA), + "RSA-AES-128-CBC-SHA": tlsCipherSuite(tls.TLS_RSA_WITH_AES_128_CBC_SHA), + "RSA-AES-128-GCM-SHA256": tlsCipherSuite(tls.TLS_RSA_WITH_AES_128_GCM_SHA256), + "RSA-AES-256-CBC-SHA": tlsCipherSuite(tls.TLS_RSA_WITH_AES_256_CBC_SHA), + "RSA-AES-256-GCM-SHA384": tlsCipherSuite(tls.TLS_RSA_WITH_AES_256_GCM_SHA384), + "RSA-RC4-128-SHA": tlsCipherSuite(tls.TLS_RSA_WITH_RC4_128_SHA), +} + +var tlsCipherSuitesInverse = make(map[tlsCipherSuite]string, len(tlsCipherSuites)) + +// Init creates a inverse representation of the values mapping. +func init() { + for cipherName, i := range tlsCipherSuites { + tlsCipherSuitesInverse[i] = cipherName + } +} + +var tlsCurveTypes = map[string]tlsCurveType{ + "P-256": tlsCurveType(tls.CurveP256), + "P-384": tlsCurveType(tls.CurveP384), + "P-521": tlsCurveType(tls.CurveP521), +} + +var tlsRenegotiationSupportTypes = map[string]tlsRenegotiationSupport{ + "never": tlsRenegotiationSupport(tls.RenegotiateNever), + "once": tlsRenegotiationSupport(tls.RenegotiateOnceAsClient), + "freely": tlsRenegotiationSupport(tls.RenegotiateFreelyAsClient), +} + +// TLSVersion type for TLS version. +type TLSVersion uint16 + +// Define all the possible TLS version. +const ( + TLSVersionSSL30 TLSVersion = tls.VersionSSL30 + TLSVersion10 TLSVersion = tls.VersionTLS10 + TLSVersion11 TLSVersion = tls.VersionTLS11 + TLSVersion12 TLSVersion = tls.VersionTLS12 +) + +// TLSDefaultVersions list of versions of TLS we should support. +var TLSDefaultVersions = []TLSVersion{ + TLSVersion10, + TLSVersion11, + TLSVersion12, +} + +type tlsClientAuth int + +const ( + tlsClientAuthNone tlsClientAuth = tlsClientAuth(tls.NoClientCert) + tlsClientAuthOptional = tlsClientAuth(tls.VerifyClientCertIfGiven) + tlsClientAuthRequired = tlsClientAuth(tls.RequireAndVerifyClientCert) +) + +var tlsClientAuthTypes = map[string]tlsClientAuth{ + "none": tlsClientAuthNone, + "optional": tlsClientAuthOptional, + "required": tlsClientAuthRequired, +} + +var tlsProtocolVersions = map[string]TLSVersion{ + "SSLv3": TLSVersionSSL30, + "SSLv3.0": TLSVersionSSL30, + "TLSv1": TLSVersion10, + "TLSv1.0": TLSVersion10, + "TLSv1.1": TLSVersion11, + "TLSv1.2": TLSVersion12, +} + +var tlsProtocolVersionsInverse = map[TLSVersion]string{ + TLSVersionSSL30: "SSLv3", + TLSVersion10: "TLSv1.0", + TLSVersion11: "TLSv1.1", + TLSVersion12: "TLSv1.2", +} + +// TLSVerificationMode represents the type of verification to do on the remote host, +// `none` or `full` and we default to `full`, internally this option is transformed into the +// `insecure` field in the `tls.Config` struct. +type TLSVerificationMode uint8 + +// Constants of the supported verification mode. +const ( + VerifyFull TLSVerificationMode = iota + VerifyNone + + // TODO: add VerifyCertificate support. Due to checks being run + // during handshake being limited, verify certificates in + // postVerifyTLSConnection + // VerifyCertificate +) + +func (v TLSVersion) String() string { + if s, ok := tlsProtocolVersionsInverse[v]; ok { + return s + } + return "unknown" +} + +//Unpack transforms the string into a constant. +func (v *TLSVersion) Unpack(s string) error { + version, found := tlsProtocolVersions[s] + if !found { + return fmt.Errorf("invalid tls version '%v'", s) + } + + *v = version + return nil +} + +var tlsVerificationModes = map[string]TLSVerificationMode{ + "": VerifyFull, + "full": VerifyFull, + "none": VerifyNone, + // "certificate": verifyCertificate, +} + +func (m TLSVerificationMode) String() string { + modes := map[TLSVerificationMode]string{ + VerifyFull: "full", + // VerifyCertificate: "certificate", + VerifyNone: "none", + } + + if s, ok := modes[m]; ok { + return s + } + return "unknown" +} + +// Unpack unpacks the string into contants. +func (m *TLSVerificationMode) Unpack(in interface{}) error { + if in == nil { + *m = VerifyFull + return nil + } + + s, ok := in.(string) + if !ok { + return fmt.Errorf("verification mode must be an identifier") + } + + mode, found := tlsVerificationModes[s] + if !found { + return fmt.Errorf("unknown verification mode '%v'", s) + } + + *m = mode + return nil +} + +func (m *tlsClientAuth) Unpack(in interface{}) error { + if in == nil { + *m = tlsClientAuthRequired + return nil + } + + s, ok := in.(string) + if !ok { + return fmt.Errorf("client authentification must be an identifier") + } + + mode, found := tlsClientAuthTypes[s] + if !found { + return fmt.Errorf("unknown client authentification mode'%v'", s) + } + + *m = mode + return nil +} + +type tlsCipherSuite uint16 + +func (cs *tlsCipherSuite) Unpack(s string) error { + suite, found := tlsCipherSuites[s] + if !found { + return fmt.Errorf("invalid tls cipher suite '%v'", s) + } + + *cs = suite + return nil +} + +func (cs tlsCipherSuite) String() string { + if s, found := tlsCipherSuitesInverse[cs]; found { + return s + } + return "unkown" +} + +type tlsCurveType tls.CurveID + +func (ct *tlsCurveType) Unpack(s string) error { + t, found := tlsCurveTypes[s] + if !found { + return fmt.Errorf("invalid tls curve type '%v'", s) + } + + *ct = t + return nil +} + +type tlsRenegotiationSupport tls.RenegotiationSupport + +func (r *tlsRenegotiationSupport) Unpack(s string) error { + t, found := tlsRenegotiationSupportTypes[s] + if !found { + return fmt.Errorf("invalid tls renegotiation type '%v'", s) + } + + *r = t + return nil +} + +// CertificateConfig define a common set of fields for a certificate. +type CertificateConfig struct { + Certificate string `config:"certificate"` + Key string `config:"key"` + Passphrase string `config:"key_passphrase"` +} + +// Validate validates the CertificateConfig +func (c *CertificateConfig) Validate() error { + hasCertificate := c.Certificate != "" + hasKey := c.Key != "" + + switch { + case hasCertificate && !hasKey: + return ErrCertificateNoKey + case !hasCertificate && hasKey: + return ErrKeyNoCertificate + } + return nil +} diff --git a/libbeat/outputs/tls.go b/libbeat/outputs/tls.go index 607aedfe2506..5d21ec9036d4 100644 --- a/libbeat/outputs/tls.go +++ b/libbeat/outputs/tls.go @@ -1,311 +1,41 @@ package outputs import ( - "bytes" - "crypto/tls" - "crypto/x509" - "encoding/pem" - "errors" - "fmt" - "io/ioutil" - - "github.com/joeshaw/multierror" - - "github.com/elastic/beats/libbeat/logp" - "github.com/elastic/beats/libbeat/outputs/transport" + "github.com/elastic/beats/libbeat/common/transport/tlscommon" ) +// Managing TLS option with the outputs package is deprecated move your code to use the tlscommon +// package. var ( // ErrNotACertificate indicates a PEM file to be loaded not being a valid // PEM file or certificate. - ErrNotACertificate = errors.New("file is not a certificate") + ErrNotACertificate = tlscommon.ErrNotACertificate // ErrCertificateNoKey indicate a configuration error with missing key file - ErrCertificateNoKey = errors.New("key file not configured") + ErrCertificateNoKey = tlscommon.ErrCertificateNoKey // ErrKeyNoCertificate indicate a configuration error with missing certificate file - ErrKeyNoCertificate = errors.New("certificate file not configured") + ErrKeyNoCertificate = tlscommon.ErrKeyNoCertificate ) // TLSConfig defines config file options for TLS clients. -type TLSConfig struct { - Enabled *bool `config:"enabled"` - VerificationMode transport.TLSVerificationMode `config:"verification_mode"` // one of 'none', 'full' - Versions []transport.TLSVersion `config:"supported_protocols"` - CipherSuites []tlsCipherSuite `config:"cipher_suites"` - CAs []string `config:"certificate_authorities"` - Certificate CertificateConfig `config:",inline"` - CurveTypes []tlsCurveType `config:"curve_types"` - Renegotiation tlsRenegotiationSupport `config:"renegotiation"` -} - -type CertificateConfig struct { - Certificate string `config:"certificate"` - Key string `config:"key"` - Passphrase string `config:"key_passphrase"` -} - -type tlsCipherSuite uint16 - -type tlsCurveType tls.CurveID - -type tlsRenegotiationSupport tls.RenegotiationSupport - -var tlsCipherSuites = map[string]tlsCipherSuite{ - "ECDHE-ECDSA-AES-128-CBC-SHA": tlsCipherSuite(tls.TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA), - "ECDHE-ECDSA-AES-128-GCM-SHA256": tlsCipherSuite(tls.TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256), - "ECDHE-ECDSA-AES-256-CBC-SHA": tlsCipherSuite(tls.TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA), - "ECDHE-ECDSA-AES-256-GCM-SHA384": tlsCipherSuite(tls.TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384), - "ECDHE-ECDSA-RC4-128-SHA": tlsCipherSuite(tls.TLS_ECDHE_ECDSA_WITH_RC4_128_SHA), - "ECDHE-RSA-3DES-CBC3-SHA": tlsCipherSuite(tls.TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA), - "ECDHE-RSA-AES-128-CBC-SHA": tlsCipherSuite(tls.TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA), - "ECDHE-RSA-AES-128-GCM-SHA256": tlsCipherSuite(tls.TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256), - "ECDHE-RSA-AES-256-CBC-SHA": tlsCipherSuite(tls.TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA), - "ECDHE-RSA-AES-256-GCM-SHA384": tlsCipherSuite(tls.TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384), - "ECDHE-RSA-RC4-128-SHA": tlsCipherSuite(tls.TLS_ECDHE_RSA_WITH_RC4_128_SHA), - "RSA-3DES-CBC3-SHA": tlsCipherSuite(tls.TLS_RSA_WITH_3DES_EDE_CBC_SHA), - "RSA-AES-128-CBC-SHA": tlsCipherSuite(tls.TLS_RSA_WITH_AES_128_CBC_SHA), - "RSA-AES-128-GCM-SHA256": tlsCipherSuite(tls.TLS_RSA_WITH_AES_128_GCM_SHA256), - "RSA-AES-256-CBC-SHA": tlsCipherSuite(tls.TLS_RSA_WITH_AES_256_CBC_SHA), - "RSA-AES-256-GCM-SHA384": tlsCipherSuite(tls.TLS_RSA_WITH_AES_256_GCM_SHA384), - "RSA-RC4-128-SHA": tlsCipherSuite(tls.TLS_RSA_WITH_RC4_128_SHA), -} - -var tlsCurveTypes = map[string]tlsCurveType{ - "P-256": tlsCurveType(tls.CurveP256), - "P-384": tlsCurveType(tls.CurveP384), - "P-521": tlsCurveType(tls.CurveP521), -} - -var tlsRenegotiationSupportTypes = map[string]tlsRenegotiationSupport{ - "never": tlsRenegotiationSupport(tls.RenegotiateNever), - "once": tlsRenegotiationSupport(tls.RenegotiateOnceAsClient), - "freely": tlsRenegotiationSupport(tls.RenegotiateFreelyAsClient), -} - -func (c *TLSConfig) Validate() error { - hasCertificate := c.Certificate.Certificate != "" - hasKey := c.Certificate.Key != "" - - switch { - case hasCertificate && !hasKey: - return ErrCertificateNoKey - case !hasCertificate && hasKey: - return ErrKeyNoCertificate - } +type TLSConfig = tlscommon.Config - return nil -} - -func (c *TLSConfig) IsEnabled() bool { - return c != nil && (c.Enabled == nil || *c.Enabled) -} +// CertificateConfig define a common set of fields for a certificate. +type CertificateConfig = tlscommon.CertificateConfig // LoadTLSConfig will load a certificate from config with all TLS based keys // defined. If Certificate and CertificateKey are configured, client authentication // will be configured. If no CAs are configured, the host CA will be used by go // built-in TLS support. -func LoadTLSConfig(config *TLSConfig) (*transport.TLSConfig, error) { - if !config.IsEnabled() { - return nil, nil - } - - fail := multierror.Errors{} - logFail := func(es ...error) { - for _, e := range es { - if e != nil { - fail = append(fail, e) - } - } - } - - var cipherSuites []uint16 - for _, suite := range config.CipherSuites { - cipherSuites = append(cipherSuites, uint16(suite)) - } - - var curves []tls.CurveID - for _, id := range config.CurveTypes { - curves = append(curves, tls.CurveID(id)) - } - - cert, err := LoadCertificate(&config.Certificate) - logFail(err) - - cas, errs := LoadCertificateAuthorities(config.CAs) - logFail(errs...) - - // fail, if any error occurred when loading certificate files - if err = fail.Err(); err != nil { - return nil, err - } - - var certs []tls.Certificate - if cert != nil { - certs = []tls.Certificate{*cert} - } - - // return config if no error occurred - return &transport.TLSConfig{ - Versions: config.Versions, - Verification: config.VerificationMode, - Certificates: certs, - RootCAs: cas, - CipherSuites: cipherSuites, - CurvePreferences: curves, - Renegotiation: tls.RenegotiationSupport(config.Renegotiation), - }, nil -} - -func LoadCertificate(config *CertificateConfig) (*tls.Certificate, error) { - certificate := config.Certificate - key := config.Key - - hasCertificate := certificate != "" - hasKey := key != "" - - switch { - case hasCertificate && !hasKey: - return nil, ErrCertificateNoKey - case !hasCertificate && hasKey: - return nil, ErrKeyNoCertificate - case !hasCertificate && !hasKey: - return nil, nil - } - - certPEM, err := ReadPEMFile(certificate, config.Passphrase) - if err != nil { - logp.Critical("Failed reading certificate file %v: %v", certificate, err) - return nil, fmt.Errorf("%v %v", err, certificate) - } - - keyPEM, err := ReadPEMFile(key, config.Passphrase) - if err != nil { - logp.Critical("Failed reading key file %v: %v", key, err) - return nil, fmt.Errorf("%v %v", err, key) - } - - cert, err := tls.X509KeyPair(certPEM, keyPEM) - if err != nil { - logp.Critical("Failed loading client certificate", err) - return nil, err - } - - return &cert, nil -} - -func ReadPEMFile(path, passphrase string) ([]byte, error) { - pass := []byte(passphrase) - var blocks []*pem.Block - - content, err := ioutil.ReadFile(path) - if err != nil { - return nil, err - } - - for len(content) > 0 { - var block *pem.Block - - block, content = pem.Decode(content) - if block == nil { - if len(blocks) == 0 { - return nil, errors.New("no pem file") - } - break - } - - if x509.IsEncryptedPEMBlock(block) { - var buffer []byte - var err error - if len(pass) == 0 { - err = errors.New("No passphrase available") - } else { - // Note, decrypting pem might succeed even with wrong password, but - // only noise will be stored in buffer in this case. - buffer, err = x509.DecryptPEMBlock(block, pass) - } - - if err != nil { - logp.Err("Dropping encrypted pem '%v' block read from %v. %v", - block.Type, path, err) - continue - } - - // DEK-Info contains encryption info. Remove header to mark block as - // unencrypted. - delete(block.Headers, "DEK-Info") - block.Bytes = buffer - } - blocks = append(blocks, block) - } - - if len(blocks) == 0 { - return nil, errors.New("no PEM blocks") - } - - // re-encode available, decrypted blocks - buffer := bytes.NewBuffer(nil) - for _, block := range blocks { - err := pem.Encode(buffer, block) - if err != nil { - return nil, err - } - } - return buffer.Bytes(), nil -} - -func LoadCertificateAuthorities(CAs []string) (*x509.CertPool, []error) { - errors := []error{} - - if len(CAs) == 0 { - return nil, nil - } - - roots := x509.NewCertPool() - for _, path := range CAs { - pemData, err := ioutil.ReadFile(path) - if err != nil { - logp.Critical("Failed reading CA certificate: %v", err) - errors = append(errors, fmt.Errorf("%v reading %v", err, path)) - continue - } - - if ok := roots.AppendCertsFromPEM(pemData); !ok { - logp.Critical("Failed reading CA certificate: %v", err) - errors = append(errors, fmt.Errorf("%v adding %v", ErrNotACertificate, path)) - continue - } - } - - return roots, errors -} - -func (cs *tlsCipherSuite) Unpack(s string) error { - suite, found := tlsCipherSuites[s] - if !found { - return fmt.Errorf("invalid tls cipher suite '%v'", s) - } - - *cs = suite - return nil -} - -func (ct *tlsCurveType) Unpack(s string) error { - t, found := tlsCurveTypes[s] - if !found { - return fmt.Errorf("invalid tls curve type '%v'", s) - } +var LoadTLSConfig = tlscommon.LoadTLSConfig - *ct = t - return nil -} +// LoadCertificate will load a certificate from disk and return a tls.Certificate or error +var LoadCertificate = tlscommon.LoadCertificate -func (r *tlsRenegotiationSupport) Unpack(s string) error { - t, found := tlsRenegotiationSupportTypes[s] - if !found { - return fmt.Errorf("invalid tls renegotiation type '%v'", s) - } +// ReadPEMFile reads a PEM format file on disk and decrypt it with the privided password and +// return the raw content. +var ReadPEMFile = tlscommon.ReadPEMFile - *r = t - return nil -} +// LoadCertificateAuthorities read the slice of CAcert and return a Certpool. +var LoadCertificateAuthorities = tlscommon.LoadCertificateAuthorities diff --git a/libbeat/outputs/transport/tls.go b/libbeat/outputs/transport/tls.go index c0eb074f4983..dc4976d221fd 100644 --- a/libbeat/outputs/transport/tls.go +++ b/libbeat/outputs/transport/tls.go @@ -2,76 +2,36 @@ package transport import ( "crypto/tls" - "crypto/x509" "errors" "fmt" "net" "sync" "time" - "github.com/elastic/beats/libbeat/logp" + "github.com/elastic/beats/libbeat/common/transport/tlscommon" "github.com/elastic/beats/libbeat/testing" ) -type TLSConfig struct { +// TLSConfig is the interface used to configure a tcp client or server from a `Config` +type TLSConfig = tlscommon.TLSConfig - // List of allowed SSL/TLS protocol versions. Connections might be dropped - // after handshake succeeded, if TLS version in use is not listed. - Versions []TLSVersion - - // Configure SSL/TLS verification mode used during handshake. By default - // VerifyFull will be used. - Verification TLSVerificationMode - - // List of certificate chains to present to the other side of the - // connection. - Certificates []tls.Certificate - - // Set of root certificate authorities use to verify server certificates. - // If RootCAs is nil, TLS might use the system its root CA set (not supported - // on MS Windows). - RootCAs *x509.CertPool - - // List of supported cipher suites. If nil, a default list provided by the - // implementation will be used. - CipherSuites []uint16 - - // Types of elliptic curves that will be used in an ECDHE handshake. If empty, - // the implementation will choose a default. - CurvePreferences []tls.CurveID - - // Renegotiation controls what types of renegotiation are supported. - // The default, never, is correct for the vast majority of applications. - Renegotiation tls.RenegotiationSupport -} - -type TLSVersion uint16 +// TLSVersion type for TLS version. +type TLSVersion = tlscommon.TLSVersion +// Define all the possible TLS version. const ( - TLSVersionSSL30 TLSVersion = tls.VersionSSL30 - TLSVersion10 TLSVersion = tls.VersionTLS10 - TLSVersion11 TLSVersion = tls.VersionTLS11 - TLSVersion12 TLSVersion = tls.VersionTLS12 + TLSVersionSSL30 = tlscommon.TLSVersionSSL30 + TLSVersion10 = tlscommon.TLSVersion10 + TLSVersion11 = tlscommon.TLSVersion11 + TLSVersion12 = tlscommon.TLSVersion12 ) -type TLSVerificationMode uint8 - +// Constants of the supported verification mode. const ( - VerifyFull TLSVerificationMode = iota - VerifyNone - - // TODO: add VerifyCertificate support. Due to checks being run - // during handshake being limited, verify certificates in - // postVerifyTLSConnection - // VerifyCertificate + VerifyFull = tlscommon.VerifyFull + VerifyNone = tlscommon.VerifyNone ) -var tlsDefaultVersions = []TLSVersion{ - TLSVersion10, - TLSVersion11, - TLSVersion12, -} - func TLSDialer(forward Dialer, config *TLSConfig, timeout time.Duration) (Dialer, error) { return TestTLSDialer(testing.NullDriver, forward, config, timeout) } @@ -184,7 +144,7 @@ func postVerifyTLSConnection(d testing.Driver, conn *tls.Conn, config *TLSConfig versions := config.Versions if versions == nil { - versions = tlsDefaultVersions + versions = tlscommon.TLSDefaultVersions } versionOK := false for _, version := range versions { @@ -198,115 +158,3 @@ func postVerifyTLSConnection(d testing.Driver, conn *tls.Conn, config *TLSConfig return nil } - -func (c *TLSConfig) BuildModuleConfig(host string) *tls.Config { - if c == nil { - // use default TLS settings, if config is empty. - return &tls.Config{ServerName: host} - } - - versions := c.Versions - if len(versions) == 0 { - versions = tlsDefaultVersions - } - - minVersion := uint16(0xffff) - maxVersion := uint16(0) - for _, version := range versions { - v := uint16(version) - if v < minVersion { - minVersion = v - } - if v > maxVersion { - maxVersion = v - } - } - - insecure := c.Verification != VerifyFull - if insecure { - logp.Warn("SSL/TLS verifications disabled.") - } - - return &tls.Config{ - ServerName: host, - MinVersion: minVersion, - MaxVersion: maxVersion, - Certificates: c.Certificates, - RootCAs: c.RootCAs, - InsecureSkipVerify: insecure, - CipherSuites: c.CipherSuites, - CurvePreferences: c.CurvePreferences, - } -} - -var tlsProtocolVersions = map[string]TLSVersion{ - "SSLv3": TLSVersionSSL30, - "SSLv3.0": TLSVersionSSL30, - "TLSv1": TLSVersion10, - "TLSv1.0": TLSVersion10, - "TLSv1.1": TLSVersion11, - "TLSv1.2": TLSVersion12, -} - -func (v TLSVersion) String() string { - versions := map[TLSVersion]string{ - TLSVersionSSL30: "SSLv3", - TLSVersion10: "TLSv1.0", - TLSVersion11: "TLSv1.1", - TLSVersion12: "TLSv1.2", - } - if s, ok := versions[v]; ok { - return s - } - return "unknown" -} - -func (v *TLSVersion) Unpack(s string) error { - version, found := tlsProtocolVersions[s] - if !found { - return fmt.Errorf("invalid tls version '%v'", s) - } - - *v = version - return nil -} - -var tlsVerificationModes = map[string]TLSVerificationMode{ - "": VerifyFull, - "full": VerifyFull, - "none": VerifyNone, - // "certificate": verifyCertificate, -} - -func (m TLSVerificationMode) String() string { - modes := map[TLSVerificationMode]string{ - VerifyFull: "full", - // VerifyCertificate: "certificate", - VerifyNone: "none", - } - - if s, ok := modes[m]; ok { - return s - } - return "unknown" -} - -func (m *TLSVerificationMode) Unpack(in interface{}) error { - if in == nil { - *m = VerifyFull - return nil - } - - s, ok := in.(string) - if !ok { - return fmt.Errorf("verification mode must be an identifier") - } - - mode, found := tlsVerificationModes[s] - if !found { - return fmt.Errorf("unknown verification mode '%v'", s) - } - - *m = mode - return nil -} diff --git a/winlogbeat/docs/fields.asciidoc b/winlogbeat/docs/fields.asciidoc index c6e7add4a5c5..48b30ad9c3a9 100644 --- a/winlogbeat/docs/fields.asciidoc +++ b/winlogbeat/docs/fields.asciidoc @@ -215,7 +215,7 @@ Contains common fields available in all event types. required: True The event log API type used to read the record. The possible values are "wineventlog" for the Windows Event Log API or "eventlogging" for the Event Logging API. -The Event Logging API was designed for Windows Server 2003 or Windows 2000 operating systems. In Windows Vista, the event logging infrastructure was redesigned. On Windows Vista or later operating systems, the Windows Event Log API is used. Winlogbeat automatically detects which API to use for reading event logs. +The Event Logging API was designed for Windows Server 2003, Windows XP, or Windows 2000 operating systems. In Windows Vista, the event logging infrastructure was redesigned. On Windows Vista or later operating systems, the Windows Event Log API is used. Winlogbeat automatically detects which API to use for reading event logs. -- From 9c9fcedcb4df74f90d6f3060eedd589101a6b8ac Mon Sep 17 00:00:00 2001 From: ph Date: Fri, 4 May 2018 13:38:54 -0400 Subject: [PATCH 2/6] Features: Allow the TCP Input to receive events over a TLS connection We can now receive events on the TCP input with a TLS connection, the input uses existing type to make sure we have the same naming convention and code used by outputs that support TLS communication (Elasticsearch and Logstash). The configuration will look like this: ``` host: "localhost:9000" ssl.enabled: true ssl.verification_mode: full # default ssl.supported_protocols: [TLSv1.1] ssl.cipher_suites: [] ssl.certificate_authorities: ["/etc/cacert"] ssl.certificate: /etc/mycert.crt ssl.key: /etc/mycert.key ssl.client_authentification: required ``` One added configuration is `client_authentification`, this option is only used in the context of server and define how we will force the authentification, it support the three following options: - `required`: Assume that the client will provide a certificate and we will verify it. (default) - `optional`: If a certificate is given by the client. - `none`: We don't validate client certificate. *Note: This commit contains a script to generate certs from a self signed CA. Fixes: #6873 --- filebeat/inputsource/network.go | 9 + filebeat/inputsource/network_metadata.go | 1 - filebeat/inputsource/tcp/client.go | 41 ++- filebeat/inputsource/tcp/config.go | 10 +- filebeat/inputsource/tcp/server.go | 31 +- .../system/config/certificates/beats1.crt | 17 ++ .../system/config/certificates/beats1.key | 28 ++ .../system/config/certificates/beats2.crt | 17 ++ .../system/config/certificates/beats2.key | 28 ++ .../system/config/certificates/cacert.cfg | 22 ++ .../system/config/certificates/cacert.crt | 23 ++ .../system/config/certificates/cacert.key | 27 ++ .../system/config/certificates/cacert.srl | 1 + .../system/config/certificates/client1.crt | 47 +++ .../system/config/certificates/client1.csr | 17 ++ .../system/config/certificates/client1.key | 27 ++ .../system/config/certificates/client2.crt | 47 +++ .../system/config/certificates/client2.csr | 17 ++ .../system/config/certificates/client2.key | 27 ++ .../certificates/generate_certificate.sh | 40 +++ filebeat/tests/system/test_tcp_tls.py | 273 ++++++++++++++++++ 21 files changed, 740 insertions(+), 10 deletions(-) delete mode 100644 filebeat/inputsource/network_metadata.go create mode 100644 filebeat/tests/system/config/certificates/beats1.crt create mode 100644 filebeat/tests/system/config/certificates/beats1.key create mode 100644 filebeat/tests/system/config/certificates/beats2.crt create mode 100644 filebeat/tests/system/config/certificates/beats2.key create mode 100644 filebeat/tests/system/config/certificates/cacert.cfg create mode 100644 filebeat/tests/system/config/certificates/cacert.crt create mode 100644 filebeat/tests/system/config/certificates/cacert.key create mode 100644 filebeat/tests/system/config/certificates/cacert.srl create mode 100644 filebeat/tests/system/config/certificates/client1.crt create mode 100644 filebeat/tests/system/config/certificates/client1.csr create mode 100644 filebeat/tests/system/config/certificates/client1.key create mode 100644 filebeat/tests/system/config/certificates/client2.crt create mode 100644 filebeat/tests/system/config/certificates/client2.csr create mode 100644 filebeat/tests/system/config/certificates/client2.key create mode 100755 filebeat/tests/system/config/certificates/generate_certificate.sh create mode 100644 filebeat/tests/system/test_tcp_tls.py diff --git a/filebeat/inputsource/network.go b/filebeat/inputsource/network.go index 699a26f20fe4..34563ffdca4b 100644 --- a/filebeat/inputsource/network.go +++ b/filebeat/inputsource/network.go @@ -14,6 +14,15 @@ type Network interface { type NetworkMetadata struct { RemoteAddr net.Addr Truncated bool + TLS *TLSMetadata +} + +// TLSMetadata defines information about the current SSL connection. +type TLSMetadata struct { + TLSVersion string + CipherSuite string + ServerName string + PeerCertificates []string } // NetworkFunc defines callback executed when a new event is received from a network source. diff --git a/filebeat/inputsource/network_metadata.go b/filebeat/inputsource/network_metadata.go deleted file mode 100644 index e283490e5be9..000000000000 --- a/filebeat/inputsource/network_metadata.go +++ /dev/null @@ -1 +0,0 @@ -package inputsource diff --git a/filebeat/inputsource/tcp/client.go b/filebeat/inputsource/tcp/client.go index 7d2e0aa124d5..6a0119f8cfff 100644 --- a/filebeat/inputsource/tcp/client.go +++ b/filebeat/inputsource/tcp/client.go @@ -2,12 +2,15 @@ package tcp import ( "bufio" + "crypto/tls" + "crypto/x509" "net" "time" "github.com/pkg/errors" "github.com/elastic/beats/filebeat/inputsource" + "github.com/elastic/beats/libbeat/common/transport/tlscommon" "github.com/elastic/beats/libbeat/logp" ) @@ -33,7 +36,7 @@ func newClient( ) *client { client := &client{ conn: conn, - log: log.With("address", conn.RemoteAddr()), + log: log.With("remote_address", conn.RemoteAddr()), callback: callback, done: make(chan struct{}), splitFunc: splitFunc, @@ -41,8 +44,10 @@ func newClient( timeout: timeout, metadata: inputsource.NetworkMetadata{ RemoteAddr: conn.RemoteAddr(), + TLS: extractSSLInformation(conn), }, } + extractSSLInformation(conn) return client } @@ -63,13 +68,21 @@ func (c *client) handle() error { } // This is a user defined limit and we should notify the user. if IsMaxReadBufferErr(err) { - c.log.Errorw("client errors", "error", err) + c.log.Errorw("client error", "error", err) } return errors.Wrap(err, "tcp client error") } r.Reset() c.callback(scanner.Bytes(), c.metadata) } + + // We are out of the scanner, either we reached EOF or another fatal error occured. + // like we failed to complete the TLS handshake or we are missing the client certificate when + // mutual auth is on, which is the default. + if err := scanner.Err(); err != nil { + return err + } + return nil } @@ -77,3 +90,27 @@ func (c *client) close() { close(c.done) c.conn.Close() } + +func extractSSLInformation(c net.Conn) *inputsource.TLSMetadata { + if tls, ok := c.(*tls.Conn); ok { + state := tls.ConnectionState() + return &inputsource.TLSMetadata{ + TLSVersion: tlscommon.ResolveTLSVersion(state.Version), + CipherSuite: tlscommon.ResolveCipherSuite(state.CipherSuite), + ServerName: state.ServerName, + PeerCertificates: extractCertificate(state.PeerCertificates), + } + } + return nil +} + +func extractCertificate(certificates []*x509.Certificate) []string { + strCertificate := make([]string, len(certificates)) + for idx, c := range certificates { + // Ignore errors here, problematics cert have failed + //the handshake at this point. + b, _ := x509.MarshalPKIXPublicKey(c.PublicKey) + strCertificate[idx] = string(b) + } + return strCertificate +} diff --git a/filebeat/inputsource/tcp/config.go b/filebeat/inputsource/tcp/config.go index afce4d1940af..3da5ba284509 100644 --- a/filebeat/inputsource/tcp/config.go +++ b/filebeat/inputsource/tcp/config.go @@ -5,6 +5,7 @@ import ( "time" "github.com/elastic/beats/libbeat/common/cfgtype" + "github.com/elastic/beats/libbeat/common/transport/tlscommon" ) // Name is the human readable name and identifier. @@ -14,10 +15,11 @@ type size uint64 // Config exposes the tcp configuration. type Config struct { - Host string `config:"host"` - LineDelimiter string `config:"line_delimiter" validate:"nonzero"` - Timeout time.Duration `config:"timeout" validate:"nonzero,positive"` - MaxMessageSize cfgtype.ByteSize `config:"max_message_size" validate:"nonzero,positive"` + Host string `config:"host"` + LineDelimiter string `config:"line_delimiter" validate:"nonzero"` + Timeout time.Duration `config:"timeout" validate:"nonzero,positive"` + MaxMessageSize cfgtype.ByteSize `config:"max_message_size" validate:"nonzero,positive"` + TLS *tlscommon.ServerConfig `config:"ssl"` } // Validate validates the Config option for the tcp input. diff --git a/filebeat/inputsource/tcp/server.go b/filebeat/inputsource/tcp/server.go index 66bccc1d16f2..28f93cd0477e 100644 --- a/filebeat/inputsource/tcp/server.go +++ b/filebeat/inputsource/tcp/server.go @@ -3,12 +3,15 @@ package tcp import ( "bufio" "bytes" + "crypto/tls" "fmt" "net" "sync" "github.com/elastic/beats/filebeat/inputsource" + "github.com/elastic/beats/libbeat/common/transport/tlscommon" "github.com/elastic/beats/libbeat/logp" + "github.com/elastic/beats/libbeat/outputs/transport" ) // Server represent a TCP server @@ -22,6 +25,7 @@ type Server struct { done chan struct{} splitFunc bufio.SplitFunc log *logp.Logger + tlsConfig *transport.TLSConfig } // New creates a new tcp server @@ -34,6 +38,11 @@ func New( return nil, fmt.Errorf("empty line delimiter") } + tlsConfig, err := tlscommon.LoadTLSServerConfig(config.TLS) + if err != nil { + return nil, err + } + sf := splitFunc([]byte(config.LineDelimiter)) return &Server{ config: config, @@ -42,13 +51,14 @@ func New( done: make(chan struct{}), splitFunc: sf, log: logp.NewLogger("tcp").With("address", config.Host), + tlsConfig: tlsConfig, }, nil } // Start listen to the TCP socket. func (s *Server) Start() error { var err error - s.Listener, err = net.Listen("tcp", s.config.Host) + s.Listener, err = s.createServer() if err != nil { return err } @@ -86,7 +96,7 @@ func (s *Server) run() { s.config.Timeout, ) - s.log.Debugw("New client", "address", conn.RemoteAddr(), "total", s.clientsCount()) + s.log.Debugw("New client", "remote_address", conn.RemoteAddr(), "total", s.clientsCount()) s.wg.Add(1) go func() { defer logp.Recover("recovering from a tcp client crash") @@ -101,7 +111,13 @@ func (s *Server) run() { s.log.Debugw("Client error", "error", err) } - s.log.Debugw("Client disconnected", "address", conn.RemoteAddr(), "total", s.clientsCount()) + s.log.Debugw( + "Client disconnected", + "remote_address", + conn.RemoteAddr(), + "total", + s.clientsCount(), + ) }() } } @@ -142,6 +158,15 @@ func (s *Server) allClients() []*client { return currentClients } +func (s *Server) createServer() (net.Listener, error) { + if s.tlsConfig != nil { + t := s.tlsConfig.BuildModuleConfig(s.config.Host) + s.log.Info("Listening over TLS") + return tls.Listen("tcp", s.config.Host, t) + } + return net.Listen("tcp", s.config.Host) +} + func (s *Server) clientsCount() int { s.RLock() defer s.RUnlock() diff --git a/filebeat/tests/system/config/certificates/beats1.crt b/filebeat/tests/system/config/certificates/beats1.crt new file mode 100644 index 000000000000..4030d82007ba --- /dev/null +++ b/filebeat/tests/system/config/certificates/beats1.crt @@ -0,0 +1,17 @@ +-----BEGIN CERTIFICATE----- +MIICpDCCAYwCCQDgN4JA8Sp4TzANBgkqhkiG9w0BAQsFADAUMRIwEAYDVQQDDAls +b2NhbGhvc3QwHhcNMTgwNTAzMjA0NDQxWhcNMTkwNTAzMjA0NDQxWjAUMRIwEAYD +VQQDDAlsb2NhbGhvc3QwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCt +cIgOk6on3kfqqUMaw9l4UUH1kX4d7ocNVbz0UcqazCoo0dXoBcUlL+6wE8RLwKgY +eTJQslTPb8XC3mcoU2pFUUXZ3xOk8Wmq9fT9KHtKQRuiAzsw3xQnA+ofhC9vCU7f +pdDbzp1e42Ixni4ajqvOOqWIAdbsP+janLfGR4n62NDmLDYDbpEzKLzcHaOd5u6B +kMSGhDe4Oq8H4WGrj1C8SZzMH2kPYMr9uMXVAHj3m7q1A6qRcJoS4AD5Rkr+cXgn +AsRLxgWU6l6+2g4MJhjx7GphNueLoZiXV3pKMWOqeBrDWbYg+c07aZWnF9O8YBGx +c8vtp4awm+A0OWfMqpXjAgMBAAEwDQYJKoZIhvcNAQELBQADggEBAHh1wBn3vKXH +Fqc85GCfko2aFy7UYFaXjNTati3RW77yhsHn2PIJzTpPu4BaTms5JTup4hmDfPr1 +IJu2ZZ6b+BwdQGngIg6Mx6zA3+4h+JEDiZiJh/v/63EX+4MdasmlBomcrBOo3OWJ +jDIFUJIxsdGtWdR1nsQml77pQf2ECo3u3yV1qvKl2QP8UrJmyU5Vr23Gz9WOCt46 +3kejega+bnsOLNcfHBvrv31zwPBzpA6lfCaCc0SURrBmWPM37/8zZZQIFBMYN30M +id2iUSr+0zZ2O0vrzsET/wsWcLBxRDuxEK3iOjE70/ljBMc/RvhfiUpU7pAmyMOc +8DHX1eqqPM4= +-----END CERTIFICATE----- diff --git a/filebeat/tests/system/config/certificates/beats1.key b/filebeat/tests/system/config/certificates/beats1.key new file mode 100644 index 000000000000..c5a50d2ec336 --- /dev/null +++ b/filebeat/tests/system/config/certificates/beats1.key @@ -0,0 +1,28 @@ +-----BEGIN PRIVATE KEY----- +MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQCtcIgOk6on3kfq +qUMaw9l4UUH1kX4d7ocNVbz0UcqazCoo0dXoBcUlL+6wE8RLwKgYeTJQslTPb8XC +3mcoU2pFUUXZ3xOk8Wmq9fT9KHtKQRuiAzsw3xQnA+ofhC9vCU7fpdDbzp1e42Ix +ni4ajqvOOqWIAdbsP+janLfGR4n62NDmLDYDbpEzKLzcHaOd5u6BkMSGhDe4Oq8H +4WGrj1C8SZzMH2kPYMr9uMXVAHj3m7q1A6qRcJoS4AD5Rkr+cXgnAsRLxgWU6l6+ +2g4MJhjx7GphNueLoZiXV3pKMWOqeBrDWbYg+c07aZWnF9O8YBGxc8vtp4awm+A0 +OWfMqpXjAgMBAAECggEAU0EYXn7th/PAa9lSN+/ZXVMMKXfspSuRson8iP8WFVZ5 +ylxnpNfYObCXj/f9GyvgxNawm2HvKiAKOy+NLyNTePC5agsWH/Aue/1S247qF8vH +Gu8YI66BuvS7FuPZ7R/3t42eA1Vb32ehBBZdJSxlNjqaqP3REFjhSsc9xDUk+777 +O6wHVSest5cfwmhqhIlbyr5nYcrw6q1WEGc/lbwC5lDJNXrw3JbkMAatadQYNiCx +7BsH8JJBQeNKrKGVXC37ny1wrR3aYnQJFAsPGlRykMhwDHy/wpmFyKgPbDyMyjNp +hDK3L7lKDlwXDexFRTI18alVARI7SIyOaVlT0XvU+QKBgQDikNv09jx5uK/NBg6C ++nIGOKkUfv101aWKfgNtkSqPX0djj6EpKpICq5RCqKcc5GL5ZcZ81/6hnvoY2xX6 +QDG7DfFOOsaMzNm/K9pUjtbF1eABUgLaadO+o+dU2K3TsVBekAUx4O2IrJHrWFK6 +Tcq+ruohkKcgqLwTnDDtdLS9TQKBgQDD+MuWUMlMC4SSHINGlZuGj09LUTF5RH3p +fHx9aJdAgIxMNgGcl70gMwBQGQKSdOn/zseS8VtdoESO9IOcmG5NsXXITNqIASFd +u4G0cvyn5rb7xbkAQWynLdvnRRloUiVm59YBuEsCo2m9USS48ODU6TxceasW5xsC +LjsAtGPH7wKBgBxXTox3+NypE6Sr60jLF1Rb5hqgQAhLaWfHl5ovHInOu1li8B/8 +KUOYPvWPr0fX8eGMr6WSR1HkVxig30DsosvpVJQamhem0F4vmCIXtBoPRPQlVCIK +NuiUDC365NOkTI9nqJ6yqkP8gkxUQhT4AjKUIsmMFLvrH4u8cApkHO/JAoGAaOgn +vAj1KWNFDZ572+48unS/IveM/3jd2n7MeanixiHKeQW0KSrFkJYcxcQNr28s0MbV +6WCQ43bnHIviZJLpAWhNP/N8TLAmN3IoBfxEKnGEZRU8atmbG4eeH5jK+CB5azQS +SQtqBDiMY08r1GEGSpOsv2hWYUVIHQu4hDEM9TsCgYEAgxvDd/gSHkanGPR3mqXt +u8IDUWBw4ORkQ0ncYqmDV6jed3v7uCAM2DHaA4ckK91nGdy05EkpTyKin3b0iRxT +TSjwO+wUlwuqQMXYEESJ5XDxy5WSDlYuvKGUcyxLDYo7OMg0UWM6JpH3c2sRy4pU +XztmTa6m0GXerVSyFgx81M8= +-----END PRIVATE KEY----- diff --git a/filebeat/tests/system/config/certificates/beats2.crt b/filebeat/tests/system/config/certificates/beats2.crt new file mode 100644 index 000000000000..c5963aa9d399 --- /dev/null +++ b/filebeat/tests/system/config/certificates/beats2.crt @@ -0,0 +1,17 @@ +-----BEGIN CERTIFICATE----- +MIICpDCCAYwCCQDGVhMwcBRF9TANBgkqhkiG9w0BAQsFADAUMRIwEAYDVQQDDAls +b2NhbGhvc3QwHhcNMTgwNTAzMjA0NDQzWhcNMTkwNTAzMjA0NDQzWjAUMRIwEAYD +VQQDDAlsb2NhbGhvc3QwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDG +8KkEAd+2Oi6QlQOQPy9DREP92iVJcRNESYnTloy3mP/iK1vPeNCvjnPWSAeiuqzm +3iOXIWiV98hk3cAXAg0Gdi/FoNzCJCJqumVu8REBTNbdHlGspMxIyAL+WNdOtTER +21G1BExjjtGki71FR2Z3wdV898zf7yEfJgGhhxCSwQ9NT1C1R++7kWb+HP/TlXWN +4XEM4TF6Czv65+x3HRA0lRVSK6I0Wy0Ct/+Du4RUCAjtOBLj6WkeMw239Wr7jqaw +3vufORWO/qqEXcpdM7LWaSV14Dh+IpQm+Px0q45gZpT93Y3jYEfwBp+QyU4ICHRw +hkBzH0kBEKsxoi3epL1tAgMBAAEwDQYJKoZIhvcNAQELBQADggEBADNfS5ESaEwg +rQ6DBjujxnVwydWLjvkNlByyJ1WTCAsGDRUltzhLK4jIDrvV/xonAnLsVpDIEiFI +O7O1UZ0Z1sLp1Mh9CHma01qmKtLSOC2w7hOKZXdG6wJxrN9s3pmu/K37BhdHZewL +gdaSc3mogsAL852cIVIgjrQjIkbo7Fs9wiD2u1nnpgthUzCE9PvlbRkTu3GJZguy +T50rHoDNJbwsm5MADjH3yCISm+94pJIlxzl/vHvYIa0YLVEG6Hm5t2+6VRr3b7FH +kNbgX7a3Vvn+NDCWnJYXmq57FdgMGHzpmMR7hgBTxQyxu1eEQ0aCkckguyF90vFi +BlGLYh2BmDA= +-----END CERTIFICATE----- diff --git a/filebeat/tests/system/config/certificates/beats2.key b/filebeat/tests/system/config/certificates/beats2.key new file mode 100644 index 000000000000..e72bf24901b4 --- /dev/null +++ b/filebeat/tests/system/config/certificates/beats2.key @@ -0,0 +1,28 @@ +-----BEGIN PRIVATE KEY----- +MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQDG8KkEAd+2Oi6Q +lQOQPy9DREP92iVJcRNESYnTloy3mP/iK1vPeNCvjnPWSAeiuqzm3iOXIWiV98hk +3cAXAg0Gdi/FoNzCJCJqumVu8REBTNbdHlGspMxIyAL+WNdOtTER21G1BExjjtGk +i71FR2Z3wdV898zf7yEfJgGhhxCSwQ9NT1C1R++7kWb+HP/TlXWN4XEM4TF6Czv6 +5+x3HRA0lRVSK6I0Wy0Ct/+Du4RUCAjtOBLj6WkeMw239Wr7jqaw3vufORWO/qqE +XcpdM7LWaSV14Dh+IpQm+Px0q45gZpT93Y3jYEfwBp+QyU4ICHRwhkBzH0kBEKsx +oi3epL1tAgMBAAECggEBAItBXN4cPa++TGgSlxr6z6ejeoCQmfctutHbNCozQS8n +Xz6/IRY6uMGa0sUVSJsFVxCIQJuC3EXV26WXf+XbHqj+Q/Rv5PfU+W6CKYyeHEwv +sFu55GwYM5Nixo2qPJSwyrd4MVqntp0eFOu8kXGUSEreGQXQI85BAotePFgIRnai +hXPSBDJxccPclOutntIieZdGatrRtKU6+Jq5O95oktJRh0NJ/7h6eVF9+zPhf1Kn +AztRjsn1Y9TrIfop9eLAUt2hG9MTdLp8cxqpfCnL9+zIWhWpQeOMfC4yKn3aHBJh +OJw1Z801XXPkqRXGg8KV9IavfzDFnAfPcSWoIJktmOECgYEA/XQh8HHq70W/9SUo +oNunqBzTyCmq+CQPDGi52wWc8or6r7jPH2VLPGrKLA+Vl/J/aLRy6ent+7s586lh +eLXqc7MIB2hMMsYqGTZlsi4LkgGyVRCEA8t8o7TAo053BNS516Ka+L+noukkgBc8 +FClUcdT+/nS3iF0eKyCngE59eiUCgYEAyPBSckeVhMwZnfQPoNt+xtpCn1UmHznC +/OLYY6T108A/EKqrlb2LW06rB9CwdIfB507yoN+p/+GNlF8l1u9zhKCRvliZ84ru +h6IVoeUxkmHEk3VGBVDfS8EQOh9Jq62VyaGEWldZm2elf3AtyZHc5xCVEeaKAvX+ +M9rAy/3AP6kCgYANekh3vccNdDsR8Sjo7OVMdkP4x+Z0jY5TTZpcgD7pUuSjxYMW +G0/V5aPclfORge6uhbH6qFrkYP9i6qXpQls2TdXmdvBeXtVMQ+1CfVpWKErwZRFw +FjkJh4oa5QhFNH6xbc8p3R8v9Y/gU9v5An2gFAB/TXuY/8Kj7neZxhK8FQKBgAGw +e5D4ZxppuOFqFuOMVOGJHjxGs/5ZNvl3Ushrr6FrIVybgrvMjypiW+/B4mnoZkny +kPmnR7+d/tm7fw7yjm8UBoWqKwkwJtc/Fp141tTbO5Ldzovm5Sm24tMKRk1KNVMv +p3Q2/crfsTWEFO536nqK2iX/YTOrK8r10N8mMAKZAoGANGgsdIrOwZO1aTxEpzto +33dtZljvONfpvhiQ7Bytj/H1nvGYTvdPmStwEQdXd/1vE4EZri93ihWAeWeSinfr +5ROWKuor0jZvzAbVUAuISV04+agQ48CDZICsk/srnPvPTJhC/YpJ8ihG2QlH2VZ0 +AIArT7DcZYLwM5m+oJrlQFY= +-----END PRIVATE KEY----- diff --git a/filebeat/tests/system/config/certificates/cacert.cfg b/filebeat/tests/system/config/certificates/cacert.cfg new file mode 100644 index 000000000000..8994ffdace28 --- /dev/null +++ b/filebeat/tests/system/config/certificates/cacert.cfg @@ -0,0 +1,22 @@ +[req] +distinguished_name = dname +[dname] +[ extensions ] +basicConstraints = critical, CA:TRUE +subjectKeyIdentifier = hash +authorityKeyIdentifier = keyid:always, issuer:always +keyUsage = critical, cRLSign, digitalSignature, keyCertSign + +[ client ] +basicConstraints = critical, CA:FALSE +subjectKeyIdentifier = hash +authorityKeyIdentifier = keyid:always, issuer:always +keyUsage = critical, nonRepudiation, digitalSignature, keyEncipherment, keyAgreement +#extendedKeyUsage = critical, serverAuth + +[ server ] +basicConstraints = critical, CA:FALSE +subjectKeyIdentifier = hash +authorityKeyIdentifier = keyid:always, issuer:always +keyUsage = critical, nonRepudiation, digitalSignature, keyEncipherment +#kextendedKeyUsage = critical, clientAuth diff --git a/filebeat/tests/system/config/certificates/cacert.crt b/filebeat/tests/system/config/certificates/cacert.crt new file mode 100644 index 000000000000..d36407a580bb --- /dev/null +++ b/filebeat/tests/system/config/certificates/cacert.crt @@ -0,0 +1,23 @@ +-----BEGIN CERTIFICATE----- +MIID6jCCAtKgAwIBAgIJAOPYgOhthM8ZMA0GCSqGSIb3DQEBCwUAMFAxCzAJBgNV +BAYTAkNBMQ8wDQYDVQQIDAZRdWViZWMxETAPBgNVBAcMCE1vbnRyZWFsMQ4wDAYD +VQQKDAViZWF0czENMAsGA1UECwwEcm9vdDAeFw0xODA1MDMyMDQ0NDdaFw0xOTA1 +MDMyMDQ0NDdaMFAxCzAJBgNVBAYTAkNBMQ8wDQYDVQQIDAZRdWViZWMxETAPBgNV +BAcMCE1vbnRyZWFsMQ4wDAYDVQQKDAViZWF0czENMAsGA1UECwwEcm9vdDCCASIw +DQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAMunCRWeX8FyHmW5rkTItJiAICBq +ru1uMLLg/XUs5OmCJ6goYFX1yuRVrxPoKsblIX7zLfLX3hQSbQWSEzELaufn7jsQ +pW4PUxesEuTqOW7PA3lTfamJ6Hr+IH4Ja3GYX0FZOZOcTBaKB6bd2H1MSg2CzjIi +UYnXlgTULbVmnkpB1UdyBLI9Z2WbqnoiGiB/D1Oko8VXzkA3xT9pgCAXHhxqK5t7 +ostCLYt7AzbSVeU6K6c+4i0VyPcxFZMdB1lcRrLkUuYeUwh/tGXXi6j6iHjS54O1 +hyJjEc79wChOqQewLSgvMj3ASdA3pqvXvQB2NTa5wzznoEx83N3DkkIfjN8CAwEA +AaOBxjCBwzAPBgNVHRMBAf8EBTADAQH/MB0GA1UdDgQWBBSjmGSd3zYagxM07hjS +e2KIJfYuGzCBgAYDVR0jBHkwd4AUo5hknd82GoMTNO4Y0ntiiCX2LhuhVKRSMFAx +CzAJBgNVBAYTAkNBMQ8wDQYDVQQIDAZRdWViZWMxETAPBgNVBAcMCE1vbnRyZWFs +MQ4wDAYDVQQKDAViZWF0czENMAsGA1UECwwEcm9vdIIJAOPYgOhthM8ZMA4GA1Ud +DwEB/wQEAwIBhjANBgkqhkiG9w0BAQsFAAOCAQEAQ+CNwnchjhHRkp5mEkWVOysU +H4ajfpsrOOyBsSgIEWW9Wg+uRglm39fgODscUTpTmFId9Y3qy317e8NU0WwhEVBd +JwO1M4s2PHUcQImnf4h8oeun0qhlxZdS8MC8ac6/jfqwqFfuvsdfub8R/o4zvuEL +ZlziVxjrAWqwuj9YtOV4Rnlivy4tEfJlpS0tAXqbEBN2PWwEmJ408Qkv3L9m1Dvs +6FsBEUoO36sPylSzyAfJQcEWlWW+j9YOnDPM40Iefcxgo4dqgL6uepvoYYERKXpR +JDvDF773yo/rZpjyWws8NJsBBt/341TJqejE/NQq5edludYcesummreMLXI16A== +-----END CERTIFICATE----- diff --git a/filebeat/tests/system/config/certificates/cacert.key b/filebeat/tests/system/config/certificates/cacert.key new file mode 100644 index 000000000000..8eddea50b368 --- /dev/null +++ b/filebeat/tests/system/config/certificates/cacert.key @@ -0,0 +1,27 @@ +-----BEGIN RSA PRIVATE KEY----- +MIIEowIBAAKCAQEAy6cJFZ5fwXIeZbmuRMi0mIAgIGqu7W4wsuD9dSzk6YInqChg +VfXK5FWvE+gqxuUhfvMt8tfeFBJtBZITMQtq5+fuOxClbg9TF6wS5Oo5bs8DeVN9 +qYnoev4gfglrcZhfQVk5k5xMFooHpt3YfUxKDYLOMiJRideWBNQttWaeSkHVR3IE +sj1nZZuqeiIaIH8PU6SjxVfOQDfFP2mAIBceHGorm3uiy0Iti3sDNtJV5Torpz7i +LRXI9zEVkx0HWVxGsuRS5h5TCH+0ZdeLqPqIeNLng7WHImMRzv3AKE6pB7AtKC8y +PcBJ0Demq9e9AHY1NrnDPOegTHzc3cOSQh+M3wIDAQABAoIBAHZljNWBtp/LTbrM +QXGB0eSbEJJoE3y7xBoqzY/S4t6SqaWMm7094Y/v9JI5Nq1dRqT8kekN8PFwaOuF +Kh0oSyW54/l4ywR6ak9n3bAyL+Oo/JcLoBHxuDPRDGjZ5xoqgK6IRf34LxAnfR1Y ++mSV9rN2KZRh+U+PA4uZI13D5CC8rYE7MO3v+5Wb9ItAJBGkyQXJAdPRpPKxitPy +UMCb86xYOOQ8UQyMUg9Cb1SI3gLCMFoz+tmzu+ooiqhU4S06DBUr8y/XDfzXfMCh +uxXSJ0q6u7oZnTpklpqRjUTwLtPIxcMxf/DfF20QG9JyZNGs4ITnYup2f2M16xoe +1pFGQPkCgYEA8D6H4L8TSMA7Zrx9vbAYYbj3kgd/8Z/pdsnO6QCbNVQJxTfGTMJx +cai3A6eAlswGE51OdR2WGl2YtZYARLIncy28kL+9PZmXmc5DBGNrFptCjMRbpt0R +Z2cgJUYUny5tomKOi49uuiOUnrPBaruYKV8xo49H0w1+H2nftjAWtN0CgYEA2QIq +ANehdyvdxjH4TJje2XLOLtzhuhMtU4I/fxHMp/njs2SG00pnUoqrcXJi1EXBd6CO +b52rJJsw9t1GMWNUZYyPNUtn6wfJh0w5Od2FoKn7aWVeP3cdWE4vRMUYzR2yCjmA +Wh9ReM1JmiuiP8ckzy19AwJjXZCpio5et+bCPusCgYEAmXMXTxI8uwct6d0TY4mK +yUBfwUJREoBVmq4kHudoO5PF+dY6LuUzmKlu3EKs+6StbPHZHy0apxSJadK5sScp +04OvIbWWpjXogzEf1Tm7OOFKjKcO83HYn/darPQqT9JT7JiO+81NqE75qrSeIhJY +inRnPFVURxYjLOVvIutsVXECgYAS1Lw+XHfXdogFJdrtEqrr5al8qZAw7G8Xewr1 +hN7kiKu4qnWEqkUzBXOBIbLvxqnWLqmNh/oM8CaclXD84ii1sy/OKR/4ZjGXuwaQ +PefVnEqDx9cY3MZAHnC9n/jZ+8SyXHEF4QfZ2r6TUUwACtDn5YOemjtzKBV+P4J6 +pNygRwKBgDzXrxQV0lOZnH9dpDDE/cE6XlyVcfrYWyj51Wa0TMTxGvIdBGuS9af1 +9Et/iyH7zCzWq0QEDcKX1G8gAk9UQr/+NXXkgpKRbVikEN7sOf2OaV9TLP0SNDa2 +Da6LQs8LtH1N2ucX4OpJPrlx/YHOqWFjRsXQAAtNH2JFMdCnlEKe +-----END RSA PRIVATE KEY----- diff --git a/filebeat/tests/system/config/certificates/cacert.srl b/filebeat/tests/system/config/certificates/cacert.srl new file mode 100644 index 000000000000..43b5cde02ed3 --- /dev/null +++ b/filebeat/tests/system/config/certificates/cacert.srl @@ -0,0 +1 @@ +A3655E382A7345FD diff --git a/filebeat/tests/system/config/certificates/client1.crt b/filebeat/tests/system/config/certificates/client1.crt new file mode 100644 index 000000000000..723363c6e3fe --- /dev/null +++ b/filebeat/tests/system/config/certificates/client1.crt @@ -0,0 +1,47 @@ +-----BEGIN CERTIFICATE----- +MIID/TCCAuWgAwIBAgIJAKNlXjgqc0X8MA0GCSqGSIb3DQEBBQUAMFAxCzAJBgNV +BAYTAkNBMQ8wDQYDVQQIDAZRdWViZWMxETAPBgNVBAcMCE1vbnRyZWFsMQ4wDAYD +VQQKDAViZWF0czENMAsGA1UECwwEcm9vdDAeFw0xODA1MDMyMDQ0NDlaFw0xOTA1 +MDMyMDQ0NDlaMGYxCzAJBgNVBAYTAkNBMQ8wDQYDVQQIDAZRdWViZWMxETAPBgNV +BAcMCE1vbnRyZWFsMQ4wDAYDVQQKDAViZWF0czEPMA0GA1UECwwGc2VydmVyMRIw +EAYDVQQDDAlsb2NhbGhvc3QwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIB +AQDDTkETmyViX+kRQsYDZvAjTo6bVhTUHdWaBj4V+VOImMMtGRayBTn3CKdkMm2L +eWAOv7lgWrccq5Ab1e2XyYxhinAf0ArUyVHhg9PI7Mt08wIJ7o5CmBU6MQ62b7W1 +FgcRVCazaVhTJ2RjQQjVUpgTvxCKv8FVFzfF4sY2WxZOejetdfb08/1oUsIGJbAM +9nB5xnuazKJ3HWUjPWgqOtB2xOakTKU0rqq//0Sv1XbpQVUDjImnPjptPz8RdWfE +h1i3k9m3NXbj/UDKSKX3sNwEkWU89rLx+GaXwsQlL6YA7fkrGMJ23V8FiYG0BySD +AI8k7gVCL0X0B7GWAHZNTC1bAgMBAAGjgcMwgcAwDAYDVR0TAQH/BAIwADAdBgNV +HQ4EFgQUpGf8kXJhEMfgSv0sYCB5seDtdIowgYAGA1UdIwR5MHeAFKOYZJ3fNhqD +EzTuGNJ7Yogl9i4boVSkUjBQMQswCQYDVQQGEwJDQTEPMA0GA1UECAwGUXVlYmVj +MREwDwYDVQQHDAhNb250cmVhbDEOMAwGA1UECgwFYmVhdHMxDTALBgNVBAsMBHJv +b3SCCQDj2IDobYTPGTAOBgNVHQ8BAf8EBAMCBeAwDQYJKoZIhvcNAQEFBQADggEB +AHo7QxfZyh2FvN8nVW/X51QjdgpzMvN7W8DkMfWKy6cp/vhIsZIqLA3qV1MvAHLh +xWAY1yVoJI5PC1XXVprVNVuh+LyvJPR92TLl5SNMT5kFUQzOZ4DqfnsOjVqaXOq6 +WXsSIxqXXpvDtG+Yy8o2l5djoLFvEUukLz6Vdre43tkZNTDzSbksz9nJv0VztYRm +rQ9c4Xchx9Gew+uW3QSIlFEwMJlw9mEts3+tM4zY0A+o/vBkVIAe75omfBM67LT5 +iKbRFtM7tgKTWWSoZ9qZmUUHgU+ffuG/0eqHklaCAQiEYN0scJSNSB4THh/CJyLz +BIU6Y+m1XCtfVsmApqj6uYM= +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIID6jCCAtKgAwIBAgIJAOPYgOhthM8ZMA0GCSqGSIb3DQEBCwUAMFAxCzAJBgNV +BAYTAkNBMQ8wDQYDVQQIDAZRdWViZWMxETAPBgNVBAcMCE1vbnRyZWFsMQ4wDAYD +VQQKDAViZWF0czENMAsGA1UECwwEcm9vdDAeFw0xODA1MDMyMDQ0NDdaFw0xOTA1 +MDMyMDQ0NDdaMFAxCzAJBgNVBAYTAkNBMQ8wDQYDVQQIDAZRdWViZWMxETAPBgNV +BAcMCE1vbnRyZWFsMQ4wDAYDVQQKDAViZWF0czENMAsGA1UECwwEcm9vdDCCASIw +DQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAMunCRWeX8FyHmW5rkTItJiAICBq +ru1uMLLg/XUs5OmCJ6goYFX1yuRVrxPoKsblIX7zLfLX3hQSbQWSEzELaufn7jsQ +pW4PUxesEuTqOW7PA3lTfamJ6Hr+IH4Ja3GYX0FZOZOcTBaKB6bd2H1MSg2CzjIi +UYnXlgTULbVmnkpB1UdyBLI9Z2WbqnoiGiB/D1Oko8VXzkA3xT9pgCAXHhxqK5t7 +ostCLYt7AzbSVeU6K6c+4i0VyPcxFZMdB1lcRrLkUuYeUwh/tGXXi6j6iHjS54O1 +hyJjEc79wChOqQewLSgvMj3ASdA3pqvXvQB2NTa5wzznoEx83N3DkkIfjN8CAwEA +AaOBxjCBwzAPBgNVHRMBAf8EBTADAQH/MB0GA1UdDgQWBBSjmGSd3zYagxM07hjS +e2KIJfYuGzCBgAYDVR0jBHkwd4AUo5hknd82GoMTNO4Y0ntiiCX2LhuhVKRSMFAx +CzAJBgNVBAYTAkNBMQ8wDQYDVQQIDAZRdWViZWMxETAPBgNVBAcMCE1vbnRyZWFs +MQ4wDAYDVQQKDAViZWF0czENMAsGA1UECwwEcm9vdIIJAOPYgOhthM8ZMA4GA1Ud +DwEB/wQEAwIBhjANBgkqhkiG9w0BAQsFAAOCAQEAQ+CNwnchjhHRkp5mEkWVOysU +H4ajfpsrOOyBsSgIEWW9Wg+uRglm39fgODscUTpTmFId9Y3qy317e8NU0WwhEVBd +JwO1M4s2PHUcQImnf4h8oeun0qhlxZdS8MC8ac6/jfqwqFfuvsdfub8R/o4zvuEL +ZlziVxjrAWqwuj9YtOV4Rnlivy4tEfJlpS0tAXqbEBN2PWwEmJ408Qkv3L9m1Dvs +6FsBEUoO36sPylSzyAfJQcEWlWW+j9YOnDPM40Iefcxgo4dqgL6uepvoYYERKXpR +JDvDF773yo/rZpjyWws8NJsBBt/341TJqejE/NQq5edludYcesummreMLXI16A== +-----END CERTIFICATE----- diff --git a/filebeat/tests/system/config/certificates/client1.csr b/filebeat/tests/system/config/certificates/client1.csr new file mode 100644 index 000000000000..fdf01b3aaecc --- /dev/null +++ b/filebeat/tests/system/config/certificates/client1.csr @@ -0,0 +1,17 @@ +-----BEGIN CERTIFICATE REQUEST----- +MIICqzCCAZMCAQAwZjELMAkGA1UEBhMCQ0ExDzANBgNVBAgMBlF1ZWJlYzERMA8G +A1UEBwwITW9udHJlYWwxDjAMBgNVBAoMBWJlYXRzMQ8wDQYDVQQLDAZzZXJ2ZXIx +EjAQBgNVBAMMCWxvY2FsaG9zdDCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoC +ggEBAMNOQRObJWJf6RFCxgNm8CNOjptWFNQd1ZoGPhX5U4iYwy0ZFrIFOfcIp2Qy +bYt5YA6/uWBatxyrkBvV7ZfJjGGKcB/QCtTJUeGD08jsy3TzAgnujkKYFToxDrZv +tbUWBxFUJrNpWFMnZGNBCNVSmBO/EIq/wVUXN8XixjZbFk56N6119vTz/WhSwgYl +sAz2cHnGe5rMoncdZSM9aCo60HbE5qRMpTSuqr//RK/VdulBVQOMiac+Om0/PxF1 +Z8SHWLeT2bc1duP9QMpIpfew3ASRZTz2svH4ZpfCxCUvpgDt+SsYwnbdXwWJgbQH +JIMAjyTuBUIvRfQHsZYAdk1MLVsCAwEAAaAAMA0GCSqGSIb3DQEBCwUAA4IBAQCn +ibx1rSgV7GNkeCpUiUwWtOTZJmSe3UVKU/zwsz/FHHIbNpx1tQZt/q+j5SksbDd0 +IY/TBEeVcDR344z6RWRAjVln7UuTsD7B+oQn4Q62Ocu7BFPKQ/TRTP8chywqFU2n +iErvzoAcVicrl9EvU5olyZswnLWVZZW3U63ymA+2zqcPqj3HtXQGFBpGziVmTeCh +UOJ9q8i9iwgeZ2xoCkfnd4KkX8fYYzgUVGSgfmnZOs/gQ8eUkt85UBLZbmGOaOxr ++Pj4svxgwG5zVGzF1s1Qe1Basf1axGajJVRNIPNL88jLIhdt41hK/K1GXMFhIZwp +ys2NJfXl94R/hdvVSBhV +-----END CERTIFICATE REQUEST----- diff --git a/filebeat/tests/system/config/certificates/client1.key b/filebeat/tests/system/config/certificates/client1.key new file mode 100644 index 000000000000..6cb0f05fd135 --- /dev/null +++ b/filebeat/tests/system/config/certificates/client1.key @@ -0,0 +1,27 @@ +-----BEGIN RSA PRIVATE KEY----- +MIIEowIBAAKCAQEAw05BE5slYl/pEULGA2bwI06Om1YU1B3VmgY+FflTiJjDLRkW +sgU59winZDJti3lgDr+5YFq3HKuQG9Xtl8mMYYpwH9AK1MlR4YPTyOzLdPMCCe6O +QpgVOjEOtm+1tRYHEVQms2lYUydkY0EI1VKYE78Qir/BVRc3xeLGNlsWTno3rXX2 +9PP9aFLCBiWwDPZwecZ7msyidx1lIz1oKjrQdsTmpEylNK6qv/9Er9V26UFVA4yJ +pz46bT8/EXVnxIdYt5PZtzV24/1Aykil97DcBJFlPPay8fhml8LEJS+mAO35KxjC +dt1fBYmBtAckgwCPJO4FQi9F9AexlgB2TUwtWwIDAQABAoIBADd00/OuPRpG45Yc +IL+8jfloiAPBmJ52bj2TAjQZHMgPoHQAyLn50/C6S1WfIA3XhBgMBqY+e/ovGPde +cl2ERFE6DwZpe3naRF7FoPBPlKH7kpuhWlG8f2KLpYLWC4GE5LLd8zNEeWj7KX0p +bUmtbzNEMH1FX686rYKKFwA+MwJLINhmYityv6Fcz+gsgRULsdpfVRgzYIMJtKLr +BffK/CTcb8dD5Ai0Z2UIU+J/81rY1dPsnVkEyrA7DuqZAcjhxxyNDfOeatlRq+lp +dU90Pg6vb4i0y5kWXZiLUsjfCJnu/KiadOrtgccY5LlN+7zVW4SR+hnG6ZCL/KWB +dDuhNwkCgYEA5SSK0huS8yw3NXpAUaF+sb+kyiQ+kyQ6IXqRO17j+wfG9hOQbwhe +W3uspCGcPVe/a9YnyVsOVsWBVxHrlv2DrDibaNblCn8nefBmYpEvkqwVlJYlx9Uq +w1daFzVxtVOqLLBUKVyvEk/aybVgEX1J+PFjBeu1Oz+VM402JjfBHq0CgYEA2jJt +LdIk5OzEIntayxA1VCN6gCbF2PqQ8ruezhFOjZH7MXzcd5eYyvK4qZGRljIS8/5T +VNImEiqnpU9euVnjRtQtfnHlqhG1nDe6P6VhMtqy1tOTfXx+943t8l1DIHfk6Pm6 +TQIZw8s66qT9bNC8Cxf+vN5Pn/y3wUxZNUjnpScCgYAb4VRauCwrFkgpY5SL2iB2 +NCEyzzIl6RSBmk4tcSBAHPQiYMMEH3qLmwKofcZq2FBcKJRytXeLK0DPfUiy+Gma +/NA781mu60W8Wnm6qHunVvTRPWufYtpvJiO6CzCopWNhSJsU5UgP7FNsk3r65cmo +VoZ74/ALI3Nd8GKUR9hhiQKBgHPSeKnt9q+eDq7PE+7ed7Bl9My5yCPZPb/bX/y6 +qxvy9YfbY5wH2I9CMEuyfblgczcZNVq9AoB6K+tQKlPxJveeAVgxVVvlcqWt3yuR +ufqopG3seUoPH8aAjGIup0dA3T3d8cqW5t5LrsaHNg7g7jBlWE8hItsl5tSwlln2 +jR/ZAoGBAJfbbBce/uCrtVFyYOMCa/Oi6nTso3JKd7xR2syqnTLtjLfmkGLADgsq +GTgxy/8RPqzhMhwitMPA25ASvpuVtTSMMqRi4Eg9Agqv97A37Bjcfs8aYcveLMNj +EzSjPpSMgY/E6EERhFZmd5HMrhWRv4dFkLb5sca9tEGpmwZOV/ot +-----END RSA PRIVATE KEY----- diff --git a/filebeat/tests/system/config/certificates/client2.crt b/filebeat/tests/system/config/certificates/client2.crt new file mode 100644 index 000000000000..fc2ead580eb5 --- /dev/null +++ b/filebeat/tests/system/config/certificates/client2.crt @@ -0,0 +1,47 @@ +-----BEGIN CERTIFICATE----- +MIID/TCCAuWgAwIBAgIJAKNlXjgqc0X9MA0GCSqGSIb3DQEBBQUAMFAxCzAJBgNV +BAYTAkNBMQ8wDQYDVQQIDAZRdWViZWMxETAPBgNVBAcMCE1vbnRyZWFsMQ4wDAYD +VQQKDAViZWF0czENMAsGA1UECwwEcm9vdDAeFw0xODA1MDMyMDQ0NTBaFw0xOTA1 +MDMyMDQ0NTBaMGYxCzAJBgNVBAYTAkNBMQ8wDQYDVQQIDAZRdWViZWMxETAPBgNV +BAcMCE1vbnRyZWFsMQ4wDAYDVQQKDAViZWF0czEPMA0GA1UECwwGY2xpZW50MRIw +EAYDVQQDDAlsb2NhbGhvc3QwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIB +AQDB6ofNCj9bALQSutD2OiXicMbmSUuwD7XQ/rk6XRXL/LwgC2VpBHf5maIgoTXe +2jA/x1I8STwbvQVXCtQbGXJQjBhEBj1PWLfJQDXrbuLNgHrGJ29rIRvrLDWW26Sj +q7W6J69KFoL8Sc6EPmBaqzrTm/JxSp6Z+z6XlyX5l7AauEOjdHOhJIdku6D6gwZX +gs+C4lxNGtWR/MFyGoswtXP1JfyKsmTab3joX8Mj6KmDG9gzMSAOVrNULYsVxJNF +8Cp5NLeqtsEV2wRkB454HsR8RXgCF4UIjYf/n81poxsFiOKTA0ySpKKDC++nio1k +c/Tz9boaOHwE77w3D0d6wAmDAgMBAAGjgcMwgcAwDAYDVR0TAQH/BAIwADAdBgNV +HQ4EFgQUcprOFjrv86fFjeOb/+RgHT3Uh0AwgYAGA1UdIwR5MHeAFKOYZJ3fNhqD +EzTuGNJ7Yogl9i4boVSkUjBQMQswCQYDVQQGEwJDQTEPMA0GA1UECAwGUXVlYmVj +MREwDwYDVQQHDAhNb250cmVhbDEOMAwGA1UECgwFYmVhdHMxDTALBgNVBAsMBHJv +b3SCCQDj2IDobYTPGTAOBgNVHQ8BAf8EBAMCA+gwDQYJKoZIhvcNAQEFBQADggEB +ALxW4VSHf16NbkX3PQsscNBOJ144Q3ZDbVQVG15dH9p/CDj6r16bJ2y8yqIgZLUP +deObu3d4NVQEsNhemy/OVbjCDclrxsswBhLvuM78mBGFTIHnaUB/UUyn0BYE5aG+ +OBfRfGB5oDkgwzgtNpp/mLDI8uIuiTu1ijMPcFXFH907yNf96LXAlGXjDhM8qzfI +lQYTq+WWwP6iKbK9HFcYrMI1G1TPVcsbNSjuEBVuWTBT7Ufc+f2bmZgY1tc6ryRd +RPTWER/7auv07wZlyarGvW8+760Qv/ffhjVa3qxZcxJ+2YHBkUKN1Ly2ZRhmN0BR +d6VLK1FLCr9vHKVvZQ26hEg= +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIID6jCCAtKgAwIBAgIJAOPYgOhthM8ZMA0GCSqGSIb3DQEBCwUAMFAxCzAJBgNV +BAYTAkNBMQ8wDQYDVQQIDAZRdWViZWMxETAPBgNVBAcMCE1vbnRyZWFsMQ4wDAYD +VQQKDAViZWF0czENMAsGA1UECwwEcm9vdDAeFw0xODA1MDMyMDQ0NDdaFw0xOTA1 +MDMyMDQ0NDdaMFAxCzAJBgNVBAYTAkNBMQ8wDQYDVQQIDAZRdWViZWMxETAPBgNV +BAcMCE1vbnRyZWFsMQ4wDAYDVQQKDAViZWF0czENMAsGA1UECwwEcm9vdDCCASIw +DQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAMunCRWeX8FyHmW5rkTItJiAICBq +ru1uMLLg/XUs5OmCJ6goYFX1yuRVrxPoKsblIX7zLfLX3hQSbQWSEzELaufn7jsQ +pW4PUxesEuTqOW7PA3lTfamJ6Hr+IH4Ja3GYX0FZOZOcTBaKB6bd2H1MSg2CzjIi +UYnXlgTULbVmnkpB1UdyBLI9Z2WbqnoiGiB/D1Oko8VXzkA3xT9pgCAXHhxqK5t7 +ostCLYt7AzbSVeU6K6c+4i0VyPcxFZMdB1lcRrLkUuYeUwh/tGXXi6j6iHjS54O1 +hyJjEc79wChOqQewLSgvMj3ASdA3pqvXvQB2NTa5wzznoEx83N3DkkIfjN8CAwEA +AaOBxjCBwzAPBgNVHRMBAf8EBTADAQH/MB0GA1UdDgQWBBSjmGSd3zYagxM07hjS +e2KIJfYuGzCBgAYDVR0jBHkwd4AUo5hknd82GoMTNO4Y0ntiiCX2LhuhVKRSMFAx +CzAJBgNVBAYTAkNBMQ8wDQYDVQQIDAZRdWViZWMxETAPBgNVBAcMCE1vbnRyZWFs +MQ4wDAYDVQQKDAViZWF0czENMAsGA1UECwwEcm9vdIIJAOPYgOhthM8ZMA4GA1Ud +DwEB/wQEAwIBhjANBgkqhkiG9w0BAQsFAAOCAQEAQ+CNwnchjhHRkp5mEkWVOysU +H4ajfpsrOOyBsSgIEWW9Wg+uRglm39fgODscUTpTmFId9Y3qy317e8NU0WwhEVBd +JwO1M4s2PHUcQImnf4h8oeun0qhlxZdS8MC8ac6/jfqwqFfuvsdfub8R/o4zvuEL +ZlziVxjrAWqwuj9YtOV4Rnlivy4tEfJlpS0tAXqbEBN2PWwEmJ408Qkv3L9m1Dvs +6FsBEUoO36sPylSzyAfJQcEWlWW+j9YOnDPM40Iefcxgo4dqgL6uepvoYYERKXpR +JDvDF773yo/rZpjyWws8NJsBBt/341TJqejE/NQq5edludYcesummreMLXI16A== +-----END CERTIFICATE----- diff --git a/filebeat/tests/system/config/certificates/client2.csr b/filebeat/tests/system/config/certificates/client2.csr new file mode 100644 index 000000000000..879a8a728ecc --- /dev/null +++ b/filebeat/tests/system/config/certificates/client2.csr @@ -0,0 +1,17 @@ +-----BEGIN CERTIFICATE REQUEST----- +MIICqzCCAZMCAQAwZjELMAkGA1UEBhMCQ0ExDzANBgNVBAgMBlF1ZWJlYzERMA8G +A1UEBwwITW9udHJlYWwxDjAMBgNVBAoMBWJlYXRzMQ8wDQYDVQQLDAZjbGllbnQx +EjAQBgNVBAMMCWxvY2FsaG9zdDCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoC +ggEBAMHqh80KP1sAtBK60PY6JeJwxuZJS7APtdD+uTpdFcv8vCALZWkEd/mZoiCh +Nd7aMD/HUjxJPBu9BVcK1BsZclCMGEQGPU9Yt8lANetu4s2AesYnb2shG+ssNZbb +pKOrtbonr0oWgvxJzoQ+YFqrOtOb8nFKnpn7PpeXJfmXsBq4Q6N0c6Ekh2S7oPqD +BleCz4LiXE0a1ZH8wXIaizC1c/Ul/IqyZNpveOhfwyPoqYMb2DMxIA5Ws1QtixXE +k0XwKnk0t6q2wRXbBGQHjngexHxFeAIXhQiNh/+fzWmjGwWI4pMDTJKkooML76eK +jWRz9PP1uho4fATvvDcPR3rACYMCAwEAAaAAMA0GCSqGSIb3DQEBCwUAA4IBAQCD +vvLJ906nOKvDEr+Fn3VXGI/IBn1MK94fQuWxc/+gVOYseXlH5wB2+PCMkhUOqNWD +s7WLGtCoOC19iPNtcRA5jntWFZZBkxh4d4IGOBrfdqHTRgMG0JBQbf6A11XxVDy0 +a2pADeM3G4ns6OQZqiu74mpXlRo4uqsDmP/M2z4S7TSkPhyq20sVQCIYO3wZgVbH +35vV8UP7OfUccUYOxcIxp/G+bS6TVaSU+3UFX6IZiScThunNw8L/xLrMWjo7jmXg +5Sr0Iq6XNf1thi7QjVezDb9bAQPpwj0YLJlMi2JcASgprwtaKPdZ1LxNsM0t9aAl +H3ncz4+aPMNNXksr4NcB +-----END CERTIFICATE REQUEST----- diff --git a/filebeat/tests/system/config/certificates/client2.key b/filebeat/tests/system/config/certificates/client2.key new file mode 100644 index 000000000000..2809dc7b18d5 --- /dev/null +++ b/filebeat/tests/system/config/certificates/client2.key @@ -0,0 +1,27 @@ +-----BEGIN RSA PRIVATE KEY----- +MIIEowIBAAKCAQEAweqHzQo/WwC0ErrQ9jol4nDG5klLsA+10P65Ol0Vy/y8IAtl +aQR3+ZmiIKE13towP8dSPEk8G70FVwrUGxlyUIwYRAY9T1i3yUA1627izYB6xidv +ayEb6yw1ltuko6u1uievShaC/EnOhD5gWqs605vycUqemfs+l5cl+ZewGrhDo3Rz +oSSHZLug+oMGV4LPguJcTRrVkfzBchqLMLVz9SX8irJk2m946F/DI+ipgxvYMzEg +DlazVC2LFcSTRfAqeTS3qrbBFdsEZAeOeB7EfEV4AheFCI2H/5/NaaMbBYjikwNM +kqSigwvvp4qNZHP08/W6Gjh8BO+8Nw9HesAJgwIDAQABAoIBAAR9FkmjvBWyLXjl +hCK+89OLAr+f4LWhl3bP/p+gOfnvzrb7LIzCwrgvWzZgJOwUpttDFN86Xr7RoEcE +hCZgb2n35DPm5RJqHk71QopBldRl7fGaRhT3vjqyWkc0rFnxhpJZitAvNzb5ymL7 +QqW2ovT0/iarMIKl8yv1HrbpUPU9VlMLgtUuQrVRt+YqswEzAbPJaQw+y9cemWCJ +dMMnu4gkXsvTSrGej6N5vr8craorfYFifYMmoBf6VVH/zRjCLPpsGZwOaFs2JdZB +Q3w5KwKn2CMgJWZvEjWdulUFf83srdWTuFMUT1ylpNfGE8VBDR0YFas5WBZOGpB7 +e12+yFECgYEA8KLzcUQnLUS8Q6c36wZCzOWgPPPr51TyJb5CG6tQiIXbYKXBLnnD +JrE8Infndo4RAc4qKue4Gqgso1PCMwjiwhjne4A4tselAIUq55Tf8M44ApwanrqQ +CyqR/74jK786R5ONnevepn+cmVTT44R+MtC/+qHIazTOQ1FcdCGTPcsCgYEAzkv2 +/S8SokEAVxnQ5liBKnmh1X3/fwsvUBPlCqv0lQ3EoOyFdazoL3Ija+A/K2OM1TwF +SZamJieg1XnuRyseU9skOO7rUsPqkuf1KkPUz1JxkJKo8Ktmg0w0dPKS3VCwL6CG +vjXwRGqK7iGem8/1W9kX6yAtWvSMpzSq63Ec7CkCgYEAg6p1j40d7owEgvP1CbjU +Ri6CfbdtZZc6I2K141PabcjoHzqyuA5RtFMXtzhqQpk7PwSiV/WP664HNpq20JvV +DyT3S8D9xyz34I/8yNfRrH35cZweiKlF9YYmeot7zQ0GA3H98+HCYtHCSrd6dKvj +LUTBNo7dDaPIFFdpQfW5Df8CgYAS9Lv/S8IEksB7QG4HnH5R7tdGDMvbWqXAT/Ot +5VsWDyvQNauVwoubQHusv/BOBlm8hkVeG6+stdt7gja452dkATD04k9RTZtSYGoQ +tibp3gN9a1yGsNk8m1X+oQOJvo5R8ggvljk7sCaP9xrh6lv7Upl2C4DfaLU78AT8 +mWo08QKBgA09UuoM2Xg2eRmhNq10wcmnR+zoPYktE92GmxXCSUnPLf3lKzhPaZkl +vrzV4QMZ9laDikQfXGappyE2RozFqYsPlO8SqKdM5rN86eCQR6lzb1AjvaOfBW6y +p8xlMHvevnp00dtzKyYwcWzYyWfYOp9+biHgOvNiOpemi9d/qKn1 +-----END RSA PRIVATE KEY----- diff --git a/filebeat/tests/system/config/certificates/generate_certificate.sh b/filebeat/tests/system/config/certificates/generate_certificate.sh new file mode 100755 index 000000000000..771f68233c8a --- /dev/null +++ b/filebeat/tests/system/config/certificates/generate_certificate.sh @@ -0,0 +1,40 @@ +#!/bin/bash +set -x +# +rm -rf *.key *.crt *.csr cacert.srl +echo "Generate simple self signed CA" +openssl req -x509 -batch -nodes -newkey rsa:2048 -keyout beats1.key \ + -out beats1.crt -days 365 -subj /CN=localhost + +openssl req -x509 -batch -nodes -newkey rsa:2048 -keyout beats2.key \ + -out beats2.crt -days 365 -subj /CN=localhost + +# Generate CA for mutual auth +echo "----" +echo "Generate CACert without a passphrase" +openssl genrsa -out cacert.key 2048 +openssl req -sha256 -config cacert.cfg -extensions extensions -new -x509 -days 365 -key cacert.key -out cacert.crt \ + -subj "/C=CA/ST=Quebec/L=Montreal/O=beats/OU=root" + +echo "----" +echo "Generate client1" +openssl genrsa -out client1.key 2048 +openssl req -sha256 -new -key client1.key -out client1.csr \ + -subj "/C=CA/ST=Quebec/L=Montreal/O=beats/OU=server/CN=localhost" +openssl x509 -req -days 365 -in client1.csr -CA cacert.crt -CAkey cacert.key -CAcreateserial \ + -out client1.crt\ + -extfile cacert.cfg -extensions server + +echo "----" +echo "Generate client2" +openssl genrsa -out client2.key 2048 +openssl req -sha256 -new -key client2.key -out client2.csr \ + -subj "/C=CA/ST=Quebec/L=Montreal/O=beats/OU=client/CN=localhost" +openssl x509 -req -days 365 -in client2.csr -CA cacert.crt -CAkey cacert.key -CAserial cacert.srl\ + -out client2.crt \ + -extfile cacert.cfg -extensions client + +echo "----" +echo "create the certificate chains" +cat cacert.crt >> client1.crt +cat cacert.crt >> client2.crt diff --git a/filebeat/tests/system/test_tcp_tls.py b/filebeat/tests/system/test_tcp_tls.py new file mode 100644 index 000000000000..b8f89458f951 --- /dev/null +++ b/filebeat/tests/system/test_tcp_tls.py @@ -0,0 +1,273 @@ +from filebeat import BaseTest +import socket +import ssl +from os import path +from nose.tools import raises, assert_raises + +NUMBER_OF_EVENTS = 2 + +CURRENT_PATH = path.dirname(__file__) +CERTPATH = path.abspath(path.join(CURRENT_PATH, "config/certificates")) + + +# Self signed certificate used without mutual and failling scenario. +CERTIFICATE1 = path.join(CERTPATH, "beats1.crt") +KEY1 = path.join(CERTPATH, "beats1.key") + +CERTIFICATE2 = path.join(CERTPATH, "beats2.crt") +KEY2 = path.join(CERTPATH, "beats2.key") + + +# Valid self signed certificate used for mutual auth. +CACERT = path.join(CERTPATH, "cacert.crt") + +CLIENT1 = path.join(CERTPATH, "client1.crt") +CLIENTKEY1 = path.join(CERTPATH, "client1.key") + +CLIENT2 = path.join(CERTPATH, "client2.crt") +CLIENTKEY2 = path.join(CERTPATH, "client2.key") + + +class Test(BaseTest): + """ + Test filebeat TCP input with TLS + """ + + def test_tcp_over_tls_and_verify_valid_server_without_mutual_auth(self): + """ + Test filebeat TCP with TLS with valid cacert without client auth. + """ + input_raw = """ +- type: tcp + host: "{host}:{port}" + enabled: true + ssl.certificate_authorities: [{cacert}] + ssl.certificate: {certificate} + ssl.key: {key} + ssl.client_authentification: optional +""" + config = { + "host": "127.0.0.1", + "port": 8080, + "cacert": CERTIFICATE1, + "certificate": CERTIFICATE1, + "key": KEY1 + } + + input_raw = input_raw.format(**config) + + self.render_config_template( + input_raw=input_raw, + inputs=False, + ) + + filebeat = self.start_beat() + + self.wait_until(lambda: self.log_contains( + "Started listening for TCP connection")) + + sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) # TCP + tls = ssl.wrap_socket(sock, cert_reqs=ssl.CERT_REQUIRED, + ca_certs=CERTIFICATE1, do_handshake_on_connect=True) + tls.connect((config.get('host'), config.get('port'))) + + for n in range(0, NUMBER_OF_EVENTS): + tls.send("Hello World: " + str(n) + "\n") + + self.wait_until(lambda: self.output_count( + lambda x: x >= NUMBER_OF_EVENTS)) + + filebeat.check_kill_and_wait() + + output = self.read_output() + + self.assert_output(output) + + sock.close() + + @raises(ssl.SSLError) + def test_tcp_over_tls_and_verify_invalid_server_without_mutual_auth(self): + """ + Test filebeat TCP with TLS with an invalid cacert and not requiring mutual auth. + """ + input_raw = """ +- type: tcp + host: "{host}:{port}" + enabled: true + ssl.certificate_authorities: [{cacert}] + ssl.certificate: {certificate} + ssl.key: {key} + ssl.client_authentification: optional +""" + config = { + "host": "127.0.0.1", + "port": 8080, + "cacert": CERTIFICATE1, + "certificate": CERTIFICATE1, + "key": KEY1 + } + + input_raw = input_raw.format(**config) + + self.render_config_template( + input_raw=input_raw, + inputs=False, + ) + + filebeat = self.start_beat() + + self.wait_until(lambda: self.log_contains( + "Started listening for TCP connection")) + + sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) # TCP + tls = ssl.wrap_socket(sock, cert_reqs=ssl.CERT_REQUIRED, + ca_certs=CERTIFICATE2, do_handshake_on_connect=True) + tls.connect((config.get('host'), config.get('port'))) + + @raises(ssl.SSLError) + def test_tcp_over_tls_mutual_auth_fails(self): + """ + Test filebeat TCP with TLS when enforcing client auth with bad client certificates. + """ + input_raw = """ +- type: tcp + host: "{host}:{port}" + enabled: true + ssl.certificate_authorities: [{cacert}] + ssl.certificate: {certificate} + ssl.key: {key} + ssl.client_authentification: required +""" + config = { + "host": "127.0.0.1", + "port": 8080, + "cacert": CERTIFICATE1, + "certificate": CERTIFICATE1, + "key": KEY1 + } + + input_raw = input_raw.format(**config) + + self.render_config_template( + input_raw=input_raw, + inputs=False, + ) + + filebeat = self.start_beat() + + self.wait_until(lambda: self.log_contains( + "Started listening for TCP connection")) + + sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) + tls = ssl.wrap_socket(sock, cert_reqs=ssl.CERT_REQUIRED, + ca_certs=CERTIFICATE1, do_handshake_on_connect=True) + tls.connect((config.get('host'), config.get('port'))) + + def test_tcp_over_tls_mutual_auth_succeed(self): + """ + Test filebeat TCP with TLS when enforcing client auth with good client certificates. + """ + input_raw = """ +- type: tcp + host: "{host}:{port}" + enabled: true + ssl.certificate_authorities: [{cacert}] + ssl.certificate: {certificate} + ssl.key: {key} + ssl.client_authentification: required +""" + config = { + "host": "127.0.0.1", + "port": 8080, + "cacert": CACERT, + "certificate": CLIENT1, + "key": CLIENTKEY1, + } + + input_raw = input_raw.format(**config) + + self.render_config_template( + input_raw=input_raw, + inputs=False, + ) + + filebeat = self.start_beat() + + self.wait_until(lambda: self.log_contains( + "Started listening for TCP connection")) + + sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) + + context = ssl.SSLContext(ssl.PROTOCOL_TLSv1_2) + context.verify_mode = ssl.CERT_REQUIRED + context.load_verify_locations(CACERT) + context.load_cert_chain(certfile=CLIENT2, keyfile=CLIENTKEY2) + + tls = context.wrap_socket(sock, server_side=False) + + tls.connect((config.get('host'), config.get('port'))) + + for n in range(0, NUMBER_OF_EVENTS): + tls.send("Hello World: " + str(n) + "\n") + + self.wait_until(lambda: self.output_count( + lambda x: x >= NUMBER_OF_EVENTS)) + + filebeat.check_kill_and_wait() + + output = self.read_output() + + self.assert_output(output) + + sock.close() + + def test_tcp_tls_with_a_plain_text_socket(self): + """ + Test filebeat TCP with TLS with a plain text connection. + """ + input_raw = """ +- type: tcp + host: "{host}:{port}" + enabled: true + ssl.certificate_authorities: [{cacert}] + ssl.certificate: {certificate} + ssl.key: {key} + ssl.client_authentification: required +""" + config = { + "host": "127.0.0.1", + "port": 8080, + "cacert": CERTIFICATE1, + "certificate": CERTIFICATE1, + "key": KEY1 + } + + input_raw = input_raw.format(**config) + + self.render_config_template( + input_raw=input_raw, + inputs=False, + ) + + filebeat = self.start_beat() + + self.wait_until(lambda: self.log_contains( + "Started listening for TCP connection")) + + sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) # TCP + sock.connect((config.get('host'), config.get('port'))) + + # The TLS handshake will close the connection, resulting in a broken pipe. + # no events should be written on disk. + with assert_raises(IOError): + for n in range(0, 100): + sock.send("Hello World: " + str(n) + "\n") + + filebeat.check_kill_and_wait() + + assert path.isfile(path.join(self.working_dir, "output/" + self.beat_name)) is False + + def assert_output(self, output): + assert len(output) == 2 + assert output[0]["prospector.type"] == "tcp" + assert output[0]["input.type"] == "tcp" From 62f04a06e95c09da102f32593c9bf721536b2bbe Mon Sep 17 00:00:00 2001 From: ph Date: Fri, 4 May 2018 13:56:22 -0400 Subject: [PATCH 3/6] DOCS: update libbeat and filebeat docs with the SSL options. --- filebeat/docs/inputs/input-common-tcp-options.asciidoc | 9 +++++++++ libbeat/docs/shared-ssl-config.asciidoc | 10 ++++++++++ 2 files changed, 19 insertions(+) diff --git a/filebeat/docs/inputs/input-common-tcp-options.asciidoc b/filebeat/docs/inputs/input-common-tcp-options.asciidoc index c82dd7ee4f0f..d4d08872abc3 100644 --- a/filebeat/docs/inputs/input-common-tcp-options.asciidoc +++ b/filebeat/docs/inputs/input-common-tcp-options.asciidoc @@ -27,3 +27,12 @@ Specify the characters used to split the incoming events. The default is '\n'. ==== `timeout` The number of seconds of inactivity before a remote connection is closed. The default is `300s`. + +[float] +[id="{beatname_lc}-input-{type}-tcp-ssl"] +===== `ssl` + +Configuration options for SSL parameters like the certificate, key and the certificate authorities +to use. + +See <> for more information. diff --git a/libbeat/docs/shared-ssl-config.asciidoc b/libbeat/docs/shared-ssl-config.asciidoc index e813bedf909e..ca3be2563e0d 100644 --- a/libbeat/docs/shared-ssl-config.asciidoc +++ b/libbeat/docs/shared-ssl-config.asciidoc @@ -168,3 +168,13 @@ are `never`, `once`, and `freely`. The default value is never. * `never` - Disables renegotiation. * `once` - Allows a remote server to request renegotiation once per connection. * `freely` - Allows a remote server to repeatedly request renegotiation. + +[float] +==== `client_authentification` + +This configures what types of client authentification are supported. The valid options +are `none`, `optional`, and `required`. The default value is required. + +* `none` - Disables client authentification. +* `optional` - When a client certificate is given, the server will verify it. +* `required` - Will require clients to provide a valid certificate. From 5dad6790dbd2fccd0efa756200c2194bf31e5439 Mon Sep 17 00:00:00 2001 From: ph Date: Fri, 4 May 2018 14:47:20 -0400 Subject: [PATCH 4/6] Refactor: Move existing class to tlscommon --- heartbeat/monitors/active/http/config.go | 4 +-- heartbeat/monitors/active/tcp/config.go | 4 +-- .../generator/{{monitor}}/config.go.tmpl | 4 +-- .../monitoring/report/elasticsearch/config.go | 28 ++++++++--------- .../report/elasticsearch/elasticsearch.go | 3 +- libbeat/outputs/elasticsearch/config.go | 30 +++++++++---------- .../outputs/elasticsearch/elasticsearch.go | 5 ++-- libbeat/outputs/kafka/config.go | 4 +-- libbeat/outputs/kafka/kafka.go | 3 +- libbeat/outputs/logstash/config.go | 4 +-- libbeat/outputs/logstash/logstash.go | 3 +- libbeat/outputs/redis/config.go | 4 +-- libbeat/outputs/redis/redis.go | 3 +- .../outputs/transport/transptest/testing.go | 8 ++--- libbeat/setup/kibana/client.go | 4 +-- libbeat/setup/kibana/config.go | 16 +++++----- metricbeat/helper/http.go | 10 +++---- .../module/kafka/consumergroup/config.go | 14 ++++----- .../kafka/consumergroup/consumergroup.go | 4 +-- metricbeat/module/kafka/partition/config.go | 16 +++++----- .../module/kafka/partition/partition.go | 4 +-- 21 files changed, 90 insertions(+), 85 deletions(-) diff --git a/heartbeat/monitors/active/http/config.go b/heartbeat/monitors/active/http/config.go index 38e5e4f3ec22..8328e1b3c687 100644 --- a/heartbeat/monitors/active/http/config.go +++ b/heartbeat/monitors/active/http/config.go @@ -6,7 +6,7 @@ import ( "time" "github.com/elastic/beats/libbeat/common/match" - "github.com/elastic/beats/libbeat/outputs" + "github.com/elastic/beats/libbeat/common/transport/tlscommon" "github.com/elastic/beats/heartbeat/monitors" ) @@ -26,7 +26,7 @@ type Config struct { Password string `config:"password"` // configure tls (if not configured HTTPS will use system defaults) - TLS *outputs.TLSConfig `config:"ssl"` + TLS *tlscommon.Config `config:"ssl"` // http(s) ping validation Check checkConfig `config:"check"` diff --git a/heartbeat/monitors/active/tcp/config.go b/heartbeat/monitors/active/tcp/config.go index c5aea4f1052c..98b80167b2d1 100644 --- a/heartbeat/monitors/active/tcp/config.go +++ b/heartbeat/monitors/active/tcp/config.go @@ -4,7 +4,7 @@ import ( "errors" "time" - "github.com/elastic/beats/libbeat/outputs" + "github.com/elastic/beats/libbeat/common/transport/tlscommon" "github.com/elastic/beats/libbeat/outputs/transport" "github.com/elastic/beats/heartbeat/monitors" @@ -22,7 +22,7 @@ type Config struct { Socks5 transport.ProxyConfig `config:",inline"` // configure tls - TLS *outputs.TLSConfig `config:"ssl"` + TLS *tlscommon.Config `config:"ssl"` Timeout time.Duration `config:"timeout"` diff --git a/heartbeat/scripts/generator/{{monitor}}/config.go.tmpl b/heartbeat/scripts/generator/{{monitor}}/config.go.tmpl index 7051ff4ddfa4..46b36a06cc46 100644 --- a/heartbeat/scripts/generator/{{monitor}}/config.go.tmpl +++ b/heartbeat/scripts/generator/{{monitor}}/config.go.tmpl @@ -3,9 +3,9 @@ package {{monitor}} import ( "time" - "github.com/elastic/beats/libbeat/outputs" "github.com/elastic/beats/libbeat/outputs/transport" + "github.com/elastic/beats/libbeat/common/transport/tlscommon" "github.com/elastic/beats/heartbeat/monitors" ) @@ -19,7 +19,7 @@ type config struct { Mode monitors.IPSettings `config:",inline"` // configure tls - TLS *outputs.TLSConfig `config:"ssl"` + TLS *tlscommon.Config `config:"ssl"` // configure validation Check checkConfig `config:"check"` diff --git a/libbeat/monitoring/report/elasticsearch/config.go b/libbeat/monitoring/report/elasticsearch/config.go index 497b8acdd46d..073a5c7ee9ca 100644 --- a/libbeat/monitoring/report/elasticsearch/config.go +++ b/libbeat/monitoring/report/elasticsearch/config.go @@ -3,7 +3,7 @@ package elasticsearch import ( "time" - "github.com/elastic/beats/libbeat/outputs" + "github.com/elastic/beats/libbeat/common/transport/tlscommon" ) // config is subset of libbeat/outputs/elasticsearch config tailored @@ -11,19 +11,19 @@ import ( type config struct { Hosts []string Protocol string - Params map[string]string `config:"parameters"` - Headers map[string]string `config:"headers"` - Username string `config:"username"` - Password string `config:"password"` - ProxyURL string `config:"proxy_url"` - CompressionLevel int `config:"compression_level" validate:"min=0, max=9"` - TLS *outputs.TLSConfig `config:"ssl"` - MaxRetries int `config:"max_retries"` - Timeout time.Duration `config:"timeout"` - Period time.Duration `config:"period"` - BulkMaxSize int `config:"bulk_max_size" validate:"min=0"` - BufferSize int `config:"buffer_size"` - Tags []string `config:"tags"` + Params map[string]string `config:"parameters"` + Headers map[string]string `config:"headers"` + Username string `config:"username"` + Password string `config:"password"` + ProxyURL string `config:"proxy_url"` + CompressionLevel int `config:"compression_level" validate:"min=0, max=9"` + TLS *tlscommon.Config `config:"ssl"` + MaxRetries int `config:"max_retries"` + Timeout time.Duration `config:"timeout"` + Period time.Duration `config:"period"` + BulkMaxSize int `config:"bulk_max_size" validate:"min=0"` + BufferSize int `config:"buffer_size"` + Tags []string `config:"tags"` } var defaultConfig = config{ diff --git a/libbeat/monitoring/report/elasticsearch/elasticsearch.go b/libbeat/monitoring/report/elasticsearch/elasticsearch.go index a78513b85734..eccedd9e73e4 100644 --- a/libbeat/monitoring/report/elasticsearch/elasticsearch.go +++ b/libbeat/monitoring/report/elasticsearch/elasticsearch.go @@ -10,6 +10,7 @@ import ( "github.com/elastic/beats/libbeat/beat" "github.com/elastic/beats/libbeat/common" + "github.com/elastic/beats/libbeat/common/transport/tlscommon" "github.com/elastic/beats/libbeat/logp" "github.com/elastic/beats/libbeat/monitoring" "github.com/elastic/beats/libbeat/monitoring/report" @@ -72,7 +73,7 @@ func makeReporter(beat beat.Info, cfg *common.Config) (report.Reporter, error) { if proxyURL != nil { logp.Info("Using proxy URL: %s", proxyURL) } - tlsConfig, err := outputs.LoadTLSConfig(config.TLS) + tlsConfig, err := tlscommon.LoadTLSConfig(config.TLS) if err != nil { return nil, err } diff --git a/libbeat/outputs/elasticsearch/config.go b/libbeat/outputs/elasticsearch/config.go index 5e07ec1cb9db..e3e16f6f50b3 100644 --- a/libbeat/outputs/elasticsearch/config.go +++ b/libbeat/outputs/elasticsearch/config.go @@ -3,24 +3,24 @@ package elasticsearch import ( "time" - "github.com/elastic/beats/libbeat/outputs" + "github.com/elastic/beats/libbeat/common/transport/tlscommon" ) type elasticsearchConfig struct { - Protocol string `config:"protocol"` - Path string `config:"path"` - Params map[string]string `config:"parameters"` - Headers map[string]string `config:"headers"` - Username string `config:"username"` - Password string `config:"password"` - ProxyURL string `config:"proxy_url"` - LoadBalance bool `config:"loadbalance"` - CompressionLevel int `config:"compression_level" validate:"min=0, max=9"` - TLS *outputs.TLSConfig `config:"ssl"` - BulkMaxSize int `config:"bulk_max_size"` - MaxRetries int `config:"max_retries"` - Timeout time.Duration `config:"timeout"` - Backoff Backoff `config:"backoff"` + Protocol string `config:"protocol"` + Path string `config:"path"` + Params map[string]string `config:"parameters"` + Headers map[string]string `config:"headers"` + Username string `config:"username"` + Password string `config:"password"` + ProxyURL string `config:"proxy_url"` + LoadBalance bool `config:"loadbalance"` + CompressionLevel int `config:"compression_level" validate:"min=0, max=9"` + TLS *tlscommon.Config `config:"ssl"` + BulkMaxSize int `config:"bulk_max_size"` + MaxRetries int `config:"max_retries"` + Timeout time.Duration `config:"timeout"` + Backoff Backoff `config:"backoff"` } type Backoff struct { diff --git a/libbeat/outputs/elasticsearch/elasticsearch.go b/libbeat/outputs/elasticsearch/elasticsearch.go index 69f2d0125121..163b79b8400f 100644 --- a/libbeat/outputs/elasticsearch/elasticsearch.go +++ b/libbeat/outputs/elasticsearch/elasticsearch.go @@ -7,6 +7,7 @@ import ( "github.com/elastic/beats/libbeat/beat" "github.com/elastic/beats/libbeat/common" + "github.com/elastic/beats/libbeat/common/transport/tlscommon" "github.com/elastic/beats/libbeat/logp" "github.com/elastic/beats/libbeat/outputs" "github.com/elastic/beats/libbeat/outputs/outil" @@ -81,7 +82,7 @@ func makeES( return outputs.Fail(err) } - tlsConfig, err := outputs.LoadTLSConfig(config.TLS) + tlsConfig, err := tlscommon.LoadTLSConfig(config.TLS) if err != nil { return outputs.Fail(err) } @@ -188,7 +189,7 @@ func NewElasticsearchClients(cfg *common.Config) ([]Client, error) { return nil, err } - tlsConfig, err := outputs.LoadTLSConfig(config.TLS) + tlsConfig, err := tlscommon.LoadTLSConfig(config.TLS) if err != nil { return nil, err } diff --git a/libbeat/outputs/kafka/config.go b/libbeat/outputs/kafka/config.go index fab2d680ce1b..ac017ee789e8 100644 --- a/libbeat/outputs/kafka/config.go +++ b/libbeat/outputs/kafka/config.go @@ -8,13 +8,13 @@ import ( "github.com/elastic/beats/libbeat/common" "github.com/elastic/beats/libbeat/common/fmtstr" - "github.com/elastic/beats/libbeat/outputs" + "github.com/elastic/beats/libbeat/common/transport/tlscommon" "github.com/elastic/beats/libbeat/outputs/codec" ) type kafkaConfig struct { Hosts []string `config:"hosts" validate:"required"` - TLS *outputs.TLSConfig `config:"ssl"` + TLS *tlscommon.Config `config:"ssl"` Timeout time.Duration `config:"timeout" validate:"min=1"` Metadata metaConfig `config:"metadata"` Key *fmtstr.EventFormatString `config:"key"` diff --git a/libbeat/outputs/kafka/kafka.go b/libbeat/outputs/kafka/kafka.go index 3756bad665bd..6a8d08eac831 100644 --- a/libbeat/outputs/kafka/kafka.go +++ b/libbeat/outputs/kafka/kafka.go @@ -12,6 +12,7 @@ import ( "github.com/elastic/beats/libbeat/beat" "github.com/elastic/beats/libbeat/common" + "github.com/elastic/beats/libbeat/common/transport/tlscommon" "github.com/elastic/beats/libbeat/logp" "github.com/elastic/beats/libbeat/monitoring" "github.com/elastic/beats/libbeat/monitoring/adapter" @@ -176,7 +177,7 @@ func newKafkaConfig(config *kafkaConfig) (*sarama.Config, error) { k.Net.KeepAlive = config.KeepAlive k.Producer.Timeout = config.BrokerTimeout - tls, err := outputs.LoadTLSConfig(config.TLS) + tls, err := tlscommon.LoadTLSConfig(config.TLS) if err != nil { return nil, err } diff --git a/libbeat/outputs/logstash/config.go b/libbeat/outputs/logstash/config.go index fef7eff8e4bf..fb95f73778f9 100644 --- a/libbeat/outputs/logstash/config.go +++ b/libbeat/outputs/logstash/config.go @@ -3,7 +3,7 @@ package logstash import ( "time" - "github.com/elastic/beats/libbeat/outputs" + "github.com/elastic/beats/libbeat/common/transport/tlscommon" "github.com/elastic/beats/libbeat/outputs/transport" ) @@ -18,7 +18,7 @@ type Config struct { Pipelining int `config:"pipelining" validate:"min=0"` CompressionLevel int `config:"compression_level" validate:"min=0, max=9"` MaxRetries int `config:"max_retries" validate:"min=-1"` - TLS *outputs.TLSConfig `config:"ssl"` + TLS *tlscommon.Config `config:"ssl"` Proxy transport.ProxyConfig `config:",inline"` Backoff Backoff `config:"backoff"` } diff --git a/libbeat/outputs/logstash/logstash.go b/libbeat/outputs/logstash/logstash.go index 8591129a6c30..72165ace6536 100644 --- a/libbeat/outputs/logstash/logstash.go +++ b/libbeat/outputs/logstash/logstash.go @@ -3,6 +3,7 @@ package logstash import ( "github.com/elastic/beats/libbeat/beat" "github.com/elastic/beats/libbeat/common" + "github.com/elastic/beats/libbeat/common/transport/tlscommon" "github.com/elastic/beats/libbeat/logp" "github.com/elastic/beats/libbeat/outputs" "github.com/elastic/beats/libbeat/outputs/transport" @@ -38,7 +39,7 @@ func makeLogstash( return outputs.Fail(err) } - tls, err := outputs.LoadTLSConfig(config.TLS) + tls, err := tlscommon.LoadTLSConfig(config.TLS) if err != nil { return outputs.Fail(err) } diff --git a/libbeat/outputs/redis/config.go b/libbeat/outputs/redis/config.go index 1a5124115da8..a419eb0aeed6 100644 --- a/libbeat/outputs/redis/config.go +++ b/libbeat/outputs/redis/config.go @@ -5,8 +5,8 @@ import ( "fmt" "time" + "github.com/elastic/beats/libbeat/common/transport/tlscommon" "github.com/elastic/beats/libbeat/logp" - "github.com/elastic/beats/libbeat/outputs" "github.com/elastic/beats/libbeat/outputs/codec" "github.com/elastic/beats/libbeat/outputs/transport" ) @@ -20,7 +20,7 @@ type redisConfig struct { Timeout time.Duration `config:"timeout"` BulkMaxSize int `config:"bulk_max_size"` MaxRetries int `config:"max_retries"` - TLS *outputs.TLSConfig `config:"ssl"` + TLS *tlscommon.Config `config:"ssl"` Proxy transport.ProxyConfig `config:",inline"` Codec codec.Config `config:"codec"` Db int `config:"db"` diff --git a/libbeat/outputs/redis/redis.go b/libbeat/outputs/redis/redis.go index bc58e4c351ad..9fd502ea2763 100644 --- a/libbeat/outputs/redis/redis.go +++ b/libbeat/outputs/redis/redis.go @@ -6,6 +6,7 @@ import ( "github.com/elastic/beats/libbeat/beat" "github.com/elastic/beats/libbeat/common" + "github.com/elastic/beats/libbeat/common/transport/tlscommon" "github.com/elastic/beats/libbeat/logp" "github.com/elastic/beats/libbeat/outputs" "github.com/elastic/beats/libbeat/outputs/codec" @@ -80,7 +81,7 @@ func makeRedis( return outputs.Fail(err) } - tls, err := outputs.LoadTLSConfig(config.TLS) + tls, err := tlscommon.LoadTLSConfig(config.TLS) if err != nil { return outputs.Fail(err) } diff --git a/libbeat/outputs/transport/transptest/testing.go b/libbeat/outputs/transport/transptest/testing.go index 795e3b4c96de..369ba2064824 100644 --- a/libbeat/outputs/transport/transptest/testing.go +++ b/libbeat/outputs/transport/transptest/testing.go @@ -14,7 +14,7 @@ import ( "testing" "time" - "github.com/elastic/beats/libbeat/outputs" + "github.com/elastic/beats/libbeat/common/transport/tlscommon" "github.com/elastic/beats/libbeat/outputs/transport" ) @@ -108,8 +108,8 @@ func NewMockServerTLS(t *testing.T, to time.Duration, cert string, proxy *transp t.Fatalf("failed to generate TCP listener") } - tlsConfig, err := outputs.LoadTLSConfig(&outputs.TLSConfig{ - Certificate: outputs.CertificateConfig{ + tlsConfig, err := tlscommon.LoadTLSConfig(&tlscommon.Config{ + Certificate: tlscommon.CertificateConfig{ Certificate: cert + ".pem", Key: cert + ".key", }, @@ -158,7 +158,7 @@ func connectTCP(timeout time.Duration) TransportFactory { func connectTLS(timeout time.Duration, certName string) TransportFactory { return func(addr string, proxy *transport.ProxyConfig) (*transport.Client, error) { - tlsConfig, err := outputs.LoadTLSConfig(&outputs.TLSConfig{ + tlsConfig, err := tlscommon.LoadTLSConfig(&tlscommon.Config{ CAs: []string{certName + ".pem"}, }) if err != nil { diff --git a/libbeat/setup/kibana/client.go b/libbeat/setup/kibana/client.go index 493eb6d89a14..e50a3fc3f91e 100644 --- a/libbeat/setup/kibana/client.go +++ b/libbeat/setup/kibana/client.go @@ -13,8 +13,8 @@ import ( "github.com/pkg/errors" "github.com/elastic/beats/libbeat/common" + "github.com/elastic/beats/libbeat/common/transport/tlscommon" "github.com/elastic/beats/libbeat/logp" - "github.com/elastic/beats/libbeat/outputs" "github.com/elastic/beats/libbeat/outputs/transport" ) @@ -91,7 +91,7 @@ func NewKibanaClient(cfg *common.Config) (*Client, error) { var dialer, tlsDialer transport.Dialer - tlsConfig, err := outputs.LoadTLSConfig(config.TLS) + tlsConfig, err := tlscommon.LoadTLSConfig(config.TLS) if err != nil { return nil, fmt.Errorf("fail to load the TLS config: %v", err) } diff --git a/libbeat/setup/kibana/config.go b/libbeat/setup/kibana/config.go index e18f561d4aef..446f88095ba5 100644 --- a/libbeat/setup/kibana/config.go +++ b/libbeat/setup/kibana/config.go @@ -3,17 +3,17 @@ package kibana import ( "time" - "github.com/elastic/beats/libbeat/outputs" + "github.com/elastic/beats/libbeat/common/transport/tlscommon" ) type kibanaConfig struct { - Protocol string `config:"protocol"` - Host string `config:"host"` - Path string `config:"path"` - Username string `config:"username"` - Password string `config:"password"` - TLS *outputs.TLSConfig `config:"ssl"` - Timeout time.Duration `config:"timeout"` + Protocol string `config:"protocol"` + Host string `config:"host"` + Path string `config:"path"` + Username string `config:"username"` + Password string `config:"password"` + TLS *tlscommon.Config `config:"ssl"` + Timeout time.Duration `config:"timeout"` } var ( diff --git a/metricbeat/helper/http.go b/metricbeat/helper/http.go index e5fbf250ceb9..5534524d2eba 100644 --- a/metricbeat/helper/http.go +++ b/metricbeat/helper/http.go @@ -10,7 +10,7 @@ import ( "net/http" "time" - "github.com/elastic/beats/libbeat/outputs" + "github.com/elastic/beats/libbeat/common/transport/tlscommon" "github.com/elastic/beats/libbeat/outputs/transport" "github.com/elastic/beats/metricbeat/mb" ) @@ -27,9 +27,9 @@ type HTTP struct { // NewHTTP creates new http helper func NewHTTP(base mb.BaseMetricSet) (*HTTP, error) { config := struct { - TLS *outputs.TLSConfig `config:"ssl"` - Timeout time.Duration `config:"timeout"` - Headers map[string]string `config:"headers"` + TLS *tlscommon.Config `config:"ssl"` + Timeout time.Duration `config:"timeout"` + Headers map[string]string `config:"headers"` }{} if err := base.Module().UnpackConfig(&config); err != nil { return nil, err @@ -39,7 +39,7 @@ func NewHTTP(base mb.BaseMetricSet) (*HTTP, error) { config.Headers = map[string]string{} } - tlsConfig, err := outputs.LoadTLSConfig(config.TLS) + tlsConfig, err := tlscommon.LoadTLSConfig(config.TLS) if err != nil { return nil, err } diff --git a/metricbeat/module/kafka/consumergroup/config.go b/metricbeat/module/kafka/consumergroup/config.go index b06710d279a1..11573a9f9fff 100644 --- a/metricbeat/module/kafka/consumergroup/config.go +++ b/metricbeat/module/kafka/consumergroup/config.go @@ -4,16 +4,16 @@ import ( "fmt" "time" - "github.com/elastic/beats/libbeat/outputs" + "github.com/elastic/beats/libbeat/common/transport/tlscommon" ) type metricsetConfig struct { - Retries int `config:"retries" validate:"min=0"` - Backoff time.Duration `config:"backoff" validate:"min=0"` - TLS *outputs.TLSConfig `config:"ssl"` - Username string `config:"username"` - Password string `config:"password"` - ClientID string `config:"client_id"` + Retries int `config:"retries" validate:"min=0"` + Backoff time.Duration `config:"backoff" validate:"min=0"` + TLS *tlscommon.Config `config:"ssl"` + Username string `config:"username"` + Password string `config:"password"` + ClientID string `config:"client_id"` Groups []string `config:"groups"` Topics []string `config:"topics"` diff --git a/metricbeat/module/kafka/consumergroup/consumergroup.go b/metricbeat/module/kafka/consumergroup/consumergroup.go index 97298a351331..6e4b5385843f 100644 --- a/metricbeat/module/kafka/consumergroup/consumergroup.go +++ b/metricbeat/module/kafka/consumergroup/consumergroup.go @@ -5,8 +5,8 @@ import ( "github.com/elastic/beats/libbeat/common" "github.com/elastic/beats/libbeat/common/cfgwarn" + "github.com/elastic/beats/libbeat/common/transport/tlscommon" "github.com/elastic/beats/libbeat/logp" - "github.com/elastic/beats/libbeat/outputs" "github.com/elastic/beats/metricbeat/mb" "github.com/elastic/beats/metricbeat/module/kafka" ) @@ -45,7 +45,7 @@ func New(base mb.BaseMetricSet) (mb.MetricSet, error) { } var tls *tls.Config - tlsCfg, err := outputs.LoadTLSConfig(config.TLS) + tlsCfg, err := tlscommon.LoadTLSConfig(config.TLS) if err != nil { return nil, err } diff --git a/metricbeat/module/kafka/partition/config.go b/metricbeat/module/kafka/partition/config.go index d5880775e4eb..5502b170edf6 100644 --- a/metricbeat/module/kafka/partition/config.go +++ b/metricbeat/module/kafka/partition/config.go @@ -4,17 +4,17 @@ import ( "fmt" "time" - "github.com/elastic/beats/libbeat/outputs" + "github.com/elastic/beats/libbeat/common/transport/tlscommon" ) type connConfig struct { - Retries int `config:"retries" validate:"min=0"` - Backoff time.Duration `config:"backoff" validate:"min=0"` - TLS *outputs.TLSConfig `config:"ssl"` - Username string `config:"username"` - Password string `config:"password"` - ClientID string `config:"client_id"` - Topics []string `config:"topics"` + Retries int `config:"retries" validate:"min=0"` + Backoff time.Duration `config:"backoff" validate:"min=0"` + TLS *tlscommon.Config `config:"ssl"` + Username string `config:"username"` + Password string `config:"password"` + ClientID string `config:"client_id"` + Topics []string `config:"topics"` } var defaultConfig = connConfig{ diff --git a/metricbeat/module/kafka/partition/partition.go b/metricbeat/module/kafka/partition/partition.go index f5f4859f9372..5947efc280cf 100644 --- a/metricbeat/module/kafka/partition/partition.go +++ b/metricbeat/module/kafka/partition/partition.go @@ -6,8 +6,8 @@ import ( "github.com/elastic/beats/libbeat/common" "github.com/elastic/beats/libbeat/common/cfgwarn" + "github.com/elastic/beats/libbeat/common/transport/tlscommon" "github.com/elastic/beats/libbeat/logp" - "github.com/elastic/beats/libbeat/outputs" "github.com/elastic/beats/metricbeat/mb" "github.com/elastic/beats/metricbeat/mb/parse" "github.com/elastic/beats/metricbeat/module/kafka" @@ -47,7 +47,7 @@ func New(base mb.BaseMetricSet) (mb.MetricSet, error) { } var tls *tls.Config - tlsCfg, err := outputs.LoadTLSConfig(config.TLS) + tlsCfg, err := tlscommon.LoadTLSConfig(config.TLS) if err != nil { return nil, err } From cebd3d6ad75228066812b211ed3923ebba95ecb8 Mon Sep 17 00:00:00 2001 From: ph Date: Fri, 4 May 2018 15:04:52 -0400 Subject: [PATCH 5/6] Adding: Developer changelog --- CHANGELOG-developer.asciidoc | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/CHANGELOG-developer.asciidoc b/CHANGELOG-developer.asciidoc index 6019b71dc0fe..228dfd0e5eb5 100644 --- a/CHANGELOG-developer.asciidoc +++ b/CHANGELOG-developer.asciidoc @@ -19,5 +19,9 @@ The list below covers the major changes between 6.3.0 and master only. ==== Breaking changes +*Affecting all Beats* + +- Moving of TLS helper functions and structs from `output/tls` to `tlscommon`. {pull}x[x] + ==== Added From 8b161914140259dd18b7b6ff7c1660be10c7aba5 Mon Sep 17 00:00:00 2001 From: ph Date: Fri, 4 May 2018 15:05:06 -0400 Subject: [PATCH 6/6] Adding: changelog --- CHANGELOG.asciidoc | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.asciidoc b/CHANGELOG.asciidoc index 168cfbcea4d0..649c40c9585e 100644 --- a/CHANGELOG.asciidoc +++ b/CHANGELOG.asciidoc @@ -147,6 +147,7 @@ https://github.com/elastic/beats/compare/v6.0.0-beta2...master[Check the HEAD di - Add support human friendly size for the UDP input. {pull}6886[6886] - Add Syslog input to ingest RFC3164 Events via TCP and UDP {pull}6842[6842] - Support MySQL 5.7.19 by mysql/slowlog {pull}6969[6969] +- Add support for TLS with client authentification to the TCP input {pull}x[x] *Heartbeat*