mirror of
https://github.com/grafana/grafana.git
synced 2025-02-25 18:55:37 -06:00
Plugins: Add option to disable TLS in the socks proxy (#79246)
* Plugins: add option to disable TLS in the socks proxy * fix allow_insecure docs * upgrade github.com/grafana/grafana-plugin-sdk-go from v0.196.0 to v0.197.0 * fix conflicts
This commit is contained in:
parent
d492100adc
commit
58678f5879
@ -1736,6 +1736,8 @@ server_name =
|
||||
proxy_address =
|
||||
# Determines if the secure socks proxy should be shown on the datasources page, defaults to true if the feature is enabled
|
||||
show_ui = true
|
||||
# Disables TLS in the secure socks proxy
|
||||
allow_insecure = false
|
||||
|
||||
################################## Feature Management ##############################################
|
||||
# Options to configure the experimental Feature Toggle Admin Page feature, which is behind the `featureToggleAdminPage` feature toggle. Use at your own risk.
|
||||
|
@ -1595,6 +1595,7 @@
|
||||
# The address of the socks5 proxy datasources should connect to
|
||||
; proxy_address =
|
||||
; show_ui = true
|
||||
; allow_insecure = false
|
||||
|
||||
################################## Feature Management ##############################################
|
||||
[feature_management]
|
||||
|
@ -32,14 +32,15 @@ To complete this task, you must first deploy a socks proxy server that supports
|
||||
|
||||
1. For Grafana to send data source connections to the socks5 server, use the following table to configure the `secure_socks_datasource_proxy` section of the `config.ini`:
|
||||
|
||||
| Key | Description | Example |
|
||||
| --------------- | ------------------------------------------ | ------------------------------- |
|
||||
| `enabled` | Enable this feature in Grafana | true |
|
||||
| `root_ca_cert` | The file path of the root ca cert | /etc/ca.crt |
|
||||
| `client_key` | The file path of the client private key | /etc/client.key |
|
||||
| `client_cert` | The file path of the client public key | /etc/client.crt |
|
||||
| `server_name` | The domain name of the proxy, used for SNI | proxy.grafana.svc.cluster.local |
|
||||
| `proxy_address` | the address of the proxy | localhost:9090 |
|
||||
| Key | Description | Example |
|
||||
| ---------------- | ------------------------------------------ | ------------------------------- |
|
||||
| `enabled` | Enable this feature in Grafana | true |
|
||||
| `root_ca_cert` | The file path of the root ca cert | /etc/ca.crt |
|
||||
| `client_key` | The file path of the client private key | /etc/client.key |
|
||||
| `client_cert` | The file path of the client public key | /etc/client.crt |
|
||||
| `server_name` | The domain name of the proxy, used for SNI | proxy.grafana.svc.cluster.local |
|
||||
| `proxy_address` | The address of the proxy | localhost:9090 |
|
||||
| `allow_insecure` | Disable TLS in the socks proxy | false |
|
||||
|
||||
1. Set up a data source and configure it to send data source connections through the proxy.
|
||||
|
||||
|
8
go.mod
8
go.mod
@ -67,9 +67,9 @@ require (
|
||||
github.com/grafana/cuetsy v0.1.11 // @grafana/grafana-as-code
|
||||
github.com/grafana/grafana-aws-sdk v0.19.1 // @grafana/aws-datasources
|
||||
github.com/grafana/grafana-azure-sdk-go v1.11.0 // @grafana/backend-platform
|
||||
github.com/grafana/grafana-plugin-sdk-go v0.196.0 // @grafana/plugins-platform-backend
|
||||
github.com/grafana/grafana-plugin-sdk-go v0.197.0 // @grafana/plugins-platform-backend
|
||||
github.com/grpc-ecosystem/go-grpc-middleware v1.4.0 // @grafana/backend-platform
|
||||
github.com/hashicorp/go-hclog v1.5.0 // @grafana/plugins-platform-backend
|
||||
github.com/hashicorp/go-hclog v1.6.1 // @grafana/plugins-platform-backend
|
||||
github.com/hashicorp/go-plugin v1.6.0 // @grafana/plugins-platform-backend
|
||||
github.com/hashicorp/go-version v1.6.0 // @grafana/backend-platform
|
||||
github.com/hashicorp/hcl/v2 v2.17.0 // @grafana/alerting-squad-backend
|
||||
@ -125,7 +125,7 @@ require (
|
||||
gopkg.in/mail.v2 v2.3.1 // @grafana/backend-platform
|
||||
gopkg.in/yaml.v2 v2.4.0 // indirect
|
||||
gopkg.in/yaml.v3 v3.0.1 // @grafana/alerting-squad-backend
|
||||
xorm.io/builder v0.3.6 // @grafana/backend-platform
|
||||
xorm.io/builder v0.3.6 // indirect; @grafana/backend-platform
|
||||
xorm.io/core v0.7.3 // @grafana/backend-platform
|
||||
xorm.io/xorm v0.8.2 // @grafana/alerting-squad-backend
|
||||
)
|
||||
@ -177,7 +177,7 @@ require (
|
||||
github.com/grpc-ecosystem/go-grpc-prometheus v1.2.1-0.20191002090509-6af20e3a5340 // indirect
|
||||
github.com/hashicorp/errwrap v1.1.0 // indirect
|
||||
github.com/hashicorp/go-msgpack v0.5.5 // indirect
|
||||
github.com/hashicorp/go-multierror v1.1.1 // @grafana/alerting-squad
|
||||
github.com/hashicorp/go-multierror v1.1.1 // indirect; @grafana/alerting-squad
|
||||
github.com/hashicorp/go-sockaddr v1.0.2 // indirect
|
||||
github.com/hashicorp/golang-lru v0.6.0 // indirect
|
||||
github.com/hashicorp/yamux v0.1.1 // indirect
|
||||
|
4
go.sum
4
go.sum
@ -1824,8 +1824,8 @@ github.com/grafana/grafana-google-sdk-go v0.1.0 h1:LKGY8z2DSxKjYfr2flZsWgTRTZ6HG
|
||||
github.com/grafana/grafana-google-sdk-go v0.1.0/go.mod h1:Vo2TKWfDVmNTELBUM+3lkrZvFtBws0qSZdXhQxRdJrE=
|
||||
github.com/grafana/grafana-plugin-sdk-go v0.94.0/go.mod h1:3VXz4nCv6wH5SfgB3mlW39s+c+LetqSCjFj7xxPC5+M=
|
||||
github.com/grafana/grafana-plugin-sdk-go v0.114.0/go.mod h1:D7x3ah+1d4phNXpbnOaxa/osSaZlwh9/ZUnGGzegRbk=
|
||||
github.com/grafana/grafana-plugin-sdk-go v0.196.0 h1:yDopQZ76Ug1UKZd2V4/MSi1k6SbeVz6o6ApwY6UP19U=
|
||||
github.com/grafana/grafana-plugin-sdk-go v0.196.0/go.mod h1:YB/80C5jTFj2jGAZVuuwsU6EVr63jjKcMgEB1nlSgiY=
|
||||
github.com/grafana/grafana-plugin-sdk-go v0.197.0 h1:5oUAQfa3gv5AX8Qhkoyuaj5E4hXbdR5mfa9P4zNQ0IE=
|
||||
github.com/grafana/grafana-plugin-sdk-go v0.197.0/go.mod h1:HC20FRnHgZprNqfcMRbrQ35gV25RctpHnRO+JbgmdqQ=
|
||||
github.com/grafana/kindsys v0.0.0-20230508162304-452481b63482 h1:1YNoeIhii4UIIQpCPU+EXidnqf449d0C3ZntAEt4KSo=
|
||||
github.com/grafana/kindsys v0.0.0-20230508162304-452481b63482/go.mod h1:GNcfpy5+SY6RVbNGQW264gC0r336Dm+0zgQ5vt6+M8Y=
|
||||
github.com/grafana/prometheus-alertmanager v0.25.1-0.20231027171310-70c52bf65758 h1:ATUhvJSJwzdzhnmzUI92fxVFqyqmcnzJ47wtHTK3LW4=
|
||||
|
@ -143,6 +143,7 @@ func (s *Service) GetConfigMap(ctx context.Context, pluginID string, _ *auth.Ext
|
||||
m[proxy.PluginSecureSocksProxyRootCACert] = s.cfg.ProxySettings.RootCA
|
||||
m[proxy.PluginSecureSocksProxyProxyAddress] = s.cfg.ProxySettings.ProxyAddress
|
||||
m[proxy.PluginSecureSocksProxyServerName] = s.cfg.ProxySettings.ServerName
|
||||
m[proxy.PluginSecureSocksProxyAllowInsecure] = strconv.FormatBool(s.cfg.ProxySettings.AllowInsecure)
|
||||
}
|
||||
|
||||
// Settings here will be extracted by grafana-azure-sdk-go from the plugin context
|
||||
@ -271,6 +272,7 @@ func (s *Service) secureSocksProxyEnvVars() []string {
|
||||
proxy.PluginSecureSocksProxyProxyAddress + "=" + s.cfg.ProxySettings.ProxyAddress,
|
||||
proxy.PluginSecureSocksProxyServerName + "=" + s.cfg.ProxySettings.ServerName,
|
||||
proxy.PluginSecureSocksProxyEnabled + "=" + strconv.FormatBool(s.cfg.ProxySettings.Enabled),
|
||||
proxy.PluginSecureSocksProxyAllowInsecure + "=" + strconv.FormatBool(s.cfg.ProxySettings.AllowInsecure),
|
||||
}
|
||||
}
|
||||
return nil
|
||||
|
@ -649,13 +649,14 @@ func TestService_GetConfigMap(t *testing.T) {
|
||||
cfg: &config.Cfg{
|
||||
Features: featuremgmt.WithFeatures("feat-2", "feat-500", "feat-1"),
|
||||
ProxySettings: setting.SecureSocksDSProxySettings{
|
||||
Enabled: true,
|
||||
ShowUI: true,
|
||||
ClientCert: "c3rt",
|
||||
ClientKey: "k3y",
|
||||
RootCA: "ca",
|
||||
ProxyAddress: "https://proxy.grafana.com",
|
||||
ServerName: "secureProxy",
|
||||
Enabled: true,
|
||||
ShowUI: true,
|
||||
ClientCert: "c3rt",
|
||||
ClientKey: "k3y",
|
||||
RootCA: "ca",
|
||||
ProxyAddress: "https://proxy.grafana.com",
|
||||
ServerName: "secureProxy",
|
||||
AllowInsecure: true,
|
||||
},
|
||||
},
|
||||
expected: map[string]string{
|
||||
@ -666,6 +667,7 @@ func TestService_GetConfigMap(t *testing.T) {
|
||||
"GF_SECURE_SOCKS_DATASOURCE_PROXY_ROOT_CA_CERT": "ca",
|
||||
"GF_SECURE_SOCKS_DATASOURCE_PROXY_PROXY_ADDRESS": "https://proxy.grafana.com",
|
||||
"GF_SECURE_SOCKS_DATASOURCE_PROXY_SERVER_NAME": "secureProxy",
|
||||
"GF_SECURE_SOCKS_DATASOURCE_PROXY_ALLOW_INSECURE": "true",
|
||||
},
|
||||
},
|
||||
{
|
||||
|
@ -528,11 +528,12 @@ func (s *Service) httpClientOptions(ctx context.Context, ds *datasources.DataSou
|
||||
},
|
||||
Timeouts: &sdkproxy.DefaultTimeoutOptions,
|
||||
ClientCfg: &sdkproxy.ClientCfg{
|
||||
ClientCert: s.cfg.SecureSocksDSProxy.ClientCert,
|
||||
ClientKey: s.cfg.SecureSocksDSProxy.ClientKey,
|
||||
RootCA: s.cfg.SecureSocksDSProxy.RootCA,
|
||||
ProxyAddress: s.cfg.SecureSocksDSProxy.ProxyAddress,
|
||||
ServerName: s.cfg.SecureSocksDSProxy.ServerName,
|
||||
ClientCert: s.cfg.SecureSocksDSProxy.ClientCert,
|
||||
ClientKey: s.cfg.SecureSocksDSProxy.ClientKey,
|
||||
RootCA: s.cfg.SecureSocksDSProxy.RootCA,
|
||||
ProxyAddress: s.cfg.SecureSocksDSProxy.ProxyAddress,
|
||||
ServerName: s.cfg.SecureSocksDSProxy.ServerName,
|
||||
AllowInsecure: s.cfg.SecureSocksDSProxy.AllowInsecure,
|
||||
},
|
||||
}
|
||||
|
||||
|
@ -7,13 +7,14 @@ import (
|
||||
)
|
||||
|
||||
type SecureSocksDSProxySettings struct {
|
||||
Enabled bool
|
||||
ShowUI bool
|
||||
ClientCert string
|
||||
ClientKey string
|
||||
RootCA string
|
||||
ProxyAddress string
|
||||
ServerName string
|
||||
Enabled bool
|
||||
ShowUI bool
|
||||
AllowInsecure bool
|
||||
ClientCert string
|
||||
ClientKey string
|
||||
RootCA string
|
||||
ProxyAddress string
|
||||
ServerName string
|
||||
}
|
||||
|
||||
func readSecureSocksDSProxySettings(iniFile *ini.File) (SecureSocksDSProxySettings, error) {
|
||||
@ -26,21 +27,27 @@ func readSecureSocksDSProxySettings(iniFile *ini.File) (SecureSocksDSProxySettin
|
||||
s.ProxyAddress = secureSocksProxySection.Key("proxy_address").MustString("")
|
||||
s.ServerName = secureSocksProxySection.Key("server_name").MustString("")
|
||||
s.ShowUI = secureSocksProxySection.Key("show_ui").MustBool(true)
|
||||
s.AllowInsecure = secureSocksProxySection.Key("allow_insecure").MustBool(false)
|
||||
|
||||
if !s.Enabled {
|
||||
return s, nil
|
||||
}
|
||||
|
||||
// all fields must be specified to use the proxy
|
||||
if s.RootCA == "" {
|
||||
return s, errors.New("rootCA required")
|
||||
} else if s.ClientCert == "" || s.ClientKey == "" {
|
||||
return s, errors.New("client key pair required")
|
||||
} else if s.ServerName == "" {
|
||||
return s, errors.New("server name required")
|
||||
} else if s.ProxyAddress == "" {
|
||||
if s.ProxyAddress == "" {
|
||||
return s, errors.New("proxy address required")
|
||||
}
|
||||
|
||||
// If the proxy is going to use TLS.
|
||||
if !s.AllowInsecure {
|
||||
// all fields must be specified to use the proxy
|
||||
if s.RootCA == "" {
|
||||
return s, errors.New("rootCA required")
|
||||
} else if s.ClientCert == "" || s.ClientKey == "" {
|
||||
return s, errors.New("client key pair required")
|
||||
} else if s.ServerName == "" {
|
||||
return s, errors.New("server name required")
|
||||
}
|
||||
}
|
||||
|
||||
return s, nil
|
||||
}
|
||||
|
154
pkg/setting/setting_secure_socks_proxy_test.go
Normal file
154
pkg/setting/setting_secure_socks_proxy_test.go
Normal file
@ -0,0 +1,154 @@
|
||||
package setting
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
"gopkg.in/ini.v1"
|
||||
)
|
||||
|
||||
func mustNewIniFile(fileContents string) *ini.File {
|
||||
file, err := ini.Load([]byte(fileContents))
|
||||
if err != nil {
|
||||
panic(fmt.Sprintf("creating ini file for test: %s", err))
|
||||
}
|
||||
return file
|
||||
}
|
||||
|
||||
func TestReadSecureSocksDSProxySettings(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
cases := []struct {
|
||||
description string
|
||||
iniFile *ini.File
|
||||
expectedSettings SecureSocksDSProxySettings
|
||||
expectedErr error
|
||||
}{
|
||||
{
|
||||
description: "default values",
|
||||
iniFile: mustNewIniFile(`
|
||||
[secure_socks_datasource_proxy]
|
||||
`),
|
||||
expectedSettings: SecureSocksDSProxySettings{
|
||||
Enabled: false,
|
||||
ClientCert: "",
|
||||
ClientKey: "",
|
||||
RootCA: "",
|
||||
ProxyAddress: "",
|
||||
ServerName: "",
|
||||
ShowUI: true,
|
||||
AllowInsecure: false,
|
||||
},
|
||||
},
|
||||
{
|
||||
description: "root ca is required",
|
||||
iniFile: mustNewIniFile(`
|
||||
[secure_socks_datasource_proxy]
|
||||
enabled = true
|
||||
proxy_address = address
|
||||
`),
|
||||
expectedErr: errors.New("rootCA required"),
|
||||
},
|
||||
{
|
||||
description: "client cert is required",
|
||||
iniFile: mustNewIniFile(`
|
||||
[secure_socks_datasource_proxy]
|
||||
enabled = true
|
||||
proxy_address = address
|
||||
root_ca_cert = cert
|
||||
`),
|
||||
expectedErr: errors.New("client key pair required"),
|
||||
},
|
||||
{
|
||||
description: "client key is required",
|
||||
iniFile: mustNewIniFile(`
|
||||
[secure_socks_datasource_proxy]
|
||||
enabled = true
|
||||
proxy_address = address
|
||||
root_ca_cert = cert1
|
||||
client_cert = cert2
|
||||
`),
|
||||
expectedErr: errors.New("client key pair required"),
|
||||
},
|
||||
{
|
||||
description: "server name is required",
|
||||
iniFile: mustNewIniFile(`
|
||||
[secure_socks_datasource_proxy]
|
||||
enabled = true
|
||||
proxy_address = address
|
||||
root_ca_cert = cert1
|
||||
client_cert = cert2
|
||||
client_key = key
|
||||
`),
|
||||
expectedErr: errors.New("server name required"),
|
||||
},
|
||||
{
|
||||
description: "proxy address is required",
|
||||
iniFile: mustNewIniFile(`
|
||||
[secure_socks_datasource_proxy]
|
||||
enabled = true
|
||||
root_ca_cert = cert1
|
||||
client_cert = cert2
|
||||
client_key = key
|
||||
server_name = name
|
||||
`),
|
||||
expectedErr: errors.New("proxy address required"),
|
||||
},
|
||||
{
|
||||
description: "root ca, client cert and client key are not required in insecure more",
|
||||
iniFile: mustNewIniFile(`
|
||||
[secure_socks_datasource_proxy]
|
||||
enabled = true
|
||||
proxy_address = address
|
||||
server_name = name
|
||||
allow_insecure = true
|
||||
`),
|
||||
expectedSettings: SecureSocksDSProxySettings{
|
||||
Enabled: true,
|
||||
ProxyAddress: "address",
|
||||
ServerName: "name",
|
||||
ShowUI: true,
|
||||
AllowInsecure: true,
|
||||
},
|
||||
},
|
||||
{
|
||||
description: "custom values",
|
||||
iniFile: mustNewIniFile(`
|
||||
[secure_socks_datasource_proxy]
|
||||
enabled = true
|
||||
client_cert = cert
|
||||
client_key = key
|
||||
root_ca_cert = root_ca
|
||||
proxy_address = proxy_address
|
||||
server_name = server_name
|
||||
show_ui = false
|
||||
allow_insecure = true
|
||||
`),
|
||||
expectedSettings: SecureSocksDSProxySettings{
|
||||
Enabled: true,
|
||||
ClientCert: "cert",
|
||||
ClientKey: "key",
|
||||
RootCA: "root_ca",
|
||||
ProxyAddress: "proxy_address",
|
||||
ServerName: "server_name",
|
||||
ShowUI: false,
|
||||
AllowInsecure: true,
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
for _, tt := range cases {
|
||||
t.Run(tt.description, func(t *testing.T) {
|
||||
settings, err := readSecureSocksDSProxySettings(tt.iniFile)
|
||||
|
||||
if tt.expectedErr != nil {
|
||||
assert.Equal(t, tt.expectedErr, err)
|
||||
} else {
|
||||
assert.Equal(t, tt.expectedSettings, settings)
|
||||
assert.NoError(t, err)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user