Commit 5d312be4 by Matt Bostock

Datasource HTTP settings: Add TLS skip verify

In c04d95f35 I changed the default for datasource HTTP requests so that
TLS is always verified.

This commit adds a checkbox to allow an admin to explicitly skip TLS
verification, for testing purposes.
parent ef52d956
...@@ -45,9 +45,17 @@ func (ds *DataSource) GetHttpTransport() (*http.Transport, error) { ...@@ -45,9 +45,17 @@ func (ds *DataSource) GetHttpTransport() (*http.Transport, error) {
return t.Transport, nil return t.Transport, nil
} }
var tlsSkipVerify, tlsClientAuth, tlsAuthWithCACert bool
if ds.JsonData != nil {
tlsClientAuth = ds.JsonData.Get("tlsClientAuth").MustBool(false)
tlsAuthWithCACert = ds.JsonData.Get("tlsAuthWithCACert").MustBool(false)
tlsSkipVerify = ds.JsonData.Get("tlsSkipVerify").MustBool(false)
}
transport := &http.Transport{ transport := &http.Transport{
TLSClientConfig: &tls.Config{ TLSClientConfig: &tls.Config{
Renegotiation: tls.RenegotiateFreelyAsClient, InsecureSkipVerify: tlsSkipVerify,
Renegotiation: tls.RenegotiateFreelyAsClient,
}, },
Proxy: http.ProxyFromEnvironment, Proxy: http.ProxyFromEnvironment,
Dial: (&net.Dialer{ Dial: (&net.Dialer{
...@@ -61,12 +69,6 @@ func (ds *DataSource) GetHttpTransport() (*http.Transport, error) { ...@@ -61,12 +69,6 @@ func (ds *DataSource) GetHttpTransport() (*http.Transport, error) {
IdleConnTimeout: 90 * time.Second, IdleConnTimeout: 90 * time.Second,
} }
var tlsClientAuth, tlsAuthWithCACert bool
if ds.JsonData != nil {
tlsClientAuth = ds.JsonData.Get("tlsClientAuth").MustBool(false)
tlsAuthWithCACert = ds.JsonData.Get("tlsAuthWithCACert").MustBool(false)
}
if tlsClientAuth || tlsAuthWithCACert { if tlsClientAuth || tlsAuthWithCACert {
decrypted := ds.SecureJsonData.Decrypt() decrypted := ds.SecureJsonData.Decrypt()
......
...@@ -29,61 +29,140 @@ func TestDataSourceCache(t *testing.T) { ...@@ -29,61 +29,140 @@ func TestDataSourceCache(t *testing.T) {
Convey("Should be using the cached proxy", func() { Convey("Should be using the cached proxy", func() {
So(t2, ShouldEqual, t1) So(t2, ShouldEqual, t1)
}) })
Convey("Should verify TLS by default", func() {
So(t1.TLSClientConfig.InsecureSkipVerify, ShouldEqual, false)
})
Convey("Should have no TLS client certificate configured", func() {
So(len(t1.TLSClientConfig.Certificates), ShouldEqual, 0)
})
Convey("Should have no user-supplied TLS CA onfigured", func() {
So(t1.TLSClientConfig.RootCAs, ShouldBeNil)
})
}) })
Convey("When getting kubernetes datasource proxy", t, func() { Convey("When caching a datasource proxy then updating it", t, func() {
clearCache() clearCache()
setting.SecretKey = "password" setting.SecretKey = "password"
json := simplejson.New() json := simplejson.New()
json.Set("tlsClientAuth", true)
json.Set("tlsAuthWithCACert", true) json.Set("tlsAuthWithCACert", true)
t := time.Now() tlsCaCert, err := util.Encrypt([]byte(caCert), "password")
So(err, ShouldBeNil)
ds := DataSource{
Id: 1,
Url: "http://k8s:8001",
Type: "Kubernetes",
SecureJsonData: map[string][]byte{"tlsCACert": tlsCaCert},
Updated: time.Now().Add(-2 * time.Minute),
}
t1, err := ds.GetHttpTransport()
So(err, ShouldBeNil)
Convey("Should verify TLS by default", func() {
So(t1.TLSClientConfig.InsecureSkipVerify, ShouldEqual, false)
})
Convey("Should have no TLS client certificate configured", func() {
So(len(t1.TLSClientConfig.Certificates), ShouldEqual, 0)
})
Convey("Should have no user-supplied TLS CA configured", func() {
So(t1.TLSClientConfig.RootCAs, ShouldBeNil)
})
ds.JsonData = nil
ds.SecureJsonData = map[string][]byte{}
ds.Updated = time.Now()
t2, err := ds.GetHttpTransport()
So(err, ShouldBeNil)
Convey("Should have no user-supplied TLS CA configured after the update", func() {
So(t2.TLSClientConfig.RootCAs, ShouldBeNil)
})
})
Convey("When caching a datasource proxy with TLS client authentication enabled", t, func() {
clearCache()
setting.SecretKey = "password"
json := simplejson.New()
json.Set("tlsClientAuth", true)
tlsClientCert, err := util.Encrypt([]byte(clientCert), "password")
So(err, ShouldBeNil)
tlsClientKey, err := util.Encrypt([]byte(clientKey), "password")
So(err, ShouldBeNil)
ds := DataSource{ ds := DataSource{
Url: "http://k8s:8001", Id: 1,
Type: "Kubernetes", Url: "http://k8s:8001",
Updated: t.Add(-2 * time.Minute), Type: "Kubernetes",
JsonData: json,
SecureJsonData: map[string][]byte{
"tlsClientCert": tlsClientCert,
"tlsClientKey": tlsClientKey,
},
} }
transport, err := ds.GetHttpTransport() tr, err := ds.GetHttpTransport()
So(err, ShouldBeNil) So(err, ShouldBeNil)
Convey("Should verify TLS certificates by default", func() { Convey("Should verify TLS by default", func() {
So(transport.TLSClientConfig.InsecureSkipVerify, ShouldEqual, false) So(tr.TLSClientConfig.InsecureSkipVerify, ShouldEqual, false)
}) })
Convey("Should have a TLS client certificate configured", func() {
So(len(tr.TLSClientConfig.Certificates), ShouldEqual, 1)
})
})
Convey("When caching a datasource proxy with a user-supplied TLS CA", t, func() {
clearCache()
setting.SecretKey = "password"
ds.JsonData = json json := simplejson.New()
json.Set("tlsAuthWithCACert", true)
tlsCaCert, _ := util.Encrypt([]byte(caCert), "password") tlsCaCert, err := util.Encrypt([]byte(caCert), "password")
tlsClientCert, _ := util.Encrypt([]byte(clientCert), "password") So(err, ShouldBeNil)
tlsClientKey, _ := util.Encrypt([]byte(clientKey), "password")
ds.SecureJsonData = map[string][]byte{ ds := DataSource{
"tlsCACert": tlsCaCert, Id: 1,
"tlsClientCert": tlsClientCert, Url: "http://k8s:8001",
"tlsClientKey": tlsClientKey, Type: "Kubernetes",
JsonData: json,
SecureJsonData: map[string][]byte{"tlsCACert": tlsCaCert},
} }
ds.Updated = t.Add(-1 * time.Minute)
transport, err = ds.GetHttpTransport() tr, err := ds.GetHttpTransport()
So(err, ShouldBeNil) So(err, ShouldBeNil)
Convey("Should add cert and verify TLS certificates", func() { Convey("Should verify TLS by default", func() {
So(transport.TLSClientConfig.InsecureSkipVerify, ShouldEqual, false) So(tr.TLSClientConfig.InsecureSkipVerify, ShouldEqual, false)
So(len(transport.TLSClientConfig.Certificates), ShouldEqual, 1) })
Convey("Should have a TLS CA configured", func() {
So(len(tr.TLSClientConfig.RootCAs.Subjects()), ShouldEqual, 1)
}) })
})
ds.JsonData = nil Convey("When caching a datasource proxy when user skips TLS verification", t, func() {
ds.SecureJsonData = map[string][]byte{} clearCache()
ds.Updated = t
json := simplejson.New()
json.Set("tlsSkipVerify", true)
ds := DataSource{
Id: 1,
Url: "http://k8s:8001",
Type: "Kubernetes",
JsonData: json,
}
transport, err = ds.GetHttpTransport() tr, err := ds.GetHttpTransport()
So(err, ShouldBeNil) So(err, ShouldBeNil)
Convey("Should remove cert but still verify TLS certificates", func() { Convey("Should skip TLS verification", func() {
So(transport.TLSClientConfig.InsecureSkipVerify, ShouldEqual, false) So(tr.TLSClientConfig.InsecureSkipVerify, ShouldEqual, true)
So(len(transport.TLSClientConfig.Certificates), ShouldEqual, 0)
}) })
}) })
} }
...@@ -115,7 +194,8 @@ FHoXIyGOdq1chmRVocdGBCF8fUoGIbuF14r53rpvcbEKtKnnP8+96luKAZLq0a4n ...@@ -115,7 +194,8 @@ FHoXIyGOdq1chmRVocdGBCF8fUoGIbuF14r53rpvcbEKtKnnP8+96luKAZLq0a4n
3lb92xM= 3lb92xM=
-----END CERTIFICATE-----` -----END CERTIFICATE-----`
const clientCert string = `-----BEGIN CERTIFICATE----- const clientCert string = `
-----BEGIN CERTIFICATE-----
MIICsjCCAZoCCQCcd8sOfstQLzANBgkqhkiG9w0BAQsFADAXMRUwEwYDVQQDDAxj MIICsjCCAZoCCQCcd8sOfstQLzANBgkqhkiG9w0BAQsFADAXMRUwEwYDVQQDDAxj
YS1rOHMtc3RobG0wHhcNMTYxMTAyMDkyNTE1WhcNMTcxMTAyMDkyNTE1WjAfMR0w YS1rOHMtc3RobG0wHhcNMTYxMTAyMDkyNTE1WhcNMTcxMTAyMDkyNTE1WjAfMR0w
GwYDVQQDDBRhZG0tZGFuaWVsLWs4cy1zdGhsbTCCASIwDQYJKoZIhvcNAQEBBQAD GwYDVQQDDBRhZG0tZGFuaWVsLWs4cy1zdGhsbTCCASIwDQYJKoZIhvcNAQEBBQAD
......
...@@ -39,13 +39,20 @@ ...@@ -39,13 +39,20 @@
</div> </div>
<h3 class="page-heading">Http Auth</h3> <h3 class="page-heading">Http Auth</h3>
<div class="gf-form-inline"> <div class="gf-form-group">
<gf-form-switch class="gf-form" label="Basic Auth" checked="current.basicAuth" label-class="width-8" switch-class="max-width-6"></gf-form-switch> <div class="gf-form-inline">
<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="Basic Auth" checked="current.basicAuth" label-class="width-8" switch-class="max-width-6"></gf-form-switch>
</div> <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 class="gf-form-inline"> </div>
<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> <div class="gf-form-inline">
<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="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>
</div>
</div>
<div class="gf-form-inline">
<gf-form-switch class="gf-form" ng-if="current.access=='proxy'" label="Skip TLS Verification (Insecure)" label-class="width-16" checked="current.jsonData.tlsSkipVerify" switch-class="max-width-6"></gf-form-switch>
</div>
</div> </div>
</div> </div>
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment