fix: TRUST_PROXY-Kommentar aktualisieren und Modus beim Start loggen

Die Kommentare beschrieben noch einen einzelnen Reverse-Proxy-Hop. Sie
beschreiben jetzt die Cloudflare/Traefik-Liste. Beim Start wird einmal
auf info-Level geloggt, ob Hop-Zahl, Liste oder der Default aktiv ist
(nur Anzahl, keine Adressen), damit eine fehlende Produktionseinstellung
auffaellt. Das Standardverhalten bleibt unveraendert.

Co-Authored-By: Claude Opus 5.5 (1M context) <[email protected]>
This commit is contained in:
Nick SzaunigandClaude Opus 5.5 committed 2026-10-12 11:23:41 +02:00
1 parent 886b4e75e1
commit d9670dcda5
2 files changed
+102 -8

No files matched your search

+35 -8
View File
@@ -1,4 +1,9 @@
import { RequestMethod, ValidationPipe, VersioningType } from '@nestjs/common';
import {
Logger,
RequestMethod,
ValidationPipe,
VersioningType,
} from '@nestjs/common';
import { NestExpressApplication } from '@nestjs/platform-express';
import helmet from 'helmet';
import cookieParser from 'cookie-parser';
@@ -7,11 +12,15 @@ import { requestLoggerMiddleware } from './common/middleware/request-logger.midd
import { noStoreMiddleware } from './common/middleware/no-store.middleware';
/**
* How many reverse-proxy hops to trust for X-Forwarded-For. It decides the
* client IP behind every rate limit and API-key IP allowlist: too few and
* all users share the proxy's IP, too many and a client can forge its own.
* A hop count ("1", the single K8s ingress) or Express' list syntax
* ("loopback, 10.0.0.0/8").
* Which proxies to trust for X-Forwarded-For. It decides the client IP behind
* every rate limit and API-key IP allowlist: trust too little and all users
* share the proxy's IP, trust too much and a client can forge its own.
*
* Production runs client -> Cloudflare -> Traefik -> backend, so the hop
* count is not stable; TRUST_PROXY is an Express list there ("loopback,
* 10.42.0.0/16, <Cloudflare IPv4+IPv6 ranges>", see
* deploy/k8s/backend/configmap.example.yaml). A plain number ("1") is a hop
* count and stays the default when the variable is unset.
*/
export function trustProxySetting(): number | string {
const raw = process.env.TRUST_PROXY?.trim();
@@ -21,11 +30,29 @@ export function trustProxySetting(): number | string {
return /^\d+$/.test(raw) ? Number(raw) : raw;
}
/** Startup log line for the active mode; never includes the addresses. */
export function describeTrustProxy(
setting: number | string,
isExplicit: boolean,
): string {
if (typeof setting === 'number') {
return isExplicit
? `TRUST_PROXY: ${setting} trusted hop(s)`
: `TRUST_PROXY not set, using default of ${setting} trusted hop`;
}
const entries = setting.split(',').filter((e) => e.trim()).length;
return `TRUST_PROXY: list of ${entries} trusted proxy range(s)`;
}
export function configureApp(app: NestExpressApplication): void {
// Trust the single reverse-proxy hop (K8s ingress) so req.ip reflects the
// Trust the configured proxies (Traefik, Cloudflare) so req.ip reflects the
// real client IP from X-Forwarded-For — required for per-client throttling
// to work correctly rather than rate-limiting all traffic together.
app.set('trust proxy', trustProxySetting());
const trustProxy = trustProxySetting();
app.set('trust proxy', trustProxy);
new Logger('Bootstrap').log(
describeTrustProxy(trustProxy, !!process.env.TRUST_PROXY?.trim()),
);
// No ETags: they let caches and proxies revalidate (and keep) personal
// responses that are meant to be no-store.
app.set('etag', false);