Secrets: Manage secure values inside any resource (#107803)

This commit is contained in:
Ryan McKinley
2025-08-14 12:31:24 +00:00
committed by GitHub
parent d08ea58243
commit d3df5b8ddd
11 changed files with 963 additions and 133 deletions
+27 -20
View File
@@ -32,6 +32,7 @@ import (
"k8s.io/client-go/tools/cache"
authtypes "github.com/grafana/authlib/types"
"github.com/grafana/grafana-app-sdk/logging"
"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"
@@ -186,33 +187,33 @@ func (s *Storage) convertToObject(data []byte, obj runtime.Object) (runtime.Obje
// in seconds (0 means forever). If no error is returned and out is not nil, out will be
// set to the read value from database.
func (s *Storage) Create(ctx context.Context, key string, obj runtime.Object, out runtime.Object, ttl uint64) error {
var err error
var permissions string
req := &resourcepb.CreateRequest{}
req.Value, permissions, err = s.prepareObjectForStorage(ctx, obj)
v, err := s.prepareObjectForStorage(ctx, obj)
if err != nil {
return s.handleManagedResourceRouting(ctx, err, resourcepb.WatchEvent_ADDED, key, obj, out)
}
req := &resourcepb.CreateRequest{
Value: v.raw.Bytes(),
}
req.Key, err = s.getKey(key)
if err != nil {
return err
}
grantPermissions, err := afterCreatePermissionCreator(ctx, req.Key, permissions, obj, s.opts.Permissions)
v.permissionCreator, err = afterCreatePermissionCreator(ctx, req.Key, v.grantPermissions, obj, s.opts.Permissions)
if err != nil {
return err
}
rsp, err := s.store.Create(ctx, req)
if err != nil {
return resource.GetError(resource.AsErrorResult(err))
return v.finish(ctx, resource.GetError(resource.AsErrorResult(err)), s.opts.SecureValues)
}
if rsp.Error != nil {
err = resource.GetError(rsp.Error)
if rsp.Error.Code == http.StatusConflict {
return storage.NewKeyExistsError(key, 0)
err = storage.NewKeyExistsError(key, 0)
}
return resource.GetError(rsp.Error)
return v.finish(ctx, err, s.opts.SecureValues)
}
if _, err := s.convertToObject(req.Value, out); err != nil {
@@ -234,12 +235,7 @@ func (s *Storage) Create(ctx context.Context, key string, obj runtime.Object, ou
})
}
// Synchronous AfterCreate permissions -- allows users to become "admin" of the thing they made
if grantPermissions != nil {
return grantPermissions(ctx)
}
return nil
return v.finish(ctx, nil, s.opts.SecureValues)
}
// Delete removes the specified key and returns the value that existed at that spot.
@@ -308,6 +304,11 @@ func (s *Storage) Delete(
if rsp.Error != nil {
return resource.GetError(rsp.Error)
}
if err = handleSecureValuesDelete(ctx, s.opts.SecureValues, meta); err != nil {
logging.FromContext(ctx).Warn("failed to delete inline secure values", "err", err)
}
if err := s.versioner.UpdateObject(out, uint64(rsp.ResourceVersion)); err != nil {
return err
}
@@ -591,21 +592,27 @@ func (s *Storage) GuaranteedUpdate(
break
}
req.Value, err = s.prepareObjectForUpdate(ctx, updatedObj, existingObj)
v, err := s.prepareObjectForUpdate(ctx, updatedObj, existingObj)
if err != nil {
return s.handleManagedResourceRouting(ctx, err, resourcepb.WatchEvent_MODIFIED, key, updatedObj, destination)
}
var rv uint64
// Only update (for real) if the bytes have changed
var rv uint64
req.Value = v.raw.Bytes()
if !bytes.Equal(req.Value, existingBytes) {
updateResponse, err := s.store.Update(ctx, req)
if err != nil {
return resource.GetError(resource.AsErrorResult(err))
err = resource.GetError(resource.AsErrorResult(err))
} else if updateResponse.Error != nil {
err = resource.GetError(updateResponse.Error)
}
if updateResponse.Error != nil {
return resource.GetError(updateResponse.Error)
// Cleanup secure values
if err = v.finish(ctx, err, s.opts.SecureValues); err != nil {
return err
}
rv = uint64(updateResponse.ResourceVersion)
}