|
|
|
@ -7,6 +7,10 @@ import ( |
|
|
|
|
|
|
|
|
|
"github.com/grafana/authlib/authz" |
|
|
|
|
"github.com/grafana/authlib/claims" |
|
|
|
|
"github.com/grafana/grafana/pkg/services/authn/grpcutils" |
|
|
|
|
"go.opentelemetry.io/otel/attribute" |
|
|
|
|
"go.opentelemetry.io/otel/trace" |
|
|
|
|
"go.opentelemetry.io/otel/trace/noop" |
|
|
|
|
) |
|
|
|
|
|
|
|
|
|
type staticAuthzClient struct { |
|
|
|
@ -38,11 +42,19 @@ type authzLimitedClient struct { |
|
|
|
|
// whitelist is a map of group to resources that are compatible with RBAC.
|
|
|
|
|
whitelist groupResource |
|
|
|
|
logger *slog.Logger |
|
|
|
|
tracer trace.Tracer |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
type AuthzOptions struct { |
|
|
|
|
Tracer trace.Tracer |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// NewAuthzLimitedClient creates a new authzLimitedClient.
|
|
|
|
|
func NewAuthzLimitedClient(client authz.AccessChecker) authz.AccessClient { |
|
|
|
|
func NewAuthzLimitedClient(client authz.AccessChecker, opts AuthzOptions) authz.AccessClient { |
|
|
|
|
logger := slog.Default().With("logger", "limited-authz-client") |
|
|
|
|
if opts.Tracer == nil { |
|
|
|
|
opts.Tracer = noop.NewTracerProvider().Tracer("limited-authz-client") |
|
|
|
|
} |
|
|
|
|
return &authzLimitedClient{ |
|
|
|
|
client: client, |
|
|
|
|
whitelist: groupResource{ |
|
|
|
@ -50,31 +62,57 @@ func NewAuthzLimitedClient(client authz.AccessChecker) authz.AccessClient { |
|
|
|
|
"folder.grafana.app": map[string]interface{}{"folders": nil}, |
|
|
|
|
}, |
|
|
|
|
logger: logger, |
|
|
|
|
tracer: opts.Tracer, |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// Check implements authz.AccessClient.
|
|
|
|
|
func (c authzLimitedClient) Check(ctx context.Context, id claims.AuthInfo, req authz.CheckRequest) (authz.CheckResponse, error) { |
|
|
|
|
ctx, span := c.tracer.Start(ctx, "authzLimitedClient.Check", trace.WithAttributes( |
|
|
|
|
attribute.String("group", req.Group), |
|
|
|
|
attribute.String("resource", req.Resource), |
|
|
|
|
attribute.Bool("fallback", grpcutils.FallbackUsed(ctx)), |
|
|
|
|
)) |
|
|
|
|
defer span.End() |
|
|
|
|
if grpcutils.FallbackUsed(ctx) { |
|
|
|
|
c.logger.Debug("Check", "group", req.Group, "resource", req.Resource, "fallback", true, "rbac", false, "allowed", true) |
|
|
|
|
return authz.CheckResponse{Allowed: true}, nil |
|
|
|
|
} |
|
|
|
|
if !c.IsCompatibleWithRBAC(req.Group, req.Resource) { |
|
|
|
|
c.logger.Debug("Check", "group", req.Group, "resource", req.Resource, "rbac", false, "allowed", true) |
|
|
|
|
c.logger.Debug("Check", "group", req.Group, "resource", req.Resource, "fallback", false, "rbac", false, "allowed", true) |
|
|
|
|
return authz.CheckResponse{Allowed: true}, nil |
|
|
|
|
} |
|
|
|
|
t := time.Now() |
|
|
|
|
resp, err := c.client.Check(ctx, id, req) |
|
|
|
|
if err != nil { |
|
|
|
|
c.logger.Error("Check", "group", req.Group, "resource", req.Resource, "rbac", true, "error", err, "duration", time.Since(t)) |
|
|
|
|
c.logger.Error("Check", "group", req.Group, "resource", req.Resource, "fallback", false, "rbac", true, "error", err, "duration", time.Since(t)) |
|
|
|
|
return resp, err |
|
|
|
|
} |
|
|
|
|
c.logger.Debug("Check", "group", req.Group, "resource", req.Resource, "rbac", true, "allowed", resp.Allowed, "duration", time.Since(t)) |
|
|
|
|
c.logger.Debug("Check", "group", req.Group, "resource", req.Resource, "fallback", false, "rbac", true, "allowed", resp.Allowed, "duration", time.Since(t)) |
|
|
|
|
return resp, nil |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// Compile implements authz.AccessClient.
|
|
|
|
|
func (c authzLimitedClient) Compile(ctx context.Context, id claims.AuthInfo, req authz.ListRequest) (authz.ItemChecker, error) { |
|
|
|
|
ctx, span := c.tracer.Start(ctx, "authzLimitedClient.Compile", trace.WithAttributes( |
|
|
|
|
attribute.String("group", req.Group), |
|
|
|
|
attribute.String("resource", req.Resource), |
|
|
|
|
)) |
|
|
|
|
defer span.End() |
|
|
|
|
return func(namespace string, name, folder string) bool { |
|
|
|
|
ctx, span := c.tracer.Start(ctx, "authzLimitedClient.Compile.Check", trace.WithAttributes( |
|
|
|
|
attribute.String("group", req.Group), |
|
|
|
|
attribute.String("resource", req.Resource), |
|
|
|
|
attribute.Bool("fallback", grpcutils.FallbackUsed(ctx)), |
|
|
|
|
)) |
|
|
|
|
defer span.End() |
|
|
|
|
if grpcutils.FallbackUsed(ctx) { |
|
|
|
|
c.logger.Debug("Check", "group", req.Group, "resource", req.Resource, "fallback", true, "rbac", false, "allowed", true) |
|
|
|
|
return true |
|
|
|
|
} |
|
|
|
|
// TODO: Implement For now we perform the check for each item.
|
|
|
|
|
if !c.IsCompatibleWithRBAC(req.Group, req.Resource) { |
|
|
|
|
c.logger.Debug("Compile.Check", "group", req.Group, "resource", req.Resource, "namespace", namespace, "name", name, "folder", folder, "rbac", false, "allowed", true) |
|
|
|
|
c.logger.Debug("Compile.Check", "group", req.Group, "resource", req.Resource, "namespace", namespace, "name", name, "folder", folder, "fallback", false, "rbac", false, "allowed", true) |
|
|
|
|
return true |
|
|
|
|
} |
|
|
|
|
t := time.Now() |
|
|
|
@ -87,10 +125,10 @@ func (c authzLimitedClient) Compile(ctx context.Context, id claims.AuthInfo, req |
|
|
|
|
Folder: folder, |
|
|
|
|
}) |
|
|
|
|
if err != nil { |
|
|
|
|
c.logger.Error("Compile.Check", "group", req.Group, "resource", req.Resource, "namespace", namespace, "name", name, "folder", folder, "rbac", true, "error", err, "duration", time.Since(t)) |
|
|
|
|
c.logger.Error("Compile.Check", "group", req.Group, "resource", req.Resource, "namespace", namespace, "name", name, "folder", folder, "fallback", false, "rbac", true, "error", err, "duration", time.Since(t)) |
|
|
|
|
return false |
|
|
|
|
} |
|
|
|
|
c.logger.Debug("Compile.Check", "group", req.Group, "resource", req.Resource, "namespace", namespace, "name", name, "folder", folder, "rbac", true, "allowed", r.Allowed, "duration", time.Since(t)) |
|
|
|
|
c.logger.Debug("Compile.Check", "group", req.Group, "resource", req.Resource, "namespace", namespace, "name", name, "folder", folder, "fallback", false, "rbac", true, "allowed", r.Allowed, "duration", time.Since(t)) |
|
|
|
|
return r.Allowed |
|
|
|
|
}, nil |
|
|
|
|
} |
|
|
|
|