From 47154c8ddba679fe2d42348f5db8cb4f417e1244 Mon Sep 17 00:00:00 2001 From: Jamie Klassen Date: Tue, 4 Jul 2023 17:57:03 -0400 Subject: [PATCH] proxy only adds auth header with nonempty token Signed-off-by: Jamie Klassen --- .changeset/shiny-meals-chew.md | 6 ++++ .../src/service/KubernetesProxy.test.ts | 20 +++++++------ .../src/service/KubernetesProxy.ts | 30 ++++++++++--------- 3 files changed, 33 insertions(+), 23 deletions(-) create mode 100644 .changeset/shiny-meals-chew.md diff --git a/.changeset/shiny-meals-chew.md b/.changeset/shiny-meals-chew.md new file mode 100644 index 0000000000..b1763a610f --- /dev/null +++ b/.changeset/shiny-meals-chew.md @@ -0,0 +1,6 @@ +--- +'@backstage/plugin-kubernetes-backend': patch +--- + +Fixed a bug where the proxy endpoint would error when used in combination with +a local kubectl proxy process and a token-based auth strategy on-cluster. diff --git a/plugins/kubernetes-backend/src/service/KubernetesProxy.test.ts b/plugins/kubernetes-backend/src/service/KubernetesProxy.test.ts index 038a3d4bad..0bbd2d167e 100644 --- a/plugins/kubernetes-backend/src/service/KubernetesProxy.test.ts +++ b/plugins/kubernetes-backend/src/service/KubernetesProxy.test.ts @@ -548,15 +548,17 @@ describe('KubernetesProxy', () => { }); worker.use( - rest.get('http://localhost:8001/api/v1/namespaces', (_req, res, ctx) => { - return res( - ctx.status(200), - ctx.json({ - kind: 'NamespaceList', - apiVersion: 'v1', - items: [], - }), - ); + rest.get('http://localhost:8001/api/v1/namespaces', (req, res, ctx) => { + return req.headers.get('Authorization') + ? res(ctx.status(401)) + : res( + ctx.status(200), + ctx.json({ + kind: 'NamespaceList', + apiVersion: 'v1', + items: [], + }), + ); }), ); diff --git a/plugins/kubernetes-backend/src/service/KubernetesProxy.ts b/plugins/kubernetes-backend/src/service/KubernetesProxy.ts index 36617bbbad..cf3009b5c9 100644 --- a/plugins/kubernetes-backend/src/service/KubernetesProxy.ts +++ b/plugins/kubernetes-backend/src/service/KubernetesProxy.ts @@ -93,14 +93,12 @@ export class KubernetesProxy { ): RequestHandler { const { permissionApi } = options; return async (req, res, next) => { - const token = getBearerTokenFromAuthorizationHeader( - req.header('authorization'), - ); - const authorizeResponse = await permissionApi.authorize( [{ permission: kubernetesProxyPermission }], { - token, + token: getBearerTokenFromAuthorizationHeader( + req.header('authorization'), + ), }, ); const auth = authorizeResponse[0]; @@ -110,15 +108,19 @@ export class KubernetesProxy { return; } - req.headers.authorization = - req.header(HEADER_KUBERNETES_AUTH) ?? - `Bearer ${ - ( - await this.getClusterForRequest(req).then(cd => - this.authTranslator.decorateClusterDetailsWithAuth(cd, {}), - ) - ).serviceAccountToken - }`; + const authHeader = req.header(HEADER_KUBERNETES_AUTH); + if (authHeader) { + req.headers.authorization = authHeader; + } else { + const { serviceAccountToken } = await this.getClusterForRequest( + req, + ).then(cd => + this.authTranslator.decorateClusterDetailsWithAuth(cd, {}), + ); + if (serviceAccountToken) { + req.headers.authorization = `Bearer ${serviceAccountToken}`; + } + } const middleware = await this.getMiddleware(req); middleware(req, res, next);