Browse Source

Backend: Adds support for HTTP/2 (#18358)

* Backend: Adds support for HTTP/2

* Adds mozilla recommended ciphers

* Updates sample.ini and config documentation
kay delaney 6 years ago
parent
commit
fb0cec5591

+ 1 - 1
conf/defaults.ini

@@ -28,7 +28,7 @@ provisioning = conf/provisioning
 
 #################################### Server ##############################
 [server]
-# Protocol (http, https, socket)
+# Protocol (http, https, h2, socket)
 protocol = http
 
 # The ip address to bind to, empty will bind to all interfaces

+ 1 - 1
conf/sample.ini

@@ -28,7 +28,7 @@
 
 #################################### Server ####################################
 [server]
-# Protocol (http, https, socket)
+# Protocol (http, https, h2, socket)
 ;protocol = http
 
 # The ip address to bind to, empty will bind to all interfaces

+ 3 - 3
docs/sources/installation/configuration.md

@@ -127,7 +127,7 @@ Another way is put a webserver like Nginx or Apache in front of Grafana and have
 
 ### protocol
 
-`http`,`https` or `socket`
+`http`,`https`,`h2` or `socket`
 
 > **Note** Grafana versions earlier than 3.0 are vulnerable to [POODLE](https://en.wikipedia.org/wiki/POODLE). So we strongly recommend to upgrade to 3.x or use a reverse proxy for ssl termination.
 
@@ -179,11 +179,11 @@ reasons.
 
 ### cert_file
 
-Path to the certificate file (if `protocol` is set to `https`).
+Path to the certificate file (if `protocol` is set to `https` or `h2`).
 
 ### cert_key
 
-Path to the certificate key file (if `protocol` is set to `https`).
+Path to the certificate key file (if `protocol` is set to `https` or `h2`).
 
 ### router_logging
 

+ 45 - 0
pkg/api/http_server.go

@@ -110,6 +110,12 @@ func (hs *HTTPServer) Run(ctx context.Context) error {
 			hs.log.Debug("server was shutdown gracefully")
 			return nil
 		}
+	case setting.HTTP2:
+		err = hs.listenAndServeH2TLS(setting.CertFile, setting.KeyFile)
+		if err == http.ErrServerClosed {
+			hs.log.Debug("server was shutdown gracefully")
+			return nil
+		}
 	case setting.HTTPS:
 		err = hs.listenAndServeTLS(setting.CertFile, setting.KeyFile)
 		if err == http.ErrServerClosed {
@@ -181,6 +187,45 @@ func (hs *HTTPServer) listenAndServeTLS(certfile, keyfile string) error {
 	return hs.httpSrv.ListenAndServeTLS(setting.CertFile, setting.KeyFile)
 }
 
+func (hs *HTTPServer) listenAndServeH2TLS(certfile, keyfile string) error {
+	if certfile == "" {
+		return fmt.Errorf("cert_file cannot be empty when using HTTP2")
+	}
+
+	if keyfile == "" {
+		return fmt.Errorf("cert_key cannot be empty when using HTTP2")
+	}
+
+	if _, err := os.Stat(setting.CertFile); os.IsNotExist(err) {
+		return fmt.Errorf(`Cannot find SSL cert_file at %v`, setting.CertFile)
+	}
+
+	if _, err := os.Stat(setting.KeyFile); os.IsNotExist(err) {
+		return fmt.Errorf(`Cannot find SSL key_file at %v`, setting.KeyFile)
+	}
+
+	tlsCfg := &tls.Config{
+		MinVersion:               tls.VersionTLS12,
+		PreferServerCipherSuites: false,
+		CipherSuites: []uint16{
+			tls.TLS_CHACHA20_POLY1305_SHA256,
+			tls.TLS_AES_128_GCM_SHA256,
+			tls.TLS_AES_256_GCM_SHA384,
+			tls.TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305,
+			tls.TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256,
+			tls.TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384,
+			tls.TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305,
+			tls.TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256,
+			tls.TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384,
+		},
+		NextProtos: []string{"h2", "http/1.1"},
+	}
+
+	hs.httpSrv.TLSConfig = tlsCfg
+
+	return hs.httpSrv.ListenAndServeTLS(setting.CertFile, setting.KeyFile)
+}
+
 func (hs *HTTPServer) newMacaron() *macaron.Macaron {
 	macaron.Env = setting.Env
 	m := macaron.New()

+ 1 - 1
pkg/middleware/middleware.go

@@ -282,7 +282,7 @@ func AddDefaultResponseHeaders() macaron.Handler {
 
 // AddSecurityHeaders adds various HTTP(S) response headers that enable various security protections behaviors in the client's browser.
 func AddSecurityHeaders(w macaron.ResponseWriter) {
-	if setting.Protocol == setting.HTTPS && setting.StrictTransportSecurity {
+	if (setting.Protocol == setting.HTTPS || setting.Protocol == setting.HTTP2) && setting.StrictTransportSecurity {
 		strictHeaderValues := []string{fmt.Sprintf("max-age=%v", setting.StrictTransportSecurityMaxAge)}
 		if setting.StrictTransportSecurityPreload {
 			strictHeaderValues = append(strictHeaderValues, "preload")

+ 6 - 0
pkg/setting/setting.go

@@ -29,6 +29,7 @@ type Scheme string
 const (
 	HTTP              Scheme = "http"
 	HTTPS             Scheme = "https"
+	HTTP2             Scheme = "h2"
 	SOCKET            Scheme = "socket"
 	DEFAULT_HTTP_ADDR string = "0.0.0.0"
 )
@@ -639,6 +640,11 @@ func (cfg *Cfg) Load(args *CommandLineArgs) error {
 		CertFile = server.Key("cert_file").String()
 		KeyFile = server.Key("cert_key").String()
 	}
+	if protocolStr == "h2" {
+		Protocol = HTTP2
+		CertFile = server.Key("cert_file").String()
+		KeyFile = server.Key("cert_key").String()
+	}
 	if protocolStr == "socket" {
 		Protocol = SOCKET
 		SocketPath = server.Key("socket").String()