From 7db848f153f083b5efafc4c3bae177eeafb99f8b Mon Sep 17 00:00:00 2001 From: bugficks Date: Tue, 15 Jan 2019 13:29:56 +0100 Subject: [PATCH 1/5] [Feature request] MySQL SSL CA in datasource connector https://github.com/grafana/grafana/issues/8570 --- pkg/tsdb/mysql/mysql.go | 44 ++++++++++++ .../datasource/mysql/partials/config.html | 68 ++++++++++++++++++- 2 files changed, 110 insertions(+), 2 deletions(-) diff --git a/pkg/tsdb/mysql/mysql.go b/pkg/tsdb/mysql/mysql.go index 35b03e489a0..e713b87e265 100644 --- a/pkg/tsdb/mysql/mysql.go +++ b/pkg/tsdb/mysql/mysql.go @@ -6,6 +6,10 @@ import ( "reflect" "strconv" "strings" + "errors" + + "crypto/x509" + "crypto/tls" "github.com/go-sql-driver/mysql" "github.com/go-xorm/core" @@ -32,6 +36,46 @@ func newMysqlQueryEndpoint(datasource *models.DataSource) (tsdb.TsdbQueryEndpoin datasource.Url, datasource.Database, ) + + var tlsSkipVerify, tlsAuth, tlsAuthWithCACert bool + if datasource.JsonData != nil { + tlsAuth = datasource.JsonData.Get("tlsAuth").MustBool(false) + tlsAuthWithCACert = datasource.JsonData.Get("tlsAuthWithCACert").MustBool(false) + tlsSkipVerify = datasource.JsonData.Get("tlsSkipVerify").MustBool(false) + } + + if tlsAuth || tlsAuthWithCACert { + + secureJsonData := datasource.SecureJsonData.Decrypt() + tlsConfig := tls.Config { + InsecureSkipVerify: tlsSkipVerify, + } + + if tlsAuthWithCACert && len(secureJsonData["tlsCACert"]) > 0 { + + caPool := x509.NewCertPool() + if ok := caPool.AppendCertsFromPEM([]byte(secureJsonData["tlsCACert"])); !ok { + return nil, errors.New("Failed to parse TLS CA PEM certificate") + } + + tlsConfig.RootCAs = caPool + } + + if tlsAuth { + certs, err := tls.X509KeyPair([]byte(secureJsonData["tlsClientCert"]), []byte(secureJsonData["tlsClientKey"])) + if err != nil { + return nil, err + } + clientCert := make([]tls.Certificate, 0, 1) + clientCert = append(clientCert, certs) + + tlsConfig.Certificates = clientCert + } + + mysql.RegisterTLSConfig(datasource.Name, &tlsConfig) + cnnstr += "&tls=" + datasource.Name + } + logger.Debug("getEngine", "connection", cnnstr) config := tsdb.SqlQueryEndpointConfiguration{ diff --git a/public/app/plugins/datasource/mysql/partials/config.html b/public/app/plugins/datasource/mysql/partials/config.html index a35633c626a..5f3ba5c1286 100644 --- a/public/app/plugins/datasource/mysql/partials/config.html +++ b/public/app/plugins/datasource/mysql/partials/config.html @@ -1,4 +1,3 @@ -

MySQL Connection

@@ -22,6 +21,72 @@
+ +
+
+ + +
+
+ +
+
+ +
+
+
TLS Auth Details
+ TLS Certs are encrypted and stored in the Grafana database. +
+
+
+
+ +
+
+ +
+ +
+ + reset +
+
+
+ +
+
+
+ +
+
+ +
+
+ + reset +
+
+ +
+
+ +
+
+ +
+
+ + reset +
+
+
+
Connection limits @@ -84,4 +149,3 @@

- From f31fe495e977cd9fe1c585e25221a423ff9a7c71 Mon Sep 17 00:00:00 2001 From: bugficks Date: Tue, 15 Jan 2019 13:54:25 +0100 Subject: [PATCH 2/5] fix go fmt --- pkg/tsdb/mysql/mysql.go | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/pkg/tsdb/mysql/mysql.go b/pkg/tsdb/mysql/mysql.go index e713b87e265..82e7cac27f0 100644 --- a/pkg/tsdb/mysql/mysql.go +++ b/pkg/tsdb/mysql/mysql.go @@ -2,14 +2,14 @@ package mysql import ( "database/sql" + "errors" "fmt" "reflect" "strconv" "strings" - "errors" - "crypto/x509" "crypto/tls" + "crypto/x509" "github.com/go-sql-driver/mysql" "github.com/go-xorm/core" @@ -47,7 +47,7 @@ func newMysqlQueryEndpoint(datasource *models.DataSource) (tsdb.TsdbQueryEndpoin if tlsAuth || tlsAuthWithCACert { secureJsonData := datasource.SecureJsonData.Decrypt() - tlsConfig := tls.Config { + tlsConfig := tls.Config{ InsecureSkipVerify: tlsSkipVerify, } From 7df5e3cebf06b39c0007bca76c9e86254fc7bc5a Mon Sep 17 00:00:00 2001 From: Marcus Efraimsson Date: Mon, 28 Jan 2019 19:37:19 +0100 Subject: [PATCH 3/5] extract tls auth settings directive from datasource http settings directive --- public/app/features/all.ts | 1 + .../datasources/partials/http_settings.html | 52 +------------- .../partials/tls_auth_settings.html | 62 +++++++++++++++++ .../settings/TlsAuthSettingsCtrl.ts | 10 +++ .../datasource/mysql/partials/config.html | 68 +++---------------- 5 files changed, 84 insertions(+), 109 deletions(-) create mode 100644 public/app/features/datasources/partials/tls_auth_settings.html create mode 100644 public/app/features/datasources/settings/TlsAuthSettingsCtrl.ts diff --git a/public/app/features/all.ts b/public/app/features/all.ts index 83146596ea0..d5e684e4a4e 100644 --- a/public/app/features/all.ts +++ b/public/app/features/all.ts @@ -12,3 +12,4 @@ import './manage-dashboards'; import './teams/CreateTeamCtrl'; import './profile/all'; import './datasources/settings/HttpSettingsCtrl'; +import './datasources/settings/TlsAuthSettingsCtrl'; diff --git a/public/app/features/datasources/partials/http_settings.html b/public/app/features/datasources/partials/http_settings.html index 521e2d3cdc6..b6f2c4fc0dd 100644 --- a/public/app/features/datasources/partials/http_settings.html +++ b/public/app/features/datasources/partials/http_settings.html @@ -101,53 +101,5 @@ -
-
-
TLS Auth Details
- TLS Certs are encrypted and stored in the Grafana database. -
-
-
-
- -
-
- -
- -
- - reset -
-
-
- -
-
-
- -
-
- -
-
- - reset -
-
- -
-
- -
-
- -
-
- - reset -
-
-
-
- + + \ No newline at end of file diff --git a/public/app/features/datasources/partials/tls_auth_settings.html b/public/app/features/datasources/partials/tls_auth_settings.html new file mode 100644 index 00000000000..c852e8ec70c --- /dev/null +++ b/public/app/features/datasources/partials/tls_auth_settings.html @@ -0,0 +1,62 @@ +
+
+
TLS Auth Details
+ TLS Certs are encrypted and stored in the Grafana database. +
+
+
+
+
+ +
+ +
+ + reset +
+
+
+ +
+
+
+
+ +
+
+ + reset +
+
+ +
+
+
+ +
+
+ + reset +
+
+
+
diff --git a/public/app/features/datasources/settings/TlsAuthSettingsCtrl.ts b/public/app/features/datasources/settings/TlsAuthSettingsCtrl.ts new file mode 100644 index 00000000000..7c21fab404c --- /dev/null +++ b/public/app/features/datasources/settings/TlsAuthSettingsCtrl.ts @@ -0,0 +1,10 @@ +import { coreModule } from 'app/core/core'; + +coreModule.directive('datasourceTlsAuthSettings', () => { + return { + scope: { + current: '=', + }, + templateUrl: 'public/app/features/datasources/partials/tls_auth_settings.html', + }; +}); diff --git a/public/app/plugins/datasource/mysql/partials/config.html b/public/app/plugins/datasource/mysql/partials/config.html index 5f3ba5c1286..8221a06e1ee 100644 --- a/public/app/plugins/datasource/mysql/partials/config.html +++ b/public/app/plugins/datasource/mysql/partials/config.html @@ -24,70 +24,20 @@
- - + +
- +
-
-
-
TLS Auth Details
- TLS Certs are encrypted and stored in the Grafana database. -
-
-
-
- -
-
- -
- -
- - reset -
-
-
- -
-
-
- -
-
- -
-
- - reset -
-
- -
-
- -
-
- -
-
- - reset -
-
-
-
- + + Connection limits From f157c19e16cdc970542867ec77eb5a61fe5f11ad Mon Sep 17 00:00:00 2001 From: Marcus Efraimsson Date: Mon, 28 Jan 2019 19:38:56 +0100 Subject: [PATCH 4/5] extract parsing of datasource tls config to method --- pkg/models/datasource_cache.go | 48 +++++++++++++++++++++------------- pkg/tsdb/mysql/mysql.go | 43 ++++-------------------------- 2 files changed, 35 insertions(+), 56 deletions(-) diff --git a/pkg/models/datasource_cache.go b/pkg/models/datasource_cache.go index 66ba66e4d39..1c895514ace 100644 --- a/pkg/models/datasource_cache.go +++ b/pkg/models/datasource_cache.go @@ -46,19 +46,16 @@ func (ds *DataSource) GetHttpTransport() (*http.Transport, error) { return t.Transport, nil } - var tlsSkipVerify, tlsClientAuth, tlsAuthWithCACert bool - if ds.JsonData != nil { - tlsClientAuth = ds.JsonData.Get("tlsAuth").MustBool(false) - tlsAuthWithCACert = ds.JsonData.Get("tlsAuthWithCACert").MustBool(false) - tlsSkipVerify = ds.JsonData.Get("tlsSkipVerify").MustBool(false) + tlsConfig, err := ds.GetTLSConfig() + if err != nil { + return nil, err } + tlsConfig.Renegotiation = tls.RenegotiateFreelyAsClient + transport := &http.Transport{ - TLSClientConfig: &tls.Config{ - InsecureSkipVerify: tlsSkipVerify, - Renegotiation: tls.RenegotiateFreelyAsClient, - }, - Proxy: http.ProxyFromEnvironment, + TLSClientConfig: tlsConfig, + Proxy: http.ProxyFromEnvironment, Dial: (&net.Dialer{ Timeout: 30 * time.Second, KeepAlive: 30 * time.Second, @@ -70,6 +67,26 @@ func (ds *DataSource) GetHttpTransport() (*http.Transport, error) { IdleConnTimeout: 90 * time.Second, } + ptc.cache[ds.Id] = cachedTransport{ + Transport: transport, + updated: ds.Updated, + } + + return transport, nil +} + +func (ds *DataSource) GetTLSConfig() (*tls.Config, error) { + var tlsSkipVerify, tlsClientAuth, tlsAuthWithCACert bool + if ds.JsonData != nil { + tlsClientAuth = ds.JsonData.Get("tlsAuth").MustBool(false) + tlsAuthWithCACert = ds.JsonData.Get("tlsAuthWithCACert").MustBool(false) + tlsSkipVerify = ds.JsonData.Get("tlsSkipVerify").MustBool(false) + } + + tlsConfig := &tls.Config{ + InsecureSkipVerify: tlsSkipVerify, + } + if tlsClientAuth || tlsAuthWithCACert { decrypted := ds.SecureJsonData.Decrypt() if tlsAuthWithCACert && len(decrypted["tlsCACert"]) > 0 { @@ -78,7 +95,7 @@ func (ds *DataSource) GetHttpTransport() (*http.Transport, error) { if !ok { return nil, errors.New("Failed to parse TLS CA PEM certificate") } - transport.TLSClientConfig.RootCAs = caPool + tlsConfig.RootCAs = caPool } if tlsClientAuth { @@ -86,14 +103,9 @@ func (ds *DataSource) GetHttpTransport() (*http.Transport, error) { if err != nil { return nil, err } - transport.TLSClientConfig.Certificates = []tls.Certificate{cert} + tlsConfig.Certificates = []tls.Certificate{cert} } } - ptc.cache[ds.Id] = cachedTransport{ - Transport: transport, - updated: ds.Updated, - } - - return transport, nil + return tlsConfig, nil } diff --git a/pkg/tsdb/mysql/mysql.go b/pkg/tsdb/mysql/mysql.go index 82e7cac27f0..d451150f1de 100644 --- a/pkg/tsdb/mysql/mysql.go +++ b/pkg/tsdb/mysql/mysql.go @@ -2,15 +2,11 @@ package mysql import ( "database/sql" - "errors" "fmt" "reflect" "strconv" "strings" - "crypto/tls" - "crypto/x509" - "github.com/go-sql-driver/mysql" "github.com/go-xorm/core" "github.com/grafana/grafana/pkg/log" @@ -37,42 +33,13 @@ func newMysqlQueryEndpoint(datasource *models.DataSource) (tsdb.TsdbQueryEndpoin datasource.Database, ) - var tlsSkipVerify, tlsAuth, tlsAuthWithCACert bool - if datasource.JsonData != nil { - tlsAuth = datasource.JsonData.Get("tlsAuth").MustBool(false) - tlsAuthWithCACert = datasource.JsonData.Get("tlsAuthWithCACert").MustBool(false) - tlsSkipVerify = datasource.JsonData.Get("tlsSkipVerify").MustBool(false) + tlsConfig, err := datasource.GetTLSConfig() + if err != nil { + return nil, err } - if tlsAuth || tlsAuthWithCACert { - - secureJsonData := datasource.SecureJsonData.Decrypt() - tlsConfig := tls.Config{ - InsecureSkipVerify: tlsSkipVerify, - } - - if tlsAuthWithCACert && len(secureJsonData["tlsCACert"]) > 0 { - - caPool := x509.NewCertPool() - if ok := caPool.AppendCertsFromPEM([]byte(secureJsonData["tlsCACert"])); !ok { - return nil, errors.New("Failed to parse TLS CA PEM certificate") - } - - tlsConfig.RootCAs = caPool - } - - if tlsAuth { - certs, err := tls.X509KeyPair([]byte(secureJsonData["tlsClientCert"]), []byte(secureJsonData["tlsClientKey"])) - if err != nil { - return nil, err - } - clientCert := make([]tls.Certificate, 0, 1) - clientCert = append(clientCert, certs) - - tlsConfig.Certificates = clientCert - } - - mysql.RegisterTLSConfig(datasource.Name, &tlsConfig) + if tlsConfig.RootCAs != nil || len(tlsConfig.Certificates) > 0 { + mysql.RegisterTLSConfig(datasource.Name, tlsConfig) cnnstr += "&tls=" + datasource.Name } From 1bc2a0af70304bee4b4a18beb5865c604cf2a942 Mon Sep 17 00:00:00 2001 From: Marcus Efraimsson Date: Fri, 8 Feb 2019 18:08:07 +0100 Subject: [PATCH 5/5] use unique datasource id when registering mysql tls config --- pkg/tsdb/mysql/mysql.go | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/pkg/tsdb/mysql/mysql.go b/pkg/tsdb/mysql/mysql.go index d451150f1de..d307e12166c 100644 --- a/pkg/tsdb/mysql/mysql.go +++ b/pkg/tsdb/mysql/mysql.go @@ -39,8 +39,9 @@ func newMysqlQueryEndpoint(datasource *models.DataSource) (tsdb.TsdbQueryEndpoin } if tlsConfig.RootCAs != nil || len(tlsConfig.Certificates) > 0 { - mysql.RegisterTLSConfig(datasource.Name, tlsConfig) - cnnstr += "&tls=" + datasource.Name + tlsConfigString := fmt.Sprintf("ds%d", datasource.Id) + mysql.RegisterTLSConfig(tlsConfigString, tlsConfig) + cnnstr += "&tls=" + tlsConfigString } logger.Debug("getEngine", "connection", cnnstr)