Zero-Trust-Netzwerke für Anwendungsentwickler
Zero-Trust-Netzwerke aus Entwicklersicht: mutual TLS, Service-Mesh-Authentifizierung und Autorisierung auf Anfrageebene für jeden Aufruf.

Der Perimeter ist tot
Traditionelle Netzwerksicherheit zieht eine Linie um die Infrastruktur: Alles innerhalb des Perimeters gilt als vertrauenswürdig, alles außerhalb nicht. Dieses Modell versagt, sobald ein einziger kompromittierter Dienst sich lateral durch das gesamte Netzwerk bewegen kann. Zero Trust geht von keinerlei implizitem Vertrauen aus – jede Anfrage, von jeder Quelle, muss ihre Identität und Berechtigung nachweisen.
Gegenseitiges TLS zwischen Diensten
Beim Standard-TLS legt nur der Server ein Zertifikat vor. Gegenseitiges TLS (mTLS) verlangt, dass sich sowohl Client als auch Server authentifizieren. Jeder Dienst besitzt ein eigenes Zertifikat, und jede Verbindung verifiziert beide Seiten.
import { createServer, createSecureContext } from "node:tls";
import { readFileSync } from "node:fs";
// Server setup with mTLS
const server = createServer(
{
key: readFileSync("/certs/service-a.key"),
cert: readFileSync("/certs/service-a.crt"),
ca: readFileSync("/certs/ca.crt"),
requestCert: true, // Require client certificate
rejectUnauthorized: true, // Reject if client cert is invalid
},
(socket) => {
const clientCert = socket.getPeerCertificate();
console.log(`Authenticated client: ${clientCert.subject.CN}`);
}
);
// HTTP client with mTLS
async function callService(url: string, body: unknown): Promise<Response> {
const agent = new Agent({
cert: readFileSync("/certs/service-b.crt"),
key: readFileSync("/certs/service-b.key"),
ca: readFileSync("/certs/ca.crt"),
});
return fetch(url, {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify(body),
// @ts-expect-error -- Node fetch supports dispatcher
dispatcher: agent,
});
}Dienstidentität und Autorisierung
mTLS weist die Identität nach. Die Autorisierung entscheidet, was diese Identität tun darf. Extrahieren Sie die Dienstidentität aus dem Zertifikat und prüfen Sie sie gegen eine Richtlinie, bevor Sie die Anfrage verarbeiten.
// ❌ Trusting any request from the internal network
app.post("/api/internal/process-payment", async (req, res) => {
// No identity check — any service on the network can call this
await processPayment(req.body);
res.json({ success: true });
});
// ✅ Verify service identity and check authorization
interface ServicePolicy {
allowedCallers: string[];
requiredScopes?: string[];
}
const endpointPolicies: Record<string, ServicePolicy> = {
"/api/internal/process-payment": {
allowedCallers: ["checkout-service", "subscription-service"],
requiredScopes: ["payments:write"],
},
"/api/internal/get-user": {
allowedCallers: ["*"], // Any authenticated service
},
};
function authorizeService(
req: Request,
res: Response,
next: NextFunction
): void {
const clientCert = (req.socket as TLSSocket).getPeerCertificate();
if (!clientCert || !clientCert.subject) {
res.status(401).json({ error: "No client certificate" });
return;
}
const serviceId = clientCert.subject.CN;
const policy = endpointPolicies[req.path];
if (!policy) {
res.status(403).json({ error: "No policy defined for endpoint" });
return;
}
const isAllowed =
policy.allowedCallers.includes("*") ||
policy.allowedCallers.includes(serviceId);
if (!isAllowed) {
console.warn(
`Service ${serviceId} denied access to ${req.path}`
);
res.status(403).json({ error: "Service not authorized" });
return;
}
next();
}Propagierung des Anfragekontexts
Zero Trust geht über die Dienstidentität hinaus. Jede Anfrage trägt Kontext – Nutzeridentität, Scopes, Trace-IDs –, den nachgelagerte Dienste unabhängig validieren, statt den Angaben vorgelagerter Dienste blind zu vertrauen.
interface RequestContext {
userId: string;
roles: string[];
scopes: string[];
traceId: string;
sourceService: string;
requestTimestamp: string;
}
// Middleware: extract and verify request context
function extractRequestContext(
req: Request,
res: Response,
next: NextFunction
): void {
const contextHeader = req.headers["x-request-context"];
if (!contextHeader || typeof contextHeader !== "string") {
res.status(401).json({ error: "Missing request context" });
return;
}
try {
// Context is signed by the API gateway
const verified = verifySignedContext(contextHeader);
req.context = verified;
next();
} catch (error) {
res.status(401).json({ error: "Invalid request context signature" });
}
}
// Every service independently verifies — never trust upstream
function verifySignedContext(token: string): RequestContext {
const decoded = jwt.verify(token, process.env.CONTEXT_PUBLIC_KEY!, {
algorithms: ["ES256"],
maxAge: "5m", // Context expires quickly
});
return decoded as RequestContext;
}Netzwerkrichtlinien in Kubernetes
Zero Trust auf Anwendungsebene ergänzt Kontrollen auf Netzwerkebene. Kubernetes-NetworkPolicies schränken ein, welche Pods miteinander kommunizieren dürfen, und sorgen so für zusätzliche Verteidigungstiefe.
# Only allow checkout-service to reach payment-service
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: payment-service-ingress
namespace: production
spec:
podSelector:
matchLabels:
app: payment-service
policyTypes:
- Ingress
ingress:
- from:
- podSelector:
matchLabels:
app: checkout-service
- podSelector:
matchLabels:
app: subscription-service
ports:
- protocol: TCP
port: 8443// Health check for zero-trust readiness
interface ZeroTrustCheck {
name: string;
check: () => Promise<boolean>;
}
const readinessChecks: ZeroTrustCheck[] = [
{
name: "mTLS certificates valid",
check: async () => {
const cert = readFileSync("/certs/service.crt", "utf8");
const parsed = new crypto.X509Certificate(cert);
return new Date(parsed.validTo) > new Date();
},
},
{
name: "Policy engine reachable",
check: async () => {
const response = await fetch("http://policy-engine:8181/health");
return response.ok;
},
},
{
name: "Context signing key loaded",
check: async () => {
return !!process.env.CONTEXT_PUBLIC_KEY;
},
},
];
async function checkZeroTrustReadiness(): Promise<{
ready: boolean;
checks: Array<{ name: string; passed: boolean }>;
}> {
const results = await Promise.all(
readinessChecks.map(async (c) => ({
name: c.name,
passed: await c.check().catch(() => false),
}))
);
return {
ready: results.every((r) => r.passed),
checks: results,
};
}Die wichtigsten Erkenntnisse
Zero Trust bedeutet, dass jede Anfrage ihre Identität und Berechtigung nachweisen muss – auch „interner" Traffic bildet keine Ausnahme. Implementieren Sie mTLS zwischen den Diensten, sodass jede Verbindung gegenseitig authentifiziert ist. Definieren Sie explizite Autorisierungsrichtlinien pro Endpoint und legen Sie fest, welche Dienste welche Endpoints aufrufen dürfen.
Propagieren Sie den Anfragekontext mit signierten, kurzlebigen Tokens, die jeder nachgelagerte Dienst unabhängig verifiziert. Legen Sie Netzwerkrichtlinien über die Kontrollen auf Anwendungsebene, um zusätzliche Verteidigungstiefe zu erreichen. Die zusätzliche Komplexität ist real, aber die Alternative – ein einzelner kompromittierter Dienst, der Ihr gesamtes Netzwerk kontrolliert – ist schlimmer. Beginnen Sie mit mTLS und Autorisierung auf Endpoint-Ebene, und fügen Sie Kontextpropagierung und Richtlinien-Engines hinzu, sobald die Zahl Ihrer Dienste wächst.


