Provisioning: allow access check to proceed even when non access policy (#112946)
* Provisioning: allow access check to proceed even when non access policy * Provisioning: access checker needs this for MT * add permissions registration * remove scopes * use in MT for now * no need to document an internal flag here * revert vscode change * refactor the authZ permission evaluation and mapper code to allow evaluating unscoped actions beyond creation * update wire * gofmt * add boolean to struct --------- Co-authored-by: IevaVasiljeva <ieva.vasiljeva@grafana.com>
This commit is contained in:
co-authored by
IevaVasiljeva
parent
445e88cb93
commit
6c728f8dec
@@ -30,6 +30,7 @@ func ProvideRegistryServiceSink(
|
||||
_ *provisioning.APIBuilder,
|
||||
_ *ofrep.APIBuilder,
|
||||
_ *secret.DependencyRegisterer,
|
||||
_ *provisioning.DependencyRegisterer,
|
||||
) *Service {
|
||||
return &Service{}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,129 @@
|
||||
package provisioning
|
||||
|
||||
import (
|
||||
"github.com/grafana/grafana/pkg/services/accesscontrol"
|
||||
"github.com/grafana/grafana/pkg/services/org"
|
||||
)
|
||||
|
||||
const (
|
||||
// Repositories
|
||||
ActionProvisioningRepositoriesCreate = "provisioning.repositories:create" // CREATE.
|
||||
ActionProvisioningRepositoriesWrite = "provisioning.repositories:write" // UPDATE.
|
||||
ActionProvisioningRepositoriesRead = "provisioning.repositories:read" // GET + LIST.
|
||||
ActionProvisioningRepositoriesDelete = "provisioning.repositories:delete" // DELETE.
|
||||
|
||||
// Jobs
|
||||
ActionProvisioningJobsCreate = "provisioning.jobs:create" // CREATE.
|
||||
ActionProvisioningJobsWrite = "provisioning.jobs:write" // UPDATE.
|
||||
ActionProvisioningJobsRead = "provisioning.jobs:read" // GET + LIST.
|
||||
ActionProvisioningJobsDelete = "provisioning.jobs:delete" // DELETE.
|
||||
|
||||
// Historic Jobs
|
||||
ActionProvisioningHistoricJobsRead = "provisioning.historicjobs:read" // GET + LIST.
|
||||
)
|
||||
|
||||
func registerAccessControlRoles(service accesscontrol.Service) error {
|
||||
// Repositories
|
||||
repositoriesReader := accesscontrol.RoleRegistration{
|
||||
Role: accesscontrol.RoleDTO{
|
||||
Name: "fixed:provisioning.repositories:reader",
|
||||
DisplayName: "Repositories Reader",
|
||||
Description: "Read and list provisioning repositories.",
|
||||
Group: "Provisioning",
|
||||
Permissions: []accesscontrol.Permission{
|
||||
{
|
||||
Action: ActionProvisioningRepositoriesRead,
|
||||
},
|
||||
},
|
||||
},
|
||||
Grants: []string{string(org.RoleAdmin)},
|
||||
}
|
||||
|
||||
repositoriesWriter := accesscontrol.RoleRegistration{
|
||||
Role: accesscontrol.RoleDTO{
|
||||
Name: "fixed:provisioning.repositories:writer",
|
||||
DisplayName: "Repositories Writer",
|
||||
Description: "Create, update and delete provisioning repositories.",
|
||||
Group: "Provisioning",
|
||||
Permissions: []accesscontrol.Permission{
|
||||
{
|
||||
Action: ActionProvisioningRepositoriesCreate,
|
||||
},
|
||||
{
|
||||
Action: ActionProvisioningRepositoriesRead,
|
||||
},
|
||||
{
|
||||
Action: ActionProvisioningRepositoriesWrite,
|
||||
},
|
||||
{
|
||||
Action: ActionProvisioningRepositoriesDelete,
|
||||
},
|
||||
},
|
||||
},
|
||||
Grants: []string{string(org.RoleAdmin)},
|
||||
}
|
||||
|
||||
// Jobs
|
||||
jobsReader := accesscontrol.RoleRegistration{
|
||||
Role: accesscontrol.RoleDTO{
|
||||
Name: "fixed:provisioning.jobs:reader",
|
||||
DisplayName: "Jobs Reader",
|
||||
Description: "Read and list provisioning jobs.",
|
||||
Group: "Provisioning",
|
||||
Permissions: []accesscontrol.Permission{
|
||||
{
|
||||
Action: ActionProvisioningJobsRead,
|
||||
},
|
||||
},
|
||||
},
|
||||
Grants: []string{string(org.RoleAdmin)},
|
||||
}
|
||||
|
||||
jobsWriter := accesscontrol.RoleRegistration{
|
||||
Role: accesscontrol.RoleDTO{
|
||||
Name: "fixed:provisioning.jobs:writer",
|
||||
DisplayName: "Jobs Writer",
|
||||
Description: "Create, update and delete provisioning jobs.",
|
||||
Group: "Provisioning",
|
||||
Permissions: []accesscontrol.Permission{
|
||||
{
|
||||
Action: ActionProvisioningJobsCreate,
|
||||
},
|
||||
{
|
||||
Action: ActionProvisioningJobsRead,
|
||||
},
|
||||
{
|
||||
Action: ActionProvisioningJobsWrite,
|
||||
},
|
||||
{
|
||||
Action: ActionProvisioningJobsDelete,
|
||||
},
|
||||
},
|
||||
},
|
||||
Grants: []string{string(org.RoleAdmin)},
|
||||
}
|
||||
|
||||
// Historic Jobs
|
||||
historicJobsReader := accesscontrol.RoleRegistration{
|
||||
Role: accesscontrol.RoleDTO{
|
||||
Name: "fixed:provisioning.historicjobs:reader",
|
||||
DisplayName: "Historic Jobs Reader",
|
||||
Description: "Read and list provisioning historic jobs.",
|
||||
Group: "Provisioning",
|
||||
Permissions: []accesscontrol.Permission{
|
||||
{
|
||||
Action: ActionProvisioningHistoricJobsRead,
|
||||
},
|
||||
},
|
||||
},
|
||||
Grants: []string{string(org.RoleAdmin)},
|
||||
}
|
||||
|
||||
return service.DeclareFixedRoles(
|
||||
repositoriesReader,
|
||||
repositoriesWriter,
|
||||
jobsReader,
|
||||
jobsWriter,
|
||||
historicJobsReader,
|
||||
)
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
package provisioning
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/grafana/grafana/pkg/services/accesscontrol"
|
||||
"github.com/grafana/grafana/pkg/services/featuremgmt"
|
||||
"github.com/grafana/grafana/pkg/setting"
|
||||
)
|
||||
|
||||
// DependencyRegisterer is set to satisfy wire gen and make sure the `RegisterDependencies` is called.
|
||||
type DependencyRegisterer struct{}
|
||||
|
||||
func RegisterDependencies(
|
||||
cfg *setting.Cfg,
|
||||
accessControlService accesscontrol.Service,
|
||||
features featuremgmt.FeatureToggles,
|
||||
) (*DependencyRegisterer, error) {
|
||||
if err := registerAccessControlRoles(accessControlService); err != nil {
|
||||
return nil, fmt.Errorf("registering access control roles: %w", err)
|
||||
}
|
||||
|
||||
return &DependencyRegisterer{}, nil
|
||||
}
|
||||
@@ -87,7 +87,8 @@ type APIBuilder struct {
|
||||
// onlyApiServer used to disable starting controllers for the standalone API server.
|
||||
// HACK:This will be removed once we have proper wire providers for the controllers.
|
||||
// TODO: Set this up in the standalone API server
|
||||
onlyApiServer bool
|
||||
onlyApiServer bool
|
||||
useExclusivelyAccessCheckerForAuthz bool
|
||||
|
||||
allowedTargets []provisioning.SyncTargetType
|
||||
allowImageRendering bool
|
||||
@@ -147,6 +148,7 @@ func NewAPIBuilder(
|
||||
minSyncInterval time.Duration,
|
||||
registry prometheus.Registerer,
|
||||
newStandaloneClientFactoryFunc func(loopbackConfigProvider apiserver.RestConfigProvider) resources.ClientFactory, // optional, only used for standalone apiserver
|
||||
useExclusivelyAccessCheckerForAuthz bool,
|
||||
) *APIBuilder {
|
||||
var clients resources.ClientFactory
|
||||
if newStandaloneClientFactoryFunc != nil {
|
||||
@@ -158,26 +160,27 @@ func NewAPIBuilder(
|
||||
resourceLister := resources.NewResourceListerForMigrations(unified, legacyMigrator, storageStatus)
|
||||
|
||||
b := &APIBuilder{
|
||||
onlyApiServer: onlyApiServer,
|
||||
tracer: tracer,
|
||||
usageStats: usageStats,
|
||||
features: features,
|
||||
repoFactory: repoFactory,
|
||||
clients: clients,
|
||||
parsers: parsers,
|
||||
repositoryResources: resources.NewRepositoryResourcesFactory(parsers, clients, resourceLister),
|
||||
resourceLister: resourceLister,
|
||||
legacyMigrator: legacyMigrator,
|
||||
storageStatus: storageStatus,
|
||||
unified: unified,
|
||||
access: access,
|
||||
jobHistoryConfig: jobHistoryConfig,
|
||||
extraWorkers: extraWorkers,
|
||||
restConfigGetter: restConfigGetter,
|
||||
allowedTargets: allowedTargets,
|
||||
allowImageRendering: allowImageRendering,
|
||||
registry: registry,
|
||||
validator: repository.NewValidator(minSyncInterval, allowedTargets, allowImageRendering),
|
||||
onlyApiServer: onlyApiServer,
|
||||
tracer: tracer,
|
||||
usageStats: usageStats,
|
||||
features: features,
|
||||
repoFactory: repoFactory,
|
||||
clients: clients,
|
||||
parsers: parsers,
|
||||
repositoryResources: resources.NewRepositoryResourcesFactory(parsers, clients, resourceLister),
|
||||
resourceLister: resourceLister,
|
||||
legacyMigrator: legacyMigrator,
|
||||
storageStatus: storageStatus,
|
||||
unified: unified,
|
||||
access: access,
|
||||
jobHistoryConfig: jobHistoryConfig,
|
||||
extraWorkers: extraWorkers,
|
||||
restConfigGetter: restConfigGetter,
|
||||
allowedTargets: allowedTargets,
|
||||
allowImageRendering: allowImageRendering,
|
||||
registry: registry,
|
||||
validator: repository.NewValidator(minSyncInterval, allowedTargets, allowImageRendering),
|
||||
useExclusivelyAccessCheckerForAuthz: useExclusivelyAccessCheckerForAuthz,
|
||||
}
|
||||
|
||||
for _, builder := range extraBuilders {
|
||||
@@ -267,6 +270,7 @@ func RegisterAPIService(
|
||||
cfg.ProvisioningMinSyncInterval,
|
||||
reg,
|
||||
nil,
|
||||
false, // TODO: first, test this on the MT side before we enable it by default in ST as well
|
||||
)
|
||||
apiregistration.RegisterAPI(builder)
|
||||
return builder, nil
|
||||
@@ -283,7 +287,9 @@ func (b *APIBuilder) GetAuthorizer() authorizer.Authorizer {
|
||||
}
|
||||
|
||||
info, ok := authlib.AuthInfoFrom(ctx)
|
||||
if ok && authlib.IsIdentityType(info.GetIdentityType(), authlib.TypeAccessPolicy) {
|
||||
// when running as standalone API server, the identity type may not always match TypeAccessPolicy
|
||||
// so we allow it to use the access checker if there is any auth info available
|
||||
if ok && (authlib.IsIdentityType(info.GetIdentityType(), authlib.TypeAccessPolicy) || b.useExclusivelyAccessCheckerForAuthz) {
|
||||
res, err := b.access.Check(ctx, info, authlib.CheckRequest{
|
||||
Verb: a.GetVerb(),
|
||||
Group: a.GetAPIGroup(),
|
||||
@@ -291,6 +297,7 @@ func (b *APIBuilder) GetAuthorizer() authorizer.Authorizer {
|
||||
Name: a.GetName(),
|
||||
Namespace: a.GetNamespace(),
|
||||
Subresource: a.GetSubresource(),
|
||||
Path: a.GetPath(),
|
||||
}, "")
|
||||
if err != nil {
|
||||
return authorizer.DecisionDeny, "failed to perform authorization", err
|
||||
|
||||
@@ -49,6 +49,7 @@ var WireSet = wire.NewSet(
|
||||
// Secrets
|
||||
secret.RegisterDependencies,
|
||||
// Provisioning
|
||||
provisioning.RegisterDependencies,
|
||||
provisioningExtras,
|
||||
|
||||
// Each must be added here *and* in the ServiceSink above
|
||||
|
||||
Reference in New Issue
Block a user