[v10.4.x] Plugins: Pass PDC file contents in requests (#85144)

* Plugins: Pass PDC file contents in requests (#84783)

* Plugins: Pass PDC file contents in requests

* go mod tidy

* undo go.mod changes

* fix linter

* fix tests

* undo unnecessary changes

* update dep

* join with comma

* update naming

* bump SDK

(cherry picked from commit b765c21d4c)

* set env + req config

* fix linter
pull/85174/head
Will Browne 1 year ago committed by GitHub
parent b560729873
commit d26a1454c8
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
  1. 12
      go.mod
  2. 20
      go.sum
  3. 23
      pkg/plugins/envvars/envvars.go
  4. 6
      pkg/plugins/envvars/envvars_test.go
  5. 2
      pkg/services/datasources/service/datasource.go
  6. 74
      pkg/setting/setting_secure_socks_proxy.go
  7. 152
      pkg/setting/setting_secure_socks_proxy_test.go

@ -63,7 +63,7 @@ require (
github.com/grafana/cuetsy v0.1.11 // @grafana/grafana-as-code
github.com/grafana/grafana-aws-sdk v0.23.1 // @grafana/aws-datasources
github.com/grafana/grafana-azure-sdk-go v1.12.0 // @grafana/partner-datasources
github.com/grafana/grafana-plugin-sdk-go v0.215.0 // @grafana/plugins-platform-backend
github.com/grafana/grafana-plugin-sdk-go v0.217.0 // @grafana/plugins-platform-backend
github.com/grpc-ecosystem/go-grpc-middleware v1.4.0 // @grafana/backend-platform
github.com/hashicorp/go-hclog v1.6.2 // @grafana/plugins-platform-backend
github.com/hashicorp/go-plugin v1.6.0 // @grafana/plugins-platform-backend
@ -105,9 +105,9 @@ require (
go.opentelemetry.io/otel/exporters/jaeger v1.10.0 // @grafana/backend-platform
go.opentelemetry.io/otel/sdk v1.24.0 // @grafana/backend-platform
go.opentelemetry.io/otel/trace v1.24.0 // @grafana/backend-platform
golang.org/x/crypto v0.19.0 // @grafana/backend-platform
golang.org/x/crypto v0.21.0 // @grafana/backend-platform
golang.org/x/exp v0.0.0-20231206192017-f3f8817b8deb // @grafana/alerting-squad-backend
golang.org/x/net v0.21.0 // @grafana/oss-big-tent @grafana/partner-datasources
golang.org/x/net v0.22.0 // @grafana/oss-big-tent @grafana/partner-datasources
golang.org/x/oauth2 v0.16.0 // @grafana/grafana-authnz-team
golang.org/x/sync v0.6.0 // @grafana/alerting-squad-backend
golang.org/x/time v0.5.0 // @grafana/backend-platform
@ -115,7 +115,7 @@ require (
gonum.org/v1/gonum v0.12.0 // @grafana/observability-metrics
google.golang.org/api v0.155.0 // @grafana/backend-platform
google.golang.org/grpc v1.62.1 // @grafana/plugins-platform-backend
google.golang.org/protobuf v1.32.0 // @grafana/plugins-platform-backend
google.golang.org/protobuf v1.33.0 // @grafana/plugins-platform-backend
gopkg.in/alexcesaro/quotedprintable.v3 v3.0.0-20150716171945-2caba252f4dc // indirect
gopkg.in/ini.v1 v1.67.0 // @grafana/alerting-squad-backend
gopkg.in/mail.v2 v2.3.1 // @grafana/backend-platform
@ -214,7 +214,7 @@ require (
go.opencensus.io v0.24.0 // indirect
go.uber.org/atomic v1.11.0 // @grafana/alerting-squad-backend
go.uber.org/goleak v1.3.0 // indirect
golang.org/x/sys v0.17.0 // indirect
golang.org/x/sys v0.18.0 // indirect
golang.org/x/text v0.14.0 // @grafana/backend-platform
golang.org/x/xerrors v0.0.0-20220907171357-04be3eba64a2 // indirect
google.golang.org/appengine v1.6.8 // indirect
@ -403,7 +403,7 @@ require (
go.starlark.net v0.0.0-20230525235612-a134d8f9ddca // indirect
go.uber.org/multierr v1.11.0 // indirect
go.uber.org/zap v1.26.0 // indirect
golang.org/x/term v0.17.0 // indirect
golang.org/x/term v0.18.0 // indirect
google.golang.org/genproto/googleapis/api v0.0.0-20240123012728-ef4313101c80 // indirect
google.golang.org/genproto/googleapis/rpc v0.0.0-20240123012728-ef4313101c80 // indirect
gopkg.in/fsnotify/fsnotify.v1 v1.4.7 // indirect

@ -2535,8 +2535,8 @@ github.com/grafana/grafana-google-sdk-go v0.1.0/go.mod h1:Vo2TKWfDVmNTELBUM+3lkr
github.com/grafana/grafana-openapi-client-go v0.0.0-20231213163343-bd475d63fb79 h1:r+mU5bGMzcXCRVAuOrTn54S80qbfVkvTdUJZfSfTNbs=
github.com/grafana/grafana-openapi-client-go v0.0.0-20231213163343-bd475d63fb79/go.mod h1:wc6Hbh3K2TgCUSfBC/BOzabItujtHMESZeFk5ZhdxhQ=
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.215.0 h1:02gwVsqYi1I+U48/MQR61eOMxiXE7KNKC8QsiMJ//qA=
github.com/grafana/grafana-plugin-sdk-go v0.215.0/go.mod h1:nBsh3jRItKQUXDF2BQkiQCPxqrsSQeb+7hiFyJTO1RE=
github.com/grafana/grafana-plugin-sdk-go v0.217.0 h1:oQjq5KRrVrhweXHxFtEMgjv1KW7hujGiRPIYrsPZ9PE=
github.com/grafana/grafana-plugin-sdk-go v0.217.0/go.mod h1:FdvSvOliqpVLnytM7e89zCFyYPDE6VOn9SIjVQRvVxM=
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.20240208102907-e82436ce63e6 h1:CBm0rwLCPDyarg9/bHJ50rBLYmyMDoyCWpgRMITZhdA=
@ -3893,8 +3893,9 @@ golang.org/x/crypto v0.14.0/go.mod h1:MVFd36DqK4CsrnJYDkBA3VC4m2GkXAM0PvzMCn4JQf
golang.org/x/crypto v0.15.0/go.mod h1:4ChreQoLWfG3xLDer1WdlH5NdlQ3+mwnQq1YTKY+72g=
golang.org/x/crypto v0.16.0/go.mod h1:gCAAfMLgwOJRpTjQ2zCCt2OcSfYMTeZVSRtQlPC7Nq4=
golang.org/x/crypto v0.18.0/go.mod h1:R0j02AL6hcrfOiy9T4ZYp/rcWeMxM3L6QYxlOuEG1mg=
golang.org/x/crypto v0.19.0 h1:ENy+Az/9Y1vSrlrvBSyna3PITt4tiZLf7sgCjZBX7Wo=
golang.org/x/crypto v0.19.0/go.mod h1:Iy9bg/ha4yyC70EfRS8jz+B6ybOBKMaSxLj6P6oBDfU=
golang.org/x/crypto v0.21.0 h1:X31++rzVUdKhX5sWmSOFZxx8UW/ldWx55cbf08iNAMA=
golang.org/x/crypto v0.21.0/go.mod h1:0BP7YvVV9gBbVKyeTG0Gyn+gZm94bibOW5BjDEYAOMs=
golang.org/x/exp v0.0.0-20180321215751-8460e604b9de/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
golang.org/x/exp v0.0.0-20180807140117-3d87b88a115f/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
@ -4080,8 +4081,8 @@ golang.org/x/net v0.17.0/go.mod h1:NxSsAGuq816PNPmqtQdLE42eU2Fs7NoRIZrHJAlaCOE=
golang.org/x/net v0.18.0/go.mod h1:/czyP5RqHAH4odGYxBJ1qz0+CE5WZ+2j1YgoEo8F2jQ=
golang.org/x/net v0.19.0/go.mod h1:CfAk/cbD4CthTvqiEl8NpboMuiuOYsAr/7NOjZJtv1U=
golang.org/x/net v0.20.0/go.mod h1:z8BVo6PvndSri0LbOE3hAn0apkU+1YvI6E70E9jsnvY=
golang.org/x/net v0.21.0 h1:AQyQV4dYCvJ7vGmJyKki9+PBdyvhkSd8EIx/qb0AYv4=
golang.org/x/net v0.21.0/go.mod h1:bIjVDfnllIU7BJ2DNgfnXvpSvtn8VRwhlsaeUTyUS44=
golang.org/x/net v0.22.0 h1:9sGLhx7iRIHEiX0oAJ3MRZMUCElJgy7Br1nO+AMN3Tc=
golang.org/x/net v0.22.0/go.mod h1:JKghWKKOSdJwpW2GEx0Ja7fmaKnMsbu+MWVZTokSYmg=
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
golang.org/x/oauth2 v0.0.0-20181003184128-c57b0facaced/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
golang.org/x/oauth2 v0.0.0-20181106182150-f42d05182288/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
@ -4319,8 +4320,9 @@ golang.org/x/sys v0.13.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.14.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/sys v0.15.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/sys v0.16.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/sys v0.17.0 h1:25cE3gD+tdBA7lp7QfhuV+rJiE9YXTcS3VG1SqssI/Y=
golang.org/x/sys v0.17.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/sys v0.18.0 h1:DBdB3niSjOA/O0blCZBqDefyWNYveAYMNF1Wum0DYQ4=
golang.org/x/sys v0.18.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw=
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
@ -4341,8 +4343,9 @@ golang.org/x/term v0.13.0/go.mod h1:LTmsnFJwVN6bCy1rVCoS+qHT1HhALEFxKncY3WNNh4U=
golang.org/x/term v0.14.0/go.mod h1:TySc+nGkYR6qt8km8wUhuFRTVSMIX3XPR58y2lC8vww=
golang.org/x/term v0.15.0/go.mod h1:BDl952bC7+uMoWR75FIrCDx79TPU9oHkTZ9yRbYOrX0=
golang.org/x/term v0.16.0/go.mod h1:yn7UURbUtPyrVJPGPq404EukNFxcm/foM+bV/bfcDsY=
golang.org/x/term v0.17.0 h1:mkTF7LCd6WGJNL3K1Ad7kwxNfYAW6a8a8QqtMblp/4U=
golang.org/x/term v0.17.0/go.mod h1:lLRBjIVuehSbZlaOtGMbcMncT+aqLLLmKrsjNrUguwk=
golang.org/x/term v0.18.0 h1:FcHjZXDMxI8mM3nwhX9HlKop4C0YQvCVCdwYl2wOtE8=
golang.org/x/term v0.18.0/go.mod h1:ILwASektA3OnRv7amZ1xhE/KTR+u50pbXfZ03+6Nx58=
golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
@ -4930,8 +4933,9 @@ google.golang.org/protobuf v1.28.1/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqw
google.golang.org/protobuf v1.29.1/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I=
google.golang.org/protobuf v1.30.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I=
google.golang.org/protobuf v1.31.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I=
google.golang.org/protobuf v1.32.0 h1:pPC6BG5ex8PDFnkbrGU3EixyhKcQ2aDuBS36lqK/C7I=
google.golang.org/protobuf v1.32.0/go.mod h1:c6P6GXX6sHbq/GpV6MGZEdwhWPcYBgnhAHhKbcUYpos=
google.golang.org/protobuf v1.33.0 h1:uNO2rsAINq/JlFpSdYEKIZ0uKD/R9cpdv0T+yoGwGmI=
google.golang.org/protobuf v1.33.0/go.mod h1:c6P6GXX6sHbq/GpV6MGZEdwhWPcYBgnhAHhKbcUYpos=
gopkg.in/DataDog/dd-trace-go.v1 v1.27.0/go.mod h1:Sp1lku8WJMvNV0kjDI4Ni/T7J/U3BO5ct5kEaoVU8+I=
gopkg.in/airbrake/gobrake.v2 v2.0.9/go.mod h1:/h5ZAUhDkGaJfjzjKLSjv6zCL6O0LLBxU4K+aSYdM/U=
gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw=

@ -152,7 +152,7 @@ func (s *Service) GetConfigMap(ctx context.Context, pluginID string, _ *auth.Ext
m[proxy.PluginSecureSocksProxyEnabled] = "true"
m[proxy.PluginSecureSocksProxyClientCert] = s.cfg.ProxySettings.ClientCert
m[proxy.PluginSecureSocksProxyClientKey] = s.cfg.ProxySettings.ClientKey
m[proxy.PluginSecureSocksProxyRootCACert] = s.cfg.ProxySettings.RootCA
m[proxy.PluginSecureSocksProxyRootCAs] = strings.Join(s.cfg.ProxySettings.RootCAs, " ")
m[proxy.PluginSecureSocksProxyProxyAddress] = s.cfg.ProxySettings.ProxyAddress
m[proxy.PluginSecureSocksProxyServerName] = s.cfg.ProxySettings.ServerName
m[proxy.PluginSecureSocksProxyAllowInsecure] = strconv.FormatBool(s.cfg.ProxySettings.AllowInsecure)
@ -287,13 +287,20 @@ func (s *Service) awsEnvVars() []string {
func (s *Service) secureSocksProxyEnvVars() []string {
if s.cfg.ProxySettings.Enabled {
return []string{
proxy.PluginSecureSocksProxyClientCert + "=" + s.cfg.ProxySettings.ClientCert,
proxy.PluginSecureSocksProxyClientKey + "=" + s.cfg.ProxySettings.ClientKey,
proxy.PluginSecureSocksProxyRootCACert + "=" + s.cfg.ProxySettings.RootCA,
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),
// nolint:staticcheck
proxy.PluginSecureSocksProxyClientCertFilePathEnvVarName + "=" + s.cfg.ProxySettings.ClientCertFilePath,
// nolint:staticcheck
proxy.PluginSecureSocksProxyClientKeyFilePathEnvVarName + "=" + s.cfg.ProxySettings.ClientKeyFilePath,
// nolint:staticcheck
proxy.PluginSecureSocksProxyRootCACertFilePathsEnvVarName + "=" + strings.Join(s.cfg.ProxySettings.RootCAFilePaths, " "),
// nolint:staticcheck
proxy.PluginSecureSocksProxyAddressEnvVarName + "=" + s.cfg.ProxySettings.ProxyAddress,
// nolint:staticcheck
proxy.PluginSecureSocksProxyServerNameEnvVarName + "=" + s.cfg.ProxySettings.ServerName,
// nolint:staticcheck
proxy.PluginSecureSocksProxyEnabledEnvVarName + "=" + strconv.FormatBool(s.cfg.ProxySettings.Enabled),
// nolint:staticcheck
proxy.PluginSecureSocksProxyAllowInsecureEnvVarName + "=" + strconv.FormatBool(s.cfg.ProxySettings.AllowInsecure),
}
}
return nil

@ -686,7 +686,7 @@ func TestService_GetConfigMap(t *testing.T) {
ShowUI: true,
ClientCert: "c3rt",
ClientKey: "k3y",
RootCA: "ca",
RootCAs: []string{"ca"},
ProxyAddress: "https://proxy.grafana.com",
ServerName: "secureProxy",
AllowInsecure: true,
@ -712,7 +712,7 @@ func TestService_GetConfigMap(t *testing.T) {
ShowUI: true,
ClientCert: "c3rt",
ClientKey: "k3y",
RootCA: "ca",
RootCAs: []string{"ca"},
ProxyAddress: "https://proxy.grafana.com",
ServerName: "secureProxy",
},
@ -730,7 +730,7 @@ func TestService_GetConfigMap(t *testing.T) {
ShowUI: true,
ClientCert: "c3rt",
ClientKey: "k3y",
RootCA: "ca",
RootCAs: []string{"ca"},
ProxyAddress: "https://proxy.grafana.com",
ServerName: "secureProxy",
},

@ -534,7 +534,7 @@ func (s *Service) httpClientOptions(ctx context.Context, ds *datasources.DataSou
ClientCfg: &sdkproxy.ClientCfg{
ClientCert: s.cfg.SecureSocksDSProxy.ClientCert,
ClientKey: s.cfg.SecureSocksDSProxy.ClientKey,
RootCA: s.cfg.SecureSocksDSProxy.RootCA,
RootCAs: s.cfg.SecureSocksDSProxy.RootCAs,
ProxyAddress: s.cfg.SecureSocksDSProxy.ProxyAddress,
ServerName: s.cfg.SecureSocksDSProxy.ServerName,
AllowInsecure: s.cfg.SecureSocksDSProxy.AllowInsecure,

@ -1,33 +1,41 @@
package setting
import (
"encoding/pem"
"errors"
"os"
"gopkg.in/ini.v1"
)
type SecureSocksDSProxySettings struct {
Enabled bool
ShowUI bool
AllowInsecure bool
ClientCert string
ClientKey string
RootCA string
ProxyAddress string
ServerName string
Enabled bool
ShowUI bool
AllowInsecure bool
ClientCert string
ClientCertFilePath string
ClientKey string
ClientKeyFilePath string
RootCAs []string
RootCAFilePaths []string
ProxyAddress string
ServerName string
}
func readSecureSocksDSProxySettings(iniFile *ini.File) (SecureSocksDSProxySettings, error) {
s := SecureSocksDSProxySettings{}
s := SecureSocksDSProxySettings{
RootCAs: []string{},
RootCAFilePaths: []string{},
}
secureSocksProxySection := iniFile.Section("secure_socks_datasource_proxy")
s.Enabled = secureSocksProxySection.Key("enabled").MustBool(false)
s.ClientCert = secureSocksProxySection.Key("client_cert").MustString("")
s.ClientKey = secureSocksProxySection.Key("client_key").MustString("")
s.RootCA = secureSocksProxySection.Key("root_ca_cert").MustString("")
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)
s.ClientCertFilePath = secureSocksProxySection.Key("client_cert").MustString("")
s.ClientKeyFilePath = secureSocksProxySection.Key("client_key").MustString("")
s.RootCAFilePaths = secureSocksProxySection.Key("root_ca_cert").Strings(" ")
if !s.Enabled {
return s, nil
@ -40,14 +48,50 @@ func readSecureSocksDSProxySettings(iniFile *ini.File) (SecureSocksDSProxySettin
// 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 == "" {
if len(s.RootCAFilePaths) == 0 {
return s, errors.New("one or more rootCA required")
} else if s.ClientCertFilePath == "" || s.ClientKeyFilePath == "" {
return s, errors.New("client key pair required")
} else if s.ServerName == "" {
return s, errors.New("server name required")
}
} else {
return s, nil
}
if s.ClientCertFilePath != "" {
certPEMBlock, err := os.ReadFile(s.ClientCertFilePath)
if err != nil {
return s, err
}
s.ClientCert = string(certPEMBlock)
}
if s.ClientKeyFilePath != "" {
keyPEMBlock, err := os.ReadFile(s.ClientKeyFilePath)
if err != nil {
return s, err
}
s.ClientKey = string(keyPEMBlock)
}
var rootCAs []string
for _, rootCAFile := range s.RootCAFilePaths {
// nolint:gosec
// The gosec G304 warning can be ignored because `rootCAFile` comes from config ini, and we check below if
// it's the right file type.
pemBytes, err := os.ReadFile(rootCAFile)
if err != nil {
return s, err
}
pemDecoded, _ := pem.Decode(pemBytes)
if pemDecoded == nil || pemDecoded.Type != "CERTIFICATE" {
return s, errors.New("root ca is invalid")
}
rootCAs = append(rootCAs, string(pemBytes))
}
s.RootCAs = rootCAs
return s, nil
}

@ -1,25 +1,46 @@
package setting
import (
"bytes"
"crypto/rand"
"crypto/rsa"
"crypto/x509"
"crypto/x509/pkix"
"encoding/pem"
"errors"
"fmt"
"math/big"
"os"
"path/filepath"
"testing"
"time"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
"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()
tempDir := t.TempDir()
testFilePath := filepath.Join(tempDir, "test")
testFileData := "foobar"
err := os.WriteFile(testFilePath, []byte(testFileData), 0600)
require.NoError(t, err)
rootCACertFilePath := filepath.Join(tempDir, "ca.cert")
// nolint:gosec
caCertFile, err := os.Create(rootCACertFilePath)
require.NoError(t, err)
defer func() {
err = caCertFile.Close()
require.NoError(t, err)
}()
rootCaFileData := createTestRootCAFile(t, rootCACertFilePath)
require.NoError(t, err)
cases := []struct {
description string
iniFile *ini.File
@ -32,24 +53,27 @@ func TestReadSecureSocksDSProxySettings(t *testing.T) {
[secure_socks_datasource_proxy]
`),
expectedSettings: SecureSocksDSProxySettings{
Enabled: false,
ClientCert: "",
ClientKey: "",
RootCA: "",
ProxyAddress: "",
ServerName: "",
ShowUI: true,
AllowInsecure: false,
Enabled: false,
ShowUI: true,
AllowInsecure: false,
ClientCertFilePath: "",
ClientCert: "",
ClientKey: "",
ClientKeyFilePath: "",
RootCAs: []string{},
RootCAFilePaths: []string{},
ProxyAddress: "",
ServerName: "",
},
},
{
description: "root ca is required",
description: "one or more root ca is required",
iniFile: mustNewIniFile(`
[secure_socks_datasource_proxy]
enabled = true
proxy_address = address
`),
expectedErr: errors.New("rootCA required"),
expectedErr: errors.New("one or more rootCA required"),
},
{
description: "client cert is required",
@ -106,35 +130,40 @@ server_name = name
allow_insecure = true
`),
expectedSettings: SecureSocksDSProxySettings{
Enabled: true,
ProxyAddress: "address",
ServerName: "name",
ShowUI: true,
AllowInsecure: true,
Enabled: true,
ProxyAddress: "address",
ServerName: "name",
ShowUI: true,
AllowInsecure: true,
RootCAFilePaths: []string{},
RootCAs: []string{},
},
},
{
description: "custom values",
iniFile: mustNewIniFile(`
iniFile: mustNewIniFile(fmt.Sprintf(`
[secure_socks_datasource_proxy]
enabled = true
client_cert = cert
client_key = key
root_ca_cert = root_ca
client_cert = %s
client_key = %s
root_ca_cert = %s
proxy_address = proxy_address
server_name = server_name
show_ui = false
allow_insecure = true
`),
allow_insecure = false
`, testFilePath, testFilePath, rootCACertFilePath)),
expectedSettings: SecureSocksDSProxySettings{
Enabled: true,
ClientCert: "cert",
ClientKey: "key",
RootCA: "root_ca",
ProxyAddress: "proxy_address",
ServerName: "server_name",
ShowUI: false,
AllowInsecure: true,
Enabled: true,
ShowUI: false,
AllowInsecure: false,
ClientCert: testFileData,
ClientCertFilePath: testFilePath,
ClientKey: testFileData,
ClientKeyFilePath: testFilePath,
RootCAs: []string{rootCaFileData},
RootCAFilePaths: []string{rootCACertFilePath},
ProxyAddress: "proxy_address",
ServerName: "server_name",
},
},
}
@ -146,9 +175,56 @@ allow_insecure = true
if tt.expectedErr != nil {
assert.Equal(t, tt.expectedErr, err)
} else {
assert.Equal(t, tt.expectedSettings, settings)
assert.NoError(t, err)
assert.Equal(t, tt.expectedSettings, settings)
}
})
}
}
func createTestRootCAFile(t *testing.T, path string) string {
t.Helper()
ca := &x509.Certificate{
SerialNumber: big.NewInt(2019),
Subject: pkix.Name{
Organization: []string{"Grafana Labs"},
CommonName: "Grafana",
},
NotBefore: time.Now(),
NotAfter: time.Now().AddDate(10, 0, 0),
IsCA: true,
ExtKeyUsage: []x509.ExtKeyUsage{x509.ExtKeyUsageClientAuth, x509.ExtKeyUsageServerAuth},
KeyUsage: x509.KeyUsageDigitalSignature | x509.KeyUsageCertSign,
BasicConstraintsValid: true,
}
caPrivKey, err := rsa.GenerateKey(rand.Reader, 4096)
require.NoError(t, err)
caBytes, err := x509.CreateCertificate(rand.Reader, ca, ca, &caPrivKey.PublicKey, caPrivKey)
require.NoError(t, err)
// nolint:gosec
caCertFile, err := os.Create(path)
require.NoError(t, err)
block := &pem.Block{
Type: "CERTIFICATE",
Bytes: caBytes,
}
err = pem.Encode(caCertFile, block)
require.NoError(t, err)
buf := new(bytes.Buffer)
err = pem.Encode(buf, block)
require.NoError(t, err)
return buf.String()
}
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
}

Loading…
Cancel
Save