feat(smart-proxy): add hot-reloadable global ingress security policy across Rust and TypeScript proxy layers
This commit is contained in:
@@ -2,6 +2,6 @@
|
||||
* SmartProxy models
|
||||
*/
|
||||
// Export everything except IAcmeOptions from interfaces
|
||||
export type { ISmartProxyOptions, ISmartProxyCertStore, IConnectionRecord, TSmartProxyCertProvisionObject, ICertProvisionEventComms, ICertificateIssuedEvent, ICertificateFailedEvent } from './interfaces.js';
|
||||
export type { ISmartProxyOptions, ISmartProxySecurityPolicy, ISmartProxyCertStore, IConnectionRecord, TSmartProxyCertProvisionObject, ICertProvisionEventComms, ICertificateIssuedEvent, ICertificateFailedEvent } from './interfaces.js';
|
||||
export * from './route-types.js';
|
||||
export * from './metrics-types.js';
|
||||
|
||||
@@ -29,6 +29,11 @@ export interface ISmartProxyCertStore {
|
||||
}
|
||||
import type { IRouteConfig } from './route-types.js';
|
||||
|
||||
export interface ISmartProxySecurityPolicy {
|
||||
blockedIps?: string[];
|
||||
blockedCidrs?: string[];
|
||||
}
|
||||
|
||||
/**
|
||||
* Provision object for static or HTTP-01 certificate
|
||||
*/
|
||||
@@ -137,6 +142,7 @@ export interface ISmartProxyOptions {
|
||||
// Rate limiting and security
|
||||
maxConnectionsPerIP?: number; // Maximum simultaneous connections from a single IP
|
||||
connectionRateLimitPerMinute?: number; // Max new connections per minute from a single IP
|
||||
securityPolicy?: ISmartProxySecurityPolicy; // Global ingress block policy, enforced before routing
|
||||
|
||||
// Enhanced keep-alive settings
|
||||
keepAliveTreatment?: 'standard' | 'extended' | 'immortal'; // How to treat keep-alive connections
|
||||
@@ -276,4 +282,4 @@ export interface IConnectionRecord {
|
||||
path?: string;
|
||||
headers?: Record<string, string>;
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import type { IProtocolCacheEntry, IProtocolDistribution } from './metrics-types.js';
|
||||
import type { IAcmeOptions, ISmartProxyOptions } from './interfaces.js';
|
||||
import type { IAcmeOptions, ISmartProxyOptions, ISmartProxySecurityPolicy } from './interfaces.js';
|
||||
import type {
|
||||
IRouteAction,
|
||||
IRouteConfig,
|
||||
@@ -75,6 +75,7 @@ export interface IRustProxyOptions {
|
||||
keepAliveInactivityMultiplier?: number;
|
||||
extendedKeepAliveLifetime?: number;
|
||||
metrics?: ISmartProxyOptions['metrics'];
|
||||
securityPolicy?: ISmartProxySecurityPolicy;
|
||||
acme?: IRustAcmeOptions;
|
||||
}
|
||||
|
||||
|
||||
@@ -7,6 +7,7 @@ import type {
|
||||
IRustRouteConfig,
|
||||
IRustStatistics,
|
||||
} from './models/rust-types.js';
|
||||
import type { ISmartProxySecurityPolicy } from './models/interfaces.js';
|
||||
|
||||
/**
|
||||
* Type-safe command definitions for the Rust proxy IPC protocol.
|
||||
@@ -15,6 +16,7 @@ type TSmartProxyCommands = {
|
||||
start: { params: { config: IRustProxyOptions }; result: void };
|
||||
stop: { params: Record<string, never>; result: void };
|
||||
updateRoutes: { params: { routes: IRustRouteConfig[] }; result: void };
|
||||
setSecurityPolicy: { params: { policy: ISmartProxySecurityPolicy }; result: void };
|
||||
getMetrics: { params: Record<string, never>; result: IRustMetricsSnapshot };
|
||||
getStatistics: { params: Record<string, never>; result: IRustStatistics };
|
||||
provisionCertificate: { params: { routeName: string }; result: void };
|
||||
@@ -139,6 +141,10 @@ export class RustProxyBridge extends plugins.EventEmitter {
|
||||
await this.bridge.sendCommand('updateRoutes', { routes });
|
||||
}
|
||||
|
||||
public async setSecurityPolicy(policy: ISmartProxySecurityPolicy): Promise<void> {
|
||||
await this.bridge.sendCommand('setSecurityPolicy', { policy });
|
||||
}
|
||||
|
||||
public async getMetrics(): Promise<IRustMetricsSnapshot> {
|
||||
return this.bridge.sendCommand('getMetrics', {} as Record<string, never>);
|
||||
}
|
||||
|
||||
@@ -17,7 +17,7 @@ import { Mutex } from './utils/mutex.js';
|
||||
import { ConcurrencySemaphore } from './utils/concurrency-semaphore.js';
|
||||
|
||||
// Types
|
||||
import type { ISmartProxyOptions, TSmartProxyCertProvisionObject, IAcmeOptions, ICertProvisionEventComms, ICertificateIssuedEvent, ICertificateFailedEvent } from './models/interfaces.js';
|
||||
import type { ISmartProxyOptions, ISmartProxySecurityPolicy, TSmartProxyCertProvisionObject, IAcmeOptions, ICertProvisionEventComms, ICertificateIssuedEvent, ICertificateFailedEvent } from './models/interfaces.js';
|
||||
import type { IRouteConfig } from './models/route-types.js';
|
||||
import type { IMetrics } from './models/metrics-types.js';
|
||||
import type { IRustCertificateStatus, IRustProxyOptions, IRustStatistics } from './models/rust-types.js';
|
||||
@@ -350,6 +350,15 @@ export class SmartProxy extends plugins.EventEmitter {
|
||||
.catch((err) => logger.log('error', `Unexpected error in cert provisioning after route update: ${err.message}`, { component: 'smart-proxy' }));
|
||||
}
|
||||
|
||||
/**
|
||||
* Update the global ingress security policy without changing routes.
|
||||
* The Rust engine applies this before route selection and backend connection.
|
||||
*/
|
||||
public async updateSecurityPolicy(policy: ISmartProxySecurityPolicy): Promise<void> {
|
||||
this.settings.securityPolicy = policy;
|
||||
await this.bridge.setSecurityPolicy(policy);
|
||||
}
|
||||
|
||||
/**
|
||||
* Provision a certificate for a named route.
|
||||
*/
|
||||
|
||||
@@ -182,6 +182,7 @@ export function buildRustProxyOptions(
|
||||
keepAliveInactivityMultiplier: settings.keepAliveInactivityMultiplier,
|
||||
extendedKeepAliveLifetime: settings.extendedKeepAliveLifetime,
|
||||
metrics: settings.metrics,
|
||||
securityPolicy: settings.securityPolicy,
|
||||
acme: serializeAcmeForRust(acme),
|
||||
};
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user