Skip to content

Commit 5ab913b

Browse files
authored
feat(orchestrator): add fine-grained RBAC (#82)
* feat(orchestrator): add fine-grained RBAC The admin can limit access to specific workflows and instances by workflow ID. Signed-off-by: Marek Libra <mlibra@redhat.com> * feat: reduce permissions to workflow and workflow.use * fix GH IDP config * add @backstage-community/plugin-rbac plugin * run prettier * add config for rbac administration * Catch exceptions from internal routes * Add auditLogger for generic router exception handler * Update documentation * Update getInstances() for authorization * yarn.lock * Let data index filter authorized instances * rebuild api reports --------- Signed-off-by: Marek Libra <mlibra@redhat.com>
1 parent d9c0c5f commit 5ab913b

File tree

23 files changed

+1496
-315
lines changed

23 files changed

+1496
-315
lines changed
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
---
2+
'@red-hat-developer-hub/backstage-plugin-orchestrator-backend': minor
3+
'@red-hat-developer-hub/backstage-plugin-orchestrator-common': minor
4+
'@red-hat-developer-hub/backstage-plugin-orchestrator': minor
5+
---
6+
7+
Access can now be managed on a per-workflow basis.

workspaces/orchestrator/README.md

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -175,6 +175,13 @@ yarn dev
175175

176176
The `orchestrator` plugin includes an extensible form for executing forms. For detailed guidance see the [Extensible Workflow Execution Form Documentation](https://github.com/redhat-developer/rhdh-plugins/blob/main/workspaces/orchestrator/plugins/orchestrator/docs/extensibleForm.md).
177177

178+
### Setting up permissions
179+
180+
The HTTP endpoints exposed by the `orchestrator-backend` can enforce authorization if the [RBAC plugin](https://github.com/backstage/community-plugins/tree/main/workspaces/rbac/plugins) is deployed.
181+
Please refer the RBAC plugin documentation for the setup steps (mind they rely on the [Backstage authentication and identity](https://backstage.io/docs/auth)).
182+
183+
More detailed info about permissions can be found in [docs/Permissions.md](docs/Permissions.md).
184+
178185
## For users
179186

180187
### Using the Orchestrator plugin in Backstage

workspaces/orchestrator/app-config.yaml

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -76,14 +76,16 @@ auth:
7676
clientSecret: ${AUTH_GITHUB_CLIENT_SECRET}
7777
signIn:
7878
resolvers:
79-
# See https://backstage.io/docs/auth/github/provider#resolvers for more resolvers
8079
- resolver: emailMatchingUserEntityProfileEmail
8180

8281
# permission:
8382
# enabled: true
8483
# rbac:
85-
# policies-csv-file: /full/path/to/the/rbac-policy.csv
84+
# policies-csv-file: ../../plugins/orchestrator/docs/rbac-policy.csv
8685
# policyFileReload: true
86+
# admin:
87+
# users:
88+
# - name: user:default/mareklibra
8789

8890
scaffolder:
8991
{}

workspaces/orchestrator/packages/app/package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
"lint": "backstage-cli package lint"
2020
},
2121
"dependencies": {
22+
"@backstage-community/plugin-rbac": "^1.33.2",
2223
"@backstage/app-defaults": "^1.5.12",
2324
"@backstage/catalog-model": "^1.7.0",
2425
"@backstage/cli": "^0.28.0",

workspaces/orchestrator/packages/app/src/App.tsx

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,7 @@ import { OrchestratorPage } from '@red-hat-developer-hub/backstage-plugin-orches
4949
import { getThemes } from '@redhat-developer/red-hat-developer-hub-theme';
5050
import { NotificationsPage } from '@backstage/plugin-notifications';
5151
import { SignalsDisplay } from '@backstage/plugin-signals';
52+
import { RbacPage } from '@backstage-community/plugin-rbac';
5253
import React from 'react';
5354
import { Navigate, Route } from 'react-router-dom';
5455
import { apis } from './apis';
@@ -131,6 +132,7 @@ const routes = (
131132
<Route path="/catalog-graph" element={<CatalogGraphPage />} />
132133
<Route path="/notifications" element={<NotificationsPage />} />
133134
<Route path="/orchestrator" element={<OrchestratorPage />} />
135+
<Route path="/rbac" element={<RbacPage />} />
134136
</FlatRoutes>
135137
);
136138

workspaces/orchestrator/packages/app/src/components/Root/Root.tsx

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,7 @@ import SearchIcon from '@mui/icons-material/Search';
4141
import { makeStyles } from '@mui/styles';
4242
import { OrchestratorIcon } from '@red-hat-developer-hub/backstage-plugin-orchestrator';
4343
import { NotificationsSidebarItem } from '@backstage/plugin-notifications';
44+
import { Administration } from '@backstage-community/plugin-rbac';
4445
import React, { PropsWithChildren } from 'react';
4546
import LogoFull from './LogoFull';
4647
import LogoIcon from './LogoIcon';
@@ -111,6 +112,7 @@ export const Root = ({ children }: PropsWithChildren<{}>) => {
111112
</SidebarGroup>
112113
<SidebarSpace />
113114
<SidebarDivider />
115+
<Administration />
114116
<SidebarGroup
115117
label="Settings"
116118
icon={<UserSettingsSignInAvatar />}

workspaces/orchestrator/packages/backend/package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@
2121
"build-image": "docker build ../.. -f Dockerfile --tag backstage"
2222
},
2323
"dependencies": {
24+
"@backstage-community/plugin-rbac-backend": "^5.2.6",
2425
"@backstage/backend-defaults": "^0.5.2",
2526
"@backstage/config": "^1.2.0",
2627
"@backstage/plugin-app-backend": "^0.3.76",

workspaces/orchestrator/packages/backend/src/index.ts

Lines changed: 3 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -38,14 +38,6 @@ backend.add(
3838
// See https://backstage.io/docs/features/software-catalog/configuration#subscribing-to-catalog-errors
3939
backend.add(import('@backstage/plugin-catalog-backend-module-logs'));
4040

41-
// permission plugin
42-
backend.add(import('@backstage/plugin-permission-backend/alpha'));
43-
44-
// See https://backstage.io/docs/permissions/getting-started for how to create your own permission policy
45-
backend.add(
46-
import('@backstage/plugin-permission-backend-module-allow-all-policy'),
47-
);
48-
4941
// search plugin
5042
backend.add(import('@backstage/plugin-search-backend/alpha'));
5143

@@ -64,4 +56,7 @@ backend.add(
6456
backend.add(import('@backstage/plugin-notifications-backend'));
6557
backend.add(import('@backstage/plugin-signals-backend'));
6658

59+
// permission plugin
60+
backend.add(import('@backstage-community/plugin-rbac-backend'));
61+
6762
backend.start();

workspaces/orchestrator/plugins/orchestrator-backend/src/service/OrchestratorService.ts

Lines changed: 9 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,9 @@ export class OrchestratorService {
3636
) {}
3737

3838
// Data Index Service Wrapper
39+
public getWorkflowIds(): string[] {
40+
return this.workflowCacheService.definitionIds;
41+
}
3942

4043
public async abortWorkflowInstance(args: {
4144
instanceId: string;
@@ -70,10 +73,10 @@ export class OrchestratorService {
7073
public async fetchInstances(args: {
7174
pagination?: Pagination;
7275
filter?: Filter;
73-
workflowId?: string;
76+
workflowIds?: string[];
7477
}): Promise<ProcessInstance[]> {
75-
const definitionIds = args.workflowId
76-
? [args.workflowId]
78+
const definitionIds = args.workflowIds
79+
? args.workflowIds
7780
: this.workflowCacheService.definitionIds;
7881
return await this.dataIndexService.fetchInstances({
7982
definitionIds: definitionIds,
@@ -83,11 +86,11 @@ export class OrchestratorService {
8386
}
8487

8588
public async fetchInstancesTotalCount(
86-
workflowId?: string,
89+
workflowIds?: string[],
8790
filter?: Filter,
8891
): Promise<number> {
89-
const definitionIds = workflowId
90-
? [workflowId]
92+
const definitionIds = workflowIds
93+
? workflowIds
9194
: this.workflowCacheService.definitionIds;
9295
return await this.dataIndexService.fetchInstancesTotalCount(
9396
definitionIds,

workspaces/orchestrator/plugins/orchestrator-backend/src/service/api/v2.ts

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -70,6 +70,10 @@ export class V2 {
7070
return result;
7171
}
7272

73+
public getWorkflowIds(): string[] {
74+
return this.orchestratorService.getWorkflowIds();
75+
}
76+
7377
public async getWorkflowOverviewById(
7478
workflowId: string,
7579
): Promise<WorkflowOverviewDTO> {
@@ -105,15 +109,15 @@ export class V2 {
105109
public async getInstances(
106110
pagination?: Pagination,
107111
filter?: Filter,
108-
workflowId?: string,
112+
workflowIds?: string[],
109113
): Promise<ProcessInstanceListResultDTO> {
110114
const instances = await this.orchestratorService.fetchInstances({
111115
pagination,
112116
filter,
113-
workflowId,
117+
workflowIds,
114118
});
115119
const totalCount = await this.orchestratorService.fetchInstancesTotalCount(
116-
workflowId,
120+
workflowIds,
117121
filter,
118122
);
119123

0 commit comments

Comments
 (0)