Merge pull request #19952 from luchillo17/fix/BCKSTG-287-k8sproxy-web-socket-fails-on-

fix: Handle Proxy WS upgrade manually for WS handshakes
This commit is contained in:
Jamie Klassen
2023-09-18 17:44:46 -04:00
committed by GitHub
6 changed files with 23 additions and 15 deletions
+1 -1
View File
@@ -18,7 +18,7 @@ import { Logger } from 'winston';
import type { ObjectsByEntityResponse } from '@backstage/plugin-kubernetes-common';
import { PermissionEvaluator } from '@backstage/plugin-permission-common';
import { PluginEndpointDiscovery } from '@backstage/backend-common';
import type { RequestHandler } from 'express';
import { RequestHandler } from 'http-proxy-middleware';
import { TokenCredential } from '@azure/identity';
// @public (undocumented)
+1 -2
View File
@@ -68,6 +68,7 @@
"@jest-mock/express": "^2.0.1",
"@kubernetes/client-node": "0.18.1",
"@types/express": "^4.17.6",
"@types/http-proxy-middleware": "^0.19.3",
"@types/luxon": "^3.0.0",
"compression": "^1.7.4",
"cors": "^2.8.5",
@@ -88,8 +89,6 @@
"@backstage/backend-test-utils": "workspace:^",
"@backstage/cli": "workspace:^",
"@types/aws4": "^1.5.1",
"@types/http-proxy-middleware": "^0.19.3",
"cross-fetch": "^3.1.5",
"mock-fs": "^5.2.0",
"msw": "^1.0.0",
"supertest": "^6.1.3",
@@ -46,7 +46,6 @@ import {
HEADER_KUBERNETES_CLUSTER,
KubernetesProxy,
} from './KubernetesProxy';
import fetch from 'cross-fetch';
import type { Request } from 'express';
@@ -757,7 +756,6 @@ describe('KubernetesProxy', () => {
const wsProxyAddress = `ws://127.0.0.1:${proxyPort}${proxyPath}${wsPath}`;
const wsAddress = `ws://localhost:${wsPort}${wsPath}`;
console.log('Ports: ', wsProxyAddress, wsAddress);
// Let this request through so it reaches the express router above
worker.use(
@@ -769,10 +767,6 @@ describe('KubernetesProxy', () => {
),
);
// Prepopulate the proxy so the WebSocket upgrade can happen, result doesn't actually matter
const result = await fetch(wsProxyAddress.replace('ws', 'http'));
expect(result.ok).toBeFalsy();
const webSocket = new WebSocket(wsProxyAddress);
const connectMessagePromise = eventPromiseFactory(webSocket, 'message');
@@ -13,7 +13,6 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import {
ErrorResponseBody,
ForwardedError,
@@ -24,16 +23,18 @@ import {
import { getBearerTokenFromAuthorizationHeader } from '@backstage/plugin-auth-node';
import { kubernetesProxyPermission } from '@backstage/plugin-kubernetes-common';
import {
PermissionEvaluator,
AuthorizeResult,
PermissionEvaluator,
} from '@backstage/plugin-permission-common';
import { bufferFromFileOrString } from '@kubernetes/client-node';
import type { Request, RequestHandler } from 'express';
import { createProxyMiddleware } from 'http-proxy-middleware';
import { createProxyMiddleware, RequestHandler } from 'http-proxy-middleware';
import { Logger } from 'winston';
import { AuthenticationStrategy } from '../auth';
import { ClusterDetails, KubernetesClustersSupplier } from '../types/types';
import type { Request } from 'express';
export const APPLICATION_JSON: string = 'application/json';
/**
@@ -121,7 +122,17 @@ export class KubernetesProxy {
}
const middleware = await this.getMiddleware(req);
middleware(req, res, next);
// If req is an upgrade handshake, use middleware upgrade instead of http request handler https://github.com/chimurai/http-proxy-middleware#external-websocket-upgrade
if (
req.header('connection')?.toLowerCase() === 'upgrade' &&
req.header('upgrade')?.toLowerCase() === 'websocket'
) {
// Missing the `head`, since it's optional we pass undefined to avoid type issues
middleware.upgrade!(req, req.socket, undefined);
} else {
middleware(req, res, next);
}
};
}