grafana/pkg/storage/unified/resource/secure.go

82 lines
2.1 KiB
Go

package resource
import (
"context"
"net/http"
"slices"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"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"
)
// The "CanReference" check exists to avoid writing references to secrets
// the user should not allow granting access. We only check it when the value changes
func canReferenceSecureValues(ctx context.Context,
obj utils.GrafanaMetaAccessor,
old utils.GrafanaMetaAccessor,
secrets secrets.InlineSecureValueSupport,
) *resourcepb.ErrorResult {
secure, err := obj.GetSecureValues()
if err != nil || len(secure) == 0 {
return AsErrorResult(err)
}
if secrets == nil {
return &resourcepb.ErrorResult{
Message: "secure storage not configured",
Code: http.StatusServiceUnavailable,
Reason: string(metav1.StatusReasonServiceUnavailable),
}
}
// All references should only set a name
names := make([]string, 0, len(secure))
for k, v := range secure {
if !v.Create.IsZero() {
return newInvalidFieldError(obj,
"unable to create values in unified storage",
"secure", k, "create")
}
if v.Remove {
return newInvalidFieldError(obj,
"unable to save the remove command",
"secure", k, "remove")
}
if v.Name == "" {
return newRequiredFieldError(obj,
"missing name",
"secure", k, "name")
}
names = append(names, v.Name)
}
// This will call the real service to check access, converting any errors to protobuf
canReference := func() *resourcepb.ErrorResult {
slices.Sort(names)
names = slices.Compact(names) //
if err := secrets.CanReference(ctx, utils.ToObjectReference(obj), names...); err != nil {
return AsErrorResult(err)
}
return nil
}
// Always check for create
if old == nil {
return canReference()
}
oldSecureValues, err := old.GetSecureValues()
if err != nil || len(secure) != len(oldSecureValues) {
return canReference()
}
for k, v := range secure {
if oldSecureValues[k].Name != v.Name {
return canReference()
}
}
return nil // no need to check if the values are the same
}