Harden edge broker defaults and compose exposure
This commit is contained in:
@@ -25,15 +25,24 @@ function jsonResponse(res, statusCode, body) {
|
||||
}
|
||||
|
||||
export function createBrokerServer(options = {}) {
|
||||
const authMode = options.authMode || process.env.EDGE_AUTH_MODE || "stub";
|
||||
const authMode = options.authMode || process.env.EDGE_AUTH_MODE || "strict";
|
||||
const sharedSecret = options.sharedSecret ?? process.env.EDGE_BROKER_SHARED_SECRET ?? "";
|
||||
const commandTimeoutMs = options.commandTimeoutMs ?? 10000;
|
||||
const agents = new Map();
|
||||
const pendingCommands = new Map();
|
||||
const browserSessions = new Map();
|
||||
const isStubMode = authMode === "stub";
|
||||
|
||||
const validateAgent = options.validateAgent || (async ({ gatewayId }) => ({ id: gatewayId }));
|
||||
const validateShellSession = options.validateShellSession || (async ({ token }) => ({ id: token, gateway_id: 1, reason: "stub" }));
|
||||
const validateAgent = options.validateAgent || (isStubMode
|
||||
? (async ({ gatewayId }) => ({ id: gatewayId }))
|
||||
: (async () => {
|
||||
throw new Error("Unauthorized");
|
||||
}));
|
||||
const validateShellSession = options.validateShellSession || (isStubMode
|
||||
? (async ({ token }) => ({ id: token, gateway_id: 1, reason: "stub" }))
|
||||
: (async () => {
|
||||
throw new Error("Unauthorized");
|
||||
}));
|
||||
const closeShellSession = options.closeShellSession || (async () => ({}));
|
||||
|
||||
const markBrowserSessionsClosed = (gatewayId, reason) => {
|
||||
@@ -113,9 +122,7 @@ export function createBrokerServer(options = {}) {
|
||||
socket.destroy();
|
||||
return;
|
||||
}
|
||||
if (authMode !== "stub") {
|
||||
await validateAgent({ gatewayId, token, headers: req.headers });
|
||||
}
|
||||
await validateAgent({ gatewayId, token, headers: req.headers });
|
||||
wss.handleUpgrade(req, socket, head, (ws) => {
|
||||
ws.gatewayId = gatewayId;
|
||||
agents.set(gatewayId, ws);
|
||||
@@ -130,9 +137,7 @@ export function createBrokerServer(options = {}) {
|
||||
socket.destroy();
|
||||
return;
|
||||
}
|
||||
const session = authMode === "stub"
|
||||
? await validateShellSession({ token })
|
||||
: await validateShellSession({ token, headers: req.headers });
|
||||
const session = await validateShellSession({ token, headers: req.headers });
|
||||
|
||||
wss.handleUpgrade(req, socket, head, (ws) => {
|
||||
ws.sessionToken = token;
|
||||
|
||||
@@ -24,6 +24,18 @@ function waitForClose(socket) {
|
||||
});
|
||||
}
|
||||
|
||||
function waitForCloseOrError(socket) {
|
||||
return new Promise((resolve) => {
|
||||
const onDone = () => {
|
||||
socket.off("error", onDone);
|
||||
socket.off("close", onDone);
|
||||
resolve();
|
||||
};
|
||||
socket.once("error", onDone);
|
||||
socket.once("close", onDone);
|
||||
});
|
||||
}
|
||||
|
||||
async function waitFor(predicate, { timeoutMs = 1000, intervalMs = 10, description = "condition" } = {}) {
|
||||
const deadline = Date.now() + timeoutMs;
|
||||
|
||||
@@ -215,3 +227,14 @@ test("broker closes browser shell sessions when the agent disconnects before she
|
||||
|
||||
await broker.close();
|
||||
});
|
||||
|
||||
test("broker defaults to strict auth when no validators are configured", async () => {
|
||||
const broker = createBrokerServer();
|
||||
const address = await broker.listen(0);
|
||||
const port = address.port;
|
||||
|
||||
const agent = new WebSocket(`ws://127.0.0.1:${port}/ws/agent?gatewayId=701&token=agent-token`);
|
||||
await waitForCloseOrError(agent);
|
||||
|
||||
await broker.close();
|
||||
});
|
||||
|
||||
@@ -24,19 +24,19 @@ test("traefik does not expose a dedicated public edge broker port", () => {
|
||||
assert.doesNotMatch(traefikSource, /edge-broker:\s*\n\s*address:\s*":4300"/);
|
||||
});
|
||||
|
||||
test("base docker compose exposes the edge broker service on port 4300", () => {
|
||||
test("base docker compose restricts edge broker host binding to loopback", () => {
|
||||
assert.match(baseComposeSource, /\bedge-broker:\b/);
|
||||
assert.match(baseComposeSource, /edge-broker:\s*\n[\s\S]*?\n\s+ports:\s*\n\s+- "4300:4300"/);
|
||||
assert.match(baseComposeSource, /edge-broker:\s*\n[\s\S]*?\n\s+ports:\s*\n\s+- "127\.0\.0\.1:4300:4300"/);
|
||||
});
|
||||
|
||||
test("example docker compose exposes the edge broker service on port 4300", () => {
|
||||
test("example docker compose restricts edge broker host binding to loopback", () => {
|
||||
assert.match(exampleComposeSource, /\bedge-broker:\b/);
|
||||
assert.match(exampleComposeSource, /edge-broker:\s*\n[\s\S]*?\n\s+ports:\s*\n\s+- "4300:4300"/);
|
||||
assert.match(exampleComposeSource, /edge-broker:\s*\n[\s\S]*?\n\s+ports:\s*\n\s+- "127\.0\.0\.1:4300:4300"/);
|
||||
});
|
||||
|
||||
test("php services receive broker websocket environment defaults", () => {
|
||||
test("compose config does not provide insecure broker secret defaults", () => {
|
||||
for (const composeSource of [baseComposeSource, exampleComposeSource]) {
|
||||
assert.match(composeSource, /EDGE_BROKER_URL:\s*\$\{EDGE_BROKER_URL:-http:\/\/edge-broker:4300\}/);
|
||||
assert.match(composeSource, /EDGE_BROKER_SHARED_SECRET:\s*\$\{EDGE_BROKER_SHARED_SECRET:-truckwash-edge-dev\}/);
|
||||
assert.match(composeSource, /EDGE_BROKER_SHARED_SECRET:\s*\$\{EDGE_BROKER_SHARED_SECRET\}/);
|
||||
}
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user