mirror of
https://github.com/grafana/grafana.git
synced 2025-02-25 18:55:37 -06:00
Verify datasource TLS and split client auth and CA
This commit is contained in:
@@ -47,8 +47,7 @@ func (ds *DataSource) GetHttpTransport() (*http.Transport, error) {
|
|||||||
|
|
||||||
transport := &http.Transport{
|
transport := &http.Transport{
|
||||||
TLSClientConfig: &tls.Config{
|
TLSClientConfig: &tls.Config{
|
||||||
InsecureSkipVerify: true,
|
Renegotiation: tls.RenegotiateFreelyAsClient,
|
||||||
Renegotiation: tls.RenegotiateFreelyAsClient,
|
|
||||||
},
|
},
|
||||||
Proxy: http.ProxyFromEnvironment,
|
Proxy: http.ProxyFromEnvironment,
|
||||||
Dial: (&net.Dialer{
|
Dial: (&net.Dialer{
|
||||||
@@ -62,15 +61,13 @@ func (ds *DataSource) GetHttpTransport() (*http.Transport, error) {
|
|||||||
IdleConnTimeout: 90 * time.Second,
|
IdleConnTimeout: 90 * time.Second,
|
||||||
}
|
}
|
||||||
|
|
||||||
var tlsAuth, tlsAuthWithCACert bool
|
var tlsClientAuth, tlsAuthWithCACert bool
|
||||||
if ds.JsonData != nil {
|
if ds.JsonData != nil {
|
||||||
tlsAuth = ds.JsonData.Get("tlsAuth").MustBool(false)
|
tlsClientAuth = ds.JsonData.Get("tlsClientAuth").MustBool(false)
|
||||||
tlsAuthWithCACert = ds.JsonData.Get("tlsAuthWithCACert").MustBool(false)
|
tlsAuthWithCACert = ds.JsonData.Get("tlsAuthWithCACert").MustBool(false)
|
||||||
}
|
}
|
||||||
|
|
||||||
if tlsAuth {
|
if tlsClientAuth || tlsAuthWithCACert {
|
||||||
transport.TLSClientConfig.InsecureSkipVerify = false
|
|
||||||
|
|
||||||
decrypted := ds.SecureJsonData.Decrypt()
|
decrypted := ds.SecureJsonData.Decrypt()
|
||||||
|
|
||||||
if tlsAuthWithCACert && len(decrypted["tlsCACert"]) > 0 {
|
if tlsAuthWithCACert && len(decrypted["tlsCACert"]) > 0 {
|
||||||
@@ -81,11 +78,13 @@ func (ds *DataSource) GetHttpTransport() (*http.Transport, error) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
cert, err := tls.X509KeyPair([]byte(decrypted["tlsClientCert"]), []byte(decrypted["tlsClientKey"]))
|
if tlsClientAuth {
|
||||||
if err != nil {
|
cert, err := tls.X509KeyPair([]byte(decrypted["tlsClientCert"]), []byte(decrypted["tlsClientKey"]))
|
||||||
return nil, err
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
transport.TLSClientConfig.Certificates = []tls.Certificate{cert}
|
||||||
}
|
}
|
||||||
transport.TLSClientConfig.Certificates = []tls.Certificate{cert}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
ptc.cache[ds.Id] = cachedTransport{
|
ptc.cache[ds.Id] = cachedTransport{
|
||||||
|
|||||||
@@ -36,7 +36,7 @@ func TestDataSourceCache(t *testing.T) {
|
|||||||
setting.SecretKey = "password"
|
setting.SecretKey = "password"
|
||||||
|
|
||||||
json := simplejson.New()
|
json := simplejson.New()
|
||||||
json.Set("tlsAuth", true)
|
json.Set("tlsClientAuth", true)
|
||||||
json.Set("tlsAuthWithCACert", true)
|
json.Set("tlsAuthWithCACert", true)
|
||||||
|
|
||||||
t := time.Now()
|
t := time.Now()
|
||||||
@@ -49,8 +49,8 @@ func TestDataSourceCache(t *testing.T) {
|
|||||||
transport, err := ds.GetHttpTransport()
|
transport, err := ds.GetHttpTransport()
|
||||||
So(err, ShouldBeNil)
|
So(err, ShouldBeNil)
|
||||||
|
|
||||||
Convey("Should disable TLS certificate verification", func() {
|
Convey("Should verify TLS certificates by default", func() {
|
||||||
So(transport.TLSClientConfig.InsecureSkipVerify, ShouldEqual, true)
|
So(transport.TLSClientConfig.InsecureSkipVerify, ShouldEqual, false)
|
||||||
})
|
})
|
||||||
|
|
||||||
ds.JsonData = json
|
ds.JsonData = json
|
||||||
@@ -69,7 +69,7 @@ func TestDataSourceCache(t *testing.T) {
|
|||||||
transport, err = ds.GetHttpTransport()
|
transport, err = ds.GetHttpTransport()
|
||||||
So(err, ShouldBeNil)
|
So(err, ShouldBeNil)
|
||||||
|
|
||||||
Convey("Should add cert and enable TLS certificate verification", func() {
|
Convey("Should add cert and verify TLS certificates", func() {
|
||||||
So(transport.TLSClientConfig.InsecureSkipVerify, ShouldEqual, false)
|
So(transport.TLSClientConfig.InsecureSkipVerify, ShouldEqual, false)
|
||||||
So(len(transport.TLSClientConfig.Certificates), ShouldEqual, 1)
|
So(len(transport.TLSClientConfig.Certificates), ShouldEqual, 1)
|
||||||
})
|
})
|
||||||
@@ -81,8 +81,8 @@ func TestDataSourceCache(t *testing.T) {
|
|||||||
transport, err = ds.GetHttpTransport()
|
transport, err = ds.GetHttpTransport()
|
||||||
So(err, ShouldBeNil)
|
So(err, ShouldBeNil)
|
||||||
|
|
||||||
Convey("Should remove cert and disable TLS certificate vertification", func() {
|
Convey("Should remove cert but still verify TLS certificates", func() {
|
||||||
So(transport.TLSClientConfig.InsecureSkipVerify, ShouldEqual, true)
|
So(transport.TLSClientConfig.InsecureSkipVerify, ShouldEqual, false)
|
||||||
So(len(transport.TLSClientConfig.Certificates), ShouldEqual, 0)
|
So(len(transport.TLSClientConfig.Certificates), ShouldEqual, 0)
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -44,7 +44,7 @@
|
|||||||
<gf-form-switch class="gf-form" label="With Credentials" tooltip="Whether credentials such as cookies or auth headers should be sent with cross-site requests." checked="current.withCredentials" label-class="width-11" switch-class="max-width-6"></gf-form-switch>
|
<gf-form-switch class="gf-form" label="With Credentials" tooltip="Whether credentials such as cookies or auth headers should be sent with cross-site requests." checked="current.withCredentials" label-class="width-11" switch-class="max-width-6"></gf-form-switch>
|
||||||
</div>
|
</div>
|
||||||
<div class="gf-form-inline">
|
<div class="gf-form-inline">
|
||||||
<gf-form-switch class="gf-form" ng-if="current.access=='proxy'" label="TLS Client Auth" label-class="width-8" checked="current.jsonData.tlsAuth" switch-class="max-width-6"></gf-form-switch>
|
<gf-form-switch class="gf-form" ng-if="current.access=='proxy'" label="TLS Client Auth" label-class="width-8" checked="current.jsonData.tlsClientAuth" switch-class="max-width-6"></gf-form-switch>
|
||||||
<gf-form-switch class="gf-form" ng-if="current.access=='proxy'" label="With CA Cert" tooltip="Optional. Needed for self-signed TLS Certs." checked="current.jsonData.tlsAuthWithCACert" label-class="width-11" switch-class="max-width-6"></gf-form-switch>
|
<gf-form-switch class="gf-form" ng-if="current.access=='proxy'" label="With CA Cert" tooltip="Optional. Needed for self-signed TLS Certs." checked="current.jsonData.tlsAuthWithCACert" label-class="width-11" switch-class="max-width-6"></gf-form-switch>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -66,7 +66,7 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="gf-form-group" ng-if="current.jsonData.tlsAuth && current.access=='proxy'">
|
<div class="gf-form-group" ng-if="(current.jsonData.tlsClientAuth || current.jsonData.tlsAuthWithCACert) && current.access=='proxy'">
|
||||||
<div class="gf-form">
|
<div class="gf-form">
|
||||||
<h6>TLS Auth Details</h6>
|
<h6>TLS Auth Details</h6>
|
||||||
<info-popover mode="header">TLS Certs are encrypted and stored in the Grafana database.</info-popover>
|
<info-popover mode="header">TLS Certs are encrypted and stored in the Grafana database.</info-popover>
|
||||||
@@ -87,29 +87,31 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="gf-form-inline">
|
<div ng-if="current.jsonData.tlsClientAuth">
|
||||||
<div class="gf-form gf-form--v-stretch">
|
<div class="gf-form-inline">
|
||||||
<label class="gf-form-label width-7">Client Cert</label>
|
<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>
|
||||||
<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-inline">
|
||||||
<div class="gf-form gf-form--v-stretch">
|
<div class="gf-form gf-form--v-stretch">
|
||||||
<label class="gf-form-label width-7">Client Key</label>
|
<label class="gf-form-label width-7">Client Key</label>
|
||||||
</div>
|
</div>
|
||||||
<div class="gf-form gf-form--grow" ng-if="!current.secureJsonFields.tlsClientKey">
|
<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>
|
<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>
|
||||||
<div class="gf-form" ng-if="current.secureJsonFields.tlsClientKey">
|
<div class="gf-form" ng-if="current.secureJsonFields.tlsClientKey">
|
||||||
<input type="text" class="gf-form-input max-width-12" disabled="disabled" value="configured">
|
<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>
|
<a class="btn btn-secondary gf-form-btn" href="#" ng-click="current.secureJsonFields.tlsClientKey = false">reset</a>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
Reference in New Issue
Block a user