Plugins: Remove support for secrets manager plugins (#101467)

* remove secrets manager code

* remove unused struct

* add test toggles back

* rollback golden file changes

* add missing TestMain

* update betterer
This commit is contained in:
Will Browne
2025-03-20 10:00:59 +00:00
committed by GitHub
parent a1a3aa0665
commit 5b67ae1876
53 changed files with 76 additions and 2896 deletions

View File

@ -4776,10 +4776,9 @@ exports[`better eslint`] = {
[0, 0, 0, "No untranslated strings in text props. Wrap text with <Trans /> or use t()", "2"],
[0, 0, 0, "No untranslated strings in text props. Wrap text with <Trans /> or use t()", "3"],
[0, 0, 0, "No untranslated strings in text props. Wrap text with <Trans /> or use t()", "4"],
[0, 0, 0, "No untranslated strings in text props. Wrap text with <Trans /> or use t()", "5"],
[0, 0, 0, "No untranslated strings. Wrap text with <Trans />", "5"],
[0, 0, 0, "No untranslated strings. Wrap text with <Trans />", "6"],
[0, 0, 0, "No untranslated strings. Wrap text with <Trans />", "7"],
[0, 0, 0, "No untranslated strings. Wrap text with <Trans />", "8"]
[0, 0, 0, "No untranslated strings. Wrap text with <Trans />", "7"]
],
"public/app/features/plugins/admin/components/InstallControls/index.tsx:5381": [
[0, 0, 0, "Do not re-export imported variable (\`./InstallControlsButton\`)", "0"],

View File

@ -441,7 +441,6 @@ protobuf: ## Compile protobuf definitions
go install google.golang.org/protobuf/cmd/protoc-gen-go
go install google.golang.org/grpc/cmd/protoc-gen-go-grpc@v1.4.0
buf generate pkg/plugins/backendplugin/pluginextensionv2 --template pkg/plugins/backendplugin/pluginextensionv2/buf.gen.yaml
buf generate pkg/plugins/backendplugin/secretsmanagerplugin --template pkg/plugins/backendplugin/secretsmanagerplugin/buf.gen.yaml
buf generate pkg/apis/secret/v0alpha1/decrypt --template pkg/apis/secret/v0alpha1/decrypt/buf.gen.yaml
buf generate pkg/storage/unified/resource --template pkg/storage/unified/resource/buf.gen.yaml
buf generate pkg/services/authz/proto/v1 --template pkg/services/authz/proto/v1/buf.gen.yaml

View File

@ -10,12 +10,12 @@
"id": {
"type": "string",
"description": "Unique name of the plugin. If the plugin is published on grafana.com, then the plugin `id` has to follow the naming conventions.",
"pattern": "^[0-9a-z]+\\-([0-9a-z]+\\-)?(app|panel|datasource|secretsmanager)$"
"pattern": "^[0-9a-z]+\\-([0-9a-z]+\\-)?(app|panel|datasource)$"
},
"type": {
"type": "string",
"description": "Plugin type.",
"enum": ["app", "datasource", "panel", "renderer", "secretsmanager"]
"enum": ["app", "datasource", "panel", "renderer"]
},
"info": {
"type": "object",
@ -183,11 +183,11 @@
"properties": {
"id": {
"type": "string",
"pattern": "^[0-9a-z]+\\-([0-9a-z]+\\-)?(app|panel|datasource|secretsmanager)$"
"pattern": "^[0-9a-z]+\\-([0-9a-z]+\\-)?(app|panel|datasource)$"
},
"type": {
"type": "string",
"enum": ["app", "datasource", "panel", "secretsmanager"]
"enum": ["app", "datasource", "panel"]
},
"name": {
"type": "string"
@ -280,7 +280,7 @@
},
"type": {
"type": "string",
"enum": ["dashboard", "page", "panel", "datasource", "secretsmanager"]
"enum": ["dashboard", "page", "panel", "datasource"]
},
"name": {
"type": "string"
@ -647,7 +647,7 @@
"id": {
"type": "string",
"description": "A unique identifier for your exposed component. This is used to reference the component in other plugins. It must be in the following format: '{PLUGIN_ID}/name-of-component/v1'.",
"pattern": "^[0-9a-z]+-([0-9a-z]+-)?(app|panel|datasource|secretsmanager)\\/[a-zA-Z0-9_-]+\\/v[0-9_.-]+$"
"pattern": "^[0-9a-z]+-([0-9a-z]+-)?(app|panel|datasource)\\/[a-zA-Z0-9_-]+\\/v[0-9_.-]+$"
},
"title": {
"type": "string",
@ -670,7 +670,7 @@
"id": {
"type": "string",
"description": "A unique identifier for your extension point. This is used to reference the extension point in other plugins. It must be in the following format: '{PLUGIN_ID}/name-of-my-extension-point/v1'.",
"pattern": "^[0-9a-z]+-([0-9a-z]+-)?(app|panel|datasource|secretsmanager)\\/[a-zA-Z0-9_-]+\\/v[0-9_.-]+$"
"pattern": "^[0-9a-z]+-([0-9a-z]+-)?(app|panel|datasource)\\/[a-zA-Z0-9_-]+\\/v[0-9_.-]+$"
},
"title": {
"type": "string",

View File

@ -215,7 +215,6 @@ export interface GrafanaConfig {
unifiedAlerting: UnifiedAlertingConfig;
angularSupportEnabled: boolean;
feedbackLinksEnabled: boolean;
secretsManagerPluginEnabled: boolean;
supportBundlesEnabled: boolean;
secureSocksDSProxyEnabled: boolean;
googleAnalyticsId: string | undefined;

View File

@ -17,7 +17,6 @@ export enum PluginType {
datasource = 'datasource',
app = 'app',
renderer = 'renderer',
secretsmanager = 'secretsmanager',
}
/** Describes status of {@link https://grafana.com/docs/grafana/latest/plugins/plugin-signatures/ | plugin signature} */

View File

@ -119,7 +119,6 @@ export class GrafanaBootConfig implements GrafanaConfig {
rendererDefaultImageWidth = 1000;
rendererDefaultImageHeight = 500;
rendererDefaultImageScale = 1;
secretsManagerPluginEnabled = false;
supportBundlesEnabled = false;
http2Enabled = false;
dateFormats?: SystemDateFormatSettings;

View File

@ -6,7 +6,6 @@ import (
"github.com/grafana/grafana/pkg/api/response"
contextmodel "github.com/grafana/grafana/pkg/services/contexthandler/model"
skv "github.com/grafana/grafana/pkg/services/secrets/kvstore"
)
func (hs *HTTPServer) AdminRotateDataEncryptionKeys(c *contextmodel.ReqContext) response.Response {
@ -50,51 +49,3 @@ func (hs *HTTPServer) AdminRollbackSecrets(c *contextmodel.ReqContext) response.
return response.Respond(http.StatusOK, "Secrets rolled back successfully")
}
// To migrate to the plugin, it must be installed and configured
// so as not to lose access to migrated secrets
func (hs *HTTPServer) AdminMigrateSecretsToPlugin(c *contextmodel.ReqContext) response.Response {
if skv.EvaluateRemoteSecretsPlugin(c.Req.Context(), hs.secretsPluginManager, hs.Cfg) != nil {
hs.log.Warn("Received secrets plugin migration request while plugin is not available")
return response.Respond(http.StatusBadRequest, "Secrets plugin is not available")
}
err := hs.secretsPluginMigrator.TriggerPluginMigration(c.Req.Context(), true)
if err != nil {
hs.log.Error("Failed to trigger secret migration to plugin", "error", err.Error())
return response.Respond(http.StatusInternalServerError, "Secret migration to plugin failed")
}
return response.Respond(http.StatusOK, "Secret migration to plugin triggered successfully")
}
// To migrate from the plugin, it must be installed only
// as it is possible the user disabled it and then wants to migrate
func (hs *HTTPServer) AdminMigrateSecretsFromPlugin(c *contextmodel.ReqContext) response.Response {
if hs.secretsPluginManager.SecretsManager(c.Req.Context()) == nil {
hs.log.Warn("Received secrets plugin migration request while plugin is not installed")
return response.Respond(http.StatusBadRequest, "Secrets plugin is not installed")
}
err := hs.secretsPluginMigrator.TriggerPluginMigration(c.Req.Context(), false)
if err != nil {
hs.log.Error("Failed to trigger secret migration from plugin", "error", err.Error())
return response.Respond(http.StatusInternalServerError, "Secret migration from plugin failed")
}
return response.Respond(http.StatusOK, "Secret migration from plugin triggered successfully")
}
func (hs *HTTPServer) AdminDeleteAllSecretsManagerPluginSecrets(c *contextmodel.ReqContext) response.Response {
if hs.secretsPluginManager.SecretsManager(c.Req.Context()) == nil {
hs.log.Warn("Received secrets plugin deletion request while plugin is not installed")
return response.Respond(http.StatusBadRequest, "Secrets plugin is not installed")
}
items, err := hs.secretsStore.GetAll(c.Req.Context())
if err != nil {
return response.Respond(http.StatusInternalServerError, "an error occurred while retrieving secrets")
}
for _, item := range items {
err := hs.secretsStore.Del(c.Req.Context(), *item.OrgId, *item.Namespace, *item.Type)
if err != nil {
return response.Respond(http.StatusInternalServerError, fmt.Sprintf("error deleting key with org=%v namespace=%v type=%v. error=%v", *item.OrgId, *item.Namespace, *item.Type, err.Error()))
}
}
return response.Respond(http.StatusOK, fmt.Sprintf("All %d Secrets Manager plugin secrets deleted", len(items)))
}

View File

@ -573,9 +573,6 @@ func (hs *HTTPServer) registerRoutes() {
adminRoute.Post("/encryption/reencrypt-data-keys", reqGrafanaAdmin, routing.Wrap(hs.AdminReEncryptEncryptionKeys))
adminRoute.Post("/encryption/reencrypt-secrets", reqGrafanaAdmin, routing.Wrap(hs.AdminReEncryptSecrets))
adminRoute.Post("/encryption/rollback-secrets", reqGrafanaAdmin, routing.Wrap(hs.AdminRollbackSecrets))
adminRoute.Post("/encryption/migrate-secrets/to-plugin", reqGrafanaAdmin, routing.Wrap(hs.AdminMigrateSecretsToPlugin))
adminRoute.Post("/encryption/migrate-secrets/from-plugin", reqGrafanaAdmin, routing.Wrap(hs.AdminMigrateSecretsFromPlugin))
adminRoute.Post("/encryption/delete-secretsmanagerplugin-secrets", reqGrafanaAdmin, routing.Wrap(hs.AdminDeleteAllSecretsManagerPluginSecrets))
adminRoute.Post("/provisioning/dashboards/reload", authorize(ac.EvalPermission(ActionProvisioningReload, ScopeProvisionersDashboards)), routing.Wrap(hs.AdminProvisioningReloadDashboards))
adminRoute.Post("/provisioning/plugins/reload", authorize(ac.EvalPermission(ActionProvisioningReload, ScopeProvisionersPlugins)), routing.Wrap(hs.AdminProvisioningReloadPlugins))

View File

@ -26,7 +26,6 @@ import (
)
var datasourcesLogger = log.New("datasources")
var secretsPluginError datasources.ErrDatasourceSecretsPluginUserFriendly
// swagger:route GET /datasources datasources getDataSources
//
@ -178,9 +177,6 @@ func (hs *HTTPServer) DeleteDataSourceById(c *contextmodel.ReqContext) response.
err = hs.DataSourcesService.DeleteDataSource(c.Req.Context(), cmd)
if err != nil {
if errors.As(err, &secretsPluginError) {
return response.Error(http.StatusInternalServerError, "Failed to delete datasource: "+err.Error(), err)
}
return response.Error(http.StatusInternalServerError, "Failed to delete datasource", err)
}
@ -257,9 +253,6 @@ func (hs *HTTPServer) DeleteDataSourceByUID(c *contextmodel.ReqContext) response
err = hs.DataSourcesService.DeleteDataSource(c.Req.Context(), cmd)
if err != nil {
if errors.As(err, &secretsPluginError) {
return response.Error(http.StatusInternalServerError, "Failed to delete datasource: "+err.Error(), err)
}
return response.Error(http.StatusInternalServerError, "Failed to delete datasource", err)
}
@ -307,9 +300,6 @@ func (hs *HTTPServer) DeleteDataSourceByName(c *contextmodel.ReqContext) respons
cmd := &datasources.DeleteDataSourceCommand{Name: name, OrgID: c.SignedInUser.GetOrgID()}
err = hs.DataSourcesService.DeleteDataSource(c.Req.Context(), cmd)
if err != nil {
if errors.As(err, &secretsPluginError) {
return response.Error(http.StatusInternalServerError, "Failed to delete datasource: "+err.Error(), err)
}
return response.Error(http.StatusInternalServerError, "Failed to delete datasource", err)
}
@ -405,10 +395,6 @@ func (hs *HTTPServer) AddDataSource(c *contextmodel.ReqContext) response.Respons
return response.Error(http.StatusConflict, err.Error(), err)
}
if errors.As(err, &secretsPluginError) {
return response.Error(http.StatusInternalServerError, "Failed to add datasource: "+err.Error(), err)
}
return response.ErrOrFallback(http.StatusInternalServerError, "Failed to add datasource", err)
}
@ -532,10 +518,6 @@ func (hs *HTTPServer) updateDataSourceByID(c *contextmodel.ReqContext, ds *datas
return response.Error(http.StatusConflict, "Datasource has already been updated by someone else. Please reload and try again", err)
}
if errors.As(err, &secretsPluginError) {
return response.Error(http.StatusInternalServerError, "Failed to update datasource: "+err.Error(), err)
}
return response.ErrOrFallback(http.StatusInternalServerError, "Failed to update datasource", err)
}

View File

@ -29,11 +29,6 @@ func (hs *HTTPServer) handleQueryMetricsError(err error) *response.NormalRespons
return response.Error(http.StatusNotFound, "Data source not found", err)
}
var secretsPlugin datasources.ErrDatasourceSecretsPluginUserFriendly
if errors.As(err, &secretsPlugin) {
return response.Error(http.StatusInternalServerError, fmt.Sprint("Secrets Plugin error: ", err.Error()), err)
}
return response.ErrOrFallback(http.StatusInternalServerError, "Query data error", err)
}

View File

@ -1,7 +1,6 @@
package api
import (
"bytes"
"context"
"encoding/json"
"errors"
@ -25,7 +24,6 @@ import (
fakeDatasources "github.com/grafana/grafana/pkg/services/datasources/fakes"
"github.com/grafana/grafana/pkg/services/pluginsintegration/pluginconfig"
"github.com/grafana/grafana/pkg/services/pluginsintegration/plugincontext"
"github.com/grafana/grafana/pkg/services/pluginsintegration/pluginsettings"
pluginSettings "github.com/grafana/grafana/pkg/services/pluginsintegration/pluginsettings/service"
"github.com/grafana/grafana/pkg/services/pluginsintegration/pluginstore"
"github.com/grafana/grafana/pkg/services/query"
@ -40,11 +38,6 @@ type fakeDataSourceRequestValidator struct {
err error
}
type secretsErrorResponseBody struct {
Error string `json:"error"`
Message string `json:"message"`
}
func (rv *fakeDataSourceRequestValidator) Validate(ds *datasources.DataSource, req *http.Request) error {
return rv.err
}
@ -93,64 +86,6 @@ func TestAPIEndpoint_Metrics_QueryMetricsV2(t *testing.T) {
})
}
func TestAPIEndpoint_Metrics_PluginDecryptionFailure(t *testing.T) {
cfg := setting.NewCfg()
ds := &fakeDatasources.FakeDataSourceService{SimulatePluginFailure: true}
db := &dbtest.FakeDB{ExpectedError: pluginsettings.ErrPluginSettingNotFound}
pcp := plugincontext.ProvideService(cfg, localcache.ProvideService(),
&pluginstore.FakePluginStore{
PluginList: []pluginstore.Plugin{
{
JSONData: plugins.JSONData{
ID: "grafana",
},
},
},
},
&fakeDatasources.FakeCacheService{},
ds, pluginSettings.ProvideService(db, secretstest.NewFakeSecretsService()), pluginconfig.NewFakePluginRequestConfigProvider(),
)
qds := query.ProvideService(
cfg,
nil,
nil,
&fakeDataSourceRequestValidator{},
&fakePluginClient{
QueryDataHandlerFunc: func(ctx context.Context, req *backend.QueryDataRequest) (*backend.QueryDataResponse, error) {
resp := backend.Responses{
"A": backend.DataResponse{
Error: errors.New("query failed"),
},
}
return &backend.QueryDataResponse{Responses: resp}, nil
},
},
pcp,
)
httpServer := SetupAPITestServer(t, func(hs *HTTPServer) {
hs.queryDataService = qds
hs.QuotaService = quotatest.New(false, nil)
hs.pluginContextProvider = pcp
})
t.Run("Status code is 500 and a secrets plugin error is returned if there is a problem getting secrets from the remote plugin", func(t *testing.T) {
req := httpServer.NewPostRequest("/api/ds/query", strings.NewReader(reqValid))
webtest.RequestWithSignedInUser(req, &user.SignedInUser{UserID: 1, OrgID: 1, Permissions: map[int64]map[string][]string{1: {datasources.ActionQuery: []string{datasources.ScopeAll}}}})
resp, err := httpServer.SendJSON(req)
require.NoError(t, err)
require.Equal(t, http.StatusInternalServerError, resp.StatusCode)
buf := new(bytes.Buffer)
_, err = buf.ReadFrom(resp.Body)
require.NoError(t, err)
require.NoError(t, resp.Body.Close())
var resObj secretsErrorResponseBody
err = json.Unmarshal(buf.Bytes(), &resObj)
require.NoError(t, err)
require.Equal(t, "", resObj.Error)
require.Contains(t, resObj.Message, "Secrets Plugin error:")
})
}
var reqValid = `{
"from": "",
"to": "",

View File

@ -228,7 +228,6 @@ type FrontendSettingsDTO struct {
RendererDefaultImageWidth int `json:"rendererDefaultImageWidth"`
RendererDefaultImageHeight int `json:"rendererDefaultImageHeight"`
RendererDefaultImageScale float64 `json:"rendererDefaultImageScale"`
SecretsManagerPluginEnabled bool `json:"secretsManagerPluginEnabled"`
Http2Enabled bool `json:"http2Enabled"`
GrafanaJavascriptAgent setting.GrafanaJavascriptAgent `json:"grafanaJavascriptAgent"`
PluginCatalogURL string `json:"pluginCatalogURL"`

View File

@ -23,7 +23,6 @@ import (
"github.com/grafana/grafana/pkg/services/licensing"
"github.com/grafana/grafana/pkg/services/pluginsintegration/pluginsettings"
"github.com/grafana/grafana/pkg/services/pluginsintegration/pluginstore"
"github.com/grafana/grafana/pkg/services/secrets/kvstore"
"github.com/grafana/grafana/pkg/setting"
"github.com/grafana/grafana/pkg/tsdb/grafanads"
"github.com/grafana/grafana/pkg/util"
@ -174,7 +173,6 @@ func (hs *HTTPServer) getFrontendSettings(c *contextmodel.ReqContext) (*dtos.Fro
}
hasAccess := accesscontrol.HasAccess(hs.AccessControl, c)
secretsManagerPluginEnabled := kvstore.EvaluateRemoteSecretsPlugin(c.Req.Context(), hs.secretsPluginManager, hs.Cfg) == nil
trustedTypesDefaultPolicyEnabled := (hs.Cfg.CSPEnabled && strings.Contains(hs.Cfg.CSPTemplate, "require-trusted-types-for")) || (hs.Cfg.CSPReportOnlyEnabled && strings.Contains(hs.Cfg.CSPReportOnlyTemplate, "require-trusted-types-for"))
isCloudMigrationTarget := hs.Features.IsEnabled(c.Req.Context(), featuremgmt.FlagOnPremToCloudMigrations) && hs.Cfg.CloudMigration.IsTarget
featureToggles := hs.Features.GetEnabled(c.Req.Context())
@ -279,7 +277,6 @@ func (hs *HTTPServer) getFrontendSettings(c *contextmodel.ReqContext) (*dtos.Fro
RendererDefaultImageWidth: hs.Cfg.RendererDefaultImageWidth,
RendererDefaultImageHeight: hs.Cfg.RendererDefaultImageHeight,
RendererDefaultImageScale: hs.Cfg.RendererDefaultImageScale,
SecretsManagerPluginEnabled: secretsManagerPluginEnabled,
Http2Enabled: hs.Cfg.Protocol == setting.HTTP2Scheme,
GrafanaJavascriptAgent: hs.Cfg.GrafanaJavascriptAgent,
PluginCatalogURL: hs.Cfg.PluginCatalogURL,

View File

@ -169,10 +169,9 @@ type HTTPServer struct {
Listener net.Listener
EncryptionService encryption.Internal
SecretsService secrets.Service
secretsPluginManager plugins.SecretsPluginManager
secretsStore secretsKV.SecretsKVStore
secretsMigrator secrets.Migrator
secretsPluginMigrator spm.SecretMigrationProvider
secretMigrationProvider spm.SecretMigrationProvider
DataSourcesService datasources.DataSourceService
cleanUpService *cleanup.CleanUpService
tracer tracing.Tracer
@ -264,8 +263,8 @@ func ProvideHTTPServer(opts ServerOptions, cfg *setting.Cfg, routeRegister routi
dashboardPermissionsService accesscontrol.DashboardPermissionsService, dashboardVersionService dashver.Service,
starService star.Service, csrfService csrf.Service, managedPlugins managedplugins.Manager,
playlistService playlist.Service, apiKeyService apikey.Service, kvStore kvstore.KVStore,
secretsMigrator secrets.Migrator, secretsPluginManager plugins.SecretsPluginManager, secretsService secrets.Service,
secretsPluginMigrator spm.SecretMigrationProvider, secretsStore secretsKV.SecretsKVStore,
secretsMigrator secrets.Migrator, secretsService secrets.Service,
secretMigrationProvider spm.SecretMigrationProvider, secretsStore secretsKV.SecretsKVStore,
publicDashboardsApi *publicdashboardsApi.Api, userService user.Service, tempUserService tempUser.Service,
loginAttemptService loginAttempt.Service, orgService org.Service, orgDeletionService org.DeletionService, teamService team.Service,
accesscontrolService accesscontrol.Service, navTreeService navtree.Service,
@ -329,9 +328,8 @@ func ProvideHTTPServer(opts ServerOptions, cfg *setting.Cfg, routeRegister routi
SocialService: socialService,
EncryptionService: encryptionService,
SecretsService: secretsService,
secretsPluginManager: secretsPluginManager,
secretsMigrator: secretsMigrator,
secretsPluginMigrator: secretsPluginMigrator,
secretMigrationProvider: secretMigrationProvider,
secretsStore: secretsStore,
DataSourcesService: dataSourcesService,
searchUsersService: searchUsersService,

View File

@ -12,7 +12,6 @@ import (
"github.com/grafana/grafana/pkg/plugins/backendplugin"
"github.com/grafana/grafana/pkg/plugins/backendplugin/pluginextensionv2"
"github.com/grafana/grafana/pkg/plugins/backendplugin/secretsmanagerplugin"
"github.com/grafana/grafana/pkg/plugins/log"
)
@ -31,14 +30,13 @@ var handshake = goplugin.HandshakeConfig{
// pluginSet is list of plugins supported on v2.
var pluginSet = map[int]goplugin.PluginSet{
grpcplugin.ProtocolVersion: {
"diagnostics": &grpcplugin.DiagnosticsGRPCPlugin{},
"resource": &grpcplugin.ResourceGRPCPlugin{},
"data": &grpcplugin.DataGRPCPlugin{},
"stream": &grpcplugin.StreamGRPCPlugin{},
"admission": &grpcplugin.AdmissionGRPCPlugin{},
"conversion": &grpcplugin.ConversionGRPCPlugin{},
"renderer": &pluginextensionv2.RendererGRPCPlugin{},
"secretsmanager": &secretsmanagerplugin.SecretsManagerGRPCPlugin{},
"diagnostics": &grpcplugin.DiagnosticsGRPCPlugin{},
"resource": &grpcplugin.ResourceGRPCPlugin{},
"data": &grpcplugin.DataGRPCPlugin{},
"stream": &grpcplugin.StreamGRPCPlugin{},
"admission": &grpcplugin.AdmissionGRPCPlugin{},
"conversion": &grpcplugin.ConversionGRPCPlugin{},
"renderer": &pluginextensionv2.RendererGRPCPlugin{},
},
}
@ -84,19 +82,15 @@ func newClientConfig(executablePath string, args []string, env []string, skipHos
// StartRendererFunc callback function called when a renderer plugin is started.
type StartRendererFunc func(pluginID string, renderer pluginextensionv2.RendererPlugin, logger log.Logger) error
// StartSecretsManagerFunc callback function called when a secrets manager plugin is started.
type StartSecretsManagerFunc func(pluginID string, secretsmanager secretsmanagerplugin.SecretsManagerPlugin, logger log.Logger) error
// PluginDescriptor is a descriptor used for registering backend plugins.
type PluginDescriptor struct {
pluginID string
executablePath string
executableArgs []string
skipHostEnvVars bool
managed bool
versionedPlugins map[int]goplugin.PluginSet
startRendererFn StartRendererFunc
startSecretsManagerFn StartSecretsManagerFunc
pluginID string
executablePath string
executableArgs []string
skipHostEnvVars bool
managed bool
versionedPlugins map[int]goplugin.PluginSet
startRendererFn StartRendererFunc
}
// NewBackendPlugin creates a new backend plugin factory used for registering a backend plugin.
@ -131,14 +125,3 @@ func NewRendererPlugin(pluginID, executablePath string, startFn StartRendererFun
startRendererFn: startFn,
})
}
// NewSecretsManagerPlugin creates a new secrets manager plugin factory used for registering a backend secrets manager plugin.
func NewSecretsManagerPlugin(pluginID, executablePath string, startFn StartSecretsManagerFunc) backendplugin.PluginFactoryFunc {
return newPlugin(PluginDescriptor{
pluginID: pluginID,
executablePath: executablePath,
managed: false,
versionedPlugins: pluginSet,
startSecretsManagerFn: startFn,
})
}

View File

@ -16,7 +16,6 @@ import (
"github.com/grafana/grafana/pkg/plugins"
"github.com/grafana/grafana/pkg/plugins/backendplugin/pluginextensionv2"
"github.com/grafana/grafana/pkg/plugins/backendplugin/secretsmanagerplugin"
"github.com/grafana/grafana/pkg/plugins/log"
)
@ -32,7 +31,6 @@ type ClientV2 struct {
grpcplugin.AdmissionClient
grpcplugin.ConversionClient
pluginextensionv2.RendererPlugin
secretsmanagerplugin.SecretsManagerPlugin
}
func newClientV2(descriptor PluginDescriptor, logger log.Logger, rpcClient plugin.ClientProtocol) (*ClientV2, error) {
@ -71,11 +69,6 @@ func newClientV2(descriptor PluginDescriptor, logger log.Logger, rpcClient plugi
return nil, err
}
rawSecretsManager, err := rpcClient.Dispense("secretsmanager")
if err != nil {
return nil, err
}
c := &ClientV2{}
if rawDiagnostics != nil {
if diagnosticsClient, ok := rawDiagnostics.(grpcplugin.DiagnosticsClient); ok {
@ -119,24 +112,12 @@ func newClientV2(descriptor PluginDescriptor, logger log.Logger, rpcClient plugi
}
}
if rawSecretsManager != nil {
if secretsManagerPlugin, ok := rawSecretsManager.(secretsmanagerplugin.SecretsManagerPlugin); ok {
c.SecretsManagerPlugin = secretsManagerPlugin
}
}
if descriptor.startRendererFn != nil {
if err := descriptor.startRendererFn(descriptor.pluginID, c.RendererPlugin, logger); err != nil {
return nil, err
}
}
if descriptor.startSecretsManagerFn != nil {
if err := descriptor.startSecretsManagerFn(descriptor.pluginID, c.SecretsManagerPlugin, logger); err != nil {
return nil, err
}
}
return c, nil
}

View File

@ -8,7 +8,6 @@ import (
"github.com/grafana/grafana/pkg/plugins/backendplugin/coreplugin"
"github.com/grafana/grafana/pkg/plugins/backendplugin/grpcplugin"
"github.com/grafana/grafana/pkg/plugins/backendplugin/pluginextensionv2"
"github.com/grafana/grafana/pkg/plugins/backendplugin/secretsmanagerplugin"
"github.com/grafana/grafana/pkg/plugins/log"
)
@ -21,7 +20,7 @@ type Service struct {
func New(providers ...PluginBackendProvider) *Service {
if len(providers) == 0 {
return New(SecretsManagerProvider, DefaultProvider)
return New(DefaultProvider)
}
return &Service{
providerChain: providers,
@ -29,7 +28,7 @@ func New(providers ...PluginBackendProvider) *Service {
}
func ProvideService(coreRegistry *coreplugin.Registry) *Service {
return New(coreRegistry.BackendFactoryProvider(), SecretsManagerProvider, DefaultProvider)
return New(coreRegistry.BackendFactoryProvider(), DefaultProvider)
}
func (s *Service) BackendFactory(ctx context.Context, p *plugins.Plugin) backendplugin.PluginFactoryFunc {
@ -53,18 +52,6 @@ var RendererProvider PluginBackendProvider = func(_ context.Context, p *plugins.
)
}
var SecretsManagerProvider PluginBackendProvider = func(_ context.Context, p *plugins.Plugin) backendplugin.PluginFactoryFunc {
if !p.IsSecretsManager() {
return nil
}
return grpcplugin.NewSecretsManagerPlugin(p.ID, p.ExecutablePath(),
func(pluginID string, secretsmanager secretsmanagerplugin.SecretsManagerPlugin, logger log.Logger) error {
p.SecretsManager = secretsmanager
return nil
},
)
}
var DefaultProvider = PluginBackendProvider(func(_ context.Context, p *plugins.Plugin) backendplugin.PluginFactoryFunc {
return grpcplugin.NewBackendPlugin(p.ID, p.ExecutablePath(), p.SkipHostEnvVars)
})

View File

@ -1,9 +0,0 @@
version: v1
plugins:
- plugin: go
out: pkg/plugins/backendplugin/secretsmanagerplugin
opt: paths=source_relative
- plugin: go-grpc
out: pkg/plugins/backendplugin/secretsmanagerplugin
opt:
- paths=source_relative

View File

@ -1,7 +0,0 @@
version: v1
breaking:
use:
- FILE
lint:
use:
- DEFAULT

View File

@ -1,921 +0,0 @@
// Code generated by protoc-gen-go. DO NOT EDIT.
// versions:
// protoc-gen-go v1.36.5
// protoc (unknown)
// source: secretsmanager.proto
package secretsmanagerplugin
import (
protoreflect "google.golang.org/protobuf/reflect/protoreflect"
protoimpl "google.golang.org/protobuf/runtime/protoimpl"
reflect "reflect"
sync "sync"
unsafe "unsafe"
)
const (
// Verify that this generated code is sufficiently up-to-date.
_ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion)
// Verify that runtime/protoimpl is sufficiently up-to-date.
_ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)
)
type Key struct {
state protoimpl.MessageState `protogen:"open.v1"`
OrgId int64 `protobuf:"varint,1,opt,name=orgId,proto3" json:"orgId,omitempty"`
Namespace string `protobuf:"bytes,2,opt,name=namespace,proto3" json:"namespace,omitempty"`
Type string `protobuf:"bytes,3,opt,name=type,proto3" json:"type,omitempty"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *Key) Reset() {
*x = Key{}
mi := &file_secretsmanager_proto_msgTypes[0]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *Key) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*Key) ProtoMessage() {}
func (x *Key) ProtoReflect() protoreflect.Message {
mi := &file_secretsmanager_proto_msgTypes[0]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use Key.ProtoReflect.Descriptor instead.
func (*Key) Descriptor() ([]byte, []int) {
return file_secretsmanager_proto_rawDescGZIP(), []int{0}
}
func (x *Key) GetOrgId() int64 {
if x != nil {
return x.OrgId
}
return 0
}
func (x *Key) GetNamespace() string {
if x != nil {
return x.Namespace
}
return ""
}
func (x *Key) GetType() string {
if x != nil {
return x.Type
}
return ""
}
type Item struct {
state protoimpl.MessageState `protogen:"open.v1"`
Key *Key `protobuf:"bytes,1,opt,name=key,proto3" json:"key,omitempty"`
Value string `protobuf:"bytes,2,opt,name=value,proto3" json:"value,omitempty"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *Item) Reset() {
*x = Item{}
mi := &file_secretsmanager_proto_msgTypes[1]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *Item) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*Item) ProtoMessage() {}
func (x *Item) ProtoReflect() protoreflect.Message {
mi := &file_secretsmanager_proto_msgTypes[1]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use Item.ProtoReflect.Descriptor instead.
func (*Item) Descriptor() ([]byte, []int) {
return file_secretsmanager_proto_rawDescGZIP(), []int{1}
}
func (x *Item) GetKey() *Key {
if x != nil {
return x.Key
}
return nil
}
func (x *Item) GetValue() string {
if x != nil {
return x.Value
}
return ""
}
type GetSecretRequest struct {
state protoimpl.MessageState `protogen:"open.v1"`
KeyDescriptor *Key `protobuf:"bytes,1,opt,name=keyDescriptor,proto3" json:"keyDescriptor,omitempty"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *GetSecretRequest) Reset() {
*x = GetSecretRequest{}
mi := &file_secretsmanager_proto_msgTypes[2]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *GetSecretRequest) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*GetSecretRequest) ProtoMessage() {}
func (x *GetSecretRequest) ProtoReflect() protoreflect.Message {
mi := &file_secretsmanager_proto_msgTypes[2]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use GetSecretRequest.ProtoReflect.Descriptor instead.
func (*GetSecretRequest) Descriptor() ([]byte, []int) {
return file_secretsmanager_proto_rawDescGZIP(), []int{2}
}
func (x *GetSecretRequest) GetKeyDescriptor() *Key {
if x != nil {
return x.KeyDescriptor
}
return nil
}
type GetSecretResponse struct {
state protoimpl.MessageState `protogen:"open.v1"`
UserFriendlyError string `protobuf:"bytes,1,opt,name=userFriendlyError,proto3" json:"userFriendlyError,omitempty"`
DecryptedValue string `protobuf:"bytes,2,opt,name=decryptedValue,proto3" json:"decryptedValue,omitempty"`
Exists bool `protobuf:"varint,3,opt,name=exists,proto3" json:"exists,omitempty"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *GetSecretResponse) Reset() {
*x = GetSecretResponse{}
mi := &file_secretsmanager_proto_msgTypes[3]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *GetSecretResponse) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*GetSecretResponse) ProtoMessage() {}
func (x *GetSecretResponse) ProtoReflect() protoreflect.Message {
mi := &file_secretsmanager_proto_msgTypes[3]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use GetSecretResponse.ProtoReflect.Descriptor instead.
func (*GetSecretResponse) Descriptor() ([]byte, []int) {
return file_secretsmanager_proto_rawDescGZIP(), []int{3}
}
func (x *GetSecretResponse) GetUserFriendlyError() string {
if x != nil {
return x.UserFriendlyError
}
return ""
}
func (x *GetSecretResponse) GetDecryptedValue() string {
if x != nil {
return x.DecryptedValue
}
return ""
}
func (x *GetSecretResponse) GetExists() bool {
if x != nil {
return x.Exists
}
return false
}
type SetSecretRequest struct {
state protoimpl.MessageState `protogen:"open.v1"`
KeyDescriptor *Key `protobuf:"bytes,1,opt,name=keyDescriptor,proto3" json:"keyDescriptor,omitempty"`
Value string `protobuf:"bytes,2,opt,name=value,proto3" json:"value,omitempty"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *SetSecretRequest) Reset() {
*x = SetSecretRequest{}
mi := &file_secretsmanager_proto_msgTypes[4]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *SetSecretRequest) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*SetSecretRequest) ProtoMessage() {}
func (x *SetSecretRequest) ProtoReflect() protoreflect.Message {
mi := &file_secretsmanager_proto_msgTypes[4]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use SetSecretRequest.ProtoReflect.Descriptor instead.
func (*SetSecretRequest) Descriptor() ([]byte, []int) {
return file_secretsmanager_proto_rawDescGZIP(), []int{4}
}
func (x *SetSecretRequest) GetKeyDescriptor() *Key {
if x != nil {
return x.KeyDescriptor
}
return nil
}
func (x *SetSecretRequest) GetValue() string {
if x != nil {
return x.Value
}
return ""
}
type SetSecretResponse struct {
state protoimpl.MessageState `protogen:"open.v1"`
UserFriendlyError string `protobuf:"bytes,1,opt,name=userFriendlyError,proto3" json:"userFriendlyError,omitempty"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *SetSecretResponse) Reset() {
*x = SetSecretResponse{}
mi := &file_secretsmanager_proto_msgTypes[5]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *SetSecretResponse) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*SetSecretResponse) ProtoMessage() {}
func (x *SetSecretResponse) ProtoReflect() protoreflect.Message {
mi := &file_secretsmanager_proto_msgTypes[5]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use SetSecretResponse.ProtoReflect.Descriptor instead.
func (*SetSecretResponse) Descriptor() ([]byte, []int) {
return file_secretsmanager_proto_rawDescGZIP(), []int{5}
}
func (x *SetSecretResponse) GetUserFriendlyError() string {
if x != nil {
return x.UserFriendlyError
}
return ""
}
type DeleteSecretRequest struct {
state protoimpl.MessageState `protogen:"open.v1"`
KeyDescriptor *Key `protobuf:"bytes,1,opt,name=keyDescriptor,proto3" json:"keyDescriptor,omitempty"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *DeleteSecretRequest) Reset() {
*x = DeleteSecretRequest{}
mi := &file_secretsmanager_proto_msgTypes[6]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *DeleteSecretRequest) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*DeleteSecretRequest) ProtoMessage() {}
func (x *DeleteSecretRequest) ProtoReflect() protoreflect.Message {
mi := &file_secretsmanager_proto_msgTypes[6]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use DeleteSecretRequest.ProtoReflect.Descriptor instead.
func (*DeleteSecretRequest) Descriptor() ([]byte, []int) {
return file_secretsmanager_proto_rawDescGZIP(), []int{6}
}
func (x *DeleteSecretRequest) GetKeyDescriptor() *Key {
if x != nil {
return x.KeyDescriptor
}
return nil
}
type DeleteSecretResponse struct {
state protoimpl.MessageState `protogen:"open.v1"`
UserFriendlyError string `protobuf:"bytes,1,opt,name=userFriendlyError,proto3" json:"userFriendlyError,omitempty"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *DeleteSecretResponse) Reset() {
*x = DeleteSecretResponse{}
mi := &file_secretsmanager_proto_msgTypes[7]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *DeleteSecretResponse) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*DeleteSecretResponse) ProtoMessage() {}
func (x *DeleteSecretResponse) ProtoReflect() protoreflect.Message {
mi := &file_secretsmanager_proto_msgTypes[7]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use DeleteSecretResponse.ProtoReflect.Descriptor instead.
func (*DeleteSecretResponse) Descriptor() ([]byte, []int) {
return file_secretsmanager_proto_rawDescGZIP(), []int{7}
}
func (x *DeleteSecretResponse) GetUserFriendlyError() string {
if x != nil {
return x.UserFriendlyError
}
return ""
}
type ListSecretsRequest struct {
state protoimpl.MessageState `protogen:"open.v1"`
KeyDescriptor *Key `protobuf:"bytes,1,opt,name=keyDescriptor,proto3" json:"keyDescriptor,omitempty"`
AllOrganizations bool `protobuf:"varint,2,opt,name=allOrganizations,proto3" json:"allOrganizations,omitempty"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *ListSecretsRequest) Reset() {
*x = ListSecretsRequest{}
mi := &file_secretsmanager_proto_msgTypes[8]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *ListSecretsRequest) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*ListSecretsRequest) ProtoMessage() {}
func (x *ListSecretsRequest) ProtoReflect() protoreflect.Message {
mi := &file_secretsmanager_proto_msgTypes[8]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use ListSecretsRequest.ProtoReflect.Descriptor instead.
func (*ListSecretsRequest) Descriptor() ([]byte, []int) {
return file_secretsmanager_proto_rawDescGZIP(), []int{8}
}
func (x *ListSecretsRequest) GetKeyDescriptor() *Key {
if x != nil {
return x.KeyDescriptor
}
return nil
}
func (x *ListSecretsRequest) GetAllOrganizations() bool {
if x != nil {
return x.AllOrganizations
}
return false
}
type ListSecretsResponse struct {
state protoimpl.MessageState `protogen:"open.v1"`
UserFriendlyError string `protobuf:"bytes,1,opt,name=userFriendlyError,proto3" json:"userFriendlyError,omitempty"`
Keys []*Key `protobuf:"bytes,2,rep,name=keys,proto3" json:"keys,omitempty"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *ListSecretsResponse) Reset() {
*x = ListSecretsResponse{}
mi := &file_secretsmanager_proto_msgTypes[9]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *ListSecretsResponse) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*ListSecretsResponse) ProtoMessage() {}
func (x *ListSecretsResponse) ProtoReflect() protoreflect.Message {
mi := &file_secretsmanager_proto_msgTypes[9]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use ListSecretsResponse.ProtoReflect.Descriptor instead.
func (*ListSecretsResponse) Descriptor() ([]byte, []int) {
return file_secretsmanager_proto_rawDescGZIP(), []int{9}
}
func (x *ListSecretsResponse) GetUserFriendlyError() string {
if x != nil {
return x.UserFriendlyError
}
return ""
}
func (x *ListSecretsResponse) GetKeys() []*Key {
if x != nil {
return x.Keys
}
return nil
}
type GetAllSecretsRequest struct {
state protoimpl.MessageState `protogen:"open.v1"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *GetAllSecretsRequest) Reset() {
*x = GetAllSecretsRequest{}
mi := &file_secretsmanager_proto_msgTypes[10]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *GetAllSecretsRequest) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*GetAllSecretsRequest) ProtoMessage() {}
func (x *GetAllSecretsRequest) ProtoReflect() protoreflect.Message {
mi := &file_secretsmanager_proto_msgTypes[10]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use GetAllSecretsRequest.ProtoReflect.Descriptor instead.
func (*GetAllSecretsRequest) Descriptor() ([]byte, []int) {
return file_secretsmanager_proto_rawDescGZIP(), []int{10}
}
type GetAllSecretsResponse struct {
state protoimpl.MessageState `protogen:"open.v1"`
UserFriendlyError string `protobuf:"bytes,1,opt,name=userFriendlyError,proto3" json:"userFriendlyError,omitempty"`
Items []*Item `protobuf:"bytes,2,rep,name=items,proto3" json:"items,omitempty"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *GetAllSecretsResponse) Reset() {
*x = GetAllSecretsResponse{}
mi := &file_secretsmanager_proto_msgTypes[11]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *GetAllSecretsResponse) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*GetAllSecretsResponse) ProtoMessage() {}
func (x *GetAllSecretsResponse) ProtoReflect() protoreflect.Message {
mi := &file_secretsmanager_proto_msgTypes[11]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use GetAllSecretsResponse.ProtoReflect.Descriptor instead.
func (*GetAllSecretsResponse) Descriptor() ([]byte, []int) {
return file_secretsmanager_proto_rawDescGZIP(), []int{11}
}
func (x *GetAllSecretsResponse) GetUserFriendlyError() string {
if x != nil {
return x.UserFriendlyError
}
return ""
}
func (x *GetAllSecretsResponse) GetItems() []*Item {
if x != nil {
return x.Items
}
return nil
}
type RenameSecretRequest struct {
state protoimpl.MessageState `protogen:"open.v1"`
KeyDescriptor *Key `protobuf:"bytes,1,opt,name=keyDescriptor,proto3" json:"keyDescriptor,omitempty"`
NewNamespace string `protobuf:"bytes,2,opt,name=newNamespace,proto3" json:"newNamespace,omitempty"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *RenameSecretRequest) Reset() {
*x = RenameSecretRequest{}
mi := &file_secretsmanager_proto_msgTypes[12]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *RenameSecretRequest) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*RenameSecretRequest) ProtoMessage() {}
func (x *RenameSecretRequest) ProtoReflect() protoreflect.Message {
mi := &file_secretsmanager_proto_msgTypes[12]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use RenameSecretRequest.ProtoReflect.Descriptor instead.
func (*RenameSecretRequest) Descriptor() ([]byte, []int) {
return file_secretsmanager_proto_rawDescGZIP(), []int{12}
}
func (x *RenameSecretRequest) GetKeyDescriptor() *Key {
if x != nil {
return x.KeyDescriptor
}
return nil
}
func (x *RenameSecretRequest) GetNewNamespace() string {
if x != nil {
return x.NewNamespace
}
return ""
}
type RenameSecretResponse struct {
state protoimpl.MessageState `protogen:"open.v1"`
UserFriendlyError string `protobuf:"bytes,1,opt,name=userFriendlyError,proto3" json:"userFriendlyError,omitempty"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *RenameSecretResponse) Reset() {
*x = RenameSecretResponse{}
mi := &file_secretsmanager_proto_msgTypes[13]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *RenameSecretResponse) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*RenameSecretResponse) ProtoMessage() {}
func (x *RenameSecretResponse) ProtoReflect() protoreflect.Message {
mi := &file_secretsmanager_proto_msgTypes[13]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use RenameSecretResponse.ProtoReflect.Descriptor instead.
func (*RenameSecretResponse) Descriptor() ([]byte, []int) {
return file_secretsmanager_proto_rawDescGZIP(), []int{13}
}
func (x *RenameSecretResponse) GetUserFriendlyError() string {
if x != nil {
return x.UserFriendlyError
}
return ""
}
var File_secretsmanager_proto protoreflect.FileDescriptor
var file_secretsmanager_proto_rawDesc = string([]byte{
0x0a, 0x14, 0x73, 0x65, 0x63, 0x72, 0x65, 0x74, 0x73, 0x6d, 0x61, 0x6e, 0x61, 0x67, 0x65, 0x72,
0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x14, 0x73, 0x65, 0x63, 0x72, 0x65, 0x74, 0x73, 0x6d,
0x61, 0x6e, 0x61, 0x67, 0x65, 0x72, 0x70, 0x6c, 0x75, 0x67, 0x69, 0x6e, 0x22, 0x4d, 0x0a, 0x03,
0x4b, 0x65, 0x79, 0x12, 0x14, 0x0a, 0x05, 0x6f, 0x72, 0x67, 0x49, 0x64, 0x18, 0x01, 0x20, 0x01,
0x28, 0x03, 0x52, 0x05, 0x6f, 0x72, 0x67, 0x49, 0x64, 0x12, 0x1c, 0x0a, 0x09, 0x6e, 0x61, 0x6d,
0x65, 0x73, 0x70, 0x61, 0x63, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x6e, 0x61,
0x6d, 0x65, 0x73, 0x70, 0x61, 0x63, 0x65, 0x12, 0x12, 0x0a, 0x04, 0x74, 0x79, 0x70, 0x65, 0x18,
0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x74, 0x79, 0x70, 0x65, 0x22, 0x49, 0x0a, 0x04, 0x49,
0x74, 0x65, 0x6d, 0x12, 0x2b, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b,
0x32, 0x19, 0x2e, 0x73, 0x65, 0x63, 0x72, 0x65, 0x74, 0x73, 0x6d, 0x61, 0x6e, 0x61, 0x67, 0x65,
0x72, 0x70, 0x6c, 0x75, 0x67, 0x69, 0x6e, 0x2e, 0x4b, 0x65, 0x79, 0x52, 0x03, 0x6b, 0x65, 0x79,
0x12, 0x14, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52,
0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x22, 0x53, 0x0a, 0x10, 0x47, 0x65, 0x74, 0x53, 0x65, 0x63,
0x72, 0x65, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x3f, 0x0a, 0x0d, 0x6b, 0x65,
0x79, 0x44, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x6f, 0x72, 0x18, 0x01, 0x20, 0x01, 0x28,
0x0b, 0x32, 0x19, 0x2e, 0x73, 0x65, 0x63, 0x72, 0x65, 0x74, 0x73, 0x6d, 0x61, 0x6e, 0x61, 0x67,
0x65, 0x72, 0x70, 0x6c, 0x75, 0x67, 0x69, 0x6e, 0x2e, 0x4b, 0x65, 0x79, 0x52, 0x0d, 0x6b, 0x65,
0x79, 0x44, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x6f, 0x72, 0x22, 0x81, 0x01, 0x0a, 0x11,
0x47, 0x65, 0x74, 0x53, 0x65, 0x63, 0x72, 0x65, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73,
0x65, 0x12, 0x2c, 0x0a, 0x11, 0x75, 0x73, 0x65, 0x72, 0x46, 0x72, 0x69, 0x65, 0x6e, 0x64, 0x6c,
0x79, 0x45, 0x72, 0x72, 0x6f, 0x72, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x11, 0x75, 0x73,
0x65, 0x72, 0x46, 0x72, 0x69, 0x65, 0x6e, 0x64, 0x6c, 0x79, 0x45, 0x72, 0x72, 0x6f, 0x72, 0x12,
0x26, 0x0a, 0x0e, 0x64, 0x65, 0x63, 0x72, 0x79, 0x70, 0x74, 0x65, 0x64, 0x56, 0x61, 0x6c, 0x75,
0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0e, 0x64, 0x65, 0x63, 0x72, 0x79, 0x70, 0x74,
0x65, 0x64, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x12, 0x16, 0x0a, 0x06, 0x65, 0x78, 0x69, 0x73, 0x74,
0x73, 0x18, 0x03, 0x20, 0x01, 0x28, 0x08, 0x52, 0x06, 0x65, 0x78, 0x69, 0x73, 0x74, 0x73, 0x22,
0x69, 0x0a, 0x10, 0x53, 0x65, 0x74, 0x53, 0x65, 0x63, 0x72, 0x65, 0x74, 0x52, 0x65, 0x71, 0x75,
0x65, 0x73, 0x74, 0x12, 0x3f, 0x0a, 0x0d, 0x6b, 0x65, 0x79, 0x44, 0x65, 0x73, 0x63, 0x72, 0x69,
0x70, 0x74, 0x6f, 0x72, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x19, 0x2e, 0x73, 0x65, 0x63,
0x72, 0x65, 0x74, 0x73, 0x6d, 0x61, 0x6e, 0x61, 0x67, 0x65, 0x72, 0x70, 0x6c, 0x75, 0x67, 0x69,
0x6e, 0x2e, 0x4b, 0x65, 0x79, 0x52, 0x0d, 0x6b, 0x65, 0x79, 0x44, 0x65, 0x73, 0x63, 0x72, 0x69,
0x70, 0x74, 0x6f, 0x72, 0x12, 0x14, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20,
0x01, 0x28, 0x09, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x22, 0x41, 0x0a, 0x11, 0x53, 0x65,
0x74, 0x53, 0x65, 0x63, 0x72, 0x65, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12,
0x2c, 0x0a, 0x11, 0x75, 0x73, 0x65, 0x72, 0x46, 0x72, 0x69, 0x65, 0x6e, 0x64, 0x6c, 0x79, 0x45,
0x72, 0x72, 0x6f, 0x72, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x11, 0x75, 0x73, 0x65, 0x72,
0x46, 0x72, 0x69, 0x65, 0x6e, 0x64, 0x6c, 0x79, 0x45, 0x72, 0x72, 0x6f, 0x72, 0x22, 0x56, 0x0a,
0x13, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x53, 0x65, 0x63, 0x72, 0x65, 0x74, 0x52, 0x65, 0x71,
0x75, 0x65, 0x73, 0x74, 0x12, 0x3f, 0x0a, 0x0d, 0x6b, 0x65, 0x79, 0x44, 0x65, 0x73, 0x63, 0x72,
0x69, 0x70, 0x74, 0x6f, 0x72, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x19, 0x2e, 0x73, 0x65,
0x63, 0x72, 0x65, 0x74, 0x73, 0x6d, 0x61, 0x6e, 0x61, 0x67, 0x65, 0x72, 0x70, 0x6c, 0x75, 0x67,
0x69, 0x6e, 0x2e, 0x4b, 0x65, 0x79, 0x52, 0x0d, 0x6b, 0x65, 0x79, 0x44, 0x65, 0x73, 0x63, 0x72,
0x69, 0x70, 0x74, 0x6f, 0x72, 0x22, 0x44, 0x0a, 0x14, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x53,
0x65, 0x63, 0x72, 0x65, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x2c, 0x0a,
0x11, 0x75, 0x73, 0x65, 0x72, 0x46, 0x72, 0x69, 0x65, 0x6e, 0x64, 0x6c, 0x79, 0x45, 0x72, 0x72,
0x6f, 0x72, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x11, 0x75, 0x73, 0x65, 0x72, 0x46, 0x72,
0x69, 0x65, 0x6e, 0x64, 0x6c, 0x79, 0x45, 0x72, 0x72, 0x6f, 0x72, 0x22, 0x81, 0x01, 0x0a, 0x12,
0x4c, 0x69, 0x73, 0x74, 0x53, 0x65, 0x63, 0x72, 0x65, 0x74, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65,
0x73, 0x74, 0x12, 0x3f, 0x0a, 0x0d, 0x6b, 0x65, 0x79, 0x44, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70,
0x74, 0x6f, 0x72, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x19, 0x2e, 0x73, 0x65, 0x63, 0x72,
0x65, 0x74, 0x73, 0x6d, 0x61, 0x6e, 0x61, 0x67, 0x65, 0x72, 0x70, 0x6c, 0x75, 0x67, 0x69, 0x6e,
0x2e, 0x4b, 0x65, 0x79, 0x52, 0x0d, 0x6b, 0x65, 0x79, 0x44, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70,
0x74, 0x6f, 0x72, 0x12, 0x2a, 0x0a, 0x10, 0x61, 0x6c, 0x6c, 0x4f, 0x72, 0x67, 0x61, 0x6e, 0x69,
0x7a, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x18, 0x02, 0x20, 0x01, 0x28, 0x08, 0x52, 0x10, 0x61,
0x6c, 0x6c, 0x4f, 0x72, 0x67, 0x61, 0x6e, 0x69, 0x7a, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x22,
0x72, 0x0a, 0x13, 0x4c, 0x69, 0x73, 0x74, 0x53, 0x65, 0x63, 0x72, 0x65, 0x74, 0x73, 0x52, 0x65,
0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x2c, 0x0a, 0x11, 0x75, 0x73, 0x65, 0x72, 0x46, 0x72,
0x69, 0x65, 0x6e, 0x64, 0x6c, 0x79, 0x45, 0x72, 0x72, 0x6f, 0x72, 0x18, 0x01, 0x20, 0x01, 0x28,
0x09, 0x52, 0x11, 0x75, 0x73, 0x65, 0x72, 0x46, 0x72, 0x69, 0x65, 0x6e, 0x64, 0x6c, 0x79, 0x45,
0x72, 0x72, 0x6f, 0x72, 0x12, 0x2d, 0x0a, 0x04, 0x6b, 0x65, 0x79, 0x73, 0x18, 0x02, 0x20, 0x03,
0x28, 0x0b, 0x32, 0x19, 0x2e, 0x73, 0x65, 0x63, 0x72, 0x65, 0x74, 0x73, 0x6d, 0x61, 0x6e, 0x61,
0x67, 0x65, 0x72, 0x70, 0x6c, 0x75, 0x67, 0x69, 0x6e, 0x2e, 0x4b, 0x65, 0x79, 0x52, 0x04, 0x6b,
0x65, 0x79, 0x73, 0x22, 0x16, 0x0a, 0x14, 0x47, 0x65, 0x74, 0x41, 0x6c, 0x6c, 0x53, 0x65, 0x63,
0x72, 0x65, 0x74, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x22, 0x77, 0x0a, 0x15, 0x47,
0x65, 0x74, 0x41, 0x6c, 0x6c, 0x53, 0x65, 0x63, 0x72, 0x65, 0x74, 0x73, 0x52, 0x65, 0x73, 0x70,
0x6f, 0x6e, 0x73, 0x65, 0x12, 0x2c, 0x0a, 0x11, 0x75, 0x73, 0x65, 0x72, 0x46, 0x72, 0x69, 0x65,
0x6e, 0x64, 0x6c, 0x79, 0x45, 0x72, 0x72, 0x6f, 0x72, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52,
0x11, 0x75, 0x73, 0x65, 0x72, 0x46, 0x72, 0x69, 0x65, 0x6e, 0x64, 0x6c, 0x79, 0x45, 0x72, 0x72,
0x6f, 0x72, 0x12, 0x30, 0x0a, 0x05, 0x69, 0x74, 0x65, 0x6d, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28,
0x0b, 0x32, 0x1a, 0x2e, 0x73, 0x65, 0x63, 0x72, 0x65, 0x74, 0x73, 0x6d, 0x61, 0x6e, 0x61, 0x67,
0x65, 0x72, 0x70, 0x6c, 0x75, 0x67, 0x69, 0x6e, 0x2e, 0x49, 0x74, 0x65, 0x6d, 0x52, 0x05, 0x69,
0x74, 0x65, 0x6d, 0x73, 0x22, 0x7a, 0x0a, 0x13, 0x52, 0x65, 0x6e, 0x61, 0x6d, 0x65, 0x53, 0x65,
0x63, 0x72, 0x65, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x3f, 0x0a, 0x0d, 0x6b,
0x65, 0x79, 0x44, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x6f, 0x72, 0x18, 0x01, 0x20, 0x01,
0x28, 0x0b, 0x32, 0x19, 0x2e, 0x73, 0x65, 0x63, 0x72, 0x65, 0x74, 0x73, 0x6d, 0x61, 0x6e, 0x61,
0x67, 0x65, 0x72, 0x70, 0x6c, 0x75, 0x67, 0x69, 0x6e, 0x2e, 0x4b, 0x65, 0x79, 0x52, 0x0d, 0x6b,
0x65, 0x79, 0x44, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x6f, 0x72, 0x12, 0x22, 0x0a, 0x0c,
0x6e, 0x65, 0x77, 0x4e, 0x61, 0x6d, 0x65, 0x73, 0x70, 0x61, 0x63, 0x65, 0x18, 0x02, 0x20, 0x01,
0x28, 0x09, 0x52, 0x0c, 0x6e, 0x65, 0x77, 0x4e, 0x61, 0x6d, 0x65, 0x73, 0x70, 0x61, 0x63, 0x65,
0x22, 0x44, 0x0a, 0x14, 0x52, 0x65, 0x6e, 0x61, 0x6d, 0x65, 0x53, 0x65, 0x63, 0x72, 0x65, 0x74,
0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x2c, 0x0a, 0x11, 0x75, 0x73, 0x65, 0x72,
0x46, 0x72, 0x69, 0x65, 0x6e, 0x64, 0x6c, 0x79, 0x45, 0x72, 0x72, 0x6f, 0x72, 0x18, 0x01, 0x20,
0x01, 0x28, 0x09, 0x52, 0x11, 0x75, 0x73, 0x65, 0x72, 0x46, 0x72, 0x69, 0x65, 0x6e, 0x64, 0x6c,
0x79, 0x45, 0x72, 0x72, 0x6f, 0x72, 0x32, 0xe8, 0x04, 0x0a, 0x0e, 0x53, 0x65, 0x63, 0x72, 0x65,
0x74, 0x73, 0x4d, 0x61, 0x6e, 0x61, 0x67, 0x65, 0x72, 0x12, 0x5c, 0x0a, 0x09, 0x47, 0x65, 0x74,
0x53, 0x65, 0x63, 0x72, 0x65, 0x74, 0x12, 0x26, 0x2e, 0x73, 0x65, 0x63, 0x72, 0x65, 0x74, 0x73,
0x6d, 0x61, 0x6e, 0x61, 0x67, 0x65, 0x72, 0x70, 0x6c, 0x75, 0x67, 0x69, 0x6e, 0x2e, 0x47, 0x65,
0x74, 0x53, 0x65, 0x63, 0x72, 0x65, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x27,
0x2e, 0x73, 0x65, 0x63, 0x72, 0x65, 0x74, 0x73, 0x6d, 0x61, 0x6e, 0x61, 0x67, 0x65, 0x72, 0x70,
0x6c, 0x75, 0x67, 0x69, 0x6e, 0x2e, 0x47, 0x65, 0x74, 0x53, 0x65, 0x63, 0x72, 0x65, 0x74, 0x52,
0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x5c, 0x0a, 0x09, 0x53, 0x65, 0x74, 0x53, 0x65,
0x63, 0x72, 0x65, 0x74, 0x12, 0x26, 0x2e, 0x73, 0x65, 0x63, 0x72, 0x65, 0x74, 0x73, 0x6d, 0x61,
0x6e, 0x61, 0x67, 0x65, 0x72, 0x70, 0x6c, 0x75, 0x67, 0x69, 0x6e, 0x2e, 0x53, 0x65, 0x74, 0x53,
0x65, 0x63, 0x72, 0x65, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x27, 0x2e, 0x73,
0x65, 0x63, 0x72, 0x65, 0x74, 0x73, 0x6d, 0x61, 0x6e, 0x61, 0x67, 0x65, 0x72, 0x70, 0x6c, 0x75,
0x67, 0x69, 0x6e, 0x2e, 0x53, 0x65, 0x74, 0x53, 0x65, 0x63, 0x72, 0x65, 0x74, 0x52, 0x65, 0x73,
0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x65, 0x0a, 0x0c, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x53,
0x65, 0x63, 0x72, 0x65, 0x74, 0x12, 0x29, 0x2e, 0x73, 0x65, 0x63, 0x72, 0x65, 0x74, 0x73, 0x6d,
0x61, 0x6e, 0x61, 0x67, 0x65, 0x72, 0x70, 0x6c, 0x75, 0x67, 0x69, 0x6e, 0x2e, 0x44, 0x65, 0x6c,
0x65, 0x74, 0x65, 0x53, 0x65, 0x63, 0x72, 0x65, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74,
0x1a, 0x2a, 0x2e, 0x73, 0x65, 0x63, 0x72, 0x65, 0x74, 0x73, 0x6d, 0x61, 0x6e, 0x61, 0x67, 0x65,
0x72, 0x70, 0x6c, 0x75, 0x67, 0x69, 0x6e, 0x2e, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x53, 0x65,
0x63, 0x72, 0x65, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x62, 0x0a, 0x0b,
0x4c, 0x69, 0x73, 0x74, 0x53, 0x65, 0x63, 0x72, 0x65, 0x74, 0x73, 0x12, 0x28, 0x2e, 0x73, 0x65,
0x63, 0x72, 0x65, 0x74, 0x73, 0x6d, 0x61, 0x6e, 0x61, 0x67, 0x65, 0x72, 0x70, 0x6c, 0x75, 0x67,
0x69, 0x6e, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x53, 0x65, 0x63, 0x72, 0x65, 0x74, 0x73, 0x52, 0x65,
0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x29, 0x2e, 0x73, 0x65, 0x63, 0x72, 0x65, 0x74, 0x73, 0x6d,
0x61, 0x6e, 0x61, 0x67, 0x65, 0x72, 0x70, 0x6c, 0x75, 0x67, 0x69, 0x6e, 0x2e, 0x4c, 0x69, 0x73,
0x74, 0x53, 0x65, 0x63, 0x72, 0x65, 0x74, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65,
0x12, 0x65, 0x0a, 0x0c, 0x52, 0x65, 0x6e, 0x61, 0x6d, 0x65, 0x53, 0x65, 0x63, 0x72, 0x65, 0x74,
0x12, 0x29, 0x2e, 0x73, 0x65, 0x63, 0x72, 0x65, 0x74, 0x73, 0x6d, 0x61, 0x6e, 0x61, 0x67, 0x65,
0x72, 0x70, 0x6c, 0x75, 0x67, 0x69, 0x6e, 0x2e, 0x52, 0x65, 0x6e, 0x61, 0x6d, 0x65, 0x53, 0x65,
0x63, 0x72, 0x65, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x2a, 0x2e, 0x73, 0x65,
0x63, 0x72, 0x65, 0x74, 0x73, 0x6d, 0x61, 0x6e, 0x61, 0x67, 0x65, 0x72, 0x70, 0x6c, 0x75, 0x67,
0x69, 0x6e, 0x2e, 0x52, 0x65, 0x6e, 0x61, 0x6d, 0x65, 0x53, 0x65, 0x63, 0x72, 0x65, 0x74, 0x52,
0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x68, 0x0a, 0x0d, 0x47, 0x65, 0x74, 0x41, 0x6c,
0x6c, 0x53, 0x65, 0x63, 0x72, 0x65, 0x74, 0x73, 0x12, 0x2a, 0x2e, 0x73, 0x65, 0x63, 0x72, 0x65,
0x74, 0x73, 0x6d, 0x61, 0x6e, 0x61, 0x67, 0x65, 0x72, 0x70, 0x6c, 0x75, 0x67, 0x69, 0x6e, 0x2e,
0x47, 0x65, 0x74, 0x41, 0x6c, 0x6c, 0x53, 0x65, 0x63, 0x72, 0x65, 0x74, 0x73, 0x52, 0x65, 0x71,
0x75, 0x65, 0x73, 0x74, 0x1a, 0x2b, 0x2e, 0x73, 0x65, 0x63, 0x72, 0x65, 0x74, 0x73, 0x6d, 0x61,
0x6e, 0x61, 0x67, 0x65, 0x72, 0x70, 0x6c, 0x75, 0x67, 0x69, 0x6e, 0x2e, 0x47, 0x65, 0x74, 0x41,
0x6c, 0x6c, 0x53, 0x65, 0x63, 0x72, 0x65, 0x74, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73,
0x65, 0x42, 0x19, 0x5a, 0x17, 0x2e, 0x2f, 0x3b, 0x73, 0x65, 0x63, 0x72, 0x65, 0x74, 0x73, 0x6d,
0x61, 0x6e, 0x61, 0x67, 0x65, 0x72, 0x70, 0x6c, 0x75, 0x67, 0x69, 0x6e, 0x62, 0x06, 0x70, 0x72,
0x6f, 0x74, 0x6f, 0x33,
})
var (
file_secretsmanager_proto_rawDescOnce sync.Once
file_secretsmanager_proto_rawDescData []byte
)
func file_secretsmanager_proto_rawDescGZIP() []byte {
file_secretsmanager_proto_rawDescOnce.Do(func() {
file_secretsmanager_proto_rawDescData = protoimpl.X.CompressGZIP(unsafe.Slice(unsafe.StringData(file_secretsmanager_proto_rawDesc), len(file_secretsmanager_proto_rawDesc)))
})
return file_secretsmanager_proto_rawDescData
}
var file_secretsmanager_proto_msgTypes = make([]protoimpl.MessageInfo, 14)
var file_secretsmanager_proto_goTypes = []any{
(*Key)(nil), // 0: secretsmanagerplugin.Key
(*Item)(nil), // 1: secretsmanagerplugin.Item
(*GetSecretRequest)(nil), // 2: secretsmanagerplugin.GetSecretRequest
(*GetSecretResponse)(nil), // 3: secretsmanagerplugin.GetSecretResponse
(*SetSecretRequest)(nil), // 4: secretsmanagerplugin.SetSecretRequest
(*SetSecretResponse)(nil), // 5: secretsmanagerplugin.SetSecretResponse
(*DeleteSecretRequest)(nil), // 6: secretsmanagerplugin.DeleteSecretRequest
(*DeleteSecretResponse)(nil), // 7: secretsmanagerplugin.DeleteSecretResponse
(*ListSecretsRequest)(nil), // 8: secretsmanagerplugin.ListSecretsRequest
(*ListSecretsResponse)(nil), // 9: secretsmanagerplugin.ListSecretsResponse
(*GetAllSecretsRequest)(nil), // 10: secretsmanagerplugin.GetAllSecretsRequest
(*GetAllSecretsResponse)(nil), // 11: secretsmanagerplugin.GetAllSecretsResponse
(*RenameSecretRequest)(nil), // 12: secretsmanagerplugin.RenameSecretRequest
(*RenameSecretResponse)(nil), // 13: secretsmanagerplugin.RenameSecretResponse
}
var file_secretsmanager_proto_depIdxs = []int32{
0, // 0: secretsmanagerplugin.Item.key:type_name -> secretsmanagerplugin.Key
0, // 1: secretsmanagerplugin.GetSecretRequest.keyDescriptor:type_name -> secretsmanagerplugin.Key
0, // 2: secretsmanagerplugin.SetSecretRequest.keyDescriptor:type_name -> secretsmanagerplugin.Key
0, // 3: secretsmanagerplugin.DeleteSecretRequest.keyDescriptor:type_name -> secretsmanagerplugin.Key
0, // 4: secretsmanagerplugin.ListSecretsRequest.keyDescriptor:type_name -> secretsmanagerplugin.Key
0, // 5: secretsmanagerplugin.ListSecretsResponse.keys:type_name -> secretsmanagerplugin.Key
1, // 6: secretsmanagerplugin.GetAllSecretsResponse.items:type_name -> secretsmanagerplugin.Item
0, // 7: secretsmanagerplugin.RenameSecretRequest.keyDescriptor:type_name -> secretsmanagerplugin.Key
2, // 8: secretsmanagerplugin.SecretsManager.GetSecret:input_type -> secretsmanagerplugin.GetSecretRequest
4, // 9: secretsmanagerplugin.SecretsManager.SetSecret:input_type -> secretsmanagerplugin.SetSecretRequest
6, // 10: secretsmanagerplugin.SecretsManager.DeleteSecret:input_type -> secretsmanagerplugin.DeleteSecretRequest
8, // 11: secretsmanagerplugin.SecretsManager.ListSecrets:input_type -> secretsmanagerplugin.ListSecretsRequest
12, // 12: secretsmanagerplugin.SecretsManager.RenameSecret:input_type -> secretsmanagerplugin.RenameSecretRequest
10, // 13: secretsmanagerplugin.SecretsManager.GetAllSecrets:input_type -> secretsmanagerplugin.GetAllSecretsRequest
3, // 14: secretsmanagerplugin.SecretsManager.GetSecret:output_type -> secretsmanagerplugin.GetSecretResponse
5, // 15: secretsmanagerplugin.SecretsManager.SetSecret:output_type -> secretsmanagerplugin.SetSecretResponse
7, // 16: secretsmanagerplugin.SecretsManager.DeleteSecret:output_type -> secretsmanagerplugin.DeleteSecretResponse
9, // 17: secretsmanagerplugin.SecretsManager.ListSecrets:output_type -> secretsmanagerplugin.ListSecretsResponse
13, // 18: secretsmanagerplugin.SecretsManager.RenameSecret:output_type -> secretsmanagerplugin.RenameSecretResponse
11, // 19: secretsmanagerplugin.SecretsManager.GetAllSecrets:output_type -> secretsmanagerplugin.GetAllSecretsResponse
14, // [14:20] is the sub-list for method output_type
8, // [8:14] is the sub-list for method input_type
8, // [8:8] is the sub-list for extension type_name
8, // [8:8] is the sub-list for extension extendee
0, // [0:8] is the sub-list for field type_name
}
func init() { file_secretsmanager_proto_init() }
func file_secretsmanager_proto_init() {
if File_secretsmanager_proto != nil {
return
}
type x struct{}
out := protoimpl.TypeBuilder{
File: protoimpl.DescBuilder{
GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
RawDescriptor: unsafe.Slice(unsafe.StringData(file_secretsmanager_proto_rawDesc), len(file_secretsmanager_proto_rawDesc)),
NumEnums: 0,
NumMessages: 14,
NumExtensions: 0,
NumServices: 1,
},
GoTypes: file_secretsmanager_proto_goTypes,
DependencyIndexes: file_secretsmanager_proto_depIdxs,
MessageInfos: file_secretsmanager_proto_msgTypes,
}.Build()
File_secretsmanager_proto = out.File
file_secretsmanager_proto_goTypes = nil
file_secretsmanager_proto_depIdxs = nil
}

View File

@ -1,78 +0,0 @@
syntax = "proto3";
package secretsmanagerplugin;
option go_package = "./;secretsmanagerplugin";
message Key {
int64 orgId = 1;
string namespace = 2;
string type = 3;
}
message Item {
Key key = 1;
string value = 2;
}
message GetSecretRequest {
Key keyDescriptor = 1;
}
message GetSecretResponse {
string userFriendlyError = 1;
string decryptedValue = 2;
bool exists = 3;
}
message SetSecretRequest {
Key keyDescriptor = 1;
string value = 2;
}
message SetSecretResponse {
string userFriendlyError = 1;
}
message DeleteSecretRequest {
Key keyDescriptor = 1;
}
message DeleteSecretResponse {
string userFriendlyError = 1;
}
message ListSecretsRequest {
Key keyDescriptor = 1;
bool allOrganizations = 2;
}
message ListSecretsResponse {
string userFriendlyError = 1;
repeated Key keys = 2;
}
message GetAllSecretsRequest {
}
message GetAllSecretsResponse {
string userFriendlyError = 1;
repeated Item items = 2;
}
message RenameSecretRequest {
Key keyDescriptor = 1;
string newNamespace = 2;
}
message RenameSecretResponse {
string userFriendlyError = 1;
}
service SecretsManager {
rpc GetSecret(GetSecretRequest) returns (GetSecretResponse);
rpc SetSecret(SetSecretRequest) returns (SetSecretResponse);
rpc DeleteSecret(DeleteSecretRequest) returns (DeleteSecretResponse);
rpc ListSecrets(ListSecretsRequest) returns (ListSecretsResponse);
rpc RenameSecret(RenameSecretRequest) returns (RenameSecretResponse);
rpc GetAllSecrets(GetAllSecretsRequest) returns (GetAllSecretsResponse);
}

View File

@ -1,61 +0,0 @@
package secretsmanagerplugin
import (
"context"
"github.com/hashicorp/go-plugin"
"google.golang.org/grpc"
)
type SecretsManagerPlugin interface {
SecretsManagerClient
}
type SecretsManagerGRPCPlugin struct {
plugin.NetRPCUnsupportedPlugin
}
func (p *SecretsManagerGRPCPlugin) GRPCServer(broker *plugin.GRPCBroker, s *grpc.Server) error {
return nil
}
func (p *SecretsManagerGRPCPlugin) GRPCClient(ctx context.Context, broker *plugin.GRPCBroker, c *grpc.ClientConn) (any, error) {
return &SecretsManagerGRPCClient{NewSecretsManagerClient(c)}, nil
}
type SecretsManagerGRPCClient struct {
SecretsManagerClient
}
// Get an item from the store
func (sm *SecretsManagerGRPCClient) GetSecret(ctx context.Context, req *GetSecretRequest, opts ...grpc.CallOption) (*GetSecretResponse, error) {
return sm.SecretsManagerClient.GetSecret(ctx, req)
}
// Set an item in the store
func (sm *SecretsManagerGRPCClient) SetSecret(ctx context.Context, req *SetSecretRequest, opts ...grpc.CallOption) (*SetSecretResponse, error) {
return sm.SecretsManagerClient.SetSecret(ctx, req)
}
// Del deletes an item from the store.
func (sm *SecretsManagerGRPCClient) DeleteSecret(ctx context.Context, req *DeleteSecretRequest, opts ...grpc.CallOption) (*DeleteSecretResponse, error) {
return sm.SecretsManagerClient.DeleteSecret(ctx, req)
}
// Keys get all keys for a given namespace.
func (sm *SecretsManagerGRPCClient) ListSecrets(ctx context.Context, req *ListSecretsRequest, opts ...grpc.CallOption) (*ListSecretsResponse, error) {
return sm.SecretsManagerClient.ListSecrets(ctx, req)
}
// Rename an item in the store
func (sm *SecretsManagerGRPCClient) RenameSecret(ctx context.Context, req *RenameSecretRequest, opts ...grpc.CallOption) (*RenameSecretResponse, error) {
return sm.SecretsManagerClient.RenameSecret(ctx, req)
}
// Get all items from the store
func (sm *SecretsManagerGRPCClient) GetAllSecrets(ctx context.Context, req *GetAllSecretsRequest, opts ...grpc.CallOption) (*GetAllSecretsResponse, error) {
return sm.SecretsManagerClient.GetAllSecrets(ctx, req)
}
var _ SecretsManagerClient = &SecretsManagerGRPCClient{}
var _ plugin.GRPCPlugin = &SecretsManagerGRPCPlugin{}

View File

@ -1,300 +0,0 @@
// Code generated by protoc-gen-go-grpc. DO NOT EDIT.
// versions:
// - protoc-gen-go-grpc v1.4.0
// - protoc (unknown)
// source: secretsmanager.proto
package secretsmanagerplugin
import (
context "context"
grpc "google.golang.org/grpc"
codes "google.golang.org/grpc/codes"
status "google.golang.org/grpc/status"
)
// This is a compile-time assertion to ensure that this generated file
// is compatible with the grpc package it is being compiled against.
// Requires gRPC-Go v1.62.0 or later.
const _ = grpc.SupportPackageIsVersion8
const (
SecretsManager_GetSecret_FullMethodName = "/secretsmanagerplugin.SecretsManager/GetSecret"
SecretsManager_SetSecret_FullMethodName = "/secretsmanagerplugin.SecretsManager/SetSecret"
SecretsManager_DeleteSecret_FullMethodName = "/secretsmanagerplugin.SecretsManager/DeleteSecret"
SecretsManager_ListSecrets_FullMethodName = "/secretsmanagerplugin.SecretsManager/ListSecrets"
SecretsManager_RenameSecret_FullMethodName = "/secretsmanagerplugin.SecretsManager/RenameSecret"
SecretsManager_GetAllSecrets_FullMethodName = "/secretsmanagerplugin.SecretsManager/GetAllSecrets"
)
// SecretsManagerClient is the client API for SecretsManager service.
//
// For semantics around ctx use and closing/ending streaming RPCs, please refer to https://pkg.go.dev/google.golang.org/grpc/?tab=doc#ClientConn.NewStream.
type SecretsManagerClient interface {
GetSecret(ctx context.Context, in *GetSecretRequest, opts ...grpc.CallOption) (*GetSecretResponse, error)
SetSecret(ctx context.Context, in *SetSecretRequest, opts ...grpc.CallOption) (*SetSecretResponse, error)
DeleteSecret(ctx context.Context, in *DeleteSecretRequest, opts ...grpc.CallOption) (*DeleteSecretResponse, error)
ListSecrets(ctx context.Context, in *ListSecretsRequest, opts ...grpc.CallOption) (*ListSecretsResponse, error)
RenameSecret(ctx context.Context, in *RenameSecretRequest, opts ...grpc.CallOption) (*RenameSecretResponse, error)
GetAllSecrets(ctx context.Context, in *GetAllSecretsRequest, opts ...grpc.CallOption) (*GetAllSecretsResponse, error)
}
type secretsManagerClient struct {
cc grpc.ClientConnInterface
}
func NewSecretsManagerClient(cc grpc.ClientConnInterface) SecretsManagerClient {
return &secretsManagerClient{cc}
}
func (c *secretsManagerClient) GetSecret(ctx context.Context, in *GetSecretRequest, opts ...grpc.CallOption) (*GetSecretResponse, error) {
cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...)
out := new(GetSecretResponse)
err := c.cc.Invoke(ctx, SecretsManager_GetSecret_FullMethodName, in, out, cOpts...)
if err != nil {
return nil, err
}
return out, nil
}
func (c *secretsManagerClient) SetSecret(ctx context.Context, in *SetSecretRequest, opts ...grpc.CallOption) (*SetSecretResponse, error) {
cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...)
out := new(SetSecretResponse)
err := c.cc.Invoke(ctx, SecretsManager_SetSecret_FullMethodName, in, out, cOpts...)
if err != nil {
return nil, err
}
return out, nil
}
func (c *secretsManagerClient) DeleteSecret(ctx context.Context, in *DeleteSecretRequest, opts ...grpc.CallOption) (*DeleteSecretResponse, error) {
cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...)
out := new(DeleteSecretResponse)
err := c.cc.Invoke(ctx, SecretsManager_DeleteSecret_FullMethodName, in, out, cOpts...)
if err != nil {
return nil, err
}
return out, nil
}
func (c *secretsManagerClient) ListSecrets(ctx context.Context, in *ListSecretsRequest, opts ...grpc.CallOption) (*ListSecretsResponse, error) {
cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...)
out := new(ListSecretsResponse)
err := c.cc.Invoke(ctx, SecretsManager_ListSecrets_FullMethodName, in, out, cOpts...)
if err != nil {
return nil, err
}
return out, nil
}
func (c *secretsManagerClient) RenameSecret(ctx context.Context, in *RenameSecretRequest, opts ...grpc.CallOption) (*RenameSecretResponse, error) {
cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...)
out := new(RenameSecretResponse)
err := c.cc.Invoke(ctx, SecretsManager_RenameSecret_FullMethodName, in, out, cOpts...)
if err != nil {
return nil, err
}
return out, nil
}
func (c *secretsManagerClient) GetAllSecrets(ctx context.Context, in *GetAllSecretsRequest, opts ...grpc.CallOption) (*GetAllSecretsResponse, error) {
cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...)
out := new(GetAllSecretsResponse)
err := c.cc.Invoke(ctx, SecretsManager_GetAllSecrets_FullMethodName, in, out, cOpts...)
if err != nil {
return nil, err
}
return out, nil
}
// SecretsManagerServer is the server API for SecretsManager service.
// All implementations must embed UnimplementedSecretsManagerServer
// for forward compatibility
type SecretsManagerServer interface {
GetSecret(context.Context, *GetSecretRequest) (*GetSecretResponse, error)
SetSecret(context.Context, *SetSecretRequest) (*SetSecretResponse, error)
DeleteSecret(context.Context, *DeleteSecretRequest) (*DeleteSecretResponse, error)
ListSecrets(context.Context, *ListSecretsRequest) (*ListSecretsResponse, error)
RenameSecret(context.Context, *RenameSecretRequest) (*RenameSecretResponse, error)
GetAllSecrets(context.Context, *GetAllSecretsRequest) (*GetAllSecretsResponse, error)
mustEmbedUnimplementedSecretsManagerServer()
}
// UnimplementedSecretsManagerServer must be embedded to have forward compatible implementations.
type UnimplementedSecretsManagerServer struct {
}
func (UnimplementedSecretsManagerServer) GetSecret(context.Context, *GetSecretRequest) (*GetSecretResponse, error) {
return nil, status.Errorf(codes.Unimplemented, "method GetSecret not implemented")
}
func (UnimplementedSecretsManagerServer) SetSecret(context.Context, *SetSecretRequest) (*SetSecretResponse, error) {
return nil, status.Errorf(codes.Unimplemented, "method SetSecret not implemented")
}
func (UnimplementedSecretsManagerServer) DeleteSecret(context.Context, *DeleteSecretRequest) (*DeleteSecretResponse, error) {
return nil, status.Errorf(codes.Unimplemented, "method DeleteSecret not implemented")
}
func (UnimplementedSecretsManagerServer) ListSecrets(context.Context, *ListSecretsRequest) (*ListSecretsResponse, error) {
return nil, status.Errorf(codes.Unimplemented, "method ListSecrets not implemented")
}
func (UnimplementedSecretsManagerServer) RenameSecret(context.Context, *RenameSecretRequest) (*RenameSecretResponse, error) {
return nil, status.Errorf(codes.Unimplemented, "method RenameSecret not implemented")
}
func (UnimplementedSecretsManagerServer) GetAllSecrets(context.Context, *GetAllSecretsRequest) (*GetAllSecretsResponse, error) {
return nil, status.Errorf(codes.Unimplemented, "method GetAllSecrets not implemented")
}
func (UnimplementedSecretsManagerServer) mustEmbedUnimplementedSecretsManagerServer() {}
// UnsafeSecretsManagerServer may be embedded to opt out of forward compatibility for this service.
// Use of this interface is not recommended, as added methods to SecretsManagerServer will
// result in compilation errors.
type UnsafeSecretsManagerServer interface {
mustEmbedUnimplementedSecretsManagerServer()
}
func RegisterSecretsManagerServer(s grpc.ServiceRegistrar, srv SecretsManagerServer) {
s.RegisterService(&SecretsManager_ServiceDesc, srv)
}
func _SecretsManager_GetSecret_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
in := new(GetSecretRequest)
if err := dec(in); err != nil {
return nil, err
}
if interceptor == nil {
return srv.(SecretsManagerServer).GetSecret(ctx, in)
}
info := &grpc.UnaryServerInfo{
Server: srv,
FullMethod: SecretsManager_GetSecret_FullMethodName,
}
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
return srv.(SecretsManagerServer).GetSecret(ctx, req.(*GetSecretRequest))
}
return interceptor(ctx, in, info, handler)
}
func _SecretsManager_SetSecret_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
in := new(SetSecretRequest)
if err := dec(in); err != nil {
return nil, err
}
if interceptor == nil {
return srv.(SecretsManagerServer).SetSecret(ctx, in)
}
info := &grpc.UnaryServerInfo{
Server: srv,
FullMethod: SecretsManager_SetSecret_FullMethodName,
}
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
return srv.(SecretsManagerServer).SetSecret(ctx, req.(*SetSecretRequest))
}
return interceptor(ctx, in, info, handler)
}
func _SecretsManager_DeleteSecret_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
in := new(DeleteSecretRequest)
if err := dec(in); err != nil {
return nil, err
}
if interceptor == nil {
return srv.(SecretsManagerServer).DeleteSecret(ctx, in)
}
info := &grpc.UnaryServerInfo{
Server: srv,
FullMethod: SecretsManager_DeleteSecret_FullMethodName,
}
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
return srv.(SecretsManagerServer).DeleteSecret(ctx, req.(*DeleteSecretRequest))
}
return interceptor(ctx, in, info, handler)
}
func _SecretsManager_ListSecrets_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
in := new(ListSecretsRequest)
if err := dec(in); err != nil {
return nil, err
}
if interceptor == nil {
return srv.(SecretsManagerServer).ListSecrets(ctx, in)
}
info := &grpc.UnaryServerInfo{
Server: srv,
FullMethod: SecretsManager_ListSecrets_FullMethodName,
}
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
return srv.(SecretsManagerServer).ListSecrets(ctx, req.(*ListSecretsRequest))
}
return interceptor(ctx, in, info, handler)
}
func _SecretsManager_RenameSecret_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
in := new(RenameSecretRequest)
if err := dec(in); err != nil {
return nil, err
}
if interceptor == nil {
return srv.(SecretsManagerServer).RenameSecret(ctx, in)
}
info := &grpc.UnaryServerInfo{
Server: srv,
FullMethod: SecretsManager_RenameSecret_FullMethodName,
}
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
return srv.(SecretsManagerServer).RenameSecret(ctx, req.(*RenameSecretRequest))
}
return interceptor(ctx, in, info, handler)
}
func _SecretsManager_GetAllSecrets_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
in := new(GetAllSecretsRequest)
if err := dec(in); err != nil {
return nil, err
}
if interceptor == nil {
return srv.(SecretsManagerServer).GetAllSecrets(ctx, in)
}
info := &grpc.UnaryServerInfo{
Server: srv,
FullMethod: SecretsManager_GetAllSecrets_FullMethodName,
}
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
return srv.(SecretsManagerServer).GetAllSecrets(ctx, req.(*GetAllSecretsRequest))
}
return interceptor(ctx, in, info, handler)
}
// SecretsManager_ServiceDesc is the grpc.ServiceDesc for SecretsManager service.
// It's only intended for direct use with grpc.RegisterService,
// and not to be introspected or modified (even as a copy)
var SecretsManager_ServiceDesc = grpc.ServiceDesc{
ServiceName: "secretsmanagerplugin.SecretsManager",
HandlerType: (*SecretsManagerServer)(nil),
Methods: []grpc.MethodDesc{
{
MethodName: "GetSecret",
Handler: _SecretsManager_GetSecret_Handler,
},
{
MethodName: "SetSecret",
Handler: _SecretsManager_SetSecret_Handler,
},
{
MethodName: "DeleteSecret",
Handler: _SecretsManager_DeleteSecret_Handler,
},
{
MethodName: "ListSecrets",
Handler: _SecretsManager_ListSecrets_Handler,
},
{
MethodName: "RenameSecret",
Handler: _SecretsManager_RenameSecret_Handler,
},
{
MethodName: "GetAllSecrets",
Handler: _SecretsManager_GetAllSecrets_Handler,
},
},
Streams: []grpc.StreamDesc{},
Metadata: "secretsmanager.proto",
}

View File

@ -98,11 +98,6 @@ type BackendFactoryProvider interface {
BackendFactory(ctx context.Context, p *Plugin) backendplugin.PluginFactoryFunc
}
type SecretsPluginManager interface {
// SecretsManager returns a secretsmanager plugin
SecretsManager(ctx context.Context) *Plugin
}
type StaticRouteResolver interface {
Routes(ctx context.Context) []*StaticRoute
}

View File

@ -64,30 +64,6 @@ func TestInitializer_Initialize(t *testing.T) {
require.NotNil(t, c)
})
t.Run("secretsmanager", func(t *testing.T) {
p := &plugins.Plugin{
JSONData: plugins.JSONData{
ID: "test",
Type: plugins.TypeSecretsManager,
Dependencies: plugins.Dependencies{
GrafanaVersion: ">=8.x",
},
Backend: true,
},
Class: plugins.ClassExternal,
}
stepFunc := BackendClientInitStep(&fakeEnvVarsProvider{}, &fakeBackendProvider{plugin: p}, fakes.InitializeNoopTracerForTest())
var err error
p, err = stepFunc(context.Background(), p)
require.NoError(t, err)
c, exists := p.Client()
require.True(t, exists)
require.NotNil(t, c)
})
t.Run("non backend plugin app", func(t *testing.T) {
p := &plugins.Plugin{
JSONData: plugins.JSONData{

View File

@ -17,7 +17,6 @@ import (
"github.com/grafana/grafana/pkg/plugins/auth"
"github.com/grafana/grafana/pkg/plugins/backendplugin"
"github.com/grafana/grafana/pkg/plugins/backendplugin/pluginextensionv2"
"github.com/grafana/grafana/pkg/plugins/backendplugin/secretsmanagerplugin"
"github.com/grafana/grafana/pkg/plugins/log"
"github.com/grafana/grafana/pkg/services/org"
"github.com/grafana/grafana/pkg/util"
@ -58,10 +57,9 @@ type Plugin struct {
ExternalService *auth.ExternalService
Renderer pluginextensionv2.RendererPlugin
SecretsManager secretsmanagerplugin.SecretsManagerPlugin
client backendplugin.Plugin
log log.Logger
Renderer pluginextensionv2.RendererPlugin
client backendplugin.Plugin
log log.Logger
SkipHostEnvVars bool
@ -126,7 +124,7 @@ type JSONData struct {
SDK bool `json:"sdk,omitempty"`
MultiValueFilterOperators bool `json:"multiValueFilterOperators,omitempty"`
// Backend (Datasource + Renderer + SecretsManager)
// Backend (Datasource + Renderer)
Executable string `json:"executable,omitempty"`
// App Service Auth Registration
@ -442,10 +440,6 @@ func (p *Plugin) ExecutablePath() string {
return p.executablePath("plugin_start")
}
if p.IsSecretsManager() {
return p.executablePath("secrets_plugin_start")
}
return p.executablePath(p.Executable)
}
@ -486,10 +480,6 @@ func (p *Plugin) IsRenderer() bool {
return p.Type == TypeRenderer
}
func (p *Plugin) IsSecretsManager() bool {
return p.Type == TypeSecretsManager
}
func (p *Plugin) IsApp() bool {
return p.Type == TypeApp
}
@ -519,22 +509,20 @@ var PluginTypes = []Type{
TypePanel,
TypeApp,
TypeRenderer,
TypeSecretsManager,
}
type Type string
const (
TypeDataSource Type = "datasource"
TypePanel Type = "panel"
TypeApp Type = "app"
TypeRenderer Type = "renderer"
TypeSecretsManager Type = "secretsmanager"
TypeDataSource Type = "datasource"
TypePanel Type = "panel"
TypeApp Type = "app"
TypeRenderer Type = "renderer"
)
func (pt Type) IsValid() bool {
switch pt {
case TypeDataSource, TypePanel, TypeApp, TypeRenderer, TypeSecretsManager:
case TypeDataSource, TypePanel, TypeApp, TypeRenderer:
return true
}
return false

View File

@ -4,25 +4,6 @@ package semconv
import "go.opentelemetry.io/otel/attribute"
// Describes Grafana service attributes.
const (
// GrafanaServiceNameKey is the attribute Key conforming to the
// "grafana.service.name" semantic conventions. It represents the service
// name.
//
// Type: string
// RequirementLevel: Optional
// Stability: stable
// Examples: 'grafana-apiserver'
grafanaServiceNameKey = attribute.Key("grafana.service.name")
)
// GrafanaServiceName returns an attribute KeyValue conforming to the
// "grafana.service.name" semantic conventions. It represents the service name.
func GrafanaServiceName(val string) attribute.KeyValue {
return grafanaServiceNameKey.String(val)
}
// Describes Grafana datasource attributes.
const (
// GrafanaDatasourceTypeKey is the attribute Key conforming to the
@ -131,8 +112,6 @@ var (
GrafanaPluginTypeApp = grafanaPluginTypeKey.String("app")
// Renderer Plugin
GrafanaPluginTypeRenderer = grafanaPluginTypeKey.String("renderer")
// Secret Manager Plugin
GrafanaPluginTypeSecretmanager = grafanaPluginTypeKey.String("secretmanager")
)
// GrafanaPluginId returns an attribute KeyValue conforming to the
@ -140,3 +119,22 @@ var (
func GrafanaPluginId(val string) attribute.KeyValue {
return grafanaPluginIdKey.String(val)
}
// Describes Grafana service attributes.
const (
// GrafanaServiceNameKey is the attribute Key conforming to the
// "grafana.service.name" semantic conventions. It represents the service
// name.
//
// Type: string
// RequirementLevel: Optional
// Stability: stable
// Examples: 'grafana-apiserver'
grafanaServiceNameKey = attribute.Key("grafana.service.name")
)
// GrafanaServiceName returns an attribute KeyValue conforming to the
// "grafana.service.name" semantic conventions. It represents the service name.
func GrafanaServiceName(val string) attribute.KeyValue {
return grafanaServiceNameKey.String(val)
}

View File

@ -31,10 +31,6 @@ groups:
value: "renderer"
brief: 'Renderer Plugin'
stability: stable
- id: secretmanager
value: "secretmanager"
brief: 'Secret Manager Plugin'
stability: stable
brief: The plugin type.
examples: datasource
stability: stable

View File

@ -363,8 +363,6 @@ var wireBasicSet = wire.NewSet(
loginattemptimpl.ProvideService,
wire.Bind(new(loginattempt.Service), new(*loginattemptimpl.Service)),
secretsMigrations.ProvideDataSourceMigrationService,
secretsMigrations.ProvideMigrateToPluginService,
secretsMigrations.ProvideMigrateFromPluginService,
secretsMigrations.ProvideSecretMigrationProvider,
wire.Bind(new(secretsMigrations.SecretMigrationProvider), new(*secretsMigrations.SecretMigrationProviderImpl)),
resourcepermissions.NewActionSetService,

View File

@ -122,11 +122,7 @@ func (s *FakeDataSourceService) GetHTTPTransport(ctx context.Context, ds *dataso
}
func (s *FakeDataSourceService) DecryptedValues(ctx context.Context, ds *datasources.DataSource) (map[string]string, error) {
if s.SimulatePluginFailure {
return nil, datasources.ErrDatasourceSecretsPluginUserFriendly{Err: "unknown error"}
}
values := make(map[string]string)
return values, nil
return make(map[string]string), nil
}
func (s *FakeDataSourceService) DecryptedValue(ctx context.Context, ds *datasources.DataSource, key string) (string, bool, error) {

View File

@ -145,15 +145,6 @@ func (ds DataSource) AllowedCookies() []string {
return []string{}
}
// Specific error type for grpc secrets management so that we can show more detailed plugin errors to users
type ErrDatasourceSecretsPluginUserFriendly struct {
Err string
}
func (e ErrDatasourceSecretsPluginUserFriendly) Error() string {
return e.Err
}
// ----------------------
// COMMANDS

View File

@ -27,7 +27,7 @@ func ProvideDiscoveryStage(cfg *config.PluginManagementCfg, pf finder.Finder, pr
FindFunc: pf.Find,
FindFilterFuncs: []discovery.FindFilterFunc{
discovery.NewPermittedPluginTypesFilterStep([]plugins.Type{
plugins.TypeDataSource, plugins.TypeApp, plugins.TypePanel, plugins.TypeSecretsManager,
plugins.TypeDataSource, plugins.TypeApp, plugins.TypePanel,
}),
func(ctx context.Context, _ plugins.Class, b []*plugins.FoundBundle) ([]*plugins.FoundBundle, error) {
return NewDuplicatePluginIDFilterStep(pr).Filter(ctx, b)

View File

@ -70,7 +70,6 @@ var WireSet = wire.NewSet(
wire.Bind(new(pluginconfig.PluginRequestConfigProvider), new(*pluginconfig.RequestConfigProvider)),
pluginstore.ProvideService,
wire.Bind(new(pluginstore.Store), new(*pluginstore.Service)),
wire.Bind(new(plugins.SecretsPluginManager), new(*pluginstore.Service)),
wire.Bind(new(plugins.StaticRouteResolver), new(*pluginstore.Service)),
process.ProvideService,
wire.Bind(new(process.Manager), new(*process.Service)),

View File

@ -94,15 +94,6 @@ func (s *Service) Plugins(ctx context.Context, pluginTypes ...plugins.Type) []Pl
return pluginsList
}
func (s *Service) SecretsManager(ctx context.Context) *plugins.Plugin {
for _, p := range s.availablePlugins(ctx) {
if p.IsSecretsManager() {
return p
}
}
return nil
}
// plugin finds a plugin with `pluginID` from the registry that is not decommissioned
func (s *Service) plugin(ctx context.Context, pluginID string) (*plugins.Plugin, bool) {
p, exists := s.pluginRegistry.Plugin(ctx, pluginID, "") // version is not required since Grafana only supports single versions of a plugin

View File

@ -120,7 +120,6 @@ func TestStore_Routes(t *testing.T) {
t.Run("Routes returns all static routes for non-decommissioned plugins", func(t *testing.T) {
p1 := &plugins.Plugin{JSONData: plugins.JSONData{ID: "a-test-renderer", Type: plugins.TypeRenderer}, FS: fakes.NewFakePluginFS("/some/dir")}
p2 := &plugins.Plugin{JSONData: plugins.JSONData{ID: "b-test-panel", Type: plugins.TypePanel}, FS: fakes.NewFakePluginFS("/grafana/")}
p3 := &plugins.Plugin{JSONData: plugins.JSONData{ID: "c-test-secrets", Type: plugins.TypeSecretsManager}, FS: fakes.NewFakePluginFS("./secrets"), Class: plugins.ClassCore}
p4 := &plugins.Plugin{JSONData: plugins.JSONData{ID: "d-test-datasource", Type: plugins.TypeDataSource}, FS: fakes.NewFakePluginFS("../test")}
p5 := &plugins.Plugin{JSONData: plugins.JSONData{ID: "e-test-app", Type: plugins.TypeApp}, FS: fakes.NewFakePluginFS("any/path")}
p6 := &plugins.Plugin{JSONData: plugins.JSONData{ID: "f-test-app", Type: plugins.TypeApp}}
@ -130,7 +129,6 @@ func TestStore_Routes(t *testing.T) {
Store: map[string]*plugins.Plugin{
p1.ID: p1,
p2.ID: p2,
p3.ID: p3,
p4.ID: p4,
p5.ID: p5,
p6.ID: p6,
@ -146,27 +144,6 @@ func TestStore_Routes(t *testing.T) {
})
}
func TestStore_SecretsManager(t *testing.T) {
t.Run("Renderer returns a single (non-decommissioned) secrets manager plugin", func(t *testing.T) {
p1 := &plugins.Plugin{JSONData: plugins.JSONData{ID: "test-renderer", Type: plugins.TypeRenderer}}
p2 := &plugins.Plugin{JSONData: plugins.JSONData{ID: "test-panel", Type: plugins.TypePanel}}
p3 := &plugins.Plugin{JSONData: plugins.JSONData{ID: "test-secrets", Type: plugins.TypeSecretsManager}}
p4 := &plugins.Plugin{JSONData: plugins.JSONData{ID: "test-datasource", Type: plugins.TypeDataSource}}
ps := New(&fakes.FakePluginRegistry{
Store: map[string]*plugins.Plugin{
p1.ID: p1,
p2.ID: p2,
p3.ID: p3,
p4.ID: p4,
},
}, &fakes.FakeLoader{})
r := ps.SecretsManager(context.Background())
require.Equal(t, p3, r)
})
}
func TestProcessManager_shutdown(t *testing.T) {
p := &plugins.Plugin{JSONData: plugins.JSONData{ID: "test-datasource", Type: plugins.TypeDataSource}} // Backend: true
backend := &fakes.FakeBackendPlugin{}

View File

@ -39,7 +39,7 @@ func TestRenderer(t *testing.T) {
r, exists := m.Renderer(context.Background())
require.False(t, exists)
require.Equal(t, 4, numLoaded)
require.Equal(t, 3, numLoaded)
require.Equal(t, 0, numUnloaded)
require.Nil(t, r)
})

View File

@ -1,3 +0,0 @@
{
"type": "secretsmanager"
}

View File

@ -5,13 +5,8 @@ import (
"time"
"github.com/grafana/grafana/pkg/infra/db"
"github.com/grafana/grafana/pkg/infra/kvstore"
"github.com/grafana/grafana/pkg/infra/log"
"github.com/grafana/grafana/pkg/plugins"
"github.com/grafana/grafana/pkg/plugins/backendplugin/secretsmanagerplugin"
"github.com/grafana/grafana/pkg/services/featuremgmt"
"github.com/grafana/grafana/pkg/services/secrets"
"github.com/grafana/grafana/pkg/setting"
)
const (
@ -22,45 +17,8 @@ const (
func ProvideService(
sqlStore db.DB,
secretsService secrets.Service,
pluginsManager plugins.SecretsPluginManager,
kvstore kvstore.KVStore,
features featuremgmt.FeatureToggles,
cfg *setting.Cfg,
) (SecretsKVStore, error) {
var logger = log.New("secrets.kvstore")
var store SecretsKVStore
ctx := context.Background()
store = NewSQLSecretsKVStore(sqlStore, secretsService, logger)
err := EvaluateRemoteSecretsPlugin(ctx, pluginsManager, cfg)
if err != nil {
logger.Debug("secrets manager evaluator returned false", "reason", err.Error())
} else {
// Attempt to start the plugin
var secretsPlugin secretsmanagerplugin.SecretsManagerPlugin
secretsPlugin, err = StartAndReturnPlugin(pluginsManager, ctx)
namespacedKVStore := GetNamespacedKVStore(kvstore)
if err != nil || secretsPlugin == nil {
logger.Error("failed to start remote secrets management plugin")
if isFatal, readErr := IsPluginStartupErrorFatal(ctx, namespacedKVStore); isFatal || readErr != nil {
// plugin error was fatal or there was an error determining if the error was fatal
logger.Error("secrets management plugin is required to start -- exiting app")
if readErr != nil {
return nil, readErr
}
return nil, err
}
} else {
// as the plugin is installed, SecretsKVStoreSQL is now replaced with
// an instance of SecretsKVStorePlugin with the sql store as a fallback
// (used for migration and in case a secret is not found).
store = NewPluginSecretsKVStore(secretsPlugin, secretsService, namespacedKVStore, features, WithCache(store, 5*time.Second, 5*time.Minute), logger)
}
}
if err != nil {
logger.Debug("secrets kvstore is using the default (SQL) implementation for secrets management")
}
store := NewSQLSecretsKVStore(sqlStore, secretsService, log.New("secrets.kvstore"))
return WithCache(store, 5*time.Second, 5*time.Minute), nil
}

View File

@ -1,108 +0,0 @@
package migrations
import (
"context"
"errors"
"fmt"
"github.com/grafana/grafana/pkg/infra/db"
"github.com/grafana/grafana/pkg/infra/kvstore"
"github.com/grafana/grafana/pkg/plugins"
"github.com/grafana/grafana/pkg/plugins/backendplugin/secretsmanagerplugin"
"github.com/grafana/grafana/pkg/services/secrets"
secretskvs "github.com/grafana/grafana/pkg/services/secrets/kvstore"
"github.com/grafana/grafana/pkg/setting"
)
var errPluginUnavailable = errors.New("remote secret management plugin is unavailable")
// MigrateFromPluginService This migrator will handle migration of the configured plugin secrets back to Grafana unified secrets
type MigrateFromPluginService struct {
cfg *setting.Cfg
sqlStore db.DB
secretsService secrets.Service
manager plugins.SecretsPluginManager
kvstore kvstore.KVStore
}
func ProvideMigrateFromPluginService(
cfg *setting.Cfg,
sqlStore db.DB,
secretsService secrets.Service,
manager plugins.SecretsPluginManager,
kvstore kvstore.KVStore,
) *MigrateFromPluginService {
return &MigrateFromPluginService{
cfg: cfg,
sqlStore: sqlStore,
secretsService: secretsService,
manager: manager,
kvstore: kvstore,
}
}
func (s *MigrateFromPluginService) Migrate(ctx context.Context) error {
logger.Debug("starting migration of plugin secrets to unified secrets")
// access the plugin directly
plugin, err := secretskvs.StartAndReturnPlugin(s.manager, context.Background())
if err != nil {
return errPluginUnavailable
}
// Get full list of secrets from the plugin
res, err := plugin.GetAllSecrets(ctx, &secretsmanagerplugin.GetAllSecretsRequest{})
if err != nil {
logger.Error("Failed to retrieve all secrets from plugin")
return err
}
totalSecrets := len(res.Items)
logger.Debug("retrieved all secrets from plugin", "num secrets", totalSecrets)
// create a secret sql store manually
secretsSql := secretskvs.NewSQLSecretsKVStore(s.sqlStore, s.secretsService, logger)
for i, item := range res.Items {
logger.Debug(fmt.Sprintf("Migrating secret %d of %d", i+1, totalSecrets), "current", i+1, "secretCount", totalSecrets)
// Add to sql store
err = secretsSql.Set(ctx, item.Key.OrgId, item.Key.Namespace, item.Key.Type, item.Value)
if err != nil {
logger.Error("Error adding secret to unified secrets", "orgId", item.Key.OrgId,
"namespace", item.Key.Namespace, "type", item.Key.Type)
return err
}
}
for i, item := range res.Items {
logger.Debug(fmt.Sprintf("Cleaning secret %d of %d", i+1, totalSecrets), "current", i+1, "secretCount", totalSecrets)
// Delete from the plugin
_, err := plugin.DeleteSecret(ctx, &secretsmanagerplugin.DeleteSecretRequest{
KeyDescriptor: &secretsmanagerplugin.Key{
OrgId: item.Key.OrgId,
Namespace: item.Key.Namespace,
Type: item.Key.Type,
}})
if err != nil {
logger.Error("Error deleting secret from plugin after migration", "orgId", item.Key.OrgId,
"namespace", item.Key.Namespace, "type", item.Key.Type)
continue
}
}
logger.Debug("Completed migration of secrets from plugin")
// The plugin is no longer needed at the moment
err = secretskvs.SetPluginStartupErrorFatal(ctx, secretskvs.GetNamespacedKVStore(s.kvstore), false)
if err != nil {
logger.Error("Failed to remove plugin error fatal flag", "error", err.Error())
}
// Reset the fatal flag setter in case another secret is created on the plugin
secretskvs.ResetPlugin()
logger.Debug("Shutting down secrets plugin now that migration is complete")
// if `use_plugin` wasn't set, stop the plugin after migration
if !s.cfg.SectionWithEnvOverrides("secrets").Key("use_plugin").MustBool(false) {
err := s.manager.SecretsManager(ctx).Stop(ctx)
if err != nil {
// Log a warning but don't throw an error
logger.Error("Error stopping secrets plugin after migration", "error", err.Error())
}
}
return nil
}

View File

@ -1,92 +0,0 @@
package migrations
import (
"context"
"testing"
"github.com/stretchr/testify/require"
"github.com/grafana/grafana/pkg/infra/db"
"github.com/grafana/grafana/pkg/infra/kvstore"
"github.com/grafana/grafana/pkg/infra/log"
"github.com/grafana/grafana/pkg/plugins/backendplugin/secretsmanagerplugin"
"github.com/grafana/grafana/pkg/services/secrets/fakes"
secretskvs "github.com/grafana/grafana/pkg/services/secrets/kvstore"
secretsManager "github.com/grafana/grafana/pkg/services/secrets/manager"
"github.com/grafana/grafana/pkg/setting"
)
// This tests will create a mock sql database and an inmemory
// implementation of the secret manager to simulate the plugin.
func TestPluginSecretMigrationService_MigrateFromPlugin(t *testing.T) {
ctx := context.Background()
t.Run("migrate secrets from secrets plugin to Grafana", func(t *testing.T) {
// --- SETUP
migratorService, plugin, sqlStore := setupTestMigrateFromPluginService(t)
addSecretToPluginStore(t, plugin, ctx, 1, "secret-1", "bogus", "value-1")
addSecretToPluginStore(t, plugin, ctx, 1, "secret-2", "bogus", "value-2")
// --- EXECUTION
err := migratorService.Migrate(ctx)
require.NoError(t, err)
// --- VALIDATIONS
validatePluginSecretsWereDeleted(t, plugin, ctx)
validateSecretWasStoredInSql(t, sqlStore, ctx, 1, "secret-1", "bogus", "value-1")
validateSecretWasStoredInSql(t, sqlStore, ctx, 1, "secret-2", "bogus", "value-2")
})
}
// Set up services used in migration
func setupTestMigrateFromPluginService(t *testing.T) (*MigrateFromPluginService, secretsmanagerplugin.SecretsManagerPlugin, *secretskvs.SecretsKVStoreSQL) {
t.Helper()
// this is to init the sql secret store inside the migration
sqlStore := db.InitTestDB(t)
secretsService := secretsManager.SetupTestService(t, fakes.NewFakeSecretsStore())
manager := secretskvs.NewFakeSecretsPluginManager(t, false)
migratorService := ProvideMigrateFromPluginService(
setting.NewCfg(),
sqlStore,
secretsService,
manager,
kvstore.ProvideService(sqlStore),
)
secretsSql := secretskvs.NewSQLSecretsKVStore(sqlStore, secretsService, log.New("test.logger"))
return migratorService, manager.SecretsManager(context.Background()).SecretsManager, secretsSql
}
func addSecretToPluginStore(t *testing.T, plugin secretsmanagerplugin.SecretsManagerPlugin, ctx context.Context, orgId int64, namespace string, typ string, value string) {
t.Helper()
_, err := plugin.SetSecret(ctx, &secretsmanagerplugin.SetSecretRequest{
KeyDescriptor: &secretsmanagerplugin.Key{
OrgId: orgId,
Namespace: namespace,
Type: typ,
},
Value: value,
})
require.NoError(t, err)
}
// validates that secrets on the plugin were deleted
func validatePluginSecretsWereDeleted(t *testing.T, plugin secretsmanagerplugin.SecretsManagerPlugin, ctx context.Context) {
t.Helper()
res, err := plugin.GetAllSecrets(ctx, &secretsmanagerplugin.GetAllSecretsRequest{})
require.NoError(t, err)
require.Equal(t, 0, len(res.Items))
}
// validates that secrets are in sql
func validateSecretWasStoredInSql(t *testing.T, sqlStore *secretskvs.SecretsKVStoreSQL, ctx context.Context, orgId int64, namespace string, typ string, expectedValue string) {
t.Helper()
res, exists, err := sqlStore.Get(ctx, orgId, namespace, typ)
require.NoError(t, err)
require.True(t, exists)
require.Equal(t, expectedValue, res)
}

View File

@ -8,7 +8,6 @@ import (
"github.com/grafana/grafana/pkg/infra/log"
"github.com/grafana/grafana/pkg/infra/serverlock"
"github.com/grafana/grafana/pkg/registry"
"github.com/grafana/grafana/pkg/setting"
)
var logger = log.New("secret.migration")
@ -22,40 +21,20 @@ type SecretMigrationService interface {
type SecretMigrationProvider interface {
registry.BackgroundService
TriggerPluginMigration(ctx context.Context, toPlugin bool) error
}
type SecretMigrationProviderImpl struct {
services []SecretMigrationService
ServerLockService *serverlock.ServerLockService
migrateToPluginService *MigrateToPluginService
migrateFromPluginService *MigrateFromPluginService
services []SecretMigrationService
ServerLockService *serverlock.ServerLockService
}
func ProvideSecretMigrationProvider(
cfg *setting.Cfg,
serverLockService *serverlock.ServerLockService,
dataSourceSecretMigrationService *DataSourceSecretMigrationService,
migrateToPluginService *MigrateToPluginService,
migrateFromPluginService *MigrateFromPluginService,
) *SecretMigrationProviderImpl {
services := make([]SecretMigrationService, 0)
services = append(services, dataSourceSecretMigrationService)
// Plugin migration should always be last; should either migrate to or from, not both
// This is because the migrateTo checks for use_plugin = true, in which case we should always
// migrate by default to ensure users don't lose access to secrets. If migration has
// already occurred, the migrateTo function will be called but it won't do anything
if cfg.SectionWithEnvOverrides("secrets").Key("migrate_from_plugin").MustBool(false) {
services = append(services, migrateFromPluginService)
} else {
services = append(services, migrateToPluginService)
}
return &SecretMigrationProviderImpl{
ServerLockService: serverLockService,
services: services,
migrateToPluginService: migrateToPluginService,
migrateFromPluginService: migrateFromPluginService,
ServerLockService: serverLockService,
services: []SecretMigrationService{dataSourceSecretMigrationService},
}
}
@ -83,23 +62,3 @@ func (s *SecretMigrationProviderImpl) Migrate(ctx context.Context) error {
}
return nil
}
// TriggerPluginMigration Kick off a migration to or from the plugin. This will block until all services have exited.
func (s *SecretMigrationProviderImpl) TriggerPluginMigration(ctx context.Context, toPlugin bool) error {
// Don't migrate if there is already one happening
return s.ServerLockService.LockExecuteAndRelease(ctx, actionName, time.Minute*10, func(context.Context) {
var err error
if toPlugin {
err = s.migrateToPluginService.Migrate(ctx)
} else {
err = s.migrateFromPluginService.Migrate(ctx)
}
if err != nil {
direction := "from_plugin"
if toPlugin {
direction = "to_plugin"
}
logger.Error("Failed to migrate plugin secrets", "direction", direction, "error", err.Error())
}
})
}

View File

@ -1,120 +0,0 @@
package migrations
import (
"context"
"errors"
"fmt"
"github.com/grafana/grafana/pkg/infra/db"
"github.com/grafana/grafana/pkg/infra/kvstore"
"github.com/grafana/grafana/pkg/plugins"
"github.com/grafana/grafana/pkg/services/secrets"
secretskvs "github.com/grafana/grafana/pkg/services/secrets/kvstore"
"github.com/grafana/grafana/pkg/setting"
)
var errSecretStoreIsNotPlugin = errors.New("SecretsKVStore is not a SecretsKVStorePlugin")
// MigrateToPluginService This migrator will handle migration of datasource secrets (aka Unified secrets)
// into the plugin secrets configured
type MigrateToPluginService struct {
secretsStore secretskvs.SecretsKVStore
cfg *setting.Cfg
sqlStore db.DB
secretsService secrets.Service
kvstore kvstore.KVStore
manager plugins.SecretsPluginManager
}
func ProvideMigrateToPluginService(
secretsStore secretskvs.SecretsKVStore,
cfg *setting.Cfg,
sqlStore db.DB,
secretsService secrets.Service,
kvstore kvstore.KVStore,
manager plugins.SecretsPluginManager,
) *MigrateToPluginService {
return &MigrateToPluginService{
secretsStore: secretsStore,
cfg: cfg,
sqlStore: sqlStore,
secretsService: secretsService,
kvstore: kvstore,
manager: manager,
}
}
func (s *MigrateToPluginService) Migrate(ctx context.Context) error {
err := secretskvs.EvaluateRemoteSecretsPlugin(ctx, s.manager, s.cfg)
hasStarted := secretskvs.HasPluginStarted(ctx, s.manager)
if err == nil && hasStarted {
logger.Debug("starting migration of unified secrets to the plugin")
// we need to get the fallback store since in this scenario the secrets store would be the plugin.
tmpStore, err := secretskvs.GetUnwrappedStoreFromCache(s.secretsStore)
if err != nil {
tmpStore = s.secretsStore
logger.Warn("secret store is not cached, this is unexpected - continuing migration anyway.")
}
pluginStore, ok := tmpStore.(*secretskvs.SecretsKVStorePlugin)
if !ok {
return errSecretStoreIsNotPlugin
}
fallbackStore := pluginStore.Fallback()
// before we start migrating, check see if plugin startup failures were already fatal
namespacedKVStore := secretskvs.GetNamespacedKVStore(s.kvstore)
wasFatal, err := secretskvs.IsPluginStartupErrorFatal(ctx, namespacedKVStore)
if err != nil {
logger.Warn("unable to determine whether plugin startup failures are fatal - continuing migration anyway.")
}
var allSec []secretskvs.Item
var totalSec int
// during migration we need to have fallback enabled while we move secrets to plugin
err = pluginStore.WithFallbackEnabled(func() error {
// get all secrets in the fallback store
allSec, err = fallbackStore.GetAll(ctx)
if err != nil {
return nil
}
totalSec := len(allSec)
logger.Debug(fmt.Sprintf("Total amount of secrets to migrate: %d", totalSec))
// We just set it again as the current secret store should be the plugin secret
for i, sec := range allSec {
logger.Debug(fmt.Sprintf("Migrating secret %d of %d", i+1, totalSec), "current", i+1, "secretCount", totalSec)
err = pluginStore.Set(ctx, *sec.OrgId, *sec.Namespace, *sec.Type, sec.Value)
if err != nil {
return err
}
}
return nil
})
if err != nil {
return err
}
// as no err was returned, when we delete all the secrets from the sql store
logger.Debug("migrated unified secrets to plugin", "number of secrets", totalSec)
for index, sec := range allSec {
logger.Debug(fmt.Sprintf("Cleaning secret %d of %d", index+1, totalSec), "current", index+1, "secretCount", totalSec)
err = fallbackStore.Del(ctx, *sec.OrgId, *sec.Namespace, *sec.Type)
if err != nil {
logger.Error("plugin migrator encountered error while deleting unified secrets")
if index == 0 && !wasFatal {
// old unified secrets still exists, so plugin startup errors are still not fatal, unless they were before we started
err := secretskvs.SetPluginStartupErrorFatal(ctx, namespacedKVStore, false)
if err != nil {
logger.Error("error reverting plugin failure fatal status", "error", err.Error())
} else {
logger.Debug("application will continue to function without the secrets plugin")
}
}
return err
}
}
logger.Debug("deleted unified secrets after migration", "number of secrets", totalSec)
}
return nil
}

View File

@ -1,152 +0,0 @@
package migrations
import (
"context"
"errors"
"testing"
"time"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
"gopkg.in/ini.v1"
"github.com/grafana/grafana/pkg/infra/db"
"github.com/grafana/grafana/pkg/infra/db/dbtest"
"github.com/grafana/grafana/pkg/infra/kvstore"
"github.com/grafana/grafana/pkg/services/featuremgmt"
"github.com/grafana/grafana/pkg/services/secrets/fakes"
secretskvs "github.com/grafana/grafana/pkg/services/secrets/kvstore"
secretsManager "github.com/grafana/grafana/pkg/services/secrets/manager"
"github.com/grafana/grafana/pkg/setting"
)
// This tests will create a mock sql database and an inmemory
// implementation of the secret manager to simulate the plugin.
func TestPluginSecretMigrationService_MigrateToPlugin(t *testing.T) {
ctx := context.Background()
t.Run("migration run ok - 2 secrets migrated", func(t *testing.T) {
// --- SETUP
migratorService, secretsStore, sqlSecretStore := setupTestMigrateToPluginService(t)
var orgId int64 = 1
namespace1, namespace2 := "namespace-test", "namespace-test2"
typ := "type-test"
value := "SUPER_SECRET"
addSecretToSqlStore(t, sqlSecretStore, ctx, orgId, namespace1, typ, value)
addSecretToSqlStore(t, sqlSecretStore, ctx, orgId, namespace2, typ, value)
// --- EXECUTION
err := migratorService.Migrate(ctx)
require.NoError(t, err)
// --- VALIDATIONS
validateSqlSecretWasDeleted(t, sqlSecretStore, ctx, orgId, namespace1, typ)
validateSqlSecretWasDeleted(t, sqlSecretStore, ctx, orgId, namespace2, typ)
validateSecretWasStoredInPlugin(t, secretsStore, ctx, orgId, namespace1, typ)
validateSecretWasStoredInPlugin(t, secretsStore, ctx, orgId, namespace1, typ)
})
}
// With fatal flag unset, do a migration with backwards compatibility disabled. When unified secrets are deleted, return an error on the first deletion
// Should result in the fatal flag remaining unset
func TestFatalPluginErr_MigrationTestWithErrorDeletingUnifiedSecrets(t *testing.T) {
p, err := secretskvs.SetupFatalCrashTest(t, false, false, true)
assert.NoError(t, err)
migration := setupTestMigratorServiceWithDeletionError(t, p.SecretsKVStore, &dbtest.FakeDB{
ExpectedError: errors.New("random error"),
}, p.KVStore)
err = migration.Migrate(context.Background())
assert.Error(t, err)
assert.Equal(t, "mocked del error", err.Error())
isFatal, err := secretskvs.IsPluginStartupErrorFatal(context.Background(), secretskvs.GetNamespacedKVStore(p.KVStore))
assert.NoError(t, err)
assert.False(t, isFatal)
}
func addSecretToSqlStore(t *testing.T, sqlSecretStore secretskvs.SecretsKVStore, ctx context.Context, orgId int64, namespace1 string, typ string, value string) {
t.Helper()
err := sqlSecretStore.Set(ctx, orgId, namespace1, typ, value)
require.NoError(t, err)
}
// validates that secrets on the sql store were deleted.
func validateSqlSecretWasDeleted(t *testing.T, sqlSecretStore secretskvs.SecretsKVStore, ctx context.Context, orgId int64, namespace1 string, typ string) {
t.Helper()
res, err := sqlSecretStore.Keys(ctx, orgId, namespace1, typ)
require.NoError(t, err)
require.Equal(t, 0, len(res))
}
// validates that secrets should be on the plugin
func validateSecretWasStoredInPlugin(t *testing.T, secretsStore secretskvs.SecretsKVStore, ctx context.Context, orgId int64, namespace1 string, typ string) {
t.Helper()
resPlugin, err := secretsStore.Keys(ctx, orgId, namespace1, typ)
require.NoError(t, err)
require.Equal(t, 1, len(resPlugin))
}
// Set up services used in migration
func setupTestMigrateToPluginService(t *testing.T) (*MigrateToPluginService, secretskvs.SecretsKVStore, secretskvs.SecretsKVStore) {
t.Helper()
rawCfg := `
[secrets]
use_plugin = true
`
raw, err := ini.Load([]byte(rawCfg))
require.NoError(t, err)
cfg := &setting.Cfg{Raw: raw}
sqlStore := db.InitTestDB(t)
// this would be the plugin - mocked at the moment
fallbackStore := secretskvs.WithCache(secretskvs.NewFakeSQLSecretsKVStore(t, sqlStore), time.Minute*5, time.Minute*5)
secretsStoreForPlugin := secretskvs.WithCache(secretskvs.NewFakePluginSecretsKVStore(t, featuremgmt.WithFeatures(), fallbackStore), time.Minute*5, time.Minute*5)
// this is to init the sql secret store inside the migration
secretsService := secretsManager.SetupTestService(t, fakes.NewFakeSecretsStore())
manager := secretskvs.NewFakeSecretsPluginManager(t, false)
migratorService := ProvideMigrateToPluginService(
secretsStoreForPlugin,
cfg,
sqlStore,
secretsService,
kvstore.ProvideService(sqlStore),
manager,
)
return migratorService, secretsStoreForPlugin, fallbackStore
}
func setupTestMigratorServiceWithDeletionError(
t *testing.T,
secretskv secretskvs.SecretsKVStore,
sqlStore db.DB,
kvstore kvstore.KVStore,
) *MigrateToPluginService {
t.Helper()
t.Cleanup(secretskvs.ResetPlugin)
cfg := secretskvs.SetupTestConfig(t)
secretsService := secretsManager.SetupTestService(t, fakes.NewFakeSecretsStore())
manager := secretskvs.NewFakeSecretsPluginManager(t, false)
migratorService := ProvideMigrateToPluginService(
secretskv,
cfg,
sqlStore,
secretsService,
kvstore,
manager,
)
fallback := secretskvs.NewFakeSecretsKVStore()
var orgId int64 = 1
str := "random string"
err := fallback.Set(context.Background(), orgId, str, str, "bogus")
require.NoError(t, err)
fallback.DeletionError(true)
err = secretskvs.ReplaceFallback(t, secretskv, fallback)
require.NoError(t, err)
return migratorService
}

View File

@ -5,9 +5,7 @@ import (
)
const (
QuitOnPluginStartupFailureKey = "quit_on_secrets_plugin_startup_failure"
PluginNamespace = "secretsmanagerplugin"
DataSourceSecretType = "datasource"
DataSourceSecretType = "datasource"
)
// Item stored in k/v store.

View File

@ -1,288 +0,0 @@
package kvstore
import (
"context"
"errors"
"fmt"
"sync"
"github.com/grafana/grafana/pkg/infra/kvstore"
"github.com/grafana/grafana/pkg/infra/log"
"github.com/grafana/grafana/pkg/plugins"
smp "github.com/grafana/grafana/pkg/plugins/backendplugin/secretsmanagerplugin"
"github.com/grafana/grafana/pkg/services/datasources"
"github.com/grafana/grafana/pkg/services/featuremgmt"
"github.com/grafana/grafana/pkg/services/secrets"
"github.com/grafana/grafana/pkg/setting"
)
var (
fatalFlagOnce sync.Once
startupOnce sync.Once
errPluginDisabledByConfig = errors.New("remote secret management plugin disabled because the property `secrets.use_plugin` is not set to `true`")
errPluginNotInstalled = errors.New("remote secret management plugin disabled because there is no installed plugin of type `secretsmanager`")
)
// SecretsKVStorePlugin provides a key/value store backed by the Grafana plugin gRPC interface
type SecretsKVStorePlugin struct {
sync.Mutex
log log.Logger
secretsPlugin smp.SecretsManagerPlugin
secretsService secrets.Service
kvstore *kvstore.NamespacedKVStore
backwardsCompatibilityDisabled bool
fallbackEnabled bool
fallbackStore SecretsKVStore
}
func NewPluginSecretsKVStore(
secretsPlugin smp.SecretsManagerPlugin,
secretsService secrets.Service,
kvstore *kvstore.NamespacedKVStore,
features featuremgmt.FeatureToggles,
fallback SecretsKVStore,
logger log.Logger,
) *SecretsKVStorePlugin {
return &SecretsKVStorePlugin{
secretsPlugin: secretsPlugin,
secretsService: secretsService,
log: logger,
kvstore: kvstore,
backwardsCompatibilityDisabled: features.IsEnabledGlobally(featuremgmt.FlagDisableSecretsCompatibility),
fallbackStore: fallback,
}
}
// Get an item from the store
// If it is the first time a secret has been retrieved and backwards compatibility is disabled, mark plugin startup errors fatal
func (kv *SecretsKVStorePlugin) Get(ctx context.Context, orgId int64, namespace string, typ string) (string, bool, error) {
req := &smp.GetSecretRequest{
KeyDescriptor: &smp.Key{
OrgId: orgId,
Namespace: namespace,
Type: typ,
},
}
res, err := kv.secretsPlugin.GetSecret(ctx, req)
if res.UserFriendlyError != "" {
err = wrapUserFriendlySecretError(res.UserFriendlyError)
}
if res.Exists {
updateFatalFlag(ctx, kv)
}
if kv.fallbackEnabled {
if err != nil || res.UserFriendlyError != "" || !res.Exists {
res.DecryptedValue, res.Exists, err = kv.fallbackStore.Get(ctx, orgId, namespace, typ)
}
}
return res.DecryptedValue, res.Exists, err
}
// Set an item in the store
// If it is the first time a secret has been set and backwards compatibility is disabled, mark plugin startup errors fatal
func (kv *SecretsKVStorePlugin) Set(ctx context.Context, orgId int64, namespace string, typ string, value string) error {
req := &smp.SetSecretRequest{
KeyDescriptor: &smp.Key{
OrgId: orgId,
Namespace: namespace,
Type: typ,
},
Value: value,
}
res, err := kv.secretsPlugin.SetSecret(ctx, req)
if err == nil && res.UserFriendlyError != "" {
err = wrapUserFriendlySecretError(res.UserFriendlyError)
}
updateFatalFlag(ctx, kv)
return err
}
// Del deletes an item from the store.
func (kv *SecretsKVStorePlugin) Del(ctx context.Context, orgId int64, namespace string, typ string) error {
req := &smp.DeleteSecretRequest{
KeyDescriptor: &smp.Key{
OrgId: orgId,
Namespace: namespace,
Type: typ,
},
}
res, err := kv.secretsPlugin.DeleteSecret(ctx, req)
if err == nil && res.UserFriendlyError != "" {
err = wrapUserFriendlySecretError(res.UserFriendlyError)
}
return err
}
// Keys get all keys for a given namespace. To query for all
// organizations the constant 'kvstore.AllOrganizations' can be passed as orgId.
func (kv *SecretsKVStorePlugin) Keys(ctx context.Context, orgId int64, namespace string, typ string) ([]Key, error) {
req := &smp.ListSecretsRequest{
KeyDescriptor: &smp.Key{
OrgId: orgId,
Namespace: namespace,
Type: typ,
},
AllOrganizations: orgId == AllOrganizations,
}
res, err := kv.secretsPlugin.ListSecrets(ctx, req)
if err != nil {
return nil, err
} else if res.UserFriendlyError != "" {
err = wrapUserFriendlySecretError(res.UserFriendlyError)
}
return parseKeys(res.Keys), err
}
// Rename an item in the store
func (kv *SecretsKVStorePlugin) Rename(ctx context.Context, orgId int64, namespace string, typ string, newNamespace string) error {
req := &smp.RenameSecretRequest{
KeyDescriptor: &smp.Key{
OrgId: orgId,
Namespace: namespace,
Type: typ,
},
NewNamespace: newNamespace,
}
res, err := kv.secretsPlugin.RenameSecret(ctx, req)
if err == nil && res.UserFriendlyError != "" {
err = wrapUserFriendlySecretError(res.UserFriendlyError)
}
return err
}
func (kv *SecretsKVStorePlugin) GetAll(ctx context.Context) ([]Item, error) {
req := &smp.GetAllSecretsRequest{}
res, err := kv.secretsPlugin.GetAllSecrets(ctx, req)
if err != nil {
return nil, err
} else if res.UserFriendlyError != "" {
err = wrapUserFriendlySecretError(res.UserFriendlyError)
}
return parseItems(res.Items), err
}
func (kv *SecretsKVStorePlugin) Fallback() SecretsKVStore {
return kv.fallbackStore
}
func (kv *SecretsKVStorePlugin) WithFallbackEnabled(fn func() error) error {
kv.Lock()
defer kv.Unlock()
kv.fallbackEnabled = true
err := fn()
kv.fallbackEnabled = false
return err
}
func parseKeys(keys []*smp.Key) []Key {
newKeys := make([]Key, 0, len(keys))
for _, k := range keys {
newKey := Key{OrgId: k.OrgId, Namespace: k.Namespace, Type: k.Type}
newKeys = append(newKeys, newKey)
}
return newKeys
}
func parseItems(items []*smp.Item) []Item {
newItems := make([]Item, 0, len(items))
for _, i := range items {
newItem := Item{OrgId: &i.Key.OrgId, Namespace: &i.Key.Namespace, Type: &i.Key.Type, Value: i.Value}
newItems = append(newItems, newItem)
}
return newItems
}
func updateFatalFlag(ctx context.Context, skv *SecretsKVStorePlugin) {
// This function makes the most sense in here because it handles all possible scenarios:
// - User changed backwards compatibility flag, so we have to migrate secrets either to or from the plugin (get or set)
// - Migration is on, so we migrate secrets to the plugin (set)
// - User doesn't migrate, but stores a new secret in the plugin (set)
// Rather than updating the flag in several places, it is cleaner to just do this check once
// Very early on. Once backwards compatibility to legacy secrets is gone in Grafana 10, this can go away as well
fatalFlagOnce.Do(func() {
skv.log.Debug("Updating plugin startup error fatal flag")
var err error
if isFatal, _ := IsPluginStartupErrorFatal(ctx, skv.kvstore); !isFatal && skv.backwardsCompatibilityDisabled {
err = SetPluginStartupErrorFatal(ctx, skv.kvstore, true)
} else if isFatal && !skv.backwardsCompatibilityDisabled {
err = SetPluginStartupErrorFatal(ctx, skv.kvstore, false)
}
if err != nil {
skv.log.Error("failed to set plugin error fatal flag", err.Error())
}
})
}
func wrapUserFriendlySecretError(ufe string) datasources.ErrDatasourceSecretsPluginUserFriendly {
return datasources.ErrDatasourceSecretsPluginUserFriendly{Err: ufe}
}
func GetNamespacedKVStore(kv kvstore.KVStore) *kvstore.NamespacedKVStore {
return kvstore.WithNamespace(kv, kvstore.AllOrganizations, PluginNamespace)
}
func IsPluginStartupErrorFatal(ctx context.Context, kvstore *kvstore.NamespacedKVStore) (bool, error) {
_, exists, err := kvstore.Get(ctx, QuitOnPluginStartupFailureKey)
if err != nil {
return false, fmt.Errorf("error retrieving key %s from kvstore. error: %w", QuitOnPluginStartupFailureKey, err)
}
return exists, nil
}
func SetPluginStartupErrorFatal(ctx context.Context, kvstore *kvstore.NamespacedKVStore, isFatal bool) error {
if !isFatal {
return kvstore.Del(ctx, QuitOnPluginStartupFailureKey)
}
return kvstore.Set(ctx, QuitOnPluginStartupFailureKey, "true")
}
func EvaluateRemoteSecretsPlugin(ctx context.Context, mg plugins.SecretsPluginManager, cfg *setting.Cfg) error {
usePlugin := cfg.SectionWithEnvOverrides("secrets").Key("use_plugin").MustBool()
if !usePlugin {
return errPluginDisabledByConfig
}
pluginInstalled := mg.SecretsManager(ctx) != nil
if !pluginInstalled {
return errPluginNotInstalled
}
return nil
}
func HasPluginStarted(ctx context.Context, mg plugins.SecretsPluginManager) bool {
return mg.SecretsManager(ctx) != nil && mg.SecretsManager(ctx).SecretsManager != nil
}
func StartAndReturnPlugin(mg plugins.SecretsPluginManager, ctx context.Context) (smp.SecretsManagerPlugin, error) {
var err error
startupOnce.Do(func() {
err = mg.SecretsManager(ctx).Start(ctx)
})
if err != nil {
return nil, err
}
return mg.SecretsManager(ctx).SecretsManager, nil
}
func ResetPlugin() {
fatalFlagOnce = sync.Once{}
startupOnce = sync.Once{}
}

View File

@ -1,82 +0,0 @@
package kvstore
import (
"context"
"testing"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
"github.com/grafana/grafana/pkg/plugins/backendplugin/secretsmanagerplugin"
"github.com/grafana/grafana/pkg/tests/testsuite"
)
func TestMain(m *testing.M) {
testsuite.Run(m)
}
// Set fatal flag to true, then simulate a plugin start failure
// Should result in an error from the secret store provider
func TestFatalPluginErr_PluginFailsToStartWithFatalFlagSet(t *testing.T) {
p, err := SetupFatalCrashTest(t, true, true, false)
assert.Error(t, err)
assert.Equal(t, "mocked failed to start", err.Error())
assert.Nil(t, p.SecretsKVStore)
}
// Set fatal flag to false, then simulate a plugin start failure
// Should result in the secret store provider returning the sql impl
func TestFatalPluginErr_PluginFailsToStartWithFatalFlagNotSet(t *testing.T) {
p, err := SetupFatalCrashTest(t, true, false, false)
assert.NoError(t, err)
require.IsType(t, &CachedKVStore{}, p.SecretsKVStore)
cachedKv, _ := p.SecretsKVStore.(*CachedKVStore)
store, err := GetUnwrappedStoreFromCache(cachedKv)
require.NoError(t, err)
assert.IsType(t, &SecretsKVStoreSQL{}, store)
}
// With fatal flag not set, store a secret in the plugin while backwards compatibility is disabled
// Should result in the fatal flag going from unset -> set to true
func TestFatalPluginErr_FatalFlagGetsSetWithBackwardsCompatDisabled(t *testing.T) {
p, err := SetupFatalCrashTest(t, false, false, true)
assert.NoError(t, err)
require.NotNil(t, p.SecretsKVStore)
err = p.SecretsKVStore.Set(context.Background(), 0, "datasource", "postgres", "my secret")
assert.NoError(t, err)
isFatal, err := IsPluginStartupErrorFatal(context.Background(), GetNamespacedKVStore(p.KVStore))
assert.NoError(t, err)
assert.True(t, isFatal)
}
// With fatal flag set, retrieve a secret from the plugin while backwards compatibility is enabled
// Should result in the fatal flag going from set to true -> unset
func TestFatalPluginErr_FatalFlagGetsUnSetWithBackwardsCompatEnabled(t *testing.T) {
p, err := SetupFatalCrashTest(t, false, true, false)
assert.NoError(t, err)
require.NotNil(t, p.SecretsKVStore)
// setup - store secret and manually bypassing the remote plugin impl
_, err = p.PluginManager.SecretsManager(context.Background()).SecretsManager.SetSecret(context.Background(), &secretsmanagerplugin.SetSecretRequest{
KeyDescriptor: &secretsmanagerplugin.Key{
OrgId: 0,
Namespace: "postgres",
Type: "datasource",
},
Value: "bogus",
})
assert.NoError(t, err)
// retrieve the secret and check values
val, exists, err := p.SecretsKVStore.Get(context.Background(), 0, "postgres", "datasource")
assert.NoError(t, err)
assert.NotNil(t, val)
assert.True(t, exists)
isFatal, err := IsPluginStartupErrorFatal(context.Background(), GetNamespacedKVStore(p.KVStore))
assert.NoError(t, err)
assert.False(t, isFatal)
}

View File

@ -12,6 +12,7 @@ import (
"github.com/grafana/grafana/pkg/infra/log"
"github.com/grafana/grafana/pkg/services/secrets/fakes"
"github.com/grafana/grafana/pkg/services/secrets/manager"
"github.com/grafana/grafana/pkg/tests/testsuite"
)
type TestCase struct {
@ -25,6 +26,10 @@ func (t *TestCase) Value() string {
return fmt.Sprintf("%d:%s:%s:%d", t.OrgId, t.Namespace, t.Type, t.Revision)
}
func TestMain(m *testing.M) {
testsuite.Run(m)
}
func TestSecretsKVStoreSQL(t *testing.T) {
sqlStore := db.InitTestDB(t)
secretsService := manager.SetupTestService(t, fakes.NewFakeSecretsStore())

View File

@ -3,25 +3,13 @@ package kvstore
import (
"context"
"errors"
"sync"
"testing"
"github.com/stretchr/testify/require"
"google.golang.org/grpc"
"gopkg.in/ini.v1"
"github.com/grafana/grafana/pkg/infra/db"
"github.com/grafana/grafana/pkg/infra/kvstore"
"github.com/grafana/grafana/pkg/infra/log"
"github.com/grafana/grafana/pkg/plugins"
"github.com/grafana/grafana/pkg/plugins/backendplugin"
"github.com/grafana/grafana/pkg/plugins/backendplugin/secretsmanagerplugin"
pluginsLogger "github.com/grafana/grafana/pkg/plugins/log"
"github.com/grafana/grafana/pkg/services/featuremgmt"
"github.com/grafana/grafana/pkg/services/secrets/fakes"
secretsmng "github.com/grafana/grafana/pkg/services/secrets/manager"
"github.com/grafana/grafana/pkg/services/sqlstore"
"github.com/grafana/grafana/pkg/setting"
)
func NewFakeSQLSecretsKVStore(t *testing.T, sqlStore *sqlstore.SQLStore) *SecretsKVStoreSQL {
@ -30,17 +18,6 @@ func NewFakeSQLSecretsKVStore(t *testing.T, sqlStore *sqlstore.SQLStore) *Secret
return NewSQLSecretsKVStore(sqlStore, secretsService, log.New("test.logger"))
}
func NewFakePluginSecretsKVStore(t *testing.T, features featuremgmt.FeatureToggles, fallback SecretsKVStore) *SecretsKVStorePlugin {
t.Helper()
sqlStore := db.InitTestDB(t)
secretsService := secretsmng.SetupTestService(t, fakes.NewFakeSecretsStore())
store := kvstore.ProvideService(sqlStore)
namespacedKVStore := GetNamespacedKVStore(store)
manager := NewFakeSecretsPluginManager(t, false)
plugin := manager.SecretsManager(context.Background()).SecretsManager
return NewPluginSecretsKVStore(plugin, secretsService, namespacedKVStore, features, fallback, log.New("test.logger"))
}
// In memory kv store used for testing
type FakeSecretsKVStore struct {
store map[Key]string
@ -127,14 +104,6 @@ func buildKey(orgId int64, namespace string, typ string) Key {
}
}
func internalToProtoKey(k Key) *secretsmanagerplugin.Key {
return &secretsmanagerplugin.Key{
OrgId: k.OrgId,
Namespace: k.Namespace,
Type: k.Type,
}
}
// Fake feature toggle - only need to check the backwards compatibility disabled flag
type fakeFeatureToggles struct {
returnValue bool
@ -158,172 +127,3 @@ func (f fakeFeatureToggles) IsEnabled(ctx context.Context, feature string) bool
func (f fakeFeatureToggles) GetEnabled(ctx context.Context) map[string]bool {
return map[string]bool{}
}
// Fake grpc secrets plugin impl
type fakeGRPCSecretsPlugin struct {
kv map[Key]string
}
func (c *fakeGRPCSecretsPlugin) GetSecret(ctx context.Context, in *secretsmanagerplugin.GetSecretRequest, opts ...grpc.CallOption) (*secretsmanagerplugin.GetSecretResponse, error) {
val, ok := c.kv[buildKey(in.KeyDescriptor.OrgId, in.KeyDescriptor.Namespace, in.KeyDescriptor.Type)]
return &secretsmanagerplugin.GetSecretResponse{
DecryptedValue: val,
Exists: ok,
}, nil
}
func (c *fakeGRPCSecretsPlugin) SetSecret(ctx context.Context, in *secretsmanagerplugin.SetSecretRequest, opts ...grpc.CallOption) (*secretsmanagerplugin.SetSecretResponse, error) {
c.kv[buildKey(in.KeyDescriptor.OrgId, in.KeyDescriptor.Namespace, in.KeyDescriptor.Type)] = in.Value
return &secretsmanagerplugin.SetSecretResponse{}, nil
}
func (c *fakeGRPCSecretsPlugin) DeleteSecret(ctx context.Context, in *secretsmanagerplugin.DeleteSecretRequest, opts ...grpc.CallOption) (*secretsmanagerplugin.DeleteSecretResponse, error) {
delete(c.kv, buildKey(in.KeyDescriptor.OrgId, in.KeyDescriptor.Namespace, in.KeyDescriptor.Type))
return &secretsmanagerplugin.DeleteSecretResponse{}, nil
}
func (c *fakeGRPCSecretsPlugin) ListSecrets(ctx context.Context, in *secretsmanagerplugin.ListSecretsRequest, opts ...grpc.CallOption) (*secretsmanagerplugin.ListSecretsResponse, error) {
res := make([]*secretsmanagerplugin.Key, 0)
for k := range c.kv {
if in.KeyDescriptor.OrgId == AllOrganizations && in.KeyDescriptor.Namespace == "" && in.KeyDescriptor.Type == "" {
res = append(res, internalToProtoKey(k))
} else if k.OrgId == in.KeyDescriptor.OrgId && k.Namespace == in.KeyDescriptor.Namespace && k.Type == in.KeyDescriptor.Type {
res = append(res, internalToProtoKey(k))
}
}
return &secretsmanagerplugin.ListSecretsResponse{
Keys: res,
}, nil
}
func (c *fakeGRPCSecretsPlugin) RenameSecret(ctx context.Context, in *secretsmanagerplugin.RenameSecretRequest, opts ...grpc.CallOption) (*secretsmanagerplugin.RenameSecretResponse, error) {
oldKey := buildKey(in.KeyDescriptor.OrgId, in.KeyDescriptor.Namespace, in.KeyDescriptor.Type)
val := c.kv[oldKey]
delete(c.kv, oldKey)
c.kv[buildKey(in.KeyDescriptor.OrgId, in.NewNamespace, in.KeyDescriptor.Type)] = val
return &secretsmanagerplugin.RenameSecretResponse{}, nil
}
func (c *fakeGRPCSecretsPlugin) GetAllSecrets(ctx context.Context, in *secretsmanagerplugin.GetAllSecretsRequest, opts ...grpc.CallOption) (*secretsmanagerplugin.GetAllSecretsResponse, error) {
items := make([]*secretsmanagerplugin.Item, 0)
for k, v := range c.kv {
items = append(items, &secretsmanagerplugin.Item{
Key: internalToProtoKey(k),
Value: v,
})
}
return &secretsmanagerplugin.GetAllSecretsResponse{
Items: items,
}, nil
}
var _ SecretsKVStore = &FakeSecretsKVStore{}
var _ secretsmanagerplugin.SecretsManagerPlugin = &fakeGRPCSecretsPlugin{}
// Fake plugin manager
type fakePluginManager struct {
shouldFailOnStart bool
plugin *plugins.Plugin
}
func (mg *fakePluginManager) SecretsManager(_ context.Context) *plugins.Plugin {
if mg.plugin != nil {
return mg.plugin
}
p := &plugins.Plugin{
SecretsManager: &fakeGRPCSecretsPlugin{
kv: make(map[Key]string),
},
}
p.RegisterClient(&fakePluginClient{
shouldFailOnStart: mg.shouldFailOnStart,
})
mg.plugin = p
return p
}
func NewFakeSecretsPluginManager(t *testing.T, shouldFailOnStart bool) plugins.SecretsPluginManager {
t.Helper()
return &fakePluginManager{
shouldFailOnStart: shouldFailOnStart,
}
}
// Fake plugin client
type fakePluginClient struct {
shouldFailOnStart bool
backendplugin.Plugin
}
func (pc *fakePluginClient) Start(_ context.Context) error {
if pc.shouldFailOnStart {
return errors.New("mocked failed to start")
}
return nil
}
func (pc *fakePluginClient) Stop(_ context.Context) error {
return nil
}
func (pc *fakePluginClient) Logger() pluginsLogger.Logger {
return pluginsLogger.NewTestLogger()
}
func SetupFatalCrashTest(
t *testing.T,
shouldFailOnStart bool,
isPluginErrorFatal bool,
isBackwardsCompatDisabled bool,
) (fatalCrashTestFields, error) {
t.Helper()
fatalFlagOnce = sync.Once{}
startupOnce = sync.Once{}
cfg := SetupTestConfig(t)
sqlStore := db.InitTestDB(t)
secretService := fakes.FakeSecretsService{}
kvstore := kvstore.ProvideService(sqlStore)
if isPluginErrorFatal {
_ = SetPluginStartupErrorFatal(context.Background(), GetNamespacedKVStore(kvstore), true)
}
features := NewFakeFeatureToggles(t, isBackwardsCompatDisabled)
manager := NewFakeSecretsPluginManager(t, shouldFailOnStart)
svc, err := ProvideService(sqlStore, secretService, manager, kvstore, features, cfg)
t.Cleanup(ResetPlugin)
return fatalCrashTestFields{
SecretsKVStore: svc,
PluginManager: manager,
KVStore: kvstore,
SqlStore: sqlStore,
}, err
}
type fatalCrashTestFields struct {
SecretsKVStore SecretsKVStore
PluginManager plugins.SecretsPluginManager
KVStore kvstore.KVStore
SqlStore db.DB
}
func SetupTestConfig(t *testing.T) *setting.Cfg {
t.Helper()
rawCfg := `
[secrets]
use_plugin = true
`
raw, err := ini.Load([]byte(rawCfg))
require.NoError(t, err)
return &setting.Cfg{Raw: raw}
}
func ReplaceFallback(t *testing.T, kv SecretsKVStore, fb SecretsKVStore) error {
t.Helper()
if store, ok := kv.(*CachedKVStore); ok {
kv = store.store
}
if store, ok := kv.(*SecretsKVStorePlugin); ok {
store.fallbackStore = fb
return nil
}
return errors.New("not a plugin store")
}

View File

@ -88,4 +88,3 @@
}
]
}

View File

@ -33,16 +33,6 @@ export const InstallControlsWarning = ({ plugin, pluginStatus, latestCompatibleV
);
}
if (plugin.type === PluginType.secretsmanager) {
return (
<Alert
severity="warning"
title="Secrets manager plugins cannot be managed by the Plugin Catalog."
className={styles.alert}
/>
);
}
if (plugin.isEnterprise && !featureEnabled('enterprise.plugins')) {
return (
<Alert severity="warning" title="" className={styles.alert}>

View File

@ -24,12 +24,6 @@ describe('PluginDetailsBody', () => {
type: PluginType.renderer,
},
},
{
name: 'secrets manager type plugin',
plugin: {
type: PluginType.secretsmanager,
},
},
{
name: 'enterprise plugin type without enterprise license',
plugin: {

View File

@ -124,7 +124,7 @@ export function mapRemoteToCatalog(plugin: RemotePlugin, error?: PluginError): C
url,
} = plugin;
const isDisabled = !!error || isDisabledSecretsPlugin(typeCode);
const isDisabled = !!error;
return {
description,
downloads,
@ -178,7 +178,7 @@ export function mapLocalToCatalog(plugin: LocalPlugin, error?: PluginError): Cat
angularDetected,
} = plugin;
const isDisabled = !!error || isDisabledSecretsPlugin(type);
const isDisabled = !!error;
return {
description,
downloads: 0,
@ -218,7 +218,7 @@ export function mapToCatalogPlugin(local?: LocalPlugin, remote?: RemotePlugin, e
const installedVersion = local?.info.version;
const id = remote?.slug || local?.id || '';
const type = local?.type || remote?.typeCode;
const isDisabled = !!error || isDisabledSecretsPlugin(type);
const isDisabled = !!error;
const keywords = remote?.keywords || local?.info.keywords || [];
let logos = {
@ -370,7 +370,6 @@ export const hasInstallControlWarning = (
const isCompatible = Boolean(latestCompatibleVersion);
return (
plugin.type === PluginType.renderer ||
plugin.type === PluginType.secretsmanager ||
(plugin.isEnterprise && !featureEnabled('enterprise.plugins')) ||
plugin.isDev ||
(!hasPermission && !isExternallyManaged) ||
@ -403,10 +402,6 @@ export function isPreinstalledPlugin(id: string): { found: boolean; withVersion:
return { found: !!plugin?.id, withVersion: !!plugin?.version };
}
function isDisabledSecretsPlugin(type?: PluginType): boolean {
return type === PluginType.secretsmanager && !config.secretsManagerPluginEnabled;
}
export function isLocalCorePlugin(local?: LocalPlugin): boolean {
return Boolean(local?.signature === 'internal');
}
@ -469,7 +464,6 @@ export function isPluginUpdatable(plugin: CatalogPlugin) {
export function shouldDisablePluginInstall(plugin: CatalogPlugin) {
if (
!isPluginModifiable(plugin) ||
plugin.type === PluginType.secretsmanager ||
(plugin.isEnterprise && !featureEnabled('enterprise.plugins')) ||
!plugin.isPublished ||
plugin.isDisabled ||

View File

@ -24,7 +24,6 @@ export enum PluginIconName {
datasource = 'database',
panel = 'credit-card',
renderer = 'capture',
secretsmanager = 'key-skeleton-alt',
}
export interface CatalogPlugin extends WithAccessControlMetadata {