From: Nizamudeen A Date: Wed, 5 Mar 2025 16:46:03 +0000 (+0530) Subject: mgr/dashboard: fix access control permissions for roles X-Git-Url: http://git-server-git.apps.pok.os.sepia.ceph.com/?a=commitdiff_plain;h=3098aca8ee3e5f373d2a70a872cebb5975a97f40;p=ceph.git mgr/dashboard: fix access control permissions for roles Since prometheus is being used in the dashboard page we need to make sure every role has prometheus read only access so that the dashboard page can load the utilization metrics. I also saw permission issue with the osd settings endpoint when its trying to get the nearfull/full ratio. so instead of failing the entire page i am proceeding with a chart that doesn't have those details when the user doesn't have permission to access the config opt. Multisite page was not accessible in the case of rgw-manager or read-only user because its trying to show the status of rgw module. This si also now gracefully handled to show the alert only when the user has sufficient permission. Fixes: https://tracker.ceph.com/issues/70331 Signed-off-by: Nizamudeen A (cherry picked from commit f4bc03e4040ca32591d9b46b79309b162c3942db) Conflicts: src/pybind/mgr/dashboard/frontend/src/app/ceph/dashboard-v3/dashboard/dashboard-v3.component.ts - kept changes only relavant to bug fix and ignored the other changes like h/w monitoring src/pybind/mgr/dashboard/frontend/src/app/ceph/rgw/rgw-multisite-details/rgw-multisite-details.component.html - ignored multisite wizard changes src/pybind/mgr/dashboard/frontend/src/app/core/navigation/administration/administration.component.html - kept the current changes since carbon is not there in squid which means this issue is not present src/pybind/mgr/dashboard/frontend/src/app/core/navigation/navigation/navigation.component.html - kept the current changes for the same reason above src/pybind/mgr/dashboard/services/access_control.py - ignored the SMB role manager and kept only what's available in squid --- diff --git a/src/pybind/mgr/dashboard/frontend/src/app/ceph/dashboard-v3/dashboard-pie/dashboard-pie.component.ts b/src/pybind/mgr/dashboard/frontend/src/app/ceph/dashboard-v3/dashboard-pie/dashboard-pie.component.ts index b0c253c33e9d..a341599e9ac5 100644 --- a/src/pybind/mgr/dashboard/frontend/src/app/ceph/dashboard-v3/dashboard-pie/dashboard-pie.component.ts +++ b/src/pybind/mgr/dashboard/frontend/src/app/ceph/dashboard-v3/dashboard-pie/dashboard-pie.component.ts @@ -15,9 +15,9 @@ export class DashboardPieComponent implements OnChanges, OnInit { @Input() data: any; @Input() - highThreshold: number; + highThreshold = 0; @Input() - lowThreshold: number; + lowThreshold = 0; color: string; @@ -160,15 +160,15 @@ export class DashboardPieComponent implements OnChanges, OnInit { const percentAvailable = this.calcPercentage(data.max - data.current, data.max); const percentUsed = this.calcPercentage(data.current, data.max); - if (fullRatioPercent >= 0 && percentUsed >= fullRatioPercent) { + if (fullRatioPercent > 0 && percentUsed >= fullRatioPercent) { this.color = 'chart-color-red'; - } else if (nearFullRatioPercent >= 0 && percentUsed >= nearFullRatioPercent) { + } else if (nearFullRatioPercent > 0 && percentUsed >= nearFullRatioPercent) { this.color = 'chart-color-yellow'; } else { this.color = 'chart-color-blue'; } - if (fullRatioPercent >= 0 && nearFullRatioPercent >= 0) { + if (fullRatioPercent > 0 && nearFullRatioPercent > 0) { chart.dataset[0].data = [ Math.round(nearFullRatioPercent), Math.round(Math.abs(nearFullRatioPercent - fullRatioPercent)), diff --git a/src/pybind/mgr/dashboard/frontend/src/app/ceph/dashboard-v3/dashboard/dashboard-v3.component.html b/src/pybind/mgr/dashboard/frontend/src/app/ceph/dashboard-v3/dashboard/dashboard-v3.component.html index ac0110728e38..3b01ad1e381e 100644 --- a/src/pybind/mgr/dashboard/frontend/src/app/ceph/dashboard-v3/dashboard/dashboard-v3.component.html +++ b/src/pybind/mgr/dashboard/frontend/src/app/ceph/dashboard-v3/dashboard/dashboard-v3.component.html @@ -203,7 +203,7 @@ [fullHeight]="true" aria-label="Capacity card"> + *ngIf="capacity"> diff --git a/src/pybind/mgr/dashboard/frontend/src/app/ceph/dashboard-v3/dashboard/dashboard-v3.component.ts b/src/pybind/mgr/dashboard/frontend/src/app/ceph/dashboard-v3/dashboard/dashboard-v3.component.ts index cf6e7116fddb..f43c15cc29e6 100644 --- a/src/pybind/mgr/dashboard/frontend/src/app/ceph/dashboard-v3/dashboard/dashboard-v3.component.ts +++ b/src/pybind/mgr/dashboard/frontend/src/app/ceph/dashboard-v3/dashboard/dashboard-v3.component.ts @@ -23,6 +23,7 @@ import { PrometheusListHelper } from '~/app/shared/helpers/prometheus-list-helpe import { PrometheusAlertService } from '~/app/shared/services/prometheus-alert.service'; import { OrchestratorService } from '~/app/shared/api/orchestrator.service'; import { AlertClass } from '~/app/shared/enum/health-icon.enum'; +import { OsdSettings } from '~/app/shared/models/osd-settings'; @Component({ selector: 'cd-dashboard-v3', @@ -32,7 +33,7 @@ import { AlertClass } from '~/app/shared/enum/health-icon.enum'; export class DashboardV3Component extends PrometheusListHelper implements OnInit, OnDestroy { detailsCardData: DashboardDetails = {}; osdSettingsService: any; - osdSettings: any; + osdSettings = new OsdSettings(); interval = new Subscription(); permissions: Permissions; enabledFeature$: FeatureTogglesMap$; @@ -90,7 +91,8 @@ export class DashboardV3Component extends PrometheusListHelper implements OnInit super.ngOnInit(); this.interval = this.refreshIntervalService.intervalData$.subscribe(() => { this.getHealth(); - this.getCapacityCardData(); + this.getCapacity(); + if (this.permissions.configOpt.read) this.getOsdSettings(); }); this.getPrometheusData(this.prometheusService.lastHourDateObject); this.getDetailsCardData(); @@ -136,16 +138,19 @@ export class DashboardV3Component extends PrometheusListHelper implements OnInit ); } - getCapacityCardData() { + private getCapacity() { + this.capacityService = this.healthService.getClusterCapacity().subscribe((data: any) => { + this.capacity = data; + }); + } + + private getOsdSettings() { this.osdSettingsService = this.osdService .getOsdSettings() .pipe(take(1)) - .subscribe((data: any) => { + .subscribe((data: OsdSettings) => { this.osdSettings = data; }); - this.capacityService = this.healthService.getClusterCapacity().subscribe((data: any) => { - this.capacity = data; - }); } public getPrometheusData(selectedTime: any) { diff --git a/src/pybind/mgr/dashboard/frontend/src/app/ceph/rgw/rgw-multisite-details/rgw-multisite-details.component.html b/src/pybind/mgr/dashboard/frontend/src/app/ceph/rgw/rgw-multisite-details/rgw-multisite-details.component.html index 3e7ac5eb8b67..4b3576b2c310 100644 --- a/src/pybind/mgr/dashboard/frontend/src/app/ceph/rgw/rgw-multisite-details/rgw-multisite-details.component.html +++ b/src/pybind/mgr/dashboard/frontend/src/app/ceph/rgw/rgw-multisite-details/rgw-multisite-details.component.html @@ -1,6 +1,7 @@
- + Services diff --git a/src/pybind/mgr/dashboard/frontend/src/app/ceph/rgw/rgw-multisite-details/rgw-multisite-details.component.ts b/src/pybind/mgr/dashboard/frontend/src/app/ceph/rgw/rgw-multisite-details/rgw-multisite-details.component.ts index 455dcebf91b8..b05112863a8a 100644 --- a/src/pybind/mgr/dashboard/frontend/src/app/ceph/rgw/rgw-multisite-details/rgw-multisite-details.component.ts +++ b/src/pybind/mgr/dashboard/frontend/src/app/ceph/rgw/rgw-multisite-details/rgw-multisite-details.component.ts @@ -19,7 +19,7 @@ import { Icons } from '~/app/shared/enum/icons.enum'; import { NotificationType } from '~/app/shared/enum/notification-type.enum'; import { CdTableAction } from '~/app/shared/models/cd-table-action'; import { CdTableSelection } from '~/app/shared/models/cd-table-selection'; -import { Permission } from '~/app/shared/models/permissions'; +import { Permissions } from '~/app/shared/models/permissions'; import { AuthStorageService } from '~/app/shared/services/auth-storage.service'; import { ModalService } from '~/app/shared/services/modal.service'; import { NotificationService } from '~/app/shared/services/notification.service'; @@ -61,7 +61,7 @@ export class RgwMultisiteDetailsComponent implements OnDestroy, OnInit { blockUI: NgBlockUI; icons = Icons; - permission: Permission; + permissions: Permissions; selection = new CdTableSelection(); createTableActions: CdTableAction[]; migrateTableAction: CdTableAction[]; @@ -117,7 +117,7 @@ export class RgwMultisiteDetailsComponent implements OnDestroy, OnInit { public mgrModuleService: MgrModuleService, private notificationService: NotificationService ) { - this.permission = this.authStorageService.getPermissions().rgw; + this.permissions = this.authStorageService.getPermissions(); } openModal(entity: any, edit = false) { @@ -263,22 +263,17 @@ export class RgwMultisiteDetailsComponent implements OnDestroy, OnInit { }, (_error) => {} ); - this.mgrModuleService.list().subscribe((moduleData: any) => { - this.rgwModuleData = moduleData.filter((module: object) => module['name'] === 'rgw'); - if (this.rgwModuleData.length > 0) { - this.rgwModuleStatus = this.rgwModuleData[0].enabled; - } - }); + + // Only get the module status if you can read from configOpt + if (this.permissions.configOpt.read) { + this.mgrModuleService.list().subscribe((moduleData: any) => { + this.rgwModuleData = moduleData.filter((module: object) => module['name'] === 'rgw'); + if (this.rgwModuleData.length > 0) { + this.rgwModuleStatus = this.rgwModuleData[0].enabled; + } + }); + } } - /* setConfigValues() { - this.rgwDaemonService - .setMultisiteConfig( - this.defaultsInfo['defaultRealmName'], - this.defaultsInfo['defaultZonegroupName'], - this.defaultsInfo['defaultZoneName'] - ) - .subscribe(() => {}); - }*/ ngOnDestroy() { this.sub.unsubscribe(); diff --git a/src/pybind/mgr/dashboard/services/access_control.py b/src/pybind/mgr/dashboard/services/access_control.py index 01d0557740b0..6ca5505e6d28 100644 --- a/src/pybind/mgr/dashboard/services/access_control.py +++ b/src/pybind/mgr/dashboard/services/access_control.py @@ -223,6 +223,7 @@ BLOCK_MGR_ROLE = Role( Scope.RBD_MIRRORING: [_P.READ, _P.CREATE, _P.UPDATE, _P.DELETE], Scope.GRAFANA: [_P.READ], Scope.NVME_OF: [_P.READ, _P.CREATE, _P.UPDATE, _P.DELETE], + Scope.PROMETHEUS: [_P.READ] }) @@ -231,6 +232,7 @@ RGW_MGR_ROLE = Role( 'rgw-manager', 'allows full permissions for the rgw scope', { Scope.RGW: [_P.READ, _P.CREATE, _P.UPDATE, _P.DELETE], Scope.GRAFANA: [_P.READ], + Scope.PROMETHEUS: [_P.READ] }) @@ -255,6 +257,7 @@ POOL_MGR_ROLE = Role( 'pool-manager', 'allows full permissions for the pool scope', { Scope.POOL: [_P.READ, _P.CREATE, _P.UPDATE, _P.DELETE], Scope.GRAFANA: [_P.READ], + Scope.PROMETHEUS: [_P.READ] }) # CephFS manager role provides all permissions for CephFS related scopes @@ -262,6 +265,7 @@ CEPHFS_MGR_ROLE = Role( 'cephfs-manager', 'allows full permissions for the cephfs scope', { Scope.CEPHFS: [_P.READ, _P.CREATE, _P.UPDATE, _P.DELETE], Scope.GRAFANA: [_P.READ], + Scope.PROMETHEUS: [_P.READ] }) GANESHA_MGR_ROLE = Role( @@ -270,6 +274,7 @@ GANESHA_MGR_ROLE = Role( Scope.CEPHFS: [_P.READ, _P.CREATE, _P.UPDATE, _P.DELETE], Scope.RGW: [_P.READ, _P.CREATE, _P.UPDATE, _P.DELETE], Scope.GRAFANA: [_P.READ], + Scope.PROMETHEUS: [_P.READ] })