mirror of
https://github.com/grafana/grafana.git
synced 2025-02-25 18:55:37 -06:00
Chore: Allow to force the download of the public key (#67486)
This commit is contained in:
parent
f8faacd54a
commit
932136807b
@ -1342,6 +1342,8 @@ plugin_catalog_url = https://grafana.com/grafana/plugins/
|
|||||||
plugin_catalog_hidden_plugins =
|
plugin_catalog_hidden_plugins =
|
||||||
# Log all backend requests for core and external plugins.
|
# Log all backend requests for core and external plugins.
|
||||||
log_backend_requests = false
|
log_backend_requests = false
|
||||||
|
# Force download of public key for verifying plugin signature on startup.
|
||||||
|
enforce_public_key_download = false
|
||||||
|
|
||||||
#################################### Grafana Live ##########################################
|
#################################### Grafana Live ##########################################
|
||||||
[live]
|
[live]
|
||||||
|
@ -1281,6 +1281,8 @@
|
|||||||
;plugin_catalog_hidden_plugins =
|
;plugin_catalog_hidden_plugins =
|
||||||
# Log all backend requests for core and external plugins.
|
# Log all backend requests for core and external plugins.
|
||||||
;log_backend_requests = false
|
;log_backend_requests = false
|
||||||
|
# Force download of public key for verifying plugin signature on startup.
|
||||||
|
;enforce_public_key_download = false
|
||||||
|
|
||||||
#################################### Grafana Live ##########################################
|
#################################### Grafana Live ##########################################
|
||||||
[live]
|
[live]
|
||||||
|
@ -12,10 +12,10 @@ import (
|
|||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/grafana/grafana/pkg/plugins"
|
"github.com/grafana/grafana/pkg/plugins"
|
||||||
"github.com/grafana/grafana/pkg/plugins/config"
|
|
||||||
"github.com/grafana/grafana/pkg/plugins/log"
|
"github.com/grafana/grafana/pkg/plugins/log"
|
||||||
"github.com/grafana/grafana/pkg/plugins/manager/signature/statickey"
|
"github.com/grafana/grafana/pkg/plugins/manager/signature/statickey"
|
||||||
"github.com/grafana/grafana/pkg/services/featuremgmt"
|
"github.com/grafana/grafana/pkg/services/featuremgmt"
|
||||||
|
"github.com/grafana/grafana/pkg/setting"
|
||||||
)
|
)
|
||||||
|
|
||||||
const publicKeySyncInterval = 10 * 24 * time.Hour // 10 days
|
const publicKeySyncInterval = 10 * 24 * time.Hour // 10 days
|
||||||
@ -29,8 +29,9 @@ type ManifestKeys struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type KeyRetriever struct {
|
type KeyRetriever struct {
|
||||||
cfg *config.Cfg
|
cfg *setting.Cfg
|
||||||
log log.Logger
|
log log.Logger
|
||||||
|
flags featuremgmt.FeatureToggles
|
||||||
|
|
||||||
lock sync.Mutex
|
lock sync.Mutex
|
||||||
cli http.Client
|
cli http.Client
|
||||||
@ -40,9 +41,10 @@ type KeyRetriever struct {
|
|||||||
|
|
||||||
var _ plugins.KeyRetriever = (*KeyRetriever)(nil)
|
var _ plugins.KeyRetriever = (*KeyRetriever)(nil)
|
||||||
|
|
||||||
func ProvideService(cfg *config.Cfg, kv plugins.KeyStore) *KeyRetriever {
|
func ProvideService(cfg *setting.Cfg, kv plugins.KeyStore, flags featuremgmt.FeatureToggles) *KeyRetriever {
|
||||||
kr := &KeyRetriever{
|
kr := &KeyRetriever{
|
||||||
cfg: cfg,
|
cfg: cfg,
|
||||||
|
flags: flags,
|
||||||
log: log.New("plugin.signature.key_retriever"),
|
log: log.New("plugin.signature.key_retriever"),
|
||||||
cli: makeHttpClient(),
|
cli: makeHttpClient(),
|
||||||
kv: kv,
|
kv: kv,
|
||||||
@ -52,7 +54,7 @@ func ProvideService(cfg *config.Cfg, kv plugins.KeyStore) *KeyRetriever {
|
|||||||
|
|
||||||
// IsDisabled disables dynamic retrieval of public keys from the API server.
|
// IsDisabled disables dynamic retrieval of public keys from the API server.
|
||||||
func (kr *KeyRetriever) IsDisabled() bool {
|
func (kr *KeyRetriever) IsDisabled() bool {
|
||||||
return !kr.cfg.Features.IsEnabled(featuremgmt.FlagPluginsAPIManifestKey)
|
return !kr.flags.IsEnabled(featuremgmt.FlagPluginsAPIManifestKey)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (kr *KeyRetriever) Run(ctx context.Context) error {
|
func (kr *KeyRetriever) Run(ctx context.Context) error {
|
||||||
@ -101,7 +103,7 @@ func (kr *KeyRetriever) updateKeys(ctx context.Context) error {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
if time.Since(*lastUpdated) < publicKeySyncInterval {
|
if !kr.cfg.PluginForcePublicKeyDownload && time.Since(*lastUpdated) < publicKeySyncInterval {
|
||||||
// Cache is still valid
|
// Cache is still valid
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
@ -9,9 +9,9 @@ import (
|
|||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/grafana/grafana/pkg/infra/kvstore"
|
"github.com/grafana/grafana/pkg/infra/kvstore"
|
||||||
"github.com/grafana/grafana/pkg/plugins/config"
|
|
||||||
"github.com/grafana/grafana/pkg/services/featuremgmt"
|
"github.com/grafana/grafana/pkg/services/featuremgmt"
|
||||||
"github.com/grafana/grafana/pkg/services/pluginsintegration/keystore"
|
"github.com/grafana/grafana/pkg/services/pluginsintegration/keystore"
|
||||||
|
"github.com/grafana/grafana/pkg/setting"
|
||||||
"github.com/stretchr/testify/require"
|
"github.com/stretchr/testify/require"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -43,13 +43,11 @@ func setFakeAPIServer(t *testing.T, publicKey string, keyID string) (*httptest.S
|
|||||||
}
|
}
|
||||||
func Test_PublicKeyUpdate(t *testing.T) {
|
func Test_PublicKeyUpdate(t *testing.T) {
|
||||||
t.Run("it should retrieve an API key", func(t *testing.T) {
|
t.Run("it should retrieve an API key", func(t *testing.T) {
|
||||||
cfg := &config.Cfg{
|
cfg := &setting.Cfg{}
|
||||||
Features: featuremgmt.WithFeatures([]interface{}{featuremgmt.FlagPluginsAPIManifestKey}...),
|
|
||||||
}
|
|
||||||
expectedKey := "fake"
|
expectedKey := "fake"
|
||||||
s, done := setFakeAPIServer(t, expectedKey, "7e4d0c6a708866e7")
|
s, done := setFakeAPIServer(t, expectedKey, "7e4d0c6a708866e7")
|
||||||
cfg.GrafanaComURL = s.URL
|
cfg.GrafanaComURL = s.URL
|
||||||
v := ProvideService(cfg, keystore.ProvideService(kvstore.NewFakeKVStore()))
|
v := ProvideService(cfg, keystore.ProvideService(kvstore.NewFakeKVStore()), featuremgmt.WithFeatures(featuremgmt.FlagPluginsAPIManifestKey))
|
||||||
go func() {
|
go func() {
|
||||||
err := v.Run(context.Background())
|
err := v.Run(context.Background())
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
@ -66,13 +64,11 @@ func Test_PublicKeyUpdate(t *testing.T) {
|
|||||||
})
|
})
|
||||||
|
|
||||||
t.Run("it should update the latest update date", func(t *testing.T) {
|
t.Run("it should update the latest update date", func(t *testing.T) {
|
||||||
cfg := &config.Cfg{
|
cfg := &setting.Cfg{}
|
||||||
Features: featuremgmt.WithFeatures([]interface{}{featuremgmt.FlagPluginsAPIManifestKey}...),
|
|
||||||
}
|
|
||||||
expectedKey := "fake"
|
expectedKey := "fake"
|
||||||
s, done := setFakeAPIServer(t, expectedKey, "7e4d0c6a708866e7")
|
s, done := setFakeAPIServer(t, expectedKey, "7e4d0c6a708866e7")
|
||||||
cfg.GrafanaComURL = s.URL
|
cfg.GrafanaComURL = s.URL
|
||||||
v := ProvideService(cfg, keystore.ProvideService(kvstore.NewFakeKVStore()))
|
v := ProvideService(cfg, keystore.ProvideService(kvstore.NewFakeKVStore()), featuremgmt.WithFeatures(featuremgmt.FlagPluginsAPIManifestKey))
|
||||||
go func() {
|
go func() {
|
||||||
err := v.Run(context.Background())
|
err := v.Run(context.Background())
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
@ -88,13 +84,11 @@ func Test_PublicKeyUpdate(t *testing.T) {
|
|||||||
})
|
})
|
||||||
|
|
||||||
t.Run("it should remove old keys", func(t *testing.T) {
|
t.Run("it should remove old keys", func(t *testing.T) {
|
||||||
cfg := &config.Cfg{
|
cfg := &setting.Cfg{}
|
||||||
Features: featuremgmt.WithFeatures([]interface{}{featuremgmt.FlagPluginsAPIManifestKey}...),
|
|
||||||
}
|
|
||||||
expectedKey := "fake"
|
expectedKey := "fake"
|
||||||
s, done := setFakeAPIServer(t, expectedKey, "other")
|
s, done := setFakeAPIServer(t, expectedKey, "other")
|
||||||
cfg.GrafanaComURL = s.URL
|
cfg.GrafanaComURL = s.URL
|
||||||
v := ProvideService(cfg, keystore.ProvideService(kvstore.NewFakeKVStore()))
|
v := ProvideService(cfg, keystore.ProvideService(kvstore.NewFakeKVStore()), featuremgmt.WithFeatures(featuremgmt.FlagPluginsAPIManifestKey))
|
||||||
go func() {
|
go func() {
|
||||||
err := v.Run(context.Background())
|
err := v.Run(context.Background())
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
@ -113,4 +107,30 @@ func Test_PublicKeyUpdate(t *testing.T) {
|
|||||||
require.Equal(t, true, found)
|
require.Equal(t, true, found)
|
||||||
require.Equal(t, expectedKey, res)
|
require.Equal(t, expectedKey, res)
|
||||||
})
|
})
|
||||||
|
|
||||||
|
t.Run("it should force-download the key", func(t *testing.T) {
|
||||||
|
cfg := &setting.Cfg{
|
||||||
|
PluginForcePublicKeyDownload: true,
|
||||||
|
}
|
||||||
|
expectedKey := "fake"
|
||||||
|
s, done := setFakeAPIServer(t, expectedKey, "7e4d0c6a708866e7")
|
||||||
|
cfg.GrafanaComURL = s.URL
|
||||||
|
v := ProvideService(cfg, keystore.ProvideService(kvstore.NewFakeKVStore()), featuremgmt.WithFeatures(featuremgmt.FlagPluginsAPIManifestKey))
|
||||||
|
// Simulate an updated key
|
||||||
|
err := v.kv.SetLastUpdated(context.Background())
|
||||||
|
require.NoError(t, err)
|
||||||
|
go func() {
|
||||||
|
err := v.Run(context.Background())
|
||||||
|
require.NoError(t, err)
|
||||||
|
}()
|
||||||
|
<-done
|
||||||
|
|
||||||
|
// wait for the lock to be free
|
||||||
|
v.lock.Lock()
|
||||||
|
defer v.lock.Unlock()
|
||||||
|
res, found, err := v.kv.Get(context.Background(), "7e4d0c6a708866e7")
|
||||||
|
require.NoError(t, err)
|
||||||
|
require.Equal(t, true, found)
|
||||||
|
require.Equal(t, expectedKey, res)
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
@ -5,20 +5,18 @@ import (
|
|||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"github.com/grafana/grafana/pkg/infra/kvstore"
|
"github.com/grafana/grafana/pkg/infra/kvstore"
|
||||||
"github.com/grafana/grafana/pkg/plugins/config"
|
|
||||||
"github.com/grafana/grafana/pkg/plugins/manager/signature/statickey"
|
"github.com/grafana/grafana/pkg/plugins/manager/signature/statickey"
|
||||||
"github.com/grafana/grafana/pkg/services/featuremgmt"
|
"github.com/grafana/grafana/pkg/services/featuremgmt"
|
||||||
"github.com/grafana/grafana/pkg/services/pluginsintegration/keyretriever/dynamic"
|
"github.com/grafana/grafana/pkg/services/pluginsintegration/keyretriever/dynamic"
|
||||||
"github.com/grafana/grafana/pkg/services/pluginsintegration/keystore"
|
"github.com/grafana/grafana/pkg/services/pluginsintegration/keystore"
|
||||||
|
"github.com/grafana/grafana/pkg/setting"
|
||||||
"github.com/stretchr/testify/require"
|
"github.com/stretchr/testify/require"
|
||||||
)
|
)
|
||||||
|
|
||||||
func Test_GetPublicKey(t *testing.T) {
|
func Test_GetPublicKey(t *testing.T) {
|
||||||
t.Run("it should return a static key", func(t *testing.T) {
|
t.Run("it should return a static key", func(t *testing.T) {
|
||||||
cfg := &config.Cfg{
|
cfg := &setting.Cfg{}
|
||||||
Features: featuremgmt.WithFeatures(),
|
kr := ProvideService(dynamic.ProvideService(cfg, keystore.ProvideService(kvstore.NewFakeKVStore()), featuremgmt.WithFeatures()))
|
||||||
}
|
|
||||||
kr := ProvideService(dynamic.ProvideService(cfg, keystore.ProvideService(kvstore.NewFakeKVStore())))
|
|
||||||
key, err := kr.GetPublicKey(context.Background(), statickey.GetDefaultKeyID())
|
key, err := kr.GetPublicKey(context.Background(), statickey.GetDefaultKeyID())
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
require.Equal(t, statickey.GetDefaultKey(), key)
|
require.Equal(t, statickey.GetDefaultKey(), key)
|
||||||
|
@ -236,6 +236,7 @@ type Cfg struct {
|
|||||||
PluginCatalogHiddenPlugins []string
|
PluginCatalogHiddenPlugins []string
|
||||||
PluginAdminEnabled bool
|
PluginAdminEnabled bool
|
||||||
PluginAdminExternalManageEnabled bool
|
PluginAdminExternalManageEnabled bool
|
||||||
|
PluginForcePublicKeyDownload bool
|
||||||
|
|
||||||
PluginsCDNURLTemplate string
|
PluginsCDNURLTemplate string
|
||||||
PluginLogBackendRequests bool
|
PluginLogBackendRequests bool
|
||||||
|
@ -30,6 +30,7 @@ func (cfg *Cfg) readPluginSettings(iniFile *ini.File) error {
|
|||||||
cfg.PluginsEnableAlpha = pluginsSection.Key("enable_alpha").MustBool(false)
|
cfg.PluginsEnableAlpha = pluginsSection.Key("enable_alpha").MustBool(false)
|
||||||
cfg.PluginsAppsSkipVerifyTLS = pluginsSection.Key("app_tls_skip_verify_insecure").MustBool(false)
|
cfg.PluginsAppsSkipVerifyTLS = pluginsSection.Key("app_tls_skip_verify_insecure").MustBool(false)
|
||||||
cfg.PluginSettings = extractPluginSettings(iniFile.Sections())
|
cfg.PluginSettings = extractPluginSettings(iniFile.Sections())
|
||||||
|
cfg.PluginForcePublicKeyDownload = pluginsSection.Key("enforce_public_key_download").MustBool(false)
|
||||||
|
|
||||||
pluginsAllowUnsigned := pluginsSection.Key("allow_loading_unsigned_plugins").MustString("")
|
pluginsAllowUnsigned := pluginsSection.Key("allow_loading_unsigned_plugins").MustString("")
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user