Просмотр исходного кода

Merge pull request #14888 from bugficks/8570-mysql-ssl-datasource

MySQL SSL CA in datasource connector
Marcus Efraimsson 6 лет назад
Родитель
Сommit
75f89ecf1f

+ 30 - 18
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
 }

+ 12 - 0
pkg/tsdb/mysql/mysql.go

@@ -32,6 +32,18 @@ func newMysqlQueryEndpoint(datasource *models.DataSource) (tsdb.TsdbQueryEndpoin
 		datasource.Url,
 		datasource.Database,
 	)
+
+	tlsConfig, err := datasource.GetTLSConfig()
+	if err != nil {
+		return nil, err
+	}
+
+	if tlsConfig.RootCAs != nil || len(tlsConfig.Certificates) > 0 {
+		tlsConfigString := fmt.Sprintf("ds%d", datasource.Id)
+		mysql.RegisterTLSConfig(tlsConfigString, tlsConfig)
+		cnnstr += "&tls=" + tlsConfigString
+	}
+
 	logger.Debug("getEngine", "connection", cnnstr)
 
 	config := tsdb.SqlQueryEndpointConfiguration{

+ 1 - 0
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';

+ 2 - 50
public/app/features/datasources/partials/http_settings.html

@@ -101,53 +101,5 @@
 		</div>
 	</div>
 
-	<div class="gf-form-group" ng-if="(current.jsonData.tlsAuth || current.jsonData.tlsAuthWithCACert) && current.access=='proxy'">
-		<div class="gf-form">
-			<h6>TLS Auth Details</h6>
-			<info-popover mode="header">TLS Certs are encrypted and stored in the Grafana database.</info-popover>
-		</div>
-		<div ng-if="current.jsonData.tlsAuthWithCACert">
-			<div class="gf-form-inline">
-				<div class="gf-form gf-form--v-stretch">
-					<label class="gf-form-label width-7">CA Cert</label>
-				</div>
-				<div class="gf-form gf-form--grow" ng-if="!current.secureJsonFields.tlsCACert">
-					<textarea rows="7" class="gf-form-input gf-form-textarea" ng-model="current.secureJsonData.tlsCACert" placeholder="Begins with -----BEGIN CERTIFICATE-----"></textarea>
-				</div>
-
-				<div class="gf-form" ng-if="current.secureJsonFields.tlsCACert">
-					<input type="text" class="gf-form-input max-width-12" disabled="disabled" value="configured">
-					<a class="btn btn-secondary gf-form-btn" href="#" ng-click="current.secureJsonFields.tlsCACert = false">reset</a>
-				</div>
-			</div>
-		</div>
-
-		<div ng-if="current.jsonData.tlsAuth">
-		<div class="gf-form-inline">
-			<div class="gf-form gf-form--v-stretch">
-				<label class="gf-form-label width-7">Client Cert</label>
-			</div>
-			<div class="gf-form gf-form--grow" ng-if="!current.secureJsonFields.tlsClientCert">
-				<textarea rows="7" class="gf-form-input gf-form-textarea" ng-model="current.secureJsonData.tlsClientCert" placeholder="Begins with -----BEGIN CERTIFICATE-----" required></textarea>
-			</div>
-			<div class="gf-form" ng-if="current.secureJsonFields.tlsClientCert">
-				<input type="text" class="gf-form-input max-width-12" disabled="disabled" value="configured">
-				<a class="btn btn-secondary gf-form-btn" href="#" ng-click="current.secureJsonFields.tlsClientCert = false">reset</a>
-			</div>
-		</div>
-
-		<div class="gf-form-inline">
-			<div class="gf-form gf-form--v-stretch">
-				<label class="gf-form-label width-7">Client Key</label>
-			</div>
-			<div class="gf-form gf-form--grow" ng-if="!current.secureJsonFields.tlsClientKey">
-				<textarea rows="7" class="gf-form-input gf-form-textarea" ng-model="current.secureJsonData.tlsClientKey" placeholder="Begins with -----BEGIN RSA PRIVATE KEY-----" required></textarea>
-			</div>
-			<div class="gf-form" ng-if="current.secureJsonFields.tlsClientKey">
-				<input type="text" class="gf-form-input max-width-12" disabled="disabled" value="configured">
-				<a class="btn btn-secondary gf-form-btn" href="#" ng-click="current.secureJsonFields.tlsClientKey = false">reset</a>
-			</div>
-		</div>
-	</div>
-</div>
-
+<datasource-tls-auth-settings current="current" ng-if="(current.jsonData.tlsAuth || current.jsonData.tlsAuthWithCACert) && current.access=='proxy'">
+</datasource-tls-auth-settings>

+ 62 - 0
public/app/features/datasources/partials/tls_auth_settings.html

@@ -0,0 +1,62 @@
+<div class="gf-form-group">
+  <div class="gf-form">
+    <h6>TLS Auth Details</h6>
+    <info-popover mode="header">TLS Certs are encrypted and stored in the Grafana database.</info-popover>
+  </div>
+  <div ng-if="current.jsonData.tlsAuthWithCACert">
+    <div class="gf-form-inline">
+      <div class="gf-form gf-form--v-stretch"><label class="gf-form-label width-7">CA Cert</label></div>
+      <div class="gf-form gf-form--grow" ng-if="!current.secureJsonFields.tlsCACert">
+        <textarea
+          rows="7"
+          class="gf-form-input gf-form-textarea"
+          ng-model="current.secureJsonData.tlsCACert"
+          placeholder="Begins with -----BEGIN CERTIFICATE-----"
+        ></textarea>
+      </div>
+
+      <div class="gf-form" ng-if="current.secureJsonFields.tlsCACert">
+        <input type="text" class="gf-form-input max-width-12" disabled="disabled" value="configured" />
+        <a class="btn btn-secondary gf-form-btn" href="#" ng-click="current.secureJsonFields.tlsCACert = false">reset</a>
+      </div>
+    </div>
+  </div>
+
+  <div ng-if="current.jsonData.tlsAuth">
+    <div class="gf-form-inline">
+      <div class="gf-form gf-form--v-stretch"><label class="gf-form-label width-7">Client Cert</label></div>
+      <div class="gf-form gf-form--grow" ng-if="!current.secureJsonFields.tlsClientCert">
+        <textarea
+          rows="7"
+          class="gf-form-input gf-form-textarea"
+          ng-model="current.secureJsonData.tlsClientCert"
+          placeholder="Begins with -----BEGIN CERTIFICATE-----"
+          required
+        ></textarea>
+      </div>
+      <div class="gf-form" ng-if="current.secureJsonFields.tlsClientCert">
+        <input type="text" class="gf-form-input max-width-12" disabled="disabled" value="configured" />
+        <a class="btn btn-secondary gf-form-btn" href="#" ng-click="current.secureJsonFields.tlsClientCert = false"
+          >reset</a
+        >
+      </div>
+    </div>
+
+    <div class="gf-form-inline">
+      <div class="gf-form gf-form--v-stretch"><label class="gf-form-label width-7">Client Key</label></div>
+      <div class="gf-form gf-form--grow" ng-if="!current.secureJsonFields.tlsClientKey">
+        <textarea
+          rows="7"
+          class="gf-form-input gf-form-textarea"
+          ng-model="current.secureJsonData.tlsClientKey"
+          placeholder="Begins with -----BEGIN RSA PRIVATE KEY-----"
+          required
+        ></textarea>
+      </div>
+      <div class="gf-form" ng-if="current.secureJsonFields.tlsClientKey">
+        <input type="text" class="gf-form-input max-width-12" disabled="disabled" value="configured" />
+        <a class="btn btn-secondary gf-form-btn" href="#" ng-click="current.secureJsonFields.tlsClientKey = false">reset</a>
+      </div>
+    </div>
+  </div>
+</div>

+ 10 - 0
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',
+  };
+});

+ 17 - 3
public/app/plugins/datasource/mysql/partials/config.html

@@ -1,4 +1,3 @@
-
 <h3 class="page-heading">MySQL Connection</h3>
 
 <div class="gf-form-group">
@@ -22,7 +21,23 @@
 			<input type="password" class="gf-form-input" ng-model='ctrl.current.password' placeholder="password"></input>
 		</div>
 	</div>
-</div>
+
+	<div class="gf-form-group">
+		<div class="gf-form-inline">
+			<gf-form-checkbox class="gf-form" label="TLS Client Auth" label-class="width-10"
+				checked="ctrl.current.jsonData.tlsAuth" switch-class="max-width-6"></gf-form-checkbox>
+			<gf-form-checkbox class="gf-form" label="With CA Cert" tooltip="Needed for
+				verifing self-signed TLS Certs" checked="ctrl.current.jsonData.tlsAuthWithCACert" label-class="width-11"
+				switch-class="max-width-6"></gf-form-checkbox>
+		</div>
+		<div class="gf-form-inline">
+			<gf-form-checkbox class="gf-form" label="Skip TLS Verify" label-class="width-10"
+				checked="ctrl.current.jsonData.tlsSkipVerify" switch-class="max-width-6"></gf-form-checkbox>
+		</div>
+	</div>
+
+<datasource-tls-auth-settings current="ctrl.current" ng-if="(ctrl.current.jsonData.tlsAuth || ctrl.current.jsonData.tlsAuthWithCACert)">
+</datasource-tls-auth-settings>
 
 <b>Connection limits</b>
 
@@ -84,4 +99,3 @@
 		</p>
 	</div>
 </div>
-