K8s/SecureValues: Wire InlineSecureValueSupport to apistore (#109449)

* inline wire

* extra fields

* add variable

* wire
This commit is contained in:
Ryan McKinley
2025-08-11 15:22:56 +03:00
committed by GitHub
parent 4682a288a3
commit e0404f924c
13 changed files with 245 additions and 191 deletions
+16 -4
View File
@@ -19,6 +19,7 @@ import (
flowcontrolrequest "k8s.io/apiserver/pkg/util/flowcontrol/request"
"k8s.io/client-go/tools/cache"
secret "github.com/grafana/grafana/pkg/registry/apis/secret/contracts"
"github.com/grafana/grafana/pkg/storage/unified/resource"
)
@@ -28,6 +29,7 @@ type StorageOptionsRegister func(gr schema.GroupResource, opts StorageOptions)
type RESTOptionsGetter struct {
client resource.ResourceClient
secrets secret.InlineSecureValueSupport
original storagebackend.Config
configProvider RestConfigProvider
@@ -35,16 +37,22 @@ type RESTOptionsGetter struct {
options map[string]StorageOptions
}
func NewRESTOptionsGetterForClient(client resource.ResourceClient, original storagebackend.Config, configProvider RestConfigProvider) *RESTOptionsGetter {
func NewRESTOptionsGetterForClient(
client resource.ResourceClient,
secrets secret.InlineSecureValueSupport,
original storagebackend.Config,
configProvider RestConfigProvider,
) *RESTOptionsGetter {
return &RESTOptionsGetter{
client: client,
secrets: secrets,
original: original,
options: make(map[string]StorageOptions),
configProvider: configProvider,
}
}
func NewRESTOptionsGetterMemory(originalStorageConfig storagebackend.Config) (*RESTOptionsGetter, error) {
func NewRESTOptionsGetterMemory(originalStorageConfig storagebackend.Config, secrets secret.InlineSecureValueSupport) (*RESTOptionsGetter, error) {
backend, err := resource.NewCDKBackend(context.Background(), resource.CDKBackendOptions{
Bucket: memblob.OpenBucket(&memblob.Options{}),
})
@@ -59,6 +67,7 @@ func NewRESTOptionsGetterMemory(originalStorageConfig storagebackend.Config) (*R
}
return NewRESTOptionsGetterForClient(
resource.NewLocalResourceClient(server),
secrets,
originalStorageConfig,
nil,
), nil
@@ -67,7 +76,7 @@ func NewRESTOptionsGetterMemory(originalStorageConfig storagebackend.Config) (*R
// Optionally, this constructor allows specifying directories
// for resources that are required to be read/watched on startup and there
// won't be any write operations that initially bootstrap their directories
func NewRESTOptionsGetterForFile(path string,
func NewRESTOptionsGetterForFileXX(path string,
originalStorageConfig storagebackend.Config,
features map[string]any) (*RESTOptionsGetter, error) {
if path == "" {
@@ -95,6 +104,7 @@ func NewRESTOptionsGetterForFile(path string,
}
return NewRESTOptionsGetterForClient(
resource.NewLocalResourceClient(server),
nil, // secrets
originalStorageConfig,
nil,
), nil
@@ -137,8 +147,10 @@ func (r *RESTOptionsGetter) GetRESTOptions(resource schema.GroupResource, _ runt
trigger storage.IndexerFuncs,
indexers *cache.Indexers,
) (storage.Interface, factory.DestroyFunc, error) {
opts := r.options[resource.String()]
opts.SecureValues = r.secrets
return NewStorage(config, r.client, keyFunc, nil, newFunc, newListFunc, getAttrsFunc,
trigger, indexers, r.configProvider, r.options[resource.String()])
trigger, indexers, r.configProvider, opts)
},
DeleteCollectionWorkers: 0,
EnableGarbageCollection: false,
+4 -1
View File
@@ -32,9 +32,9 @@ import (
"k8s.io/client-go/tools/cache"
authtypes "github.com/grafana/authlib/types"
"github.com/grafana/grafana/pkg/apimachinery/utils"
grafanaregistry "github.com/grafana/grafana/pkg/apiserver/registry/generic"
secrets "github.com/grafana/grafana/pkg/registry/apis/secret/contracts"
"github.com/grafana/grafana/pkg/storage/unified/resource"
"github.com/grafana/grafana/pkg/storage/unified/resourcepb"
)
@@ -61,6 +61,9 @@ type StorageOptions struct {
// Add internalID label when missing
RequireDeprecatedInternalID bool
// Process inline secure values
SecureValues secrets.InlineSecureValueSupport
// Temporary fix to support adding default permissions AfterCreate
Permissions DefaultPermissionSetter
}
+16 -14
View File
@@ -6,24 +6,23 @@ import (
"path/filepath"
"time"
"go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc"
"gocloud.dev/blob/fileblob"
"google.golang.org/grpc"
"google.golang.org/grpc/credentials/insecure"
otgrpc "github.com/opentracing-contrib/go-grpc"
"github.com/opentracing/opentracing-go"
"github.com/prometheus/client_golang/prometheus"
"github.com/prometheus/client_golang/prometheus/promauto"
"go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc"
"gocloud.dev/blob/fileblob"
"google.golang.org/grpc"
"google.golang.org/grpc/credentials/insecure"
"github.com/grafana/authlib/types"
"github.com/grafana/dskit/flagext"
"github.com/grafana/dskit/grpcclient"
"github.com/grafana/dskit/middleware"
"github.com/grafana/dskit/services"
infraDB "github.com/grafana/grafana/pkg/infra/db"
"github.com/grafana/grafana/pkg/infra/tracing"
secrets "github.com/grafana/grafana/pkg/registry/apis/secret/contracts"
"github.com/grafana/grafana/pkg/services/apiserver/options"
"github.com/grafana/grafana/pkg/services/featuremgmt"
"github.com/grafana/grafana/pkg/setting"
@@ -36,13 +35,14 @@ import (
)
type Options struct {
Cfg *setting.Cfg
Features featuremgmt.FeatureToggles
DB infraDB.DB
Tracer tracing.Tracer
Reg prometheus.Registerer
Authzc types.AccessClient
Docs resource.DocumentBuilderSupplier
Cfg *setting.Cfg
Features featuremgmt.FeatureToggles
DB infraDB.DB
Tracer tracing.Tracer
Reg prometheus.Registerer
Authzc types.AccessClient
Docs resource.DocumentBuilderSupplier
SecureValues secrets.InlineSecureValueSupport
}
type clientMetrics struct {
@@ -64,7 +64,7 @@ func ProvideUnifiedStorageClient(opts *Options,
SearchServerAddress: apiserverCfg.Key("search_server_address").MustString(""),
BlobStoreURL: apiserverCfg.Key("blob_url").MustString(""),
BlobThresholdBytes: apiserverCfg.Key("blob_threshold_bytes").MustInt(options.BlobThresholdDefault),
}, opts.Cfg, opts.Features, opts.DB, opts.Tracer, opts.Reg, opts.Authzc, opts.Docs, storageMetrics, indexMetrics)
}, opts.Cfg, opts.Features, opts.DB, opts.Tracer, opts.Reg, opts.Authzc, opts.Docs, storageMetrics, indexMetrics, opts.SecureValues)
if err == nil {
// Used to get the folder stats
client = federated.NewFederatedClient(
@@ -86,6 +86,7 @@ func newClient(opts options.StorageOptions,
docs resource.DocumentBuilderSupplier,
storageMetrics *resource.StorageMetrics,
indexMetrics *resource.BleveIndexMetrics,
secure secrets.InlineSecureValueSupport,
) (resource.ResourceClient, error) {
ctx := context.Background()
@@ -168,6 +169,7 @@ func newClient(opts options.StorageOptions,
StorageMetrics: storageMetrics,
IndexMetrics: indexMetrics,
Features: features,
SecureValues: secure,
}
if cfg.QOSEnabled {
+5 -3
View File
@@ -6,6 +6,9 @@ import (
"strings"
"testing"
"github.com/stretchr/testify/require"
"google.golang.org/grpc"
authlib "github.com/grafana/authlib/types"
"github.com/grafana/grafana/pkg/apimachinery/identity"
"github.com/grafana/grafana/pkg/services/apiserver/options"
@@ -13,9 +16,6 @@ import (
"github.com/grafana/grafana/pkg/setting"
"github.com/grafana/grafana/pkg/storage/unified/resource"
"github.com/grafana/grafana/pkg/storage/unified/resourcepb"
"github.com/stretchr/testify/require"
"google.golang.org/grpc"
)
func TestUnifiedStorageClient(t *testing.T) {
@@ -45,6 +45,7 @@ func TestUnifiedStorageClient(t *testing.T) {
nil,
nil,
nil,
nil,
)
require.NoError(t, err)
@@ -78,6 +79,7 @@ func TestUnifiedStorageClient(t *testing.T) {
nil,
nil,
nil,
nil,
)
require.NoError(t, err)
+20 -11
View File
@@ -21,8 +21,8 @@ import (
claims "github.com/grafana/authlib/types"
"github.com/grafana/dskit/backoff"
"github.com/grafana/dskit/ring"
"github.com/grafana/grafana/pkg/apimachinery/utils"
secrets "github.com/grafana/grafana/pkg/registry/apis/secret/contracts"
"github.com/grafana/grafana/pkg/storage/unified/resourcepb"
"github.com/grafana/grafana/pkg/util/scheduler"
)
@@ -208,6 +208,9 @@ type ResourceServerOptions struct {
// Link RBAC
AccessClient claims.AccessClient
// Manage secure values
SecureValues secrets.InlineSecureValueSupport
// Callbacks for startup and shutdown
Lifecycle LifecycleHooks
@@ -297,6 +300,7 @@ func NewResourceServer(opts ResourceServerOptions) (ResourceServer, error) {
blob: blobstore,
diagnostics: opts.Diagnostics,
access: opts.AccessClient,
secure: opts.SecureValues,
writeHooks: opts.WriteHooks,
lifecycle: opts.Lifecycle,
now: opts.Now,
@@ -333,6 +337,7 @@ type server struct {
log *slog.Logger
backend StorageBackend
blob BlobSupport
secure secrets.InlineSecureValueSupport
search *searchSupport
diagnostics resourcepb.DiagnosticsServer
access claims.AccessClient
@@ -444,16 +449,6 @@ func (s *server) newEvent(ctx context.Context, user claims.AuthInfo, key *resour
return nil, NewBadRequestError("can not save annotation: " + utils.AnnoKeyGrantPermissions)
}
// Verify that this resource can reference secure values
secure, err := obj.GetSecureValues()
if err != nil {
return nil, AsErrorResult(err)
}
if len(secure) > 0 {
// See: https://github.com/grafana/grafana/pull/107803
return nil, NewBadRequestError("Saving secure values is not yet supported")
}
event := &WriteEvent{
Value: value,
Key: key,
@@ -477,6 +472,20 @@ func (s *server) newEvent(ctx context.Context, user claims.AuthInfo, key *resour
}
}
// Verify that this resource can reference secure values
secure, err := obj.GetSecureValues()
if err != nil {
return nil, AsErrorResult(err)
}
if len(secure) > 0 {
if s.secure == nil {
return nil, NewBadRequestError("secure storage not configured")
}
// See: https://github.com/grafana/grafana/pull/107803
return nil, NewBadRequestError("Saving secure values is not yet supported")
}
if key.Namespace != obj.GetNamespace() {
return nil, NewBadRequestError("key/namespace do not match")
}
+4 -2
View File
@@ -11,8 +11,8 @@ import (
"github.com/grafana/authlib/types"
"github.com/grafana/dskit/ring"
"github.com/grafana/dskit/services"
infraDB "github.com/grafana/grafana/pkg/infra/db"
secrets "github.com/grafana/grafana/pkg/registry/apis/secret/contracts"
"github.com/grafana/grafana/pkg/services/featuremgmt"
"github.com/grafana/grafana/pkg/services/sqlstore/migrator"
"github.com/grafana/grafana/pkg/setting"
@@ -38,6 +38,7 @@ type ServerOptions struct {
IndexMetrics *resource.BleveIndexMetrics
Features featuremgmt.FeatureToggles
QOSQueue QOSEnqueueDequeuer
SecureValues secrets.InlineSecureValueSupport
Ring *ring.Ring
RingLifecycler *ring.BasicLifecycler
}
@@ -52,7 +53,8 @@ func NewResourceServer(
Blob: resource.BlobConfig{
URL: apiserverCfg.Key("blob_url").MustString(""),
},
Reg: opts.Reg,
Reg: opts.Reg,
SecureValues: opts.SecureValues,
}
if opts.AccessClient != nil {
serverOptions.AccessClient = resource.NewAuthzLimitedClient(opts.AccessClient, resource.AuthzOptions{Tracer: opts.Tracer, Registry: opts.Reg})