Browse Source

[Feature request] MySQL SSL CA in datasource connector
https://github.com/grafana/grafana/issues/8570

bugficks 7 years ago
parent
commit
7db848f153
2 changed files with 110 additions and 2 deletions
  1. 44 0
      pkg/tsdb/mysql/mysql.go
  2. 66 2
      public/app/plugins/datasource/mysql/partials/config.html

+ 44 - 0
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{

+ 66 - 2
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,6 +21,72 @@
 			<input type="password" class="gf-form-input" ng-model='ctrl.current.password' placeholder="password"></input>
 		</div>
 	</div>
+
+	<div class="gf-form-group">
+		<div class="gf-form-inline">
+			<gf-form-switch class="gf-form" label="TLS Client Auth" label-class="width-10" checked="ctrl.current.jsonData.tlsAuth"
+				switch-class="max-width-6"></gf-form-switch>
+			<gf-form-switch 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-switch>
+		</div>
+		<div class="gf-form-inline">
+			<gf-form-switch class="gf-form" label="Skip TLS Verify" label-class="width-10" checked="ctrl.current.jsonData.tlsSkipVerify"
+				switch-class="max-width-6"></gf-form-switch>
+		</div>
+	</div>
+
+	<div class="gf-form-group" ng-if="(ctrl.current.jsonData.tlsAuth || ctrl.current.jsonData.tlsAuthWithCACert)">
+		<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="ctrl.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="!ctrl.current.secureJsonFields.tlsCACert">
+					<textarea rows="7" class="gf-form-input gf-form-textarea" ng-model="ctrl.current.secureJsonData.tlsCACert"
+						placeholder="Begins with -----BEGIN CERTIFICATE-----"></textarea>
+				</div>
+
+				<div class="gf-form" ng-if="ctrl.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="ctrl.current.secureJsonFields.tlsCACert = false">reset</a>
+				</div>
+			</div>
+		</div>
+
+		<div ng-if="ctrl.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="!ctrl.current.secureJsonFields.tlsClientCert">
+					<textarea rows="7" class="gf-form-input gf-form-textarea" ng-model="ctrl.current.secureJsonData.tlsClientCert"
+						placeholder="Begins with -----BEGIN CERTIFICATE-----" required></textarea>
+				</div>
+				<div class="gf-form" ng-if="ctrl.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="ctrl.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="!ctrl.current.secureJsonFields.tlsClientKey">
+					<textarea rows="7" class="gf-form-input gf-form-textarea" ng-model="ctrl.current.secureJsonData.tlsClientKey"
+						placeholder="Begins with -----BEGIN RSA PRIVATE KEY-----" required></textarea>
+				</div>
+				<div class="gf-form" ng-if="ctrl.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="ctrl.current.secureJsonFields.tlsClientKey = false">reset</a>
+				</div>
+			</div>
+		</div>
+	</div>
 </div>
 
 <b>Connection limits</b>
@@ -84,4 +149,3 @@
 		</p>
 	</div>
 </div>
-