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
This commit is contained in:
Will Browne 2024-03-22 13:52:24 +01:00 committed by GitHub
parent 0b4c81158e
commit b765c21d4c
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
8 changed files with 198 additions and 71 deletions

8
go.mod
View File

@ -51,7 +51,7 @@ require (
github.com/grafana/cuetsy v0.1.11 // @grafana/grafana-as-code github.com/grafana/cuetsy v0.1.11 // @grafana/grafana-as-code
github.com/grafana/grafana-aws-sdk v0.25.0 // @grafana/aws-datasources github.com/grafana/grafana-aws-sdk v0.25.0 // @grafana/aws-datasources
github.com/grafana/grafana-azure-sdk-go/v2 v2.0.1 // @grafana/partner-datasources github.com/grafana/grafana-azure-sdk-go/v2 v2.0.1 // @grafana/partner-datasources
github.com/grafana/grafana-plugin-sdk-go v0.216.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/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-hclog v1.6.2 // @grafana/plugins-platform-backend
github.com/hashicorp/go-plugin v1.6.0 // @grafana/plugins-platform-backend github.com/hashicorp/go-plugin v1.6.0 // @grafana/plugins-platform-backend
@ -109,7 +109,7 @@ require (
gopkg.in/mail.v2 v2.3.1 // @grafana/backend-platform gopkg.in/mail.v2 v2.3.1 // @grafana/backend-platform
gopkg.in/yaml.v2 v2.4.0 // indirect gopkg.in/yaml.v2 v2.4.0 // indirect
gopkg.in/yaml.v3 v3.0.1 // @grafana/alerting-squad-backend gopkg.in/yaml.v3 v3.0.1 // @grafana/alerting-squad-backend
xorm.io/builder v0.3.6 // indirect; @grafana/backend-platform xorm.io/builder v0.3.6 // @grafana/backend-platform
xorm.io/core v0.7.3 // @grafana/backend-platform xorm.io/core v0.7.3 // @grafana/backend-platform
xorm.io/xorm v0.8.2 // @grafana/alerting-squad-backend xorm.io/xorm v0.8.2 // @grafana/alerting-squad-backend
) )
@ -161,7 +161,7 @@ require (
github.com/grpc-ecosystem/go-grpc-prometheus v1.2.1-0.20191002090509-6af20e3a5340 // indirect 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/errwrap v1.1.0 // indirect
github.com/hashicorp/go-msgpack v0.5.5 // indirect github.com/hashicorp/go-msgpack v0.5.5 // indirect
github.com/hashicorp/go-multierror v1.1.1 // indirect; @grafana/alerting-squad github.com/hashicorp/go-multierror v1.1.1 // @grafana/alerting-squad
github.com/hashicorp/go-sockaddr v1.0.6 // indirect github.com/hashicorp/go-sockaddr v1.0.6 // indirect
github.com/hashicorp/golang-lru v0.6.0 // indirect github.com/hashicorp/golang-lru v0.6.0 // indirect
github.com/hashicorp/yamux v0.1.1 // indirect github.com/hashicorp/yamux v0.1.1 // indirect
@ -317,7 +317,7 @@ require (
github.com/googleapis/enterprise-certificate-proxy v0.3.2 // indirect github.com/googleapis/enterprise-certificate-proxy v0.3.2 // indirect
github.com/grafana/regexp v0.0.0-20221123153739-15dc172cd2db // indirect github.com/grafana/regexp v0.0.0-20221123153739-15dc172cd2db // indirect
github.com/hashicorp/go-immutable-radix v1.3.1 // indirect github.com/hashicorp/go-immutable-radix v1.3.1 // indirect
github.com/hashicorp/golang-lru/v2 v2.0.7 // indirect; @grafana/alerting-squad-backend github.com/hashicorp/golang-lru/v2 v2.0.7 // @grafana/alerting-squad-backend
github.com/hashicorp/memberlist v0.5.0 // indirect github.com/hashicorp/memberlist v0.5.0 // indirect
github.com/inconshreveable/mousetrap v1.1.0 // indirect github.com/inconshreveable/mousetrap v1.1.0 // indirect
github.com/invopop/yaml v0.2.0 // indirect github.com/invopop/yaml v0.2.0 // indirect

4
go.sum
View File

@ -2184,8 +2184,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 h1:r+mU5bGMzcXCRVAuOrTn54S80qbfVkvTdUJZfSfTNbs=
github.com/grafana/grafana-openapi-client-go v0.0.0-20231213163343-bd475d63fb79/go.mod h1:wc6Hbh3K2TgCUSfBC/BOzabItujtHMESZeFk5ZhdxhQ= 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.114.0/go.mod h1:D7x3ah+1d4phNXpbnOaxa/osSaZlwh9/ZUnGGzegRbk=
github.com/grafana/grafana-plugin-sdk-go v0.216.0 h1:DftszjdGZM6hikBazyB7CdrhyYOwUct9s5lA/BwSl2c= github.com/grafana/grafana-plugin-sdk-go v0.217.0 h1:oQjq5KRrVrhweXHxFtEMgjv1KW7hujGiRPIYrsPZ9PE=
github.com/grafana/grafana-plugin-sdk-go v0.216.0/go.mod h1:FdvSvOliqpVLnytM7e89zCFyYPDE6VOn9SIjVQRvVxM= github.com/grafana/grafana-plugin-sdk-go v0.217.0/go.mod h1:FdvSvOliqpVLnytM7e89zCFyYPDE6VOn9SIjVQRvVxM=
github.com/grafana/grafana/pkg/apimachinery v0.0.0-20240226124929-648abdbd0ea4 h1:hpyusz8c3yRFoJPlA0o34rWnsLbaOOBZleqRhFBi5Lg= github.com/grafana/grafana/pkg/apimachinery v0.0.0-20240226124929-648abdbd0ea4 h1:hpyusz8c3yRFoJPlA0o34rWnsLbaOOBZleqRhFBi5Lg=
github.com/grafana/grafana/pkg/apimachinery v0.0.0-20240226124929-648abdbd0ea4/go.mod h1:vrRQJuNprTWqwm6JPxHf3BoTJhvO15QMEjQ7Q/YUOnI= github.com/grafana/grafana/pkg/apimachinery v0.0.0-20240226124929-648abdbd0ea4/go.mod h1:vrRQJuNprTWqwm6JPxHf3BoTJhvO15QMEjQ7Q/YUOnI=
github.com/grafana/grafana/pkg/apiserver v0.0.0-20240226124929-648abdbd0ea4 h1:tIbI5zgos92vwJ8lV3zwHwuxkV03GR3FGLkFW9V5LxY= github.com/grafana/grafana/pkg/apiserver v0.0.0-20240226124929-648abdbd0ea4 h1:tIbI5zgos92vwJ8lV3zwHwuxkV03GR3FGLkFW9V5LxY=

View File

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

View File

@ -122,13 +122,20 @@ func (p *EnvVarsProvider) awsEnvVars(pluginID string) []string {
func (p *EnvVarsProvider) secureSocksProxyEnvVars() []string { func (p *EnvVarsProvider) secureSocksProxyEnvVars() []string {
if p.cfg.ProxySettings.Enabled { if p.cfg.ProxySettings.Enabled {
return []string{ return []string{
envVar(proxy.PluginSecureSocksProxyClientCert, p.cfg.ProxySettings.ClientCert), // nolint:staticcheck
envVar(proxy.PluginSecureSocksProxyClientKey, p.cfg.ProxySettings.ClientKey), envVar(proxy.PluginSecureSocksProxyClientCertFilePathEnvVarName, p.cfg.ProxySettings.ClientCertFilePath),
envVar(proxy.PluginSecureSocksProxyRootCACert, p.cfg.ProxySettings.RootCA), // nolint:staticcheck
envVar(proxy.PluginSecureSocksProxyProxyAddress, p.cfg.ProxySettings.ProxyAddress), envVar(proxy.PluginSecureSocksProxyClientKeyFilePathEnvVarName, p.cfg.ProxySettings.ClientKeyFilePath),
envVar(proxy.PluginSecureSocksProxyServerName, p.cfg.ProxySettings.ServerName), // nolint:staticcheck
envVar(proxy.PluginSecureSocksProxyEnabled, strconv.FormatBool(p.cfg.ProxySettings.Enabled)), envVar(proxy.PluginSecureSocksProxyRootCACertFilePathsEnvVarName, strings.Join(p.cfg.ProxySettings.RootCAFilePaths, " ")),
envVar(proxy.PluginSecureSocksProxyAllowInsecure, strconv.FormatBool(p.cfg.ProxySettings.AllowInsecure)), // nolint:staticcheck
envVar(proxy.PluginSecureSocksProxyAddressEnvVarName, p.cfg.ProxySettings.ProxyAddress),
// nolint:staticcheck
envVar(proxy.PluginSecureSocksProxyServerNameEnvVarName, p.cfg.ProxySettings.ServerName),
// nolint:staticcheck
envVar(proxy.PluginSecureSocksProxyEnabledEnvVarName, strconv.FormatBool(p.cfg.ProxySettings.Enabled)),
// nolint:staticcheck
envVar(proxy.PluginSecureSocksProxyAllowInsecureEnvVarName, strconv.FormatBool(p.cfg.ProxySettings.AllowInsecure)),
} }
} }
return nil return nil

View File

@ -75,7 +75,7 @@ func (s *RequestConfigProvider) PluginRequestConfig(ctx context.Context, pluginI
m[proxy.PluginSecureSocksProxyEnabled] = "true" m[proxy.PluginSecureSocksProxyEnabled] = "true"
m[proxy.PluginSecureSocksProxyClientCert] = s.cfg.ProxySettings.ClientCert m[proxy.PluginSecureSocksProxyClientCert] = s.cfg.ProxySettings.ClientCert
m[proxy.PluginSecureSocksProxyClientKey] = s.cfg.ProxySettings.ClientKey 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.PluginSecureSocksProxyProxyAddress] = s.cfg.ProxySettings.ProxyAddress
m[proxy.PluginSecureSocksProxyServerName] = s.cfg.ProxySettings.ServerName m[proxy.PluginSecureSocksProxyServerName] = s.cfg.ProxySettings.ServerName
m[proxy.PluginSecureSocksProxyAllowInsecure] = strconv.FormatBool(s.cfg.ProxySettings.AllowInsecure) m[proxy.PluginSecureSocksProxyAllowInsecure] = strconv.FormatBool(s.cfg.ProxySettings.AllowInsecure)

View File

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

View File

@ -1,33 +1,41 @@
package setting package setting
import ( import (
"encoding/pem"
"errors" "errors"
"os"
"gopkg.in/ini.v1" "gopkg.in/ini.v1"
) )
type SecureSocksDSProxySettings struct { type SecureSocksDSProxySettings struct {
Enabled bool Enabled bool
ShowUI bool ShowUI bool
AllowInsecure bool AllowInsecure bool
ClientCert string ClientCert string
ClientKey string ClientCertFilePath string
RootCA string ClientKey string
ProxyAddress string ClientKeyFilePath string
ServerName string RootCAs []string
RootCAFilePaths []string
ProxyAddress string
ServerName string
} }
func readSecureSocksDSProxySettings(iniFile *ini.File) (SecureSocksDSProxySettings, error) { func readSecureSocksDSProxySettings(iniFile *ini.File) (SecureSocksDSProxySettings, error) {
s := SecureSocksDSProxySettings{} s := SecureSocksDSProxySettings{
RootCAs: []string{},
RootCAFilePaths: []string{},
}
secureSocksProxySection := iniFile.Section("secure_socks_datasource_proxy") secureSocksProxySection := iniFile.Section("secure_socks_datasource_proxy")
s.Enabled = secureSocksProxySection.Key("enabled").MustBool(false) 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.ProxyAddress = secureSocksProxySection.Key("proxy_address").MustString("")
s.ServerName = secureSocksProxySection.Key("server_name").MustString("") s.ServerName = secureSocksProxySection.Key("server_name").MustString("")
s.ShowUI = secureSocksProxySection.Key("show_ui").MustBool(true) s.ShowUI = secureSocksProxySection.Key("show_ui").MustBool(true)
s.AllowInsecure = secureSocksProxySection.Key("allow_insecure").MustBool(false) 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 { if !s.Enabled {
return s, nil return s, nil
@ -40,14 +48,50 @@ func readSecureSocksDSProxySettings(iniFile *ini.File) (SecureSocksDSProxySettin
// If the proxy is going to use TLS. // If the proxy is going to use TLS.
if !s.AllowInsecure { if !s.AllowInsecure {
// all fields must be specified to use the proxy // all fields must be specified to use the proxy
if s.RootCA == "" { if len(s.RootCAFilePaths) == 0 {
return s, errors.New("rootCA required") return s, errors.New("one or more rootCA required")
} else if s.ClientCert == "" || s.ClientKey == "" { } else if s.ClientCertFilePath == "" || s.ClientKeyFilePath == "" {
return s, errors.New("client key pair required") return s, errors.New("client key pair required")
} else if s.ServerName == "" { } else if s.ServerName == "" {
return s, errors.New("server name required") 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 return s, nil
} }

View File

@ -1,25 +1,46 @@
package setting package setting
import ( import (
"bytes"
"crypto/rand"
"crypto/rsa"
"crypto/x509"
"crypto/x509/pkix"
"encoding/pem"
"errors" "errors"
"fmt" "fmt"
"math/big"
"os"
"path/filepath"
"testing" "testing"
"time"
"github.com/stretchr/testify/assert" "github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
"gopkg.in/ini.v1" "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) { func TestReadSecureSocksDSProxySettings(t *testing.T) {
t.Parallel() 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 { cases := []struct {
description string description string
iniFile *ini.File iniFile *ini.File
@ -32,24 +53,27 @@ func TestReadSecureSocksDSProxySettings(t *testing.T) {
[secure_socks_datasource_proxy] [secure_socks_datasource_proxy]
`), `),
expectedSettings: SecureSocksDSProxySettings{ expectedSettings: SecureSocksDSProxySettings{
Enabled: false, Enabled: false,
ClientCert: "", ShowUI: true,
ClientKey: "", AllowInsecure: false,
RootCA: "", ClientCertFilePath: "",
ProxyAddress: "", ClientCert: "",
ServerName: "", ClientKey: "",
ShowUI: true, ClientKeyFilePath: "",
AllowInsecure: false, RootCAs: []string{},
RootCAFilePaths: []string{},
ProxyAddress: "",
ServerName: "",
}, },
}, },
{ {
description: "root ca is required", description: "one or more root ca is required",
iniFile: mustNewIniFile(` iniFile: mustNewIniFile(`
[secure_socks_datasource_proxy] [secure_socks_datasource_proxy]
enabled = true enabled = true
proxy_address = address proxy_address = address
`), `),
expectedErr: errors.New("rootCA required"), expectedErr: errors.New("one or more rootCA required"),
}, },
{ {
description: "client cert is required", description: "client cert is required",
@ -106,35 +130,40 @@ server_name = name
allow_insecure = true allow_insecure = true
`), `),
expectedSettings: SecureSocksDSProxySettings{ expectedSettings: SecureSocksDSProxySettings{
Enabled: true, Enabled: true,
ProxyAddress: "address", ProxyAddress: "address",
ServerName: "name", ServerName: "name",
ShowUI: true, ShowUI: true,
AllowInsecure: true, AllowInsecure: true,
RootCAFilePaths: []string{},
RootCAs: []string{},
}, },
}, },
{ {
description: "custom values", description: "custom values",
iniFile: mustNewIniFile(` iniFile: mustNewIniFile(fmt.Sprintf(`
[secure_socks_datasource_proxy] [secure_socks_datasource_proxy]
enabled = true enabled = true
client_cert = cert client_cert = %s
client_key = key client_key = %s
root_ca_cert = root_ca root_ca_cert = %s
proxy_address = proxy_address proxy_address = proxy_address
server_name = server_name server_name = server_name
show_ui = false show_ui = false
allow_insecure = true allow_insecure = false
`), `, testFilePath, testFilePath, rootCACertFilePath)),
expectedSettings: SecureSocksDSProxySettings{ expectedSettings: SecureSocksDSProxySettings{
Enabled: true, Enabled: true,
ClientCert: "cert", ShowUI: false,
ClientKey: "key", AllowInsecure: false,
RootCA: "root_ca", ClientCert: testFileData,
ProxyAddress: "proxy_address", ClientCertFilePath: testFilePath,
ServerName: "server_name", ClientKey: testFileData,
ShowUI: false, ClientKeyFilePath: testFilePath,
AllowInsecure: true, RootCAs: []string{rootCaFileData},
RootCAFilePaths: []string{rootCACertFilePath},
ProxyAddress: "proxy_address",
ServerName: "server_name",
}, },
}, },
} }
@ -146,9 +175,56 @@ allow_insecure = true
if tt.expectedErr != nil { if tt.expectedErr != nil {
assert.Equal(t, tt.expectedErr, err) assert.Equal(t, tt.expectedErr, err)
} else { } else {
assert.Equal(t, tt.expectedSettings, settings)
assert.NoError(t, err) 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
}