mirror of
https://github.com/n8n-io/n8n.git
synced 2026-09-19 01:45:48 +08:00
fix(core): Restore AWS Secrets Manager connection reuse (#36426)
Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 4.8
parent
c0b3a12a1c
commit
56bb5f593d
@@ -74,6 +74,40 @@ describe('getNodeAgent', () => {
|
||||
});
|
||||
});
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// getNodeAgent — connection-reuse options propagate across all routing paths
|
||||
//
|
||||
// Callers may pass connection-management options (e.g. `keepAlive`,
|
||||
// `maxSockets`) to enable connection reuse. Regardless of how the request is
|
||||
// routed, those options must reach the constructed agent — otherwise a proxied
|
||||
// deployment would silently drop them.
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
describe('getNodeAgent connection-reuse options', () => {
|
||||
// keep-alive/maxSockets are connection-management options, so Node's Agent (and
|
||||
// the proxy agents that extend it) expose them as instance properties.
|
||||
function getReuseOptions(agent: http.Agent | https.Agent): {
|
||||
keepAlive: unknown;
|
||||
maxSockets: unknown;
|
||||
} {
|
||||
const a = agent as { keepAlive?: unknown; maxSockets?: unknown };
|
||||
return { keepAlive: a.keepAlive, maxSockets: a.maxSockets };
|
||||
}
|
||||
|
||||
it.each([
|
||||
['direct (proxy: false)', { proxy: false } as const],
|
||||
['env proxy', { proxy: 'env' } as const],
|
||||
['explicit proxy URL', { proxy: 'http://proxy.internal:3128' } as const],
|
||||
])('forwards keepAlive/maxSockets on the %s path', (_label, transportOptions) => {
|
||||
const { httpAgent, httpsAgent } = makeFacade()
|
||||
.transport(transportOptions)
|
||||
.getNodeAgent({ keepAlive: true, maxSockets: 50 });
|
||||
|
||||
expect(getReuseOptions(httpAgent)).toEqual({ keepAlive: true, maxSockets: 50 });
|
||||
expect(getReuseOptions(httpsAgent)).toEqual({ keepAlive: true, maxSockets: 50 });
|
||||
});
|
||||
});
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// getNodeAgent — SSRF lookup injection
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
+5
@@ -105,6 +105,11 @@ describe('AwsSecretsManager', () => {
|
||||
|
||||
expect(outboundHttp.transport).toHaveBeenCalledWith({ ssrf: 'disabled' });
|
||||
|
||||
// Request connection reuse from our agents. Smithy treats a supplied agent as
|
||||
// external and skips its own keep-alive defaults, so we pass them explicitly to
|
||||
// restore the AWS SDK-equivalent behavior (Smithy NodeHttpHandler defaults).
|
||||
expect(transport.getNodeAgent).toHaveBeenCalledWith({ keepAlive: true, maxSockets: 50 });
|
||||
|
||||
// The SDK client is built with our agents as its requestHandler, while the
|
||||
// region and credentials it was already given are left untouched.
|
||||
const SecretsManagerMock = SecretsManager as unknown as Mock;
|
||||
|
||||
@@ -136,11 +136,15 @@ export class AwsSecretsManager extends SecretsProvider {
|
||||
// Drive the AWS SDK's HTTP transport through n8n's outbound client,
|
||||
// so its calls reuse our agents (proxy + TLS) like every other outbound request.
|
||||
// SigV4 signing and the credential chain stay with the SDK.
|
||||
//
|
||||
// Keep connections pooled so the sequential ListSecrets/BatchGetSecretValue refresh
|
||||
// reuses sockets instead of paying a fresh TLS handshake per request. `maxSockets`
|
||||
// caps concurrent sockets, matching the AWS SDK's own defaults.
|
||||
clientConfig.requestHandler = this.outboundHttp
|
||||
.transport({
|
||||
ssrf: 'disabled', // fixed AWS-resolved Secrets Manager host, not user-controlled
|
||||
})
|
||||
.getNodeAgent();
|
||||
.getNodeAgent({ keepAlive: true, maxSockets: 50 });
|
||||
|
||||
const { SecretsManager } = await import('@aws-sdk/client-secrets-manager');
|
||||
this.client = new SecretsManager(clientConfig);
|
||||
|
||||
Reference in New Issue
Block a user