From 77c972d27e3fd3b0c70937c226c4971fa36c89f7 Mon Sep 17 00:00:00 2001 From: reggie-k Date: Wed, 13 Jul 2022 19:08:29 +0300 Subject: [PATCH] fix: UI part for logs RBAC - do not display the logs tab when no RBAC in place (#7211) (#9828) * show logs tab only upon explicit rbac allow policy Signed-off-by: reggie-k * 2.4.7 docs edit Signed-off-by: reggie-k --- CHANGELOG.md | 8 ++- docs/operator-manual/upgrading/2.3-2.4.md | 8 ++- .../resource-details/resource-details.tsx | 68 +++++++++++-------- .../app/shared/services/accounts-service.ts | 4 ++ 4 files changed, 56 insertions(+), 32 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 83a83fc3f4e41..77726bea826bb 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -13,9 +13,13 @@ commands, and helps to troubleshoot the application state. Argo CD is used to manage the critical infrastructure of multiple organizations, which makes security the top priority of the project. We've listened to your feedback and introduced additional access control settings that control access to Kubernetes Pod logs and the new Web Terminal feature. -#### Known UI Issue for Pod Logs Access +#### Pod Logs UI -Currently, upon pressing the "LOGS" tab in pod view by users who don't have an explicit allow get logs policy, the red "unable to load data: Internal error" is received in the bottom of the screen, and "Failed to load data, please try again" is displayed. +Since 2.4.7, the LOGS tab in pod view is visible in the UI only for users with explicit allow get logs policy. + +#### Known pod logs UI issue prior to 2.4.7 + +Upon pressing the "LOGS" tab in pod view by users who don't have an explicit allow get logs policy, the red "unable to load data: Internal error" is received in the bottom of the screen, and "Failed to load data, please try again" is displayed. ### OpenTelemetry Tracing Integration diff --git a/docs/operator-manual/upgrading/2.3-2.4.md b/docs/operator-manual/upgrading/2.3-2.4.md index 590b61642a1d7..a57ae8ea8f8aa 100644 --- a/docs/operator-manual/upgrading/2.3-2.4.md +++ b/docs/operator-manual/upgrading/2.3-2.4.md @@ -151,9 +151,13 @@ p, role:test-db-admins, applications, *, staging-db-admins/*, allow p, role:test-db-admins, logs, get, staging-db-admins/*, allow ``` -## Known UI issue +### Pod Logs UI -Currently, upon pressing the "LOGS" tab in pod view by users who don't have an explicit allow get logs policy, the red "unable to load data: Internal error" is received in the bottom of the screen, and "Failed to load data, please try again" is displayed. +Since 2.4.7, the LOGS tab in pod view is visible in the UI only for users with explicit allow get logs policy. + +### Known pod logs UI issue prior to 2.4.7 + +Upon pressing the "LOGS" tab in pod view by users who don't have an explicit allow get logs policy, the red "unable to load data: Internal error" is received in the bottom of the screen, and "Failed to load data, please try again" is displayed. ## Test repo-server with its new dedicated Service Account diff --git a/ui/src/app/applications/components/resource-details/resource-details.tsx b/ui/src/app/applications/components/resource-details/resource-details.tsx index 04c8a4453f52f..53d4ff46b6db6 100644 --- a/ui/src/app/applications/components/resource-details/resource-details.tsx +++ b/ui/src/app/applications/components/resource-details/resource-details.tsx @@ -42,7 +42,16 @@ export const ResourceDetails = (props: ResourceDetailsProps) => { const page = parseInt(new URLSearchParams(appContext.history.location.search).get('page'), 10) || 0; const untilTimes = (new URLSearchParams(appContext.history.location.search).get('untilTimes') || '').split(',') || []; - const getResourceTabs = (node: ResourceNode, state: State, podState: State, events: Event[], extensionTabs: ResourceTabExtension[], tabs: Tab[], execEnabled: boolean) => { + const getResourceTabs = ( + node: ResourceNode, + state: State, + podState: State, + events: Event[], + extensionTabs: ResourceTabExtension[], + tabs: Tab[], + execEnabled: boolean, + logsAllowed: boolean + ) => { if (!node || node === undefined) { return []; } @@ -78,30 +87,32 @@ export const ResourceDetails = (props: ResourceDetailsProps) => { const onClickContainer = (group: any, i: number) => SelectNode(selectedNodeKey, group.offset + i, 'logs', appContext); - tabs = tabs.concat([ - { - key: 'logs', - icon: 'fa fa-align-left', - title: 'LOGS', - content: ( -
- appContext.navigation.goto('.', {page: pageData.number, untilTimes: pageData.untilTimes.join(',')})} - containerGroups={containerGroups} - onClickContainer={onClickContainer} - /> -
- ) - } - ]); + if (logsAllowed) { + tabs = tabs.concat([ + { + key: 'logs', + icon: 'fa fa-align-left', + title: 'LOGS', + content: ( +
+ appContext.navigation.goto('.', {page: pageData.number, untilTimes: pageData.untilTimes.join(',')})} + containerGroups={containerGroups} + onClickContainer={onClickContainer} + /> +
+ ) + } + ]); + } if (execEnabled) { tabs = tabs.concat([ { @@ -258,8 +269,8 @@ export const ResourceDetails = (props: ResourceDetailsProps) => { const settings = await services.authService.settings(); const execEnabled = settings.execEnabled; - - return {controlledState, liveState, events, podState, execEnabled}; + const logsAllowed = await services.accounts.canI('logs', 'get', application.spec.project + '/' + application.metadata.name); + return {controlledState, liveState, events, podState, execEnabled, logsAllowed}; }}> {data => ( @@ -303,7 +314,8 @@ export const ResourceDetails = (props: ResourceDetailsProps) => { content: } ], - data.execEnabled + data.execEnabled, + data.logsAllowed )} selectedTabKey={props.tab} onTabSelected={selected => appContext.navigation.goto('.', {tab: selected}, {replace: true})} diff --git a/ui/src/app/shared/services/accounts-service.ts b/ui/src/app/shared/services/accounts-service.ts index 8820fa46dd697..008505a63714a 100644 --- a/ui/src/app/shared/services/accounts-service.ts +++ b/ui/src/app/shared/services/accounts-service.ts @@ -27,4 +27,8 @@ export class AccountsService { public deleteToken(name: string, id: string): Promise { return requests.delete(`/account/${name}/token/${id}`); } + + public canI(resource: string, action: string, subresource: string): Promise { + return requests.get(`/account/can-i/${resource}/${action}/${subresource}`).then(res => res.body.value === 'yes'); + } }