@aikidosec/broker-client 1.0.1 → 1.0.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +8 -3
- package/app/client.js +41 -41
- package/app/resourceManager.js +8 -2
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -55,9 +55,11 @@ Resource IDs are displayed in the Aikido UI when you register them.
|
|
|
55
55
|
|
|
56
56
|
**Optional:**
|
|
57
57
|
- `ALLOWED_INTERNAL_SUBNETS` - Comma-separated subnet whitelist (e.g., `10.0.0.0/8,172.16.0.0/12`)
|
|
58
|
-
- `DNS_SERVERS` - Custom DNS servers for internal hostname resolution
|
|
59
|
-
- `
|
|
60
|
-
- `HTTP_PROXY` -
|
|
58
|
+
- `DNS_SERVERS` - Custom DNS servers for internal hostname resolution (e.g., `8.8.8.8,8.8.4.4`)
|
|
59
|
+
- `NODE_EXTRA_CA_CERTS` - Path to custom CA certificate bundle for self-signed certificates (e.g., `/certs/corporate-ca.crt`)
|
|
60
|
+
- `HTTP_PROXY` - Proxy server for HTTP requests (e.g., `http://proxy.company.local:8080`)
|
|
61
|
+
- `HTTPS_PROXY` - Proxy server for HTTPS requests (e.g., `http://proxy.company.local:8080`)
|
|
62
|
+
- `ALL_PROXY` - Universal proxy fallback for all protocols if protocol-specific proxy is not set
|
|
61
63
|
|
|
62
64
|
## How It Works
|
|
63
65
|
|
|
@@ -74,6 +76,9 @@ Resource IDs are displayed in the Aikido UI when you register them.
|
|
|
74
76
|
CLIENT_SECRET=aikido_broker_123_123_123456789
|
|
75
77
|
ALLOWED_INTERNAL_SUBNETS=10.0.0.0/8,172.16.0.0/12
|
|
76
78
|
HTTP_PROXY=http://proxy.company.local:8080
|
|
79
|
+
HTTPS_PROXY=http://proxy.company.local:8080
|
|
80
|
+
NODE_EXTRA_CA_CERTS=/certs/corporate-ca.crt
|
|
81
|
+
DNS_SERVERS=10.0.0.1,10.0.0.2
|
|
77
82
|
```
|
|
78
83
|
|
|
79
84
|
After registering resources through the Aikido UI, they will be accessible via subdomains like:
|
package/app/client.js
CHANGED
|
@@ -35,42 +35,12 @@ const DNS_SERVERS = process.env.DNS_SERVERS
|
|
|
35
35
|
? process.env.DNS_SERVERS.split(',').map(s => s.trim()).filter(s => s)
|
|
36
36
|
: null;
|
|
37
37
|
|
|
38
|
-
// Optional: Custom CA certificate bundle for self-signed certificates
|
|
39
|
-
const CUSTOM_CA_BUNDLE = process.env.CUSTOM_CA_BUNDLE || null;
|
|
40
|
-
|
|
41
|
-
// Optional: HTTP proxy for outbound requests to internal resources
|
|
42
|
-
const HTTP_PROXY = process.env.HTTP_PROXY || null;
|
|
43
|
-
|
|
44
|
-
// Determine TLS verification setting
|
|
45
|
-
let httpsAgent = null;
|
|
46
|
-
if (CUSTOM_CA_BUNDLE) {
|
|
47
|
-
const https = await import('https');
|
|
48
|
-
const ca = fs.readFileSync(CUSTOM_CA_BUNDLE);
|
|
49
|
-
httpsAgent = new https.Agent({ ca });
|
|
50
|
-
log.info(`Using custom CA bundle: ${CUSTOM_CA_BUNDLE}`);
|
|
51
|
-
} else {
|
|
52
|
-
log.info("Using system CA certificates for TLS verification");
|
|
53
|
-
}
|
|
54
|
-
|
|
55
38
|
// Configure axios defaults
|
|
56
39
|
const axiosConfig = {
|
|
57
40
|
timeout: 30000,
|
|
58
|
-
maxRedirects: 5
|
|
59
|
-
httpsAgent
|
|
41
|
+
maxRedirects: 5
|
|
60
42
|
};
|
|
61
43
|
|
|
62
|
-
if (HTTP_PROXY) {
|
|
63
|
-
const proxyUrl = new URL(HTTP_PROXY);
|
|
64
|
-
axiosConfig.proxy = {
|
|
65
|
-
host: proxyUrl.hostname,
|
|
66
|
-
port: proxyUrl.port || 80,
|
|
67
|
-
protocol: proxyUrl.protocol
|
|
68
|
-
};
|
|
69
|
-
log.info(`Using HTTP proxy for internal requests: ${HTTP_PROXY}`);
|
|
70
|
-
} else {
|
|
71
|
-
log.info("No HTTP proxy configured for internal requests");
|
|
72
|
-
}
|
|
73
|
-
|
|
74
44
|
// Create axios instance for internal requests
|
|
75
45
|
const internalHttpClient = axios.create(axiosConfig);
|
|
76
46
|
|
|
@@ -113,7 +83,6 @@ async function resolveInternalHostname(hostname) {
|
|
|
113
83
|
const dnsPromises = await import('dns/promises');
|
|
114
84
|
const result = await dnsPromises.resolve4(hostname);
|
|
115
85
|
const ip = result[0];
|
|
116
|
-
log.debug(`Resolved ${hostname} to ${ip} (system DNS)`);
|
|
117
86
|
return ip;
|
|
118
87
|
} catch (e) {
|
|
119
88
|
log.error(`Failed to resolve ${hostname}: ${e.message}`);
|
|
@@ -192,13 +161,11 @@ function isInternalUrl(url) {
|
|
|
192
161
|
// Not an IP, allow it through if we have custom DNS configured
|
|
193
162
|
// The actual resolution will happen in the forward_request handler
|
|
194
163
|
if (DNS_SERVERS !== null && DNS_SERVERS.length > 0) {
|
|
195
|
-
log.debug(`Hostname ${hostname} will be resolved with custom DNS during forward`);
|
|
196
164
|
return true;
|
|
197
165
|
}
|
|
198
166
|
|
|
199
167
|
// For system DNS, we can't do synchronous lookup here
|
|
200
168
|
// Allow all private hostnames through and validate during forward
|
|
201
|
-
log.debug(`Hostname ${hostname} will be validated during forward`);
|
|
202
169
|
return true;
|
|
203
170
|
}
|
|
204
171
|
}
|
|
@@ -313,6 +280,30 @@ socket.on('disconnect', () => {
|
|
|
313
280
|
log.warn("Disconnected from broker server");
|
|
314
281
|
});
|
|
315
282
|
|
|
283
|
+
socket.on('connect_error', (error) => {
|
|
284
|
+
log.error(`Socket.IO connection error: ${error.message}`);
|
|
285
|
+
if (error.description) {
|
|
286
|
+
log.error(` Description: ${JSON.stringify(error.description)}`);
|
|
287
|
+
}
|
|
288
|
+
if (error.context) {
|
|
289
|
+
log.error(` Context: ${JSON.stringify(error.context)}`);
|
|
290
|
+
}
|
|
291
|
+
log.error(` Type: ${error.type || 'unknown'}`);
|
|
292
|
+
});
|
|
293
|
+
|
|
294
|
+
// Manager events (on socket.io)
|
|
295
|
+
socket.io.on('error', (error) => {
|
|
296
|
+
log.error(`Socket.IO Manager error: ${error.message || JSON.stringify(error)}`);
|
|
297
|
+
});
|
|
298
|
+
|
|
299
|
+
socket.io.on('reconnect_error', (error) => {
|
|
300
|
+
log.error(`Socket.IO reconnection error: ${error.message}`);
|
|
301
|
+
});
|
|
302
|
+
|
|
303
|
+
socket.io.on('reconnect_failed', () => {
|
|
304
|
+
log.error(`Socket.IO reconnection failed after all attempts`);
|
|
305
|
+
});
|
|
306
|
+
|
|
316
307
|
socket.on('forward_request', async (data, callback) => {
|
|
317
308
|
/**
|
|
318
309
|
* Receive request from broker server and forward to internal resource
|
|
@@ -407,11 +398,13 @@ async function registerWithServer() {
|
|
|
407
398
|
|
|
408
399
|
for (let attempt = 0; attempt < maxRetries; attempt++) {
|
|
409
400
|
try {
|
|
401
|
+
const axiosConfig = {
|
|
402
|
+
timeout: 10000
|
|
403
|
+
};
|
|
404
|
+
|
|
410
405
|
const response = await axios.post(serverUrl, {
|
|
411
406
|
client_secret: CLIENT_SECRET
|
|
412
|
-
},
|
|
413
|
-
timeout: 10000
|
|
414
|
-
});
|
|
407
|
+
}, axiosConfig);
|
|
415
408
|
|
|
416
409
|
if (response.status === 200) {
|
|
417
410
|
const clientId = response.data.client_id;
|
|
@@ -449,7 +442,14 @@ async function registerWithServer() {
|
|
|
449
442
|
log.warn(`Registration attempt ${attempt + 1} failed: ${response.status} - ${response.data}`);
|
|
450
443
|
}
|
|
451
444
|
} catch (error) {
|
|
452
|
-
|
|
445
|
+
if (error.response) {
|
|
446
|
+
// HTTP error response
|
|
447
|
+
log.warn(`Registration attempt ${attempt + 1} failed: ${error.response.status} - ${JSON.stringify(error.response.data)}`);
|
|
448
|
+
} else {
|
|
449
|
+
// Error setting up request
|
|
450
|
+
log.warn(`Registration attempt ${attempt + 1} failed: ${error.message}`);
|
|
451
|
+
}
|
|
452
|
+
|
|
453
453
|
if (getClientId() !== null) {
|
|
454
454
|
// If we have a client_id already, don't retry
|
|
455
455
|
// we should try once to deal with secret rotation
|
|
@@ -498,10 +498,10 @@ async function main() {
|
|
|
498
498
|
log.info(`Registered resources: ${Object.keys(registeredResources).length > 0 ? Object.keys(registeredResources).join(', ') : 'None'}`);
|
|
499
499
|
|
|
500
500
|
log.info(`Server URL: ${SERVER_URL}`);
|
|
501
|
-
if (HTTP_PROXY) {
|
|
502
|
-
log.info(`
|
|
501
|
+
if (process.env.HTTP_PROXY || process.env.HTTPS_PROXY) {
|
|
502
|
+
log.info(`Proxy configured: HTTP_PROXY=${process.env.HTTP_PROXY || 'not set'}, HTTPS_PROXY=${process.env.HTTPS_PROXY || 'not set'}`);
|
|
503
503
|
} else {
|
|
504
|
-
log.info("
|
|
504
|
+
log.info("Proxy: Not configured");
|
|
505
505
|
}
|
|
506
506
|
|
|
507
507
|
// Register with server (creates client_id file, waits for propagation)
|
package/app/resourceManager.js
CHANGED
|
@@ -102,7 +102,7 @@ export class ResourceManager {
|
|
|
102
102
|
this._resources = { ...resourcesDict };
|
|
103
103
|
this._saveToFile();
|
|
104
104
|
} else {
|
|
105
|
-
log.
|
|
105
|
+
log.info("No resource changes detected");
|
|
106
106
|
}
|
|
107
107
|
}
|
|
108
108
|
|
|
@@ -183,7 +183,13 @@ export class ResourceManager {
|
|
|
183
183
|
}
|
|
184
184
|
|
|
185
185
|
} catch (error) {
|
|
186
|
-
|
|
186
|
+
if (error.response) {
|
|
187
|
+
// HTTP error response
|
|
188
|
+
log.error(`Error fetching resources from broker: ${error.response.status} - ${JSON.stringify(error.response.data)}`);
|
|
189
|
+
} else {
|
|
190
|
+
// Error setting up request
|
|
191
|
+
log.error(`Error fetching resources from broker: ${error.message}`);
|
|
192
|
+
}
|
|
187
193
|
}
|
|
188
194
|
}
|
|
189
195
|
|
package/package.json
CHANGED