@@ -16,7 +16,6 @@ import (
1616)
1717
1818var (
19-
2019 // PluginSecureSocksProxyEnabled is a constant for the GF_SECURE_SOCKS_DATASOURCE_PROXY_SERVER_ENABLED
2120 // environment variable used to specify if a secure socks proxy is allowed to be used for datasource connections.
2221 PluginSecureSocksProxyEnabled = "GF_SECURE_SOCKS_DATASOURCE_PROXY_SERVER_ENABLED"
@@ -37,62 +36,63 @@ var (
3736 PluginSecureSocksProxyServerName = "GF_SECURE_SOCKS_DATASOURCE_PROXY_SERVER_NAME"
3837)
3938
40- // SecureSocksProxyConfig contains the information needed to allow datasource connections to be
41- // proxied to a secure socks proxy
42- type secureSocksProxyConfig struct {
43- clientCert string
44- clientKey string
45- rootCA string
46- proxyAddress string
47- serverName string
39+ // Client is the main Proxy Client interface.
40+ type Client interface {
41+ SecureSocksProxyEnabled (opts * Options ) bool
42+ ConfigureSecureSocksHTTPProxy (transport * http.Transport , opts * Options ) error
43+ NewSecureSocksProxyContextDialer (opts * Options ) (proxy.Dialer , error )
4844}
4945
50- // SecureSocksProxyEnabled checks if the Grafana instance allows the secure socks proxy to be used
51- // and the datasource options specify to use the proxy
52- func SecureSocksProxyEnabled (opts * Options ) bool {
53- if opts == nil {
54- return false
55- }
46+ // ClientCfg contains the information needed to allow datasource connections to be
47+ // proxied to a secure socks proxy.
48+ type ClientCfg struct {
49+ Enabled bool
50+ ClientCert string
51+ ClientKey string
52+ RootCA string
53+ ProxyAddress string
54+ ServerName string
55+ }
5656
57- if ! opts .Enabled {
58- return false
59- }
57+ // Cli is the default Proxy Client.
58+ var Cli = New ()
6059
61- if value , ok := os .LookupEnv (PluginSecureSocksProxyEnabled ); ok {
62- enabledOnInst , err := strconv .ParseBool (value )
63- if err != nil {
64- return false
65- }
60+ // New creates a new proxy client from the environment variables set by the grafana-server in the plugin.
61+ func New () Client {
62+ return NewWithCfg (getConfigFromEnv ())
63+ }
6664
67- return enabledOnInst
65+ // NewWithCfg creates a new proxy client from a given config.
66+ func NewWithCfg (cfg * ClientCfg ) Client {
67+ return & cfgProxyWrapper {
68+ cfg : cfg ,
6869 }
70+ }
6971
70- return false
72+ type cfgProxyWrapper struct {
73+ cfg * ClientCfg
7174}
7275
73- // SecureSocksProxyEnabledOnDS checks the datasource json data for `enableSecureSocksProxy`
74- // to determine if the secure socks proxy should be enabled on it
75- func SecureSocksProxyEnabledOnDS ( jsonData map [ string ] interface {} ) bool {
76- res , enabled := jsonData [ "enableSecureSocksProxy" ]
77- if ! enabled {
76+ // SecureSocksProxyEnabled checks if the Grafana instance allows the secure socks proxy to be used
77+ // and the datasource options specify to use the proxy
78+ func ( p * cfgProxyWrapper ) SecureSocksProxyEnabled ( opts * Options ) bool {
79+ // it cannot be enabled if it's not enabled on Grafana
80+ if p . cfg == nil || ! p . cfg . Enabled {
7881 return false
7982 }
8083
81- if val , ok := res .(bool ); ok {
82- return val
83- }
84-
85- return false
84+ // if it's enabled on Grafana, check if the datasource is using it
85+ return (opts != nil ) && opts .Enabled
8686}
8787
8888// ConfigureSecureSocksHTTPProxy takes a http.DefaultTransport and wraps it in a socks5 proxy with TLS
8989// if it is enabled on the datasource and the grafana instance
90- func ConfigureSecureSocksHTTPProxy (transport * http.Transport , opts * Options ) error {
91- if ! SecureSocksProxyEnabled (opts ) {
90+ func ( p * cfgProxyWrapper ) ConfigureSecureSocksHTTPProxy (transport * http.Transport , opts * Options ) error {
91+ if ! p . SecureSocksProxyEnabled (opts ) {
9292 return nil
9393 }
9494
95- dialSocksProxy , err := NewSecureSocksProxyContextDialer (opts )
95+ dialSocksProxy , err := p . NewSecureSocksProxyContextDialer (opts )
9696 if err != nil {
9797 return err
9898 }
@@ -107,17 +107,15 @@ func ConfigureSecureSocksHTTPProxy(transport *http.Transport, opts *Options) err
107107}
108108
109109// NewSecureSocksProxyContextDialer returns a proxy context dialer that can be used to allow datasource connections to go through a secure socks proxy
110- func NewSecureSocksProxyContextDialer (opts * Options ) (proxy.Dialer , error ) {
111- var err error
112- cfg , err := getConfigFromEnv ()
113- if err != nil {
114- return nil , err
110+ func (p * cfgProxyWrapper ) NewSecureSocksProxyContextDialer (opts * Options ) (proxy.Dialer , error ) {
111+ if ! p .SecureSocksProxyEnabled (opts ) {
112+ return nil , fmt .Errorf ("proxy not enabled" )
115113 }
116114
117115 clientOpts := setDefaults (opts )
118116
119117 certPool := x509 .NewCertPool ()
120- for _ , rootCAFile := range strings .Split (cfg .rootCA , " " ) {
118+ for _ , rootCAFile := range strings .Split (p . cfg .RootCA , " " ) {
121119 // nolint:gosec
122120 // The gosec G304 warning can be ignored because `rootCAFile` comes from config ini
123121 // and we check below if it's the right file type
@@ -136,15 +134,15 @@ func NewSecureSocksProxyContextDialer(opts *Options) (proxy.Dialer, error) {
136134 }
137135 }
138136
139- cert , err := tls .LoadX509KeyPair (cfg .clientCert , cfg .clientKey )
137+ cert , err := tls .LoadX509KeyPair (p . cfg .ClientCert , p . cfg .ClientKey )
140138 if err != nil {
141139 return nil , err
142140 }
143141
144142 tlsDialer := & tls.Dialer {
145143 Config : & tls.Config {
146144 Certificates : []tls.Certificate {cert },
147- ServerName : cfg .serverName ,
145+ ServerName : p . cfg .ServerName ,
148146 RootCAs : certPool ,
149147 MinVersion : tls .VersionTLS13 ,
150148 },
@@ -154,15 +152,15 @@ func NewSecureSocksProxyContextDialer(opts *Options) (proxy.Dialer, error) {
154152 },
155153 }
156154
157- var dsInfo * proxy.Auth
155+ var auth * proxy.Auth
158156 if clientOpts .Auth != nil {
159- dsInfo = & proxy.Auth {
157+ auth = & proxy.Auth {
160158 User : clientOpts .Auth .Username ,
161159 Password : clientOpts .Auth .Password ,
162160 }
163161 }
164162
165- dialSocksProxy , err := proxy .SOCKS5 ("tcp" , cfg .proxyAddress , dsInfo , tlsDialer )
163+ dialSocksProxy , err := proxy .SOCKS5 ("tcp" , p . cfg .ProxyAddress , auth , tlsDialer )
166164 if err != nil {
167165 return nil , err
168166 }
@@ -171,47 +169,70 @@ func NewSecureSocksProxyContextDialer(opts *Options) (proxy.Dialer, error) {
171169}
172170
173171// getConfigFromEnv gets the needed proxy information from the env variables that Grafana set with the values from the config ini
174- func getConfigFromEnv () (* secureSocksProxyConfig , error ) {
172+ func getConfigFromEnv () * ClientCfg {
173+ if value , ok := os .LookupEnv (PluginSecureSocksProxyEnabled ); ok {
174+ enabled , err := strconv .ParseBool (value )
175+ if err != nil || ! enabled {
176+ return nil
177+ }
178+ }
179+
175180 clientCert := ""
176181 if value , ok := os .LookupEnv (PluginSecureSocksProxyClientCert ); ok {
177182 clientCert = value
178183 } else {
179- return nil , fmt . Errorf ( "missing client cert" )
184+ return nil
180185 }
181186
182187 clientKey := ""
183188 if value , ok := os .LookupEnv (PluginSecureSocksProxyClientKey ); ok {
184189 clientKey = value
185190 } else {
186- return nil , fmt . Errorf ( "missing client key" )
191+ return nil
187192 }
188193
189194 rootCA := ""
190195 if value , ok := os .LookupEnv (PluginSecureSocksProxyRootCACert ); ok {
191196 rootCA = value
192197 } else {
193- return nil , fmt . Errorf ( "missing root ca" )
198+ return nil
194199 }
195200
196201 proxyAddress := ""
197202 if value , ok := os .LookupEnv (PluginSecureSocksProxyProxyAddress ); ok {
198203 proxyAddress = value
199204 } else {
200- return nil , fmt . Errorf ( "missing proxy address" )
205+ return nil
201206 }
202207
203208 serverName := ""
204209 if value , ok := os .LookupEnv (PluginSecureSocksProxyServerName ); ok {
205210 serverName = value
206211 } else {
207- return nil , fmt .Errorf ("missing server name" )
212+ return nil
213+ }
214+
215+ return & ClientCfg {
216+ Enabled : true ,
217+ ClientCert : clientCert ,
218+ ClientKey : clientKey ,
219+ RootCA : rootCA ,
220+ ProxyAddress : proxyAddress ,
221+ ServerName : serverName ,
222+ }
223+ }
224+
225+ // SecureSocksProxyEnabledOnDS checks the datasource json data for `enableSecureSocksProxy`
226+ // to determine if the secure socks proxy should be enabled on it
227+ func SecureSocksProxyEnabledOnDS (jsonData map [string ]interface {}) bool {
228+ res , enabled := jsonData ["enableSecureSocksProxy" ]
229+ if ! enabled {
230+ return false
231+ }
232+
233+ if val , ok := res .(bool ); ok {
234+ return val
208235 }
209236
210- return & secureSocksProxyConfig {
211- clientCert : clientCert ,
212- clientKey : clientKey ,
213- rootCA : rootCA ,
214- proxyAddress : proxyAddress ,
215- serverName : serverName ,
216- }, nil
237+ return false
217238}
0 commit comments