Server: Support HTTPS and HTTP/2 over Unix domain sockets (#118155)
This commit introduces a new protocol scheme 'sockettls' (internal constant SocketHTTP2Scheme) that enables serving TLS-encrypted traffic over Unix domain sockets. Previously, Grafana supported plain HTTP over Unix sockets via the 'socket' protocol, but there was no way to enable TLS or HTTP/2 when using sockets. This is useful when Grafana is behind a reverse proxy that communicates via sockets and requires end-to-end encryption or HTTP/2 features. Key changes: - pkg/setting: Added SocketHTTP2Scheme and updated readServerSettings to parse the 'sockettls' protocol. This includes support for socket paths, GID/mode permissions, and TLS certificate/key configuration. - pkg/api: Modified HTTPServer to support listening on Unix sockets when TLS is enabled. Updated Run, getListener, and configureTLS to correctly handle the new scheme. - pkg/services/rendering: Updated getGrafanaCallbackURL to use 'https' scheme for the new socket-based scheme, ensuring correct callback URLs. - pkg/services/frontend: Enabled the Http2Enabled flag for the new scheme to inform the frontend about HTTP/2 availability. - conf: Updated defaults.ini and sample.ini to include 'sockettls' in the documented protocol options. - docs: Updated configuration documentation to reflect the new protocol.
This commit is contained in:
+1
-1
@@ -37,7 +37,7 @@ permitted_provisioning_paths = devenv/dev-dashboards|conf/provisioning
|
||||
|
||||
#################################### Server ##############################
|
||||
[server]
|
||||
# Protocol (http, https, h2, socket)
|
||||
# Protocol (http, https, h2, socket, socket_h2)
|
||||
protocol = http
|
||||
|
||||
# Minimum TLS version allowed. By default, this value is empty. Accepted values are: TLS1.2, TLS1.3. If nothing is set TLS1.2 would be taken
|
||||
|
||||
+1
-1
@@ -35,7 +35,7 @@
|
||||
|
||||
#################################### Server ####################################
|
||||
[server]
|
||||
# Protocol (http, https, h2, socket)
|
||||
# Protocol (http, https, h2, socket, socket_h2)
|
||||
;protocol = http
|
||||
|
||||
# Minimum TLS version allowed. By default, this value is empty. Accepted values are: TLS1.2, TLS1.3. If nothing is set TLS1.2 would be taken
|
||||
|
||||
@@ -222,7 +222,7 @@ Dashboards are reloaded when the JSON files change.
|
||||
|
||||
#### `protocol`
|
||||
|
||||
`http`,`https`,`h2` or `socket`
|
||||
`http`,`https`,`h2`,`socket` or `socket_h2`
|
||||
|
||||
#### `min_tls_version`
|
||||
|
||||
|
||||
@@ -307,7 +307,7 @@ func (hs *HTTPServer) getFrontendSettings(c *contextmodel.ReqContext) (*dtos.Fro
|
||||
RendererDefaultImageWidth: hs.Cfg.RendererDefaultImageWidth,
|
||||
RendererDefaultImageHeight: hs.Cfg.RendererDefaultImageHeight,
|
||||
RendererDefaultImageScale: hs.Cfg.RendererDefaultImageScale,
|
||||
Http2Enabled: hs.Cfg.Protocol == setting.HTTP2Scheme,
|
||||
Http2Enabled: hs.Cfg.Protocol == setting.HTTP2Scheme || hs.Cfg.Protocol == setting.SocketHTTP2Scheme,
|
||||
GrafanaJavascriptAgent: hs.Cfg.GrafanaJavascriptAgent,
|
||||
PluginCatalogURL: hs.Cfg.PluginCatalogURL,
|
||||
PluginAdminEnabled: hs.Cfg.PluginAdminEnabled,
|
||||
|
||||
@@ -453,7 +453,7 @@ func (hs *HTTPServer) Run(ctx context.Context) error {
|
||||
hs.httpSrv.ErrorLog = stdlog.New(customErrorLogger, "", 0)
|
||||
|
||||
switch hs.Cfg.Protocol {
|
||||
case setting.HTTP2Scheme, setting.HTTPSScheme:
|
||||
case setting.HTTP2Scheme, setting.HTTPSScheme, setting.SocketHTTP2Scheme:
|
||||
if err := hs.configureTLS(); err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -499,7 +499,7 @@ func (hs *HTTPServer) Run(ctx context.Context) error {
|
||||
}
|
||||
return err
|
||||
}
|
||||
case setting.HTTP2Scheme, setting.HTTPSScheme:
|
||||
case setting.HTTP2Scheme, setting.HTTPSScheme, setting.SocketHTTP2Scheme:
|
||||
if err := hs.httpSrv.ServeTLS(listener, "", ""); err != nil {
|
||||
if errors.Is(err, http.ErrServerClosed) {
|
||||
hs.log.Debug("server was shutdown gracefully")
|
||||
@@ -528,7 +528,7 @@ func (hs *HTTPServer) getListener() (net.Listener, error) {
|
||||
return nil, fmt.Errorf("failed to open listener on address %s: %w", hs.httpSrv.Addr, err)
|
||||
}
|
||||
return listener, nil
|
||||
case setting.SocketScheme:
|
||||
case setting.SocketScheme, setting.SocketHTTP2Scheme:
|
||||
listener, err := net.ListenUnix("unix", &net.UnixAddr{Name: hs.Cfg.SocketPath, Net: "unix"})
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to open listener for socket %s: %w", hs.Cfg.SocketPath, err)
|
||||
@@ -840,7 +840,7 @@ func (hs *HTTPServer) getDefaultCiphers(tlsVersion uint16, protocol string) []ui
|
||||
tls.TLS_RSA_WITH_AES_256_GCM_SHA384,
|
||||
}
|
||||
}
|
||||
if protocol == "h2" {
|
||||
if protocol == "h2" || protocol == "socket_h2" {
|
||||
return []uint16{
|
||||
tls.TLS_CHACHA20_POLY1305_SHA256,
|
||||
tls.TLS_AES_128_GCM_SHA256,
|
||||
@@ -965,7 +965,7 @@ func (hs *HTTPServer) configureTLS() error {
|
||||
|
||||
hs.httpSrv.TLSConfig = tlsCfg
|
||||
|
||||
if hs.Cfg.Protocol == setting.HTTP2Scheme {
|
||||
if hs.Cfg.Protocol == setting.HTTP2Scheme || hs.Cfg.Protocol == setting.SocketHTTP2Scheme {
|
||||
hs.httpSrv.TLSConfig.NextProtos = []string{"h2", "http/1.1"}
|
||||
}
|
||||
|
||||
|
||||
@@ -42,7 +42,7 @@ func NewFSRequestConfig(cfg *setting.Cfg, license licensing.Licensing) FSRequest
|
||||
GoogleAnalytics4SendManualPageViews: cfg.GoogleAnalytics4SendManualPageViews,
|
||||
GoogleAnalyticsId: cfg.GoogleAnalyticsID,
|
||||
GrafanaJavascriptAgent: cfg.GrafanaJavascriptAgent,
|
||||
Http2Enabled: cfg.Protocol == setting.HTTP2Scheme,
|
||||
Http2Enabled: cfg.Protocol == setting.HTTP2Scheme || cfg.Protocol == setting.SocketHTTP2Scheme,
|
||||
JwtHeaderName: cfg.JWTAuth.HeaderName,
|
||||
JwtUrlLogin: cfg.JWTAuth.URLLogin,
|
||||
LdapEnabled: cfg.LDAPAuthEnabled,
|
||||
|
||||
@@ -413,7 +413,7 @@ func (rs *RenderingService) getGrafanaCallbackURL(path string) string {
|
||||
switch protocol {
|
||||
case setting.HTTPScheme:
|
||||
protocol = "http"
|
||||
case setting.HTTP2Scheme, setting.HTTPSScheme:
|
||||
case setting.HTTP2Scheme, setting.HTTPSScheme, setting.SocketHTTP2Scheme:
|
||||
protocol = "https"
|
||||
default:
|
||||
// TODO: Handle other schemes?
|
||||
|
||||
+18
-9
@@ -37,10 +37,11 @@ import (
|
||||
type Scheme string
|
||||
|
||||
const (
|
||||
HTTPScheme Scheme = "http"
|
||||
HTTPSScheme Scheme = "https"
|
||||
HTTP2Scheme Scheme = "h2"
|
||||
SocketScheme Scheme = "socket"
|
||||
HTTPScheme Scheme = "http"
|
||||
HTTPSScheme Scheme = "https"
|
||||
HTTP2Scheme Scheme = "h2"
|
||||
SocketScheme Scheme = "socket"
|
||||
SocketHTTP2Scheme Scheme = "socket_h2"
|
||||
)
|
||||
|
||||
const (
|
||||
@@ -1983,23 +1984,31 @@ func (cfg *Cfg) readServerSettings(iniFile *ini.File) error {
|
||||
|
||||
protocolStr := valueAsString(server, "protocol", "http")
|
||||
|
||||
if protocolStr == "https" {
|
||||
switch protocolStr {
|
||||
case "https":
|
||||
cfg.Protocol = HTTPSScheme
|
||||
cfg.CertFile = server.Key("cert_file").String()
|
||||
cfg.KeyFile = server.Key("cert_key").String()
|
||||
cfg.CertPassword = server.Key("cert_pass").String()
|
||||
}
|
||||
if protocolStr == "h2" {
|
||||
case "h2":
|
||||
cfg.Protocol = HTTP2Scheme
|
||||
cfg.CertFile = server.Key("cert_file").String()
|
||||
cfg.KeyFile = server.Key("cert_key").String()
|
||||
cfg.CertPassword = server.Key("cert_pass").String()
|
||||
}
|
||||
if protocolStr == "socket" {
|
||||
case "socket":
|
||||
cfg.Protocol = SocketScheme
|
||||
cfg.SocketGid = server.Key("socket_gid").MustInt(-1)
|
||||
cfg.SocketMode = server.Key("socket_mode").MustInt(0660)
|
||||
cfg.SocketPath = server.Key("socket").String()
|
||||
case "socket_h2":
|
||||
cfg.Protocol = SocketHTTP2Scheme
|
||||
cfg.SocketGid = server.Key("socket_gid").MustInt(-1)
|
||||
cfg.SocketMode = server.Key("socket_mode").MustInt(0660)
|
||||
cfg.SocketPath = server.Key("socket").String()
|
||||
cfg.CertFile = server.Key("cert_file").String()
|
||||
cfg.KeyFile = server.Key("cert_key").String()
|
||||
cfg.CertPassword = server.Key("cert_pass").String()
|
||||
default:
|
||||
}
|
||||
|
||||
cfg.MinTLSVersion = valueAsString(server, "min_tls_version", "TLS1.2")
|
||||
|
||||
Reference in New Issue
Block a user