AuthZ: Redirect legacy resource permissions handler to k8s (part II) (#114356)

* move restconfig to options

* Add K8s API redirects for write operations

* Revert restConfigProvider changes to receivers, service accounts, and teams

* discard changing team permissions

* lint

* cleanup

* trigger build

* address feedback

* improve test coverage

* lint

* trigger build

* refactor
This commit is contained in:
mohammad-hamid
2025-12-16 11:43:03 -05:00
committed by GitHub
parent ad7e066703
commit 482bb6a2fb
3 changed files with 499 additions and 4 deletions
@@ -33,6 +33,7 @@ type api struct {
permissions []string
features featuremgmt.FeatureToggles
restConfigProvider apiserver.RestConfigProvider
logger log.Logger
}
func newApi(cfg *setting.Cfg, ac accesscontrol.AccessControl, router routing.RouteRegister, manager *Service, features featuremgmt.FeatureToggles, restConfigProvider apiserver.RestConfigProvider) *api {
@@ -41,7 +42,23 @@ func newApi(cfg *setting.Cfg, ac accesscontrol.AccessControl, router routing.Rou
for i := len(manager.permissions) - 1; i >= 0; i-- {
permissions = append(permissions, manager.permissions[i])
}
return &api{cfg, ac, router, manager, permissions, features, restConfigProvider}
return &api{
cfg: cfg,
ac: ac,
router: router,
service: manager,
permissions: permissions,
features: features,
restConfigProvider: restConfigProvider,
logger: log.New("resource-permissions-api"),
}
}
// shouldUseK8sAPIs returns true if both feature flags for K8s API redirect are enabled
func (a *api) shouldUseK8sAPIs() bool {
//nolint:staticcheck // not yet migrated to OpenFeature
return a.features.IsEnabledGlobally(featuremgmt.FlagKubernetesAuthZHandlerRedirect) &&
a.features.IsEnabledGlobally(featuremgmt.FlagKubernetesAuthzResourcePermissionApis)
}
func (a *api) registerEndpoints() {
@@ -189,11 +206,10 @@ func (a *api) getPermissions(c *contextmodel.ReqContext) response.Response {
return response.JSON(http.StatusOK, k8sPermissions)
}
span.RecordError(err)
logger := log.New("resource-permissions-api")
if errors.Is(err, ErrRestConfigNotAvailable) {
logger.Debug("k8s API not available for resource permissions, falling back to legacy", "error", err, "resourceID", resourceID, "resource", a.service.options.Resource)
a.logger.Debug("k8s API not available for resource permissions, falling back to legacy", "error", err, "resourceID", resourceID, "resource", a.service.options.Resource)
} else {
logger.Warn("Failed to get resource permissions from k8s API, falling back to legacy", "error", err, "resourceID", resourceID, "resource", a.service.options.Resource)
a.logger.Warn("Failed to get resource permissions from k8s API, falling back to legacy", "error", err, "resourceID", resourceID, "resource", a.service.options.Resource)
}
}
@@ -304,6 +320,19 @@ func (a *api) setUserPermission(c *contextmodel.ReqContext) response.Response {
return response.Error(http.StatusBadRequest, "bad request data", err)
}
if a.shouldUseK8sAPIs() {
err := a.setUserPermissionToK8s(c.Req.Context(), c.Namespace, resourceID, userID, cmd.Permission)
if err == nil {
return permissionSetResponse(cmd)
}
span.RecordError(err)
if errors.Is(err, ErrRestConfigNotAvailable) {
a.logger.Debug("k8s API not available for resource permissions, falling back to legacy", "error", err, "resourceID", resourceID, "resource", a.service.options.Resource)
} else {
a.logger.Warn("Failed to set user permission in k8s API, falling back to legacy", "error", err, "resourceID", resourceID, "resource", a.service.options.Resource)
}
}
_, err = a.service.SetUserPermission(c.Req.Context(), c.GetOrgID(), accesscontrol.User{ID: userID}, resourceID, cmd.Permission)
if err != nil {
return response.Err(err)
@@ -361,6 +390,19 @@ func (a *api) setTeamPermission(c *contextmodel.ReqContext) response.Response {
return response.Error(http.StatusBadRequest, "bad request data", err)
}
if a.shouldUseK8sAPIs() {
err := a.setTeamPermissionToK8s(c.Req.Context(), c.Namespace, resourceID, teamID, cmd.Permission)
if err == nil {
return permissionSetResponse(cmd)
}
span.RecordError(err)
if errors.Is(err, ErrRestConfigNotAvailable) {
a.logger.Debug("k8s API not available for resource permissions, falling back to legacy", "error", err, "resourceID", resourceID, "resource", a.service.options.Resource)
} else {
a.logger.Warn("Failed to set team permission in k8s API, falling back to legacy", "error", err, "resourceID", resourceID, "resource", a.service.options.Resource)
}
}
_, err = a.service.SetTeamPermission(c.Req.Context(), c.GetOrgID(), teamID, resourceID, cmd.Permission)
if err != nil {
return response.Err(err)
@@ -415,6 +457,17 @@ func (a *api) setBuiltinRolePermission(c *contextmodel.ReqContext) response.Resp
return response.Error(http.StatusBadRequest, "bad request data", err)
}
if a.shouldUseK8sAPIs() {
err := a.setBuiltInRolePermissionToK8s(c.Req.Context(), c.Namespace, resourceID, builtInRole, cmd.Permission)
if err == nil {
return permissionSetResponse(cmd)
}
span.RecordError(err)
if errors.Is(err, ErrRestConfigNotAvailable) {
a.logger.Debug("k8s API not available for resource permissions, falling back to legacy", "error", err, "resourceID", resourceID, "resource", a.service.options.Resource)
}
}
_, err := a.service.SetBuiltInRolePermission(c.Req.Context(), c.GetOrgID(), builtInRole, resourceID, cmd.Permission)
if err != nil {
return response.Err(err)
@@ -463,6 +516,17 @@ func (a *api) setPermissions(c *contextmodel.ReqContext) response.Response {
return response.Error(http.StatusBadRequest, "Bad request data: "+err.Error(), err)
}
if a.shouldUseK8sAPIs() {
err := a.setResourcePermissionsToK8s(c.Req.Context(), c.Namespace, resourceID, cmd.Permissions)
if err == nil {
return response.Success("Permissions updated")
}
span.RecordError(err)
if errors.Is(err, ErrRestConfigNotAvailable) {
a.logger.Debug("k8s API not available for resource permissions, falling back to legacy", "error", err, "resourceID", resourceID, "resource", a.service.options.Resource)
}
}
_, err := a.service.SetPermissions(ctx, c.GetOrgID(), resourceID, cmd.Permissions...)
if err != nil {
return response.Err(err)