From 73115bcc898254fa4d97198331cdd450c71672be Mon Sep 17 00:00:00 2001 From: Dominika Zemanovicova Date: Fri, 22 Nov 2024 10:36:10 +0100 Subject: [PATCH] Split resource permission Signed-off-by: Dominika Zemanovicova --- .changeset/real-foxes-film.md | 4 +++- .../src/auth/requirePermission.ts | 9 ++++++--- .../src/routes/resourcesRoutes.ts | 15 ++++++++++++-- .../src/service/KubernetesBuilder.test.ts | 2 ++ .../src/service/KubernetesBuilder.ts | 16 +++++++++++++-- plugins/kubernetes-common/report.api.md | 6 ++++++ plugins/kubernetes-common/src/index.ts | 2 ++ plugins/kubernetes-common/src/permissions.ts | 20 ++++++++++++++++++- 8 files changed, 65 insertions(+), 9 deletions(-) diff --git a/.changeset/real-foxes-film.md b/.changeset/real-foxes-film.md index 757146d624..750db7e175 100644 --- a/.changeset/real-foxes-film.md +++ b/.changeset/real-foxes-film.md @@ -3,4 +3,6 @@ '@backstage/plugin-kubernetes-common': minor --- -Introduced resource permission type to be used with the kubernetes endpoint's permission framework integration for all endpoints except the proxy endpoints. +The `/clusters` endpoint is now protected by the `kubernetes.cluster` permission. +The `/services` endpoint is now protected by the `kubernetes.service` permission. +The `/resources` endpoints are now protected by the `kubernetes.resource` permission. diff --git a/plugins/kubernetes-backend/src/auth/requirePermission.ts b/plugins/kubernetes-backend/src/auth/requirePermission.ts index 8f0463bd5b..9934ed653d 100644 --- a/plugins/kubernetes-backend/src/auth/requirePermission.ts +++ b/plugins/kubernetes-backend/src/auth/requirePermission.ts @@ -19,13 +19,16 @@ import type { PermissionsService, } from '@backstage/backend-plugin-api'; import { NotAllowedError } from '@backstage/errors'; -import { kubernetesResourcePermission } from '@backstage/plugin-kubernetes-common'; -import { AuthorizeResult } from '@backstage/plugin-permission-common'; +import { + AuthorizeResult, + type BasicPermission, +} from '@backstage/plugin-permission-common'; import express from 'express'; export async function requirePermission( permissionApi: PermissionsService, + permissionRequired: BasicPermission, httpAuth: HttpAuthService, req: express.Request, ) { @@ -33,7 +36,7 @@ export async function requirePermission( await permissionApi.authorize( [ { - permission: kubernetesResourcePermission, + permission: permissionRequired, }, ], { diff --git a/plugins/kubernetes-backend/src/routes/resourcesRoutes.ts b/plugins/kubernetes-backend/src/routes/resourcesRoutes.ts index 091080bdcc..ab3c7d8e06 100644 --- a/plugins/kubernetes-backend/src/routes/resourcesRoutes.ts +++ b/plugins/kubernetes-backend/src/routes/resourcesRoutes.ts @@ -25,6 +25,7 @@ import { KubernetesObjectsProvider } from '@backstage/plugin-kubernetes-node'; import { AuthService, HttpAuthService } from '@backstage/backend-plugin-api'; import { PermissionEvaluator } from '@backstage/plugin-permission-common'; import { requirePermission } from '../auth/requirePermission'; +import { kubernetesResourcePermission } from '@backstage/plugin-kubernetes-common'; export const addResourceRoutesToRouter = ( router: express.Router, @@ -65,7 +66,12 @@ export const addResourceRoutesToRouter = ( }; router.post('/resources/workloads/query', async (req, res) => { - await requirePermission(permissionApi, httpAuth, req); + await requirePermission( + permissionApi, + kubernetesResourcePermission, + httpAuth, + req, + ); const entity = await getEntityByReq(req); const response = await objectsProvider.getKubernetesObjectsByEntity( { @@ -78,7 +84,12 @@ export const addResourceRoutesToRouter = ( }); router.post('/resources/custom/query', async (req, res) => { - await requirePermission(permissionApi, httpAuth, req); + await requirePermission( + permissionApi, + kubernetesResourcePermission, + httpAuth, + req, + ); const entity = await getEntityByReq(req); if (!req.body.customResources) { diff --git a/plugins/kubernetes-backend/src/service/KubernetesBuilder.test.ts b/plugins/kubernetes-backend/src/service/KubernetesBuilder.test.ts index 8669299d2e..84de5d5575 100644 --- a/plugins/kubernetes-backend/src/service/KubernetesBuilder.test.ts +++ b/plugins/kubernetes-backend/src/service/KubernetesBuilder.test.ts @@ -796,6 +796,8 @@ metadata: permissions: [ { type: 'basic', name: 'kubernetes.proxy', attributes: {} }, { type: 'basic', name: 'kubernetes.resource', attributes: {} }, + { type: 'basic', name: 'kubernetes.service', attributes: {} }, + { type: 'basic', name: 'kubernetes.cluster', attributes: {} }, ], rules: [], }); diff --git a/plugins/kubernetes-backend/src/service/KubernetesBuilder.ts b/plugins/kubernetes-backend/src/service/KubernetesBuilder.ts index ea5c725d8f..ed864dcf60 100644 --- a/plugins/kubernetes-backend/src/service/KubernetesBuilder.ts +++ b/plugins/kubernetes-backend/src/service/KubernetesBuilder.ts @@ -18,7 +18,9 @@ import { Config } from '@backstage/config'; import { ANNOTATION_KUBERNETES_AUTH_PROVIDER, ANNOTATION_KUBERNETES_OIDC_TOKEN_PROVIDER, + kubernetesClusterPermission, kubernetesPermissions, + kubernetesServicePermission, } from '@backstage/plugin-kubernetes-common'; import { PermissionEvaluator } from '@backstage/plugin-permission-common'; import { createPermissionIntegrationRouter } from '@backstage/plugin-permission-node'; @@ -394,7 +396,12 @@ export class KubernetesBuilder { ); // @deprecated router.post('/services/:serviceId', async (req, res) => { - await requirePermission(permissionApi, httpAuth, req); + await requirePermission( + permissionApi, + kubernetesServicePermission, + httpAuth, + req, + ); const serviceId = req.params.serviceId; const requestBody: ObjectsByEntityRequest = req.body; try { @@ -415,7 +422,12 @@ export class KubernetesBuilder { }); router.get('/clusters', async (req, res) => { - await requirePermission(permissionApi, httpAuth, req); + await requirePermission( + permissionApi, + kubernetesClusterPermission, + httpAuth, + req, + ); const credentials = await httpAuth.credentials(req); const clusterDetails = await this.fetchClusterDetails(clusterSupplier, { credentials, diff --git a/plugins/kubernetes-common/report.api.md b/plugins/kubernetes-common/report.api.md index b40ae89c82..bc953c9781 100644 --- a/plugins/kubernetes-common/report.api.md +++ b/plugins/kubernetes-common/report.api.md @@ -317,6 +317,9 @@ export interface JobsFetchResponse { type: 'jobs'; } +// @public +export const kubernetesClusterPermission: BasicPermission; + // @public (undocumented) export type KubernetesErrorTypes = | 'BAD_REQUEST' @@ -350,6 +353,9 @@ export interface KubernetesRequestBody { // @public export const kubernetesResourcePermission: BasicPermission; +// @public +export const kubernetesServicePermission: BasicPermission; + // @public (undocumented) export interface LimitRangeFetchResponse { // (undocumented) diff --git a/plugins/kubernetes-common/src/index.ts b/plugins/kubernetes-common/src/index.ts index 76a4c0b7e7..43a0500a9c 100644 --- a/plugins/kubernetes-common/src/index.ts +++ b/plugins/kubernetes-common/src/index.ts @@ -25,7 +25,9 @@ export * from './catalog-entity-constants'; export * from './certificate-authority-constants'; export { kubernetesProxyPermission, + kubernetesClusterPermission, kubernetesResourcePermission, + kubernetesServicePermission, kubernetesPermissions, } from './permissions'; export * from './error-detection'; diff --git a/plugins/kubernetes-common/src/permissions.ts b/plugins/kubernetes-common/src/permissions.ts index 928b5c7d06..c96c183af6 100644 --- a/plugins/kubernetes-common/src/permissions.ts +++ b/plugins/kubernetes-common/src/permissions.ts @@ -24,7 +24,7 @@ export const kubernetesProxyPermission = createPermission({ attributes: {}, }); -/** This permission is used to check access to the resources endpoints +/** This permission is used to check access to the /resources endpoints * @public */ export const kubernetesResourcePermission = createPermission({ @@ -32,6 +32,22 @@ export const kubernetesResourcePermission = createPermission({ attributes: {}, }); +/** This permission is used to check access to the /services endpoint + * @public + */ +export const kubernetesServicePermission = createPermission({ + name: 'kubernetes.service', + attributes: {}, +}); + +/** This permission is used to check access to the /clusters endpoint + * @public + */ +export const kubernetesClusterPermission = createPermission({ + name: 'kubernetes.cluster', + attributes: {}, +}); + /** * List of all Kubernetes permissions. * @public @@ -39,4 +55,6 @@ export const kubernetesResourcePermission = createPermission({ export const kubernetesPermissions = [ kubernetesProxyPermission, kubernetesResourcePermission, + kubernetesServicePermission, + kubernetesClusterPermission, ];