Skip to content

Commit aa5d1fd

Browse files
secure socks proxy: add option to disable tls in the socks proxy dialer (#833)
* secure socks proxy: add option to disable tls in the socks proxy dialer * check error when parsing GF_SECURE_SOCKS_DATASOURCE_PROXY_ALLOW_INSECURE * remove comment about tls config from cfgProxyWrapper.ConfigureSecureSocksHTTPProxy * cfgProxyWrapper.NewSecureSocksProxyContextDialer: extract TLS dialer instantiation to a method * update getConfigFromEnv to handle allowInsecure
1 parent f135b5d commit aa5d1fd

File tree

5 files changed

+253
-53
lines changed

5 files changed

+253
-53
lines changed

backend/common.go

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -125,7 +125,11 @@ func (s *DataSourceInstanceSettings) HTTPClientOptions(ctx context.Context) (htt
125125
setCustomOptionsFromHTTPSettings(&opts, httpSettings)
126126

127127
cfg := GrafanaConfigFromContext(ctx)
128-
opts.ProxyOptions, err = s.ProxyOptions(cfg.proxy().clientCfg)
128+
proxy, err := cfg.proxy()
129+
if err != nil {
130+
return opts, err
131+
}
132+
opts.ProxyOptions, err = s.ProxyOptions(proxy.clientCfg)
129133
if err != nil {
130134
return opts, err
131135
}

backend/config.go

Lines changed: 22 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -101,19 +101,33 @@ type Proxy struct {
101101
clientCfg *proxy.ClientCfg
102102
}
103103

104-
func (c *GrafanaCfg) proxy() Proxy {
104+
func (c *GrafanaCfg) proxy() (Proxy, error) {
105105
if v, exists := c.config[proxy.PluginSecureSocksProxyEnabled]; exists && v == strconv.FormatBool(true) {
106+
var (
107+
allowInsecure = false
108+
err error
109+
)
110+
111+
if v := c.Get(proxy.PluginSecureSocksProxyAllowInsecure); v != "" {
112+
allowInsecure, err = strconv.ParseBool(c.Get(proxy.PluginSecureSocksProxyAllowInsecure))
113+
if err != nil {
114+
return Proxy{}, fmt.Errorf("parsing %s, value must be a boolean: %w", proxy.PluginSecureSocksProxyAllowInsecure, err)
115+
}
116+
}
117+
106118
return Proxy{
107119
clientCfg: &proxy.ClientCfg{
108-
ClientCert: c.Get(proxy.PluginSecureSocksProxyClientCert),
109-
ClientKey: c.Get(proxy.PluginSecureSocksProxyClientKey),
110-
RootCA: c.Get(proxy.PluginSecureSocksProxyRootCACert),
111-
ProxyAddress: c.Get(proxy.PluginSecureSocksProxyProxyAddress),
112-
ServerName: c.Get(proxy.PluginSecureSocksProxyServerName),
120+
ClientCert: c.Get(proxy.PluginSecureSocksProxyClientCert),
121+
ClientKey: c.Get(proxy.PluginSecureSocksProxyClientKey),
122+
RootCA: c.Get(proxy.PluginSecureSocksProxyRootCACert),
123+
ProxyAddress: c.Get(proxy.PluginSecureSocksProxyProxyAddress),
124+
ServerName: c.Get(proxy.PluginSecureSocksProxyServerName),
125+
AllowInsecure: allowInsecure,
113126
},
114-
}
127+
}, nil
115128
}
116-
return Proxy{}
129+
130+
return Proxy{}, nil
117131
}
118132

119133
func (c *GrafanaCfg) AppURL() (string, error) {

backend/config_test.go

Lines changed: 29 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import (
44
"context"
55
"testing"
66

7+
"github.com/stretchr/testify/assert"
78
"github.com/stretchr/testify/require"
89

910
"github.com/grafana/grafana-plugin-sdk-go/backend/proxy"
@@ -109,14 +110,41 @@ func TestConfig(t *testing.T) {
109110
},
110111
},
111112
},
113+
{
114+
name: "feature toggles disabled and insecure proxy enabled",
115+
cfg: NewGrafanaCfg(map[string]string{
116+
featuretoggles.EnabledFeatures: "",
117+
proxy.PluginSecureSocksProxyEnabled: "true",
118+
proxy.PluginSecureSocksProxyProxyAddress: "localhost:1234",
119+
proxy.PluginSecureSocksProxyServerName: "localhost",
120+
proxy.PluginSecureSocksProxyClientKey: "clientKey",
121+
proxy.PluginSecureSocksProxyClientCert: "clientCert",
122+
proxy.PluginSecureSocksProxyRootCACert: "rootCACert",
123+
proxy.PluginSecureSocksProxyAllowInsecure: "true",
124+
}),
125+
expectedFeatureToggles: FeatureToggles{},
126+
expectedProxy: Proxy{
127+
clientCfg: &proxy.ClientCfg{
128+
ClientCert: "clientCert",
129+
ClientKey: "clientKey",
130+
RootCA: "rootCACert",
131+
ProxyAddress: "localhost:1234",
132+
ServerName: "localhost",
133+
AllowInsecure: true,
134+
},
135+
},
136+
},
112137
}
113138

114139
for _, tc := range tcs {
115140
ctx := WithGrafanaConfig(context.Background(), tc.cfg)
116141
cfg := GrafanaConfigFromContext(ctx)
117142

118143
require.Equal(t, tc.expectedFeatureToggles, cfg.FeatureToggles())
119-
require.Equal(t, tc.expectedProxy, cfg.proxy())
144+
proxy, err := cfg.proxy()
145+
assert.NoError(t, err)
146+
147+
require.Equal(t, tc.expectedProxy, proxy)
120148
}
121149
})
122150
}

backend/proxy/secure_socks_proxy.go

Lines changed: 70 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ import (
66
"crypto/x509"
77
"encoding/pem"
88
"errors"
9+
"fmt"
910
"net"
1011
"net/http"
1112
"os"
@@ -39,6 +40,9 @@ var (
3940
// PluginSecureSocksProxyServerName is a constant for the GF_SECURE_SOCKS_DATASOURCE_PROXY_SERVER_NAME
4041
// environment variable used to specify the server name of the secure socks proxy.
4142
PluginSecureSocksProxyServerName = "GF_SECURE_SOCKS_DATASOURCE_PROXY_SERVER_NAME"
43+
// PluginSecureSocksProxyAllowInsecure is a constant for the GF_SECURE_SOCKS_DATASOURCE_PROXY_ALLOW_INSECURE
44+
// environment variable used to specify if the proxy should use a TLS dialer.
45+
PluginSecureSocksProxyAllowInsecure = "GF_SECURE_SOCKS_DATASOURCE_PROXY_ALLOW_INSECURE"
4246
)
4347

4448
var (
@@ -60,11 +64,12 @@ type Client interface {
6064
// ClientCfg contains the information needed to allow datasource connections to be
6165
// proxied to a secure socks proxy.
6266
type ClientCfg struct {
63-
ClientCert string
64-
ClientKey string
65-
RootCA string
66-
ProxyAddress string
67-
ServerName string
67+
ClientCert string
68+
ClientKey string
69+
RootCA string
70+
ProxyAddress string
71+
ServerName string
72+
AllowInsecure bool
6873
}
6974

7075
// New creates a new proxy client from a given config.
@@ -119,6 +124,38 @@ func (p *cfgProxyWrapper) NewSecureSocksProxyContextDialer() (proxy.Dialer, erro
119124
return nil, errors.New("proxy not enabled")
120125
}
121126

127+
var dialer proxy.Dialer
128+
129+
if p.opts.ClientCfg.AllowInsecure {
130+
dialer = &net.Dialer{
131+
Timeout: p.opts.Timeouts.Timeout,
132+
KeepAlive: p.opts.Timeouts.KeepAlive,
133+
}
134+
} else {
135+
d, err := p.getTLSDialer()
136+
if err != nil {
137+
return nil, fmt.Errorf("instantiating tls dialer: %w", err)
138+
}
139+
dialer = d
140+
}
141+
142+
var auth *proxy.Auth
143+
if p.opts.Auth != nil {
144+
auth = &proxy.Auth{
145+
User: p.opts.Auth.Username,
146+
Password: p.opts.Auth.Password,
147+
}
148+
}
149+
150+
dialSocksProxy, err := proxy.SOCKS5("tcp", p.opts.ClientCfg.ProxyAddress, auth, dialer)
151+
if err != nil {
152+
return nil, err
153+
}
154+
155+
return newInstrumentedSocksDialer(dialSocksProxy), nil
156+
}
157+
158+
func (p *cfgProxyWrapper) getTLSDialer() (*tls.Dialer, error) {
122159
certPool := x509.NewCertPool()
123160
for _, rootCAFile := range strings.Split(p.opts.ClientCfg.RootCA, " ") {
124161
// nolint:gosec
@@ -144,7 +181,7 @@ func (p *cfgProxyWrapper) NewSecureSocksProxyContextDialer() (proxy.Dialer, erro
144181
return nil, err
145182
}
146183

147-
tlsDialer := &tls.Dialer{
184+
return &tls.Dialer{
148185
Config: &tls.Config{
149186
Certificates: []tls.Certificate{cert},
150187
ServerName: p.opts.ClientCfg.ServerName,
@@ -155,22 +192,7 @@ func (p *cfgProxyWrapper) NewSecureSocksProxyContextDialer() (proxy.Dialer, erro
155192
Timeout: p.opts.Timeouts.Timeout,
156193
KeepAlive: p.opts.Timeouts.KeepAlive,
157194
},
158-
}
159-
160-
var auth *proxy.Auth
161-
if p.opts.Auth != nil {
162-
auth = &proxy.Auth{
163-
User: p.opts.Auth.Username,
164-
Password: p.opts.Auth.Password,
165-
}
166-
}
167-
168-
dialSocksProxy, err := proxy.SOCKS5("tcp", p.opts.ClientCfg.ProxyAddress, auth, tlsDialer)
169-
if err != nil {
170-
return nil, err
171-
}
172-
173-
return newInstrumentedSocksDialer(dialSocksProxy), nil
195+
}, nil
174196
}
175197

176198
// getConfigFromEnv gets the needed proxy information from the env variables that Grafana set with the values from the config ini
@@ -182,6 +204,26 @@ func getConfigFromEnv() *ClientCfg {
182204
}
183205
}
184206

207+
proxyAddress := ""
208+
if value, ok := os.LookupEnv(PluginSecureSocksProxyProxyAddress); ok {
209+
proxyAddress = value
210+
} else {
211+
return nil
212+
}
213+
214+
allowInsecure := false
215+
if value, ok := os.LookupEnv(PluginSecureSocksProxyAllowInsecure); ok {
216+
allowInsecure, _ = strconv.ParseBool(value)
217+
}
218+
219+
// We only need to fill these fields on insecure mode.
220+
if allowInsecure {
221+
return &ClientCfg{
222+
ProxyAddress: proxyAddress,
223+
AllowInsecure: allowInsecure,
224+
}
225+
}
226+
185227
clientCert := ""
186228
if value, ok := os.LookupEnv(PluginSecureSocksProxyClientCert); ok {
187229
clientCert = value
@@ -203,13 +245,6 @@ func getConfigFromEnv() *ClientCfg {
203245
return nil
204246
}
205247

206-
proxyAddress := ""
207-
if value, ok := os.LookupEnv(PluginSecureSocksProxyProxyAddress); ok {
208-
proxyAddress = value
209-
} else {
210-
return nil
211-
}
212-
213248
serverName := ""
214249
if value, ok := os.LookupEnv(PluginSecureSocksProxyServerName); ok {
215250
serverName = value
@@ -218,11 +253,12 @@ func getConfigFromEnv() *ClientCfg {
218253
}
219254

220255
return &ClientCfg{
221-
ClientCert: clientCert,
222-
ClientKey: clientKey,
223-
RootCA: rootCA,
224-
ProxyAddress: proxyAddress,
225-
ServerName: serverName,
256+
ClientCert: clientCert,
257+
ClientKey: clientKey,
258+
RootCA: rootCA,
259+
ProxyAddress: proxyAddress,
260+
ServerName: serverName,
261+
AllowInsecure: false,
226262
}
227263
}
228264

0 commit comments

Comments
 (0)