From 16c5d0e4b765347eeccb44c2d0309ea049713bbf Mon Sep 17 00:00:00 2001 From: Matt Bostock Date: Thu, 28 Sep 2017 11:10:59 +0100 Subject: [PATCH 01/59] Always verify TLS unless explicitly told otherwise TLS was not being verified in a number of places: - connections to grafana.com - connections to OAuth providers when TLS client authentication was enabled - connections to self-hosted Grafana installations when using the CLI tool TLS should always be verified unless the user explicitly enables an option to skip verification. Removes some instances where `InsecureSkipVerify` is explicitly set to `false`, the default, to help avoid confusion and make it more difficult to regress on this fix by accident. Adds a `--insecure` flag to `grafana-cli` to skip TLS verification. Adds a `tls_skip_verify_insecure` setting for OAuth. Adds a `app_tls_skip_verify_insecure` setting under a new `[plugins]` section. I'm not super happy with the way the global setting is used by `pkg/api/app_routes.go` but that seems to be the existing pattern used. --- pkg/api/app_routes.go | 29 +++++++++++++----------- pkg/api/grafana_com_proxy.go | 4 +--- pkg/api/login_oauth.go | 2 +- pkg/cmd/grafana-cli/main.go | 10 ++++++-- pkg/cmd/grafana-cli/services/services.go | 7 +++--- pkg/setting/setting.go | 6 +++++ pkg/setting/setting_oauth.go | 1 + pkg/social/social.go | 1 + 8 files changed, 38 insertions(+), 22 deletions(-) diff --git a/pkg/api/app_routes.go b/pkg/api/app_routes.go index 8992f8f66d6..3d1c4e96bd2 100644 --- a/pkg/api/app_routes.go +++ b/pkg/api/app_routes.go @@ -13,24 +13,27 @@ import ( "github.com/grafana/grafana/pkg/middleware" m "github.com/grafana/grafana/pkg/models" "github.com/grafana/grafana/pkg/plugins" + "github.com/grafana/grafana/pkg/setting" "github.com/grafana/grafana/pkg/util" ) -var pluginProxyTransport = &http.Transport{ - TLSClientConfig: &tls.Config{ - InsecureSkipVerify: true, - Renegotiation: tls.RenegotiateFreelyAsClient, - }, - Proxy: http.ProxyFromEnvironment, - Dial: (&net.Dialer{ - Timeout: 30 * time.Second, - KeepAlive: 30 * time.Second, - DualStack: true, - }).Dial, - TLSHandshakeTimeout: 10 * time.Second, -} +var pluginProxyTransport *http.Transport func InitAppPluginRoutes(r *macaron.Macaron) { + pluginProxyTransport = &http.Transport{ + TLSClientConfig: &tls.Config{ + InsecureSkipVerify: setting.PluginAppsSkipVerifyTLS, + Renegotiation: tls.RenegotiateFreelyAsClient, + }, + Proxy: http.ProxyFromEnvironment, + Dial: (&net.Dialer{ + Timeout: 30 * time.Second, + KeepAlive: 30 * time.Second, + DualStack: true, + }).Dial, + TLSHandshakeTimeout: 10 * time.Second, + } + for _, plugin := range plugins.Apps { for _, route := range plugin.Routes { url := util.JoinUrlFragments("/api/plugin-proxy/"+plugin.Id, route.Path) diff --git a/pkg/api/grafana_com_proxy.go b/pkg/api/grafana_com_proxy.go index 015f690adda..a2a446b48eb 100644 --- a/pkg/api/grafana_com_proxy.go +++ b/pkg/api/grafana_com_proxy.go @@ -1,7 +1,6 @@ package api import ( - "crypto/tls" "net" "net/http" "net/http/httputil" @@ -14,8 +13,7 @@ import ( ) var grafanaComProxyTransport = &http.Transport{ - TLSClientConfig: &tls.Config{InsecureSkipVerify: false}, - Proxy: http.ProxyFromEnvironment, + Proxy: http.ProxyFromEnvironment, Dial: (&net.Dialer{ Timeout: 30 * time.Second, KeepAlive: 30 * time.Second, diff --git a/pkg/api/login_oauth.go b/pkg/api/login_oauth.go index 4be49915fd9..426f3f048b4 100644 --- a/pkg/api/login_oauth.go +++ b/pkg/api/login_oauth.go @@ -97,7 +97,7 @@ func OAuthLogin(ctx *middleware.Context) { tr := &http.Transport{ TLSClientConfig: &tls.Config{ - InsecureSkipVerify: true, + InsecureSkipVerify: setting.OAuthService.OAuthInfos[name].TlsSkipVerify, Certificates: []tls.Certificate{cert}, RootCAs: caCertPool, }, diff --git a/pkg/cmd/grafana-cli/main.go b/pkg/cmd/grafana-cli/main.go index 73548c3b159..86eb6bc271a 100644 --- a/pkg/cmd/grafana-cli/main.go +++ b/pkg/cmd/grafana-cli/main.go @@ -17,8 +17,6 @@ var version = "master" func main() { setupLogging() - services.Init(version) - app := cli.NewApp() app.Name = "Grafana cli" app.Usage = "" @@ -44,12 +42,20 @@ func main() { Value: "", EnvVar: "GF_PLUGIN_URL", }, + cli.BoolFlag{ + Name: "insecure", + Usage: "Skip TLS verification (insecure)", + }, cli.BoolFlag{ Name: "debug, d", Usage: "enable debug logging", }, } + app.Before = func(c *cli.Context) error { + services.Init(version, c.GlobalBool("insecure")) + return nil + } app.Commands = commands.Commands app.CommandNotFound = cmdNotFound diff --git a/pkg/cmd/grafana-cli/services/services.go b/pkg/cmd/grafana-cli/services/services.go index d3a05430944..d13e90d6a2f 100644 --- a/pkg/cmd/grafana-cli/services/services.go +++ b/pkg/cmd/grafana-cli/services/services.go @@ -22,7 +22,7 @@ var ( grafanaVersion string ) -func Init(version string) { +func Init(version string, skipTLSVerify bool) { grafanaVersion = version tr := &http.Transport{ @@ -36,8 +36,9 @@ func Init(version string) { IdleConnTimeout: 90 * time.Second, TLSHandshakeTimeout: 10 * time.Second, ExpectContinueTimeout: 1 * time.Second, - - TLSClientConfig: &tls.Config{InsecureSkipVerify: false}, + TLSClientConfig: &tls.Config{ + InsecureSkipVerify: skipTLSVerify, + }, } HttpClient = http.Client{ diff --git a/pkg/setting/setting.go b/pkg/setting/setting.go index f2ba16fa675..ca65fe581af 100644 --- a/pkg/setting/setting.go +++ b/pkg/setting/setting.go @@ -122,6 +122,9 @@ var ( // Basic Auth BasicAuthEnabled bool + // Plugin settings + PluginAppsSkipVerifyTLS bool + // Session settings. SessionOptions session.Options @@ -560,6 +563,9 @@ func NewConfigContext(args *CommandLineArgs) error { authBasic := Cfg.Section("auth.basic") BasicAuthEnabled = authBasic.Key("enabled").MustBool(true) + // global plugin settings + PluginAppsSkipVerifyTLS = Cfg.Section("plugins").Key("app_tls_skip_verify_insecure").MustBool(false) + // PhantomJS rendering ImagesDir = filepath.Join(DataPath, "png") PhantomDir = filepath.Join(HomePath, "vendor/phantomjs") diff --git a/pkg/setting/setting_oauth.go b/pkg/setting/setting_oauth.go index bc52d2336c3..ee2e812415b 100644 --- a/pkg/setting/setting_oauth.go +++ b/pkg/setting/setting_oauth.go @@ -13,6 +13,7 @@ type OAuthInfo struct { TlsClientCert string TlsClientKey string TlsClientCa string + TlsSkipVerify bool } type OAuther struct { diff --git a/pkg/social/social.go b/pkg/social/social.go index 9d2a53946c7..d40c0a0c965 100644 --- a/pkg/social/social.go +++ b/pkg/social/social.go @@ -66,6 +66,7 @@ func NewOAuthService() { TlsClientCert: sec.Key("tls_client_cert").String(), TlsClientKey: sec.Key("tls_client_key").String(), TlsClientCa: sec.Key("tls_client_ca").String(), + TlsSkipVerify: sec.Key("tls_skip_verify_insecure").MustBool(), } if !info.Enabled { From f2f8ca52d96e9bc5120828dba125e476bd5edf49 Mon Sep 17 00:00:00 2001 From: Matt Bostock Date: Fri, 6 Oct 2017 15:03:46 +0100 Subject: [PATCH 02/59] OAuth: Check both TLS client cert and key If either is set, try to use them. This should help avoid a situation where someone has half-configured TLS client authentication and it doesn't work without raising an obvious error. --- pkg/api/login_oauth.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pkg/api/login_oauth.go b/pkg/api/login_oauth.go index 426f3f048b4..be54a5af855 100644 --- a/pkg/api/login_oauth.go +++ b/pkg/api/login_oauth.go @@ -81,7 +81,7 @@ func OAuthLogin(ctx *middleware.Context) { // initialize oauth2 context oauthCtx := oauth2.NoContext - if setting.OAuthService.OAuthInfos[name].TlsClientCert != "" { + if setting.OAuthService.OAuthInfos[name].TlsClientCert != "" || setting.OAuthService.OAuthInfos[name].TlsClientKey != "" { cert, err := tls.LoadX509KeyPair(setting.OAuthService.OAuthInfos[name].TlsClientCert, setting.OAuthService.OAuthInfos[name].TlsClientKey) if err != nil { log.Fatal(err) From ccf093da8121948dc177437328c80e31b48a5406 Mon Sep 17 00:00:00 2001 From: Matt Bostock Date: Fri, 6 Oct 2017 15:16:26 +0100 Subject: [PATCH 03/59] OAuth: Separate TLS client auth and CA config It should be specify to either use TLS client authentication or use a user-supplied CA; previously you had to enable client authentication to use a custom CA. --- pkg/api/login_oauth.go | 29 +++++++++++++++-------------- 1 file changed, 15 insertions(+), 14 deletions(-) diff --git a/pkg/api/login_oauth.go b/pkg/api/login_oauth.go index be54a5af855..a11b591f7d1 100644 --- a/pkg/api/login_oauth.go +++ b/pkg/api/login_oauth.go @@ -78,16 +78,25 @@ func OAuthLogin(ctx *middleware.Context) { } // handle call back + tr := &http.Transport{ + TLSClientConfig: &tls.Config{ + InsecureSkipVerify: setting.OAuthService.OAuthInfos[name].TlsSkipVerify, + }, + } + sslcli := &http.Client{ + Transport: tr, + } - // initialize oauth2 context - oauthCtx := oauth2.NoContext if setting.OAuthService.OAuthInfos[name].TlsClientCert != "" || setting.OAuthService.OAuthInfos[name].TlsClientKey != "" { cert, err := tls.LoadX509KeyPair(setting.OAuthService.OAuthInfos[name].TlsClientCert, setting.OAuthService.OAuthInfos[name].TlsClientKey) if err != nil { log.Fatal(err) } - // Load CA cert + tr.TLSClientConfig.Certificates = append(tr.TLSClientConfig.Certificates, cert) + } + + if setting.OAuthService.OAuthInfos[name].TlsClientCa != "" { caCert, err := ioutil.ReadFile(setting.OAuthService.OAuthInfos[name].TlsClientCa) if err != nil { log.Fatal(err) @@ -95,19 +104,11 @@ func OAuthLogin(ctx *middleware.Context) { caCertPool := x509.NewCertPool() caCertPool.AppendCertsFromPEM(caCert) - tr := &http.Transport{ - TLSClientConfig: &tls.Config{ - InsecureSkipVerify: setting.OAuthService.OAuthInfos[name].TlsSkipVerify, - Certificates: []tls.Certificate{cert}, - RootCAs: caCertPool, - }, - } - sslcli := &http.Client{Transport: tr} - - oauthCtx = context.Background() - oauthCtx = context.WithValue(oauthCtx, oauth2.HTTPClient, sslcli) + tr.TLSClientConfig.RootCAs = caCertPool } + oauthCtx := context.WithValue(context.Background(), oauth2.HTTPClient, sslcli) + // get token from provider token, err := connect.Exchange(oauthCtx, code) if err != nil { From 83f1ae4e3e3478027274c33dc077ac697b23ae55 Mon Sep 17 00:00:00 2001 From: Matt Bostock Date: Fri, 6 Oct 2017 15:23:06 +0100 Subject: [PATCH 04/59] OAuth: Rename sslcli Rename `sslcli` to the more descriptive `oauthClient`. --- pkg/api/login_oauth.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pkg/api/login_oauth.go b/pkg/api/login_oauth.go index a11b591f7d1..b1109e61c3d 100644 --- a/pkg/api/login_oauth.go +++ b/pkg/api/login_oauth.go @@ -83,7 +83,7 @@ func OAuthLogin(ctx *middleware.Context) { InsecureSkipVerify: setting.OAuthService.OAuthInfos[name].TlsSkipVerify, }, } - sslcli := &http.Client{ + oauthClient := &http.Client{ Transport: tr, } @@ -107,7 +107,7 @@ func OAuthLogin(ctx *middleware.Context) { tr.TLSClientConfig.RootCAs = caCertPool } - oauthCtx := context.WithValue(context.Background(), oauth2.HTTPClient, sslcli) + oauthCtx := context.WithValue(context.Background(), oauth2.HTTPClient, oauthClient) // get token from provider token, err := connect.Exchange(oauthCtx, code) From d60339a9b144ca24983bec8d33668b4a52fa74a3 Mon Sep 17 00:00:00 2001 From: utkarshcmu Date: Mon, 9 Oct 2017 18:07:44 -0700 Subject: [PATCH 05/59] Kafka REST Proxy works with Grafana --- pkg/services/alerting/notifiers/kafka.go | 120 ++++++++++++++++++ .../app/features/alerting/alert_tab_ctrl.ts | 1 + 2 files changed, 121 insertions(+) create mode 100644 pkg/services/alerting/notifiers/kafka.go diff --git a/pkg/services/alerting/notifiers/kafka.go b/pkg/services/alerting/notifiers/kafka.go new file mode 100644 index 00000000000..52bbcd74b9e --- /dev/null +++ b/pkg/services/alerting/notifiers/kafka.go @@ -0,0 +1,120 @@ +package notifiers + +import ( + "strconv" + + "fmt" + + "github.com/grafana/grafana/pkg/bus" + "github.com/grafana/grafana/pkg/components/simplejson" + "github.com/grafana/grafana/pkg/log" + m "github.com/grafana/grafana/pkg/models" + "github.com/grafana/grafana/pkg/services/alerting" +) + +func init() { + alerting.RegisterNotifier(&alerting.NotifierPlugin{ + Type: "kafka", + Name: "Kafka REST Proxy", + Description: "Sends notifications to Kafka Rest Proxy", + Factory: NewKafkaNotifier, + OptionsTemplate: ` +

Kafka settings

+
+ Kafka REST Proxy + +
+
+ Topic + +
+ `, + }) +} + +func NewKafkaNotifier(model *m.AlertNotification) (alerting.Notifier, error) { + endpoint := model.Settings.Get("kafkaRestProxy").MustString() + if endpoint == "" { + return nil, alerting.ValidationError{Reason: "Could not find kafka rest proxy endpoint property in settings"} + } + topic := model.Settings.Get("kafkaTopic").MustString() + if topic == "" { + return nil, alerting.ValidationError{Reason: "Could not find kafka topic property in settings"} + } + + return &KafkaNotifier{ + NotifierBase: NewNotifierBase(model.Id, model.IsDefault, model.Name, model.Type, model.Settings), + Endpoint: endpoint, + Topic: topic, + log: log.New("alerting.notifier.kafka"), + }, nil +} + +type KafkaNotifier struct { + NotifierBase + Endpoint string + Topic string + log log.Logger +} + +func (this *KafkaNotifier) Notify(evalContext *alerting.EvalContext) error { + + state := evalContext.Rule.State + + customData := "Triggered metrics:\n\n" + for _, evt := range evalContext.EvalMatches { + customData = customData + fmt.Sprintf("%s: %v\n", evt.Metric, evt.Value) + } + + this.log.Info("Notifying Kafka", "alert_state", state) + + recordJSON := simplejson.New() + records := make([]interface{}, 1) + + bodyJSON := simplejson.New() + bodyJSON.Set("description", evalContext.Rule.Name+" - "+evalContext.Rule.Message) + bodyJSON.Set("client", "Grafana") + bodyJSON.Set("details", customData) + bodyJSON.Set("incident_key", "alertId-"+strconv.FormatInt(evalContext.Rule.Id, 10)) + + ruleUrl, err := evalContext.GetRuleUrl() + if err != nil { + this.log.Error("Failed get rule link", "error", err) + return err + } + bodyJSON.Set("client_url", ruleUrl) + + if evalContext.ImagePublicUrl != "" { + contexts := make([]interface{}, 1) + imageJSON := simplejson.New() + imageJSON.Set("type", "image") + imageJSON.Set("src", evalContext.ImagePublicUrl) + contexts[0] = imageJSON + bodyJSON.Set("contexts", contexts) + } + + valueJSON := simplejson.New() + valueJSON.Set("value", bodyJSON) + records[0] = valueJSON + recordJSON.Set("records", records) + body, _ := recordJSON.MarshalJSON() + + topicUrl := this.Endpoint+"/topics/"+this.Topic + + cmd := &m.SendWebhookSync{ + Url: topicUrl, + Body: string(body), + HttpMethod: "POST", + HttpHeader: map[string]string{ + "Content-Type": "application/vnd.kafka.json.v2+json", + "Accept": "application/vnd.kafka.v2+json", + }, + } + + if err := bus.DispatchCtx(evalContext.Ctx, cmd); err != nil { + this.log.Error("Failed to send notification to Kafka", "error", err, "body", string(body)) + return err + } + + return nil +} diff --git a/public/app/features/alerting/alert_tab_ctrl.ts b/public/app/features/alerting/alert_tab_ctrl.ts index 677eec31060..25c23580ed7 100644 --- a/public/app/features/alerting/alert_tab_ctrl.ts +++ b/public/app/features/alerting/alert_tab_ctrl.ts @@ -94,6 +94,7 @@ export class AlertTabCtrl { case "opsgenie": return "fa fa-bell"; case "hipchat": return "fa fa-mail-forward"; case "pushover": return "fa fa-mobile"; + case "kafka": return "fa fa-random"; } return 'fa fa-bell'; } From 138bee99ef3f7d7b78180e56455c694ca00252c2 Mon Sep 17 00:00:00 2001 From: utkarshcmu Date: Mon, 9 Oct 2017 18:12:12 -0700 Subject: [PATCH 06/59] Added tests --- pkg/services/alerting/notifiers/kafka_test.go | 55 +++++++++++++++++++ 1 file changed, 55 insertions(+) create mode 100644 pkg/services/alerting/notifiers/kafka_test.go diff --git a/pkg/services/alerting/notifiers/kafka_test.go b/pkg/services/alerting/notifiers/kafka_test.go new file mode 100644 index 00000000000..977bea7cf17 --- /dev/null +++ b/pkg/services/alerting/notifiers/kafka_test.go @@ -0,0 +1,55 @@ +package notifiers + +import ( + "testing" + + "github.com/grafana/grafana/pkg/components/simplejson" + m "github.com/grafana/grafana/pkg/models" + . "github.com/smartystreets/goconvey/convey" +) + +func TestKafkaNotifier(t *testing.T) { + Convey("Kafka notifier tests", t, func() { + + Convey("Parsing alert notification from settings", func() { + Convey("empty settings should return error", func() { + json := `{ }` + + settingsJSON, _ := simplejson.NewJson([]byte(json)) + model := &m.AlertNotification{ + Name: "kafka_testing", + Type: "kafka", + Settings: settingsJSON, + } + + _, err := NewKafkaNotifier(model) + So(err, ShouldNotBeNil) + }) + + Convey("settings should send an event to kafka", func() { + json := ` + { + "kafkaEndpoint": "http://localhost:8082", + "kafkaTopic": "topic1" + }` + + settingsJSON, _ := simplejson.NewJson([]byte(json)) + model := &m.AlertNotification{ + Name: "kafka_testing", + Type: "kafka", + Settings: settingsJSON, + } + + not, err := NewKafkaNotifier(model) + kafkaNotifier := not.(*KafkaNotifier) + + So(err, ShouldBeNil) + So(kafkaNotifier.Name, ShouldEqual, "kafka_testing") + So(kafkaNotifier.Type, ShouldEqual, "kafka") + So(kafkaNotifier.Endpoint, ShouldEqual, "http://localhost:8082") + So(kafkaNotifier.Topic, ShouldEqual, "topic1") + }) + + }) + }) +} From a562dc7c2be3aa8430121b05bd2e43cb2175cfef Mon Sep 17 00:00:00 2001 From: utkarshcmu Date: Mon, 9 Oct 2017 18:12:39 -0700 Subject: [PATCH 07/59] gofmt fixes --- pkg/services/alerting/notifiers/kafka.go | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/pkg/services/alerting/notifiers/kafka.go b/pkg/services/alerting/notifiers/kafka.go index 52bbcd74b9e..92f6489106b 100644 --- a/pkg/services/alerting/notifiers/kafka.go +++ b/pkg/services/alerting/notifiers/kafka.go @@ -38,9 +38,9 @@ func NewKafkaNotifier(model *m.AlertNotification) (alerting.Notifier, error) { return nil, alerting.ValidationError{Reason: "Could not find kafka rest proxy endpoint property in settings"} } topic := model.Settings.Get("kafkaTopic").MustString() - if topic == "" { - return nil, alerting.ValidationError{Reason: "Could not find kafka topic property in settings"} - } + if topic == "" { + return nil, alerting.ValidationError{Reason: "Could not find kafka topic property in settings"} + } return &KafkaNotifier{ NotifierBase: NewNotifierBase(model.Id, model.IsDefault, model.Name, model.Type, model.Settings), @@ -52,9 +52,9 @@ func NewKafkaNotifier(model *m.AlertNotification) (alerting.Notifier, error) { type KafkaNotifier struct { NotifierBase - Endpoint string - Topic string - log log.Logger + Endpoint string + Topic string + log log.Logger } func (this *KafkaNotifier) Notify(evalContext *alerting.EvalContext) error { @@ -99,16 +99,16 @@ func (this *KafkaNotifier) Notify(evalContext *alerting.EvalContext) error { recordJSON.Set("records", records) body, _ := recordJSON.MarshalJSON() - topicUrl := this.Endpoint+"/topics/"+this.Topic + topicUrl := this.Endpoint + "/topics/" + this.Topic cmd := &m.SendWebhookSync{ Url: topicUrl, Body: string(body), HttpMethod: "POST", HttpHeader: map[string]string{ - "Content-Type": "application/vnd.kafka.json.v2+json", - "Accept": "application/vnd.kafka.v2+json", - }, + "Content-Type": "application/vnd.kafka.json.v2+json", + "Accept": "application/vnd.kafka.v2+json", + }, } if err := bus.DispatchCtx(evalContext.Ctx, cmd); err != nil { From da47dc8947f57ed37a58e6b087c539b2a63b3eed Mon Sep 17 00:00:00 2001 From: utkarshcmu Date: Mon, 9 Oct 2017 18:56:05 -0700 Subject: [PATCH 08/59] Fixed failing go tests --- pkg/services/alerting/notifiers/kafka_test.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pkg/services/alerting/notifiers/kafka_test.go b/pkg/services/alerting/notifiers/kafka_test.go index 977bea7cf17..045976cb14b 100644 --- a/pkg/services/alerting/notifiers/kafka_test.go +++ b/pkg/services/alerting/notifiers/kafka_test.go @@ -29,7 +29,7 @@ func TestKafkaNotifier(t *testing.T) { Convey("settings should send an event to kafka", func() { json := ` { - "kafkaEndpoint": "http://localhost:8082", + "kafkaRestProxy": "http://localhost:8082", "kafkaTopic": "topic1" }` From 8aff343ce333ebac672487e04a1aac54df238a8e Mon Sep 17 00:00:00 2001 From: utkarshcmu Date: Tue, 10 Oct 2017 02:11:02 -0700 Subject: [PATCH 09/59] Added docs for Kafka alerting --- docs/sources/alerting/notifications.md | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/docs/sources/alerting/notifications.md b/docs/sources/alerting/notifications.md index de9e5abd472..102134f34dd 100644 --- a/docs/sources/alerting/notifications.md +++ b/docs/sources/alerting/notifications.md @@ -115,6 +115,17 @@ In DingTalk PC Client: Dingtalk supports the following "message type": `text`, `link` and `markdown`. Only the `text` message type is supported. +### Kafka + +Notifications can be sent to a Kafka topic from Grafana using [Kafka REST Proxy](https://docs.confluent.io/1.0/kafka-rest/docs/index.html). +There are couple of configurations options which need to be set in Grafana UI under Kafka Settings: + +1. Kafka REST Proxy endpoint. + +2. Kafka Topic. + +Once these two properties are set, you can send the alerts to Kafka for further processing or throttling them. + ### Other Supported Notification Channels Grafana also supports the following Notification Channels: From 592c46c8b54eca5d1b03e72e6c8def2140cd2cdd Mon Sep 17 00:00:00 2001 From: Matt Bostock Date: Thu, 28 Sep 2017 10:39:03 +0100 Subject: [PATCH 10/59] Tests: Clarify what InsecureSkipVerify does --- pkg/models/datasource_cache_test.go | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/pkg/models/datasource_cache_test.go b/pkg/models/datasource_cache_test.go index 5e821ea28c4..8b36cc68e2a 100644 --- a/pkg/models/datasource_cache_test.go +++ b/pkg/models/datasource_cache_test.go @@ -49,7 +49,7 @@ func TestDataSourceCache(t *testing.T) { transport, err := ds.GetHttpTransport() So(err, ShouldBeNil) - Convey("Should have no cert", func() { + Convey("Should disable TLS certificate verification", func() { So(transport.TLSClientConfig.InsecureSkipVerify, ShouldEqual, true) }) @@ -69,7 +69,7 @@ func TestDataSourceCache(t *testing.T) { transport, err = ds.GetHttpTransport() So(err, ShouldBeNil) - Convey("Should add cert", func() { + Convey("Should add cert and enable TLS certificate verification", func() { So(transport.TLSClientConfig.InsecureSkipVerify, ShouldEqual, false) So(len(transport.TLSClientConfig.Certificates), ShouldEqual, 1) }) @@ -81,7 +81,7 @@ func TestDataSourceCache(t *testing.T) { transport, err = ds.GetHttpTransport() So(err, ShouldBeNil) - Convey("Should remove cert", func() { + Convey("Should remove cert and disable TLS certificate vertification", func() { So(transport.TLSClientConfig.InsecureSkipVerify, ShouldEqual, true) So(len(transport.TLSClientConfig.Certificates), ShouldEqual, 0) }) From 4719a8c8dd9f22505f1a91a53cd418f5b9e6ee85 Mon Sep 17 00:00:00 2001 From: Matt Bostock Date: Thu, 28 Sep 2017 10:41:12 +0100 Subject: [PATCH 11/59] Tidy spacing in datasource TLS settings --- .../plugins/partials/ds_http_settings.html | 25 +++++-------------- 1 file changed, 6 insertions(+), 19 deletions(-) diff --git a/public/app/features/plugins/partials/ds_http_settings.html b/public/app/features/plugins/partials/ds_http_settings.html index 62c3e477446..d10b8cbf9bc 100644 --- a/public/app/features/plugins/partials/ds_http_settings.html +++ b/public/app/features/plugins/partials/ds_http_settings.html @@ -39,26 +39,13 @@

Http Auth

- -
- - - - -
- - - - + + +
+
+ +
From 43169e4302a6e0ffcc01d9108965b1b4feaad5d6 Mon Sep 17 00:00:00 2001 From: Matt Bostock Date: Thu, 28 Sep 2017 11:04:01 +0100 Subject: [PATCH 12/59] Verify datasource TLS and split client auth and CA --- pkg/models/datasource_cache.go | 21 ++++---- pkg/models/datasource_cache_test.go | 12 ++--- .../plugins/partials/ds_http_settings.html | 48 ++++++++++--------- 3 files changed, 41 insertions(+), 40 deletions(-) diff --git a/pkg/models/datasource_cache.go b/pkg/models/datasource_cache.go index 158018b0f0a..14d3c6c2fc1 100644 --- a/pkg/models/datasource_cache.go +++ b/pkg/models/datasource_cache.go @@ -47,8 +47,7 @@ func (ds *DataSource) GetHttpTransport() (*http.Transport, error) { transport := &http.Transport{ TLSClientConfig: &tls.Config{ - InsecureSkipVerify: true, - Renegotiation: tls.RenegotiateFreelyAsClient, + Renegotiation: tls.RenegotiateFreelyAsClient, }, Proxy: http.ProxyFromEnvironment, Dial: (&net.Dialer{ @@ -62,15 +61,13 @@ func (ds *DataSource) GetHttpTransport() (*http.Transport, error) { IdleConnTimeout: 90 * time.Second, } - var tlsAuth, tlsAuthWithCACert bool + var tlsClientAuth, tlsAuthWithCACert bool 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) } - if tlsAuth { - transport.TLSClientConfig.InsecureSkipVerify = false - + if tlsClientAuth || tlsAuthWithCACert { decrypted := ds.SecureJsonData.Decrypt() 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 err != nil { - return nil, err + if tlsClientAuth { + cert, err := tls.X509KeyPair([]byte(decrypted["tlsClientCert"]), []byte(decrypted["tlsClientKey"])) + if err != nil { + return nil, err + } + transport.TLSClientConfig.Certificates = []tls.Certificate{cert} } - transport.TLSClientConfig.Certificates = []tls.Certificate{cert} } ptc.cache[ds.Id] = cachedTransport{ diff --git a/pkg/models/datasource_cache_test.go b/pkg/models/datasource_cache_test.go index 8b36cc68e2a..bbd1c563ad1 100644 --- a/pkg/models/datasource_cache_test.go +++ b/pkg/models/datasource_cache_test.go @@ -36,7 +36,7 @@ func TestDataSourceCache(t *testing.T) { setting.SecretKey = "password" json := simplejson.New() - json.Set("tlsAuth", true) + json.Set("tlsClientAuth", true) json.Set("tlsAuthWithCACert", true) t := time.Now() @@ -49,8 +49,8 @@ func TestDataSourceCache(t *testing.T) { transport, err := ds.GetHttpTransport() So(err, ShouldBeNil) - Convey("Should disable TLS certificate verification", func() { - So(transport.TLSClientConfig.InsecureSkipVerify, ShouldEqual, true) + Convey("Should verify TLS certificates by default", func() { + So(transport.TLSClientConfig.InsecureSkipVerify, ShouldEqual, false) }) ds.JsonData = json @@ -69,7 +69,7 @@ func TestDataSourceCache(t *testing.T) { transport, err = ds.GetHttpTransport() 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(len(transport.TLSClientConfig.Certificates), ShouldEqual, 1) }) @@ -81,8 +81,8 @@ func TestDataSourceCache(t *testing.T) { transport, err = ds.GetHttpTransport() So(err, ShouldBeNil) - Convey("Should remove cert and disable TLS certificate vertification", func() { - So(transport.TLSClientConfig.InsecureSkipVerify, ShouldEqual, true) + Convey("Should remove cert but still verify TLS certificates", func() { + So(transport.TLSClientConfig.InsecureSkipVerify, ShouldEqual, false) So(len(transport.TLSClientConfig.Certificates), ShouldEqual, 0) }) }) diff --git a/public/app/features/plugins/partials/ds_http_settings.html b/public/app/features/plugins/partials/ds_http_settings.html index d10b8cbf9bc..6ea3a3cde1a 100644 --- a/public/app/features/plugins/partials/ds_http_settings.html +++ b/public/app/features/plugins/partials/ds_http_settings.html @@ -44,7 +44,7 @@
- +
@@ -66,7 +66,7 @@ -
+
TLS Auth Details
TLS Certs are encrypted and stored in the Grafana database. @@ -87,29 +87,31 @@
-
-
- +
+
+
+ +
+
+ +
+
+ + reset +
-
- -
-
- - reset -
-
-
-
- -
-
- -
-
- - reset +
+
+ +
+
+ +
+
+ + reset +
From a286ffa5f2ad2280ffcc060f02c291dc2f229241 Mon Sep 17 00:00:00 2001 From: Matt Bostock Date: Thu, 28 Sep 2017 11:14:12 +0100 Subject: [PATCH 13/59] Alias macron package in app_routes.go ...to make this file compatible with goimports: https://godoc.org/golang.org/x/tools/cmd/goimports --- pkg/api/app_routes.go | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/pkg/api/app_routes.go b/pkg/api/app_routes.go index 8992f8f66d6..2baa9ddd75a 100644 --- a/pkg/api/app_routes.go +++ b/pkg/api/app_routes.go @@ -6,14 +6,13 @@ import ( "net/http" "time" - "gopkg.in/macaron.v1" - "github.com/grafana/grafana/pkg/api/pluginproxy" "github.com/grafana/grafana/pkg/log" "github.com/grafana/grafana/pkg/middleware" m "github.com/grafana/grafana/pkg/models" "github.com/grafana/grafana/pkg/plugins" "github.com/grafana/grafana/pkg/util" + macaron "gopkg.in/macaron.v1" ) var pluginProxyTransport = &http.Transport{ From ef52d956bfc6fdb2f371f68b0b25f0a20d4c4ed4 Mon Sep 17 00:00:00 2001 From: Matt Bostock Date: Thu, 28 Sep 2017 11:25:20 +0100 Subject: [PATCH 14/59] Make URL capitalisation consistent in UI URL is an acronym, it should be all caps. --- .../features/plugins/partials/ds_http_settings.html | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/public/app/features/plugins/partials/ds_http_settings.html b/public/app/features/plugins/partials/ds_http_settings.html index 6ea3a3cde1a..c11a44578a3 100644 --- a/public/app/features/plugins/partials/ds_http_settings.html +++ b/public/app/features/plugins/partials/ds_http_settings.html @@ -5,19 +5,19 @@
- Url + URL -

Specify a complete HTTP url (for example http://your_server:8080)

+

Specify a complete HTTP URL (for example http://your_server:8080)

- Your access method is Direct, this means the url + Your access method is Direct, this means the URL needs to be accessible from the browser. - Your access method is currently Proxy, this means the url + Your access method is currently Proxy, this means the URL needs to be accessible from the grafana backend.
@@ -30,7 +30,7 @@
- Direct = url is used directly from browser
+ Direct = URL is used directly from browser
Proxy = Grafana backend will proxy the request
From 5d312be419b29b1fa0f7fd805a741462a9d45993 Mon Sep 17 00:00:00 2001 From: Matt Bostock Date: Thu, 28 Sep 2017 14:10:14 +0100 Subject: [PATCH 15/59] 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. --- pkg/models/datasource_cache.go | 16 +- pkg/models/datasource_cache_test.go | 148 ++++++++++++++---- .../plugins/partials/ds_http_settings.html | 21 ++- 3 files changed, 137 insertions(+), 48 deletions(-) diff --git a/pkg/models/datasource_cache.go b/pkg/models/datasource_cache.go index 14d3c6c2fc1..f6c7ee67c5a 100644 --- a/pkg/models/datasource_cache.go +++ b/pkg/models/datasource_cache.go @@ -45,9 +45,17 @@ func (ds *DataSource) GetHttpTransport() (*http.Transport, error) { 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{ TLSClientConfig: &tls.Config{ - Renegotiation: tls.RenegotiateFreelyAsClient, + InsecureSkipVerify: tlsSkipVerify, + Renegotiation: tls.RenegotiateFreelyAsClient, }, Proxy: http.ProxyFromEnvironment, Dial: (&net.Dialer{ @@ -61,12 +69,6 @@ func (ds *DataSource) GetHttpTransport() (*http.Transport, error) { 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 { decrypted := ds.SecureJsonData.Decrypt() diff --git a/pkg/models/datasource_cache_test.go b/pkg/models/datasource_cache_test.go index bbd1c563ad1..d427cc84bf9 100644 --- a/pkg/models/datasource_cache_test.go +++ b/pkg/models/datasource_cache_test.go @@ -29,61 +29,140 @@ func TestDataSourceCache(t *testing.T) { Convey("Should be using the cached proxy", func() { 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() + setting.SecretKey = "password" + + json := simplejson.New() + json.Set("tlsAuthWithCACert", true) + + 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{ + Id: 1, + Url: "http://k8s:8001", + Type: "Kubernetes", + JsonData: json, + SecureJsonData: map[string][]byte{ + "tlsClientCert": tlsClientCert, + "tlsClientKey": tlsClientKey, + }, + } + + tr, err := ds.GetHttpTransport() + So(err, ShouldBeNil) + + Convey("Should verify TLS by default", func() { + 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" + + json := simplejson.New() json.Set("tlsAuthWithCACert", true) - t := time.Now() + tlsCaCert, err := util.Encrypt([]byte(caCert), "password") + So(err, ShouldBeNil) + ds := DataSource{ - Url: "http://k8s:8001", - Type: "Kubernetes", - Updated: t.Add(-2 * time.Minute), + Id: 1, + Url: "http://k8s:8001", + Type: "Kubernetes", + JsonData: json, + SecureJsonData: map[string][]byte{"tlsCACert": tlsCaCert}, } - transport, err := ds.GetHttpTransport() + tr, err := ds.GetHttpTransport() So(err, ShouldBeNil) - Convey("Should verify TLS certificates by default", func() { - So(transport.TLSClientConfig.InsecureSkipVerify, ShouldEqual, false) + Convey("Should verify TLS by default", func() { + So(tr.TLSClientConfig.InsecureSkipVerify, ShouldEqual, false) }) + Convey("Should have a TLS CA configured", func() { + So(len(tr.TLSClientConfig.RootCAs.Subjects()), ShouldEqual, 1) + }) + }) - ds.JsonData = json + Convey("When caching a datasource proxy when user skips TLS verification", t, func() { + clearCache() - tlsCaCert, _ := util.Encrypt([]byte(caCert), "password") - tlsClientCert, _ := util.Encrypt([]byte(clientCert), "password") - tlsClientKey, _ := util.Encrypt([]byte(clientKey), "password") + json := simplejson.New() + json.Set("tlsSkipVerify", true) - ds.SecureJsonData = map[string][]byte{ - "tlsCACert": tlsCaCert, - "tlsClientCert": tlsClientCert, - "tlsClientKey": tlsClientKey, + ds := DataSource{ + Id: 1, + Url: "http://k8s:8001", + Type: "Kubernetes", + JsonData: json, } - ds.Updated = t.Add(-1 * time.Minute) - transport, err = ds.GetHttpTransport() + tr, err := ds.GetHttpTransport() So(err, ShouldBeNil) - Convey("Should add cert and verify TLS certificates", func() { - So(transport.TLSClientConfig.InsecureSkipVerify, ShouldEqual, false) - So(len(transport.TLSClientConfig.Certificates), ShouldEqual, 1) - }) - - ds.JsonData = nil - ds.SecureJsonData = map[string][]byte{} - ds.Updated = t - - transport, err = ds.GetHttpTransport() - So(err, ShouldBeNil) - - Convey("Should remove cert but still verify TLS certificates", func() { - So(transport.TLSClientConfig.InsecureSkipVerify, ShouldEqual, false) - So(len(transport.TLSClientConfig.Certificates), ShouldEqual, 0) + Convey("Should skip TLS verification", func() { + So(tr.TLSClientConfig.InsecureSkipVerify, ShouldEqual, true) }) }) } @@ -115,7 +194,8 @@ FHoXIyGOdq1chmRVocdGBCF8fUoGIbuF14r53rpvcbEKtKnnP8+96luKAZLq0a4n 3lb92xM= -----END CERTIFICATE-----` -const clientCert string = `-----BEGIN CERTIFICATE----- +const clientCert string = ` +-----BEGIN CERTIFICATE----- MIICsjCCAZoCCQCcd8sOfstQLzANBgkqhkiG9w0BAQsFADAXMRUwEwYDVQQDDAxj YS1rOHMtc3RobG0wHhcNMTYxMTAyMDkyNTE1WhcNMTcxMTAyMDkyNTE1WjAfMR0w GwYDVQQDDBRhZG0tZGFuaWVsLWs4cy1zdGhsbTCCASIwDQYJKoZIhvcNAQEBBQAD diff --git a/public/app/features/plugins/partials/ds_http_settings.html b/public/app/features/plugins/partials/ds_http_settings.html index c11a44578a3..1aff62e0d20 100644 --- a/public/app/features/plugins/partials/ds_http_settings.html +++ b/public/app/features/plugins/partials/ds_http_settings.html @@ -39,13 +39,20 @@

Http Auth

-
- - -
-
- - +
+
+ + +
+
+ + +
+
+ +
+ +
From e23c678df9ef6dd2b7e827372e4317af0d10c693 Mon Sep 17 00:00:00 2001 From: Matt Bostock Date: Thu, 28 Sep 2017 14:20:09 +0100 Subject: [PATCH 16/59] Datasource settings: Make HTTP all caps It's an acronym, so it should be all caps. --- public/app/features/plugins/partials/ds_http_settings.html | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/public/app/features/plugins/partials/ds_http_settings.html b/public/app/features/plugins/partials/ds_http_settings.html index 1aff62e0d20..1d8582c06d1 100644 --- a/public/app/features/plugins/partials/ds_http_settings.html +++ b/public/app/features/plugins/partials/ds_http_settings.html @@ -1,7 +1,7 @@
-

Http settings

+

HTTP settings

@@ -38,7 +38,7 @@
-

Http Auth

+

HTTP Auth

From f6aa0e41e50ac2b596a7c2e7b33297e5f33c31e1 Mon Sep 17 00:00:00 2001 From: Matt Bostock Date: Thu, 28 Sep 2017 14:55:32 +0100 Subject: [PATCH 17/59] Return error if datasource TLS CA not parsed --- pkg/models/datasource_cache.go | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/pkg/models/datasource_cache.go b/pkg/models/datasource_cache.go index f6c7ee67c5a..79c67691df7 100644 --- a/pkg/models/datasource_cache.go +++ b/pkg/models/datasource_cache.go @@ -3,6 +3,7 @@ package models import ( "crypto/tls" "crypto/x509" + "errors" "net" "net/http" "sync" @@ -71,13 +72,13 @@ func (ds *DataSource) GetHttpTransport() (*http.Transport, error) { if tlsClientAuth || tlsAuthWithCACert { decrypted := ds.SecureJsonData.Decrypt() - if tlsAuthWithCACert && len(decrypted["tlsCACert"]) > 0 { caPool := x509.NewCertPool() ok := caPool.AppendCertsFromPEM([]byte(decrypted["tlsCACert"])) - if ok { - transport.TLSClientConfig.RootCAs = caPool + if !ok { + return nil, errors.New("Failed to parse TLS CA PEM certificate") } + transport.TLSClientConfig.RootCAs = caPool } if tlsClientAuth { From 4f3856adfbfc71f1d779f3dd49994e295098c346 Mon Sep 17 00:00:00 2001 From: Matt Bostock Date: Mon, 2 Oct 2017 15:06:02 +0100 Subject: [PATCH 18/59] Retain old name for TLS client auth I renamed `tlsAuth` to `tlsClientAuth` to better describe the fact that this variable is used to enable TLS client authentication (as opposed to server authentication) in c04d95f35. However, changing the name breaks backwards compatibility for existing installations using this feature and Grafana does not have a standardised way of migrating changes in the schema: https://github.com/grafana/grafana/pull/9377#issuecomment-333063543 For reasons of expediency given the severity of the bug (not verifying TLS), keep the old name. --- pkg/models/datasource_cache.go | 2 +- pkg/models/datasource_cache_test.go | 2 +- public/app/features/plugins/partials/ds_http_settings.html | 6 +++--- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/pkg/models/datasource_cache.go b/pkg/models/datasource_cache.go index 79c67691df7..b4a4e7f8a4d 100644 --- a/pkg/models/datasource_cache.go +++ b/pkg/models/datasource_cache.go @@ -48,7 +48,7 @@ func (ds *DataSource) GetHttpTransport() (*http.Transport, error) { var tlsSkipVerify, tlsClientAuth, tlsAuthWithCACert bool if ds.JsonData != nil { - tlsClientAuth = ds.JsonData.Get("tlsClientAuth").MustBool(false) + tlsClientAuth = ds.JsonData.Get("tlsAuth").MustBool(false) tlsAuthWithCACert = ds.JsonData.Get("tlsAuthWithCACert").MustBool(false) tlsSkipVerify = ds.JsonData.Get("tlsSkipVerify").MustBool(false) } diff --git a/pkg/models/datasource_cache_test.go b/pkg/models/datasource_cache_test.go index d427cc84bf9..85ece0bbdcc 100644 --- a/pkg/models/datasource_cache_test.go +++ b/pkg/models/datasource_cache_test.go @@ -87,7 +87,7 @@ func TestDataSourceCache(t *testing.T) { setting.SecretKey = "password" json := simplejson.New() - json.Set("tlsClientAuth", true) + json.Set("tlsAuth", true) tlsClientCert, err := util.Encrypt([]byte(clientCert), "password") So(err, ShouldBeNil) diff --git a/public/app/features/plugins/partials/ds_http_settings.html b/public/app/features/plugins/partials/ds_http_settings.html index 1d8582c06d1..ac21c6f9ed8 100644 --- a/public/app/features/plugins/partials/ds_http_settings.html +++ b/public/app/features/plugins/partials/ds_http_settings.html @@ -45,7 +45,7 @@
- +
@@ -73,7 +73,7 @@
-
+
TLS Auth Details
TLS Certs are encrypted and stored in the Grafana database. @@ -94,7 +94,7 @@
-
+
From 2f73208ca887c7a19496a5b76fb8c0134749d93c Mon Sep 17 00:00:00 2001 From: Paul Mestemaker Date: Wed, 11 Oct 2017 15:57:33 -0700 Subject: [PATCH 19/59] Update unsaved_changes_modal.ts --- public/app/features/dashboard/unsaved_changes_modal.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/public/app/features/dashboard/unsaved_changes_modal.ts b/public/app/features/dashboard/unsaved_changes_modal.ts index cacfbe0f045..ab3ece1b8a2 100644 --- a/public/app/features/dashboard/unsaved_changes_modal.ts +++ b/public/app/features/dashboard/unsaved_changes_modal.ts @@ -18,7 +18,7 @@ const template = `