diff --git a/conf/defaults.ini b/conf/defaults.ini
index ade66815710..519de55ab3a 100644
--- a/conf/defaults.ini
+++ b/conf/defaults.ini
@@ -1399,8 +1399,11 @@ plugin_catalog_url = https://grafana.com/grafana/plugins/
plugin_catalog_hidden_plugins =
# Log all backend requests for core and external plugins.
log_backend_requests = false
-# Force download of public key for verifying plugin signature on startup.
-enforce_public_key_download = false
+# Disable download of the public key for verifying plugin signature.
+public_key_retrieval_disabled = false
+# Force download of the public key for verifying plugin signature on startup. If disabled, the public key will be retrieved every 10 days.
+# Requires public_key_retrieval_disabled to be false to have any effect.
+public_key_retrieval_on_startup = false
#################################### Grafana Live ##########################################
[live]
diff --git a/conf/sample.ini b/conf/sample.ini
index 911132f720e..8bb0b9d9b53 100644
--- a/conf/sample.ini
+++ b/conf/sample.ini
@@ -1326,8 +1326,11 @@
;plugin_catalog_hidden_plugins =
# Log all backend requests for core and external plugins.
;log_backend_requests = false
-# Force download of public key for verifying plugin signature on startup.
-;enforce_public_key_download = false
+# Disable download of the public key for verifying plugin signature.
+; public_key_retrieval_disabled = false
+# Force download of the public key for verifying plugin signature on startup. If disabled, the public key will be retrieved every 10 days.
+# Requires public_key_retrieval_disabled to be false to have any effect.
+; public_key_retrieval_on_startup = false
#################################### Grafana Live ##########################################
[live]
diff --git a/docs/sources/setup-grafana/configure-grafana/_index.md b/docs/sources/setup-grafana/configure-grafana/_index.md
index 44b3d5f811e..620d8fb227e 100644
--- a/docs/sources/setup-grafana/configure-grafana/_index.md
+++ b/docs/sources/setup-grafana/configure-grafana/_index.md
@@ -2033,6 +2033,14 @@ Custom install/learn more URL for enterprise plugins. Defaults to https://grafan
Enter a comma-separated list of plugin identifiers to hide in the plugin catalog.
+### public_key_retrieval_disabled
+
+Disable download of the public key for verifying plugin signature. The default is `false`. If disabled, it will use the hardcoded public key.
+
+### public_key_retrieval_on_startup
+
+Force download of the public key for verifying plugin signature on startup. The default is `false`. If disabled, the public key will be retrieved every 10 days. Requires `public_key_retrieval_disabled` to be false to have any effect.
+
## [live]
diff --git a/docs/sources/setup-grafana/configure-grafana/feature-toggles/index.md b/docs/sources/setup-grafana/configure-grafana/feature-toggles/index.md
index 1f3f9d12f48..d61fabe78a8 100644
--- a/docs/sources/setup-grafana/configure-grafana/feature-toggles/index.md
+++ b/docs/sources/setup-grafana/configure-grafana/feature-toggles/index.md
@@ -108,7 +108,6 @@ Experimental features might be changed or removed without prior notice.
| `alertStateHistoryLokiOnly` | Disable Grafana alerts from emitting annotations when a remote Loki instance is available. |
| `unifiedRequestLog` | Writes error logs to the request logger |
| `pyroscopeFlameGraph` | Changes flame graph to pyroscope one |
-| `pluginsAPIManifestKey` | Use grafana.com API to retrieve the public manifest key |
| `extraThemes` | Enables extra themes |
| `lokiPredefinedOperations` | Adds predefined query operations to Loki query editor |
| `pluginsFrontendSandbox` | Enables the plugins frontend sandbox |
diff --git a/packages/grafana-data/src/types/featureToggles.gen.ts b/packages/grafana-data/src/types/featureToggles.gen.ts
index ed48409bb9b..656f35f3260 100644
--- a/packages/grafana-data/src/types/featureToggles.gen.ts
+++ b/packages/grafana-data/src/types/featureToggles.gen.ts
@@ -90,7 +90,6 @@ export interface FeatureToggles {
refactorVariablesTimeRange?: boolean;
useCachingService?: boolean;
enableElasticsearchBackendQuerying?: boolean;
- pluginsAPIManifestKey?: boolean;
advancedDataSourcePicker?: boolean;
faroDatasourceSelector?: boolean;
enableDatagridEditing?: boolean;
diff --git a/pkg/services/featuremgmt/registry.go b/pkg/services/featuremgmt/registry.go
index 7aa8b4c0c88..87881d457fa 100644
--- a/pkg/services/featuremgmt/registry.go
+++ b/pkg/services/featuremgmt/registry.go
@@ -487,12 +487,6 @@ var (
Stage: FeatureStagePublicPreview,
Owner: grafanaObservabilityLogsSquad,
},
- {
- Name: "pluginsAPIManifestKey",
- Description: "Use grafana.com API to retrieve the public manifest key",
- Stage: FeatureStageExperimental,
- Owner: grafanaPluginsPlatformSquad,
- },
{
Name: "advancedDataSourcePicker",
Description: "Enable a new data source picker with contextual information, recently used order and advanced mode",
diff --git a/pkg/services/featuremgmt/toggles_gen.csv b/pkg/services/featuremgmt/toggles_gen.csv
index a9cba470996..402eff8fd73 100644
--- a/pkg/services/featuremgmt/toggles_gen.csv
+++ b/pkg/services/featuremgmt/toggles_gen.csv
@@ -71,7 +71,6 @@ externalServiceAuth,experimental,@grafana/grafana-authnz-team,true,false,false,f
refactorVariablesTimeRange,preview,@grafana/dashboards-squad,false,false,false,false
useCachingService,GA,@grafana/grafana-operator-experience-squad,false,false,true,false
enableElasticsearchBackendQuerying,preview,@grafana/observability-logs,false,false,false,false
-pluginsAPIManifestKey,experimental,@grafana/plugins-platform-backend,false,false,false,false
advancedDataSourcePicker,GA,@grafana/dashboards-squad,false,false,false,true
faroDatasourceSelector,preview,@grafana/app-o11y,false,false,false,true
enableDatagridEditing,preview,@grafana/grafana-bi-squad,false,false,false,true
diff --git a/pkg/services/featuremgmt/toggles_gen.go b/pkg/services/featuremgmt/toggles_gen.go
index 2ab472b452c..108242217dd 100644
--- a/pkg/services/featuremgmt/toggles_gen.go
+++ b/pkg/services/featuremgmt/toggles_gen.go
@@ -295,10 +295,6 @@ const (
// Enable the processing of queries and responses in the Elasticsearch data source through backend
FlagEnableElasticsearchBackendQuerying = "enableElasticsearchBackendQuerying"
- // FlagPluginsAPIManifestKey
- // Use grafana.com API to retrieve the public manifest key
- FlagPluginsAPIManifestKey = "pluginsAPIManifestKey"
-
// FlagAdvancedDataSourcePicker
// Enable a new data source picker with contextual information, recently used order and advanced mode
FlagAdvancedDataSourcePicker = "advancedDataSourcePicker"
diff --git a/pkg/services/pluginsintegration/keyretriever/dynamic/dynamic_retriever.go b/pkg/services/pluginsintegration/keyretriever/dynamic/dynamic_retriever.go
index 17948954fef..0b0be7c6dc9 100644
--- a/pkg/services/pluginsintegration/keyretriever/dynamic/dynamic_retriever.go
+++ b/pkg/services/pluginsintegration/keyretriever/dynamic/dynamic_retriever.go
@@ -14,7 +14,6 @@ import (
"github.com/grafana/grafana/pkg/plugins"
"github.com/grafana/grafana/pkg/plugins/log"
"github.com/grafana/grafana/pkg/plugins/manager/signature/statickey"
- "github.com/grafana/grafana/pkg/services/featuremgmt"
"github.com/grafana/grafana/pkg/setting"
)
@@ -29,9 +28,8 @@ type ManifestKeys struct {
}
type KeyRetriever struct {
- cfg *setting.Cfg
- log log.Logger
- flags featuremgmt.FeatureToggles
+ cfg *setting.Cfg
+ log log.Logger
lock sync.Mutex
cli http.Client
@@ -41,20 +39,19 @@ type KeyRetriever struct {
var _ plugins.KeyRetriever = (*KeyRetriever)(nil)
-func ProvideService(cfg *setting.Cfg, kv plugins.KeyStore, flags featuremgmt.FeatureToggles) *KeyRetriever {
+func ProvideService(cfg *setting.Cfg, kv plugins.KeyStore) *KeyRetriever {
kr := &KeyRetriever{
- cfg: cfg,
- flags: flags,
- log: log.New("plugin.signature.key_retriever"),
- cli: makeHttpClient(),
- kv: kv,
+ cfg: cfg,
+ log: log.New("plugin.signature.key_retriever"),
+ cli: makeHttpClient(),
+ kv: kv,
}
return kr
}
// IsDisabled disables dynamic retrieval of public keys from the API server.
func (kr *KeyRetriever) IsDisabled() bool {
- return !kr.flags.IsEnabled(featuremgmt.FlagPluginsAPIManifestKey)
+ return kr.cfg.PluginSkipPublicKeyDownload
}
func (kr *KeyRetriever) Run(ctx context.Context) error {
diff --git a/pkg/services/pluginsintegration/keyretriever/dynamic/dynamic_retriever_test.go b/pkg/services/pluginsintegration/keyretriever/dynamic/dynamic_retriever_test.go
index f395e61ee00..d0fe7dfeca2 100644
--- a/pkg/services/pluginsintegration/keyretriever/dynamic/dynamic_retriever_test.go
+++ b/pkg/services/pluginsintegration/keyretriever/dynamic/dynamic_retriever_test.go
@@ -9,7 +9,6 @@ import (
"time"
"github.com/grafana/grafana/pkg/infra/kvstore"
- "github.com/grafana/grafana/pkg/services/featuremgmt"
"github.com/grafana/grafana/pkg/services/pluginsintegration/keystore"
"github.com/grafana/grafana/pkg/setting"
"github.com/stretchr/testify/require"
@@ -47,7 +46,7 @@ func Test_PublicKeyUpdate(t *testing.T) {
expectedKey := "fake"
s, done := setFakeAPIServer(t, expectedKey, "7e4d0c6a708866e7")
cfg.GrafanaComURL = s.URL
- v := ProvideService(cfg, keystore.ProvideService(kvstore.NewFakeKVStore()), featuremgmt.WithFeatures(featuremgmt.FlagPluginsAPIManifestKey))
+ v := ProvideService(cfg, keystore.ProvideService(kvstore.NewFakeKVStore()))
go func() {
err := v.Run(context.Background())
require.NoError(t, err)
@@ -68,7 +67,7 @@ func Test_PublicKeyUpdate(t *testing.T) {
expectedKey := "fake"
s, done := setFakeAPIServer(t, expectedKey, "7e4d0c6a708866e7")
cfg.GrafanaComURL = s.URL
- v := ProvideService(cfg, keystore.ProvideService(kvstore.NewFakeKVStore()), featuremgmt.WithFeatures(featuremgmt.FlagPluginsAPIManifestKey))
+ v := ProvideService(cfg, keystore.ProvideService(kvstore.NewFakeKVStore()))
go func() {
err := v.Run(context.Background())
require.NoError(t, err)
@@ -88,7 +87,7 @@ func Test_PublicKeyUpdate(t *testing.T) {
expectedKey := "fake"
s, done := setFakeAPIServer(t, expectedKey, "other")
cfg.GrafanaComURL = s.URL
- v := ProvideService(cfg, keystore.ProvideService(kvstore.NewFakeKVStore()), featuremgmt.WithFeatures(featuremgmt.FlagPluginsAPIManifestKey))
+ v := ProvideService(cfg, keystore.ProvideService(kvstore.NewFakeKVStore()))
go func() {
err := v.Run(context.Background())
require.NoError(t, err)
@@ -115,7 +114,7 @@ func Test_PublicKeyUpdate(t *testing.T) {
expectedKey := "fake"
s, done := setFakeAPIServer(t, expectedKey, "7e4d0c6a708866e7")
cfg.GrafanaComURL = s.URL
- v := ProvideService(cfg, keystore.ProvideService(kvstore.NewFakeKVStore()), featuremgmt.WithFeatures(featuremgmt.FlagPluginsAPIManifestKey))
+ v := ProvideService(cfg, keystore.ProvideService(kvstore.NewFakeKVStore()))
// Simulate an updated key
err := v.kv.SetLastUpdated(context.Background())
require.NoError(t, err)
diff --git a/pkg/services/pluginsintegration/keyretriever/retriever_test.go b/pkg/services/pluginsintegration/keyretriever/retriever_test.go
index 283c688fa71..90a41b6f845 100644
--- a/pkg/services/pluginsintegration/keyretriever/retriever_test.go
+++ b/pkg/services/pluginsintegration/keyretriever/retriever_test.go
@@ -6,7 +6,6 @@ import (
"github.com/grafana/grafana/pkg/infra/kvstore"
"github.com/grafana/grafana/pkg/plugins/manager/signature/statickey"
- "github.com/grafana/grafana/pkg/services/featuremgmt"
"github.com/grafana/grafana/pkg/services/pluginsintegration/keyretriever/dynamic"
"github.com/grafana/grafana/pkg/services/pluginsintegration/keystore"
"github.com/grafana/grafana/pkg/setting"
@@ -16,7 +15,7 @@ import (
func Test_GetPublicKey(t *testing.T) {
t.Run("it should return a static key", func(t *testing.T) {
cfg := &setting.Cfg{}
- 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())
require.NoError(t, err)
require.Equal(t, statickey.GetDefaultKey(), key)
diff --git a/pkg/setting/setting.go b/pkg/setting/setting.go
index 498d0f89df7..2f764a320e1 100644
--- a/pkg/setting/setting.go
+++ b/pkg/setting/setting.go
@@ -241,6 +241,7 @@ type Cfg struct {
PluginAdminEnabled bool
PluginAdminExternalManageEnabled bool
PluginForcePublicKeyDownload bool
+ PluginSkipPublicKeyDownload bool
PluginsCDNURLTemplate string
PluginLogBackendRequests bool
diff --git a/pkg/setting/setting_plugins.go b/pkg/setting/setting_plugins.go
index 9d95154895d..8eaaf1f8f04 100644
--- a/pkg/setting/setting_plugins.go
+++ b/pkg/setting/setting_plugins.go
@@ -30,7 +30,8 @@ func (cfg *Cfg) readPluginSettings(iniFile *ini.File) error {
cfg.PluginsEnableAlpha = pluginsSection.Key("enable_alpha").MustBool(false)
cfg.PluginsAppsSkipVerifyTLS = pluginsSection.Key("app_tls_skip_verify_insecure").MustBool(false)
cfg.PluginSettings = extractPluginSettings(iniFile.Sections())
- cfg.PluginForcePublicKeyDownload = pluginsSection.Key("enforce_public_key_download").MustBool(false)
+ cfg.PluginSkipPublicKeyDownload = pluginsSection.Key("public_key_retrieval_disabled").MustBool(false)
+ cfg.PluginForcePublicKeyDownload = pluginsSection.Key("public_key_retrieval_on_startup").MustBool(false)
pluginsAllowUnsigned := pluginsSection.Key("allow_loading_unsigned_plugins").MustString("")