from perimeter-based trust to workload-identity verification, automated policy enforcement, and continuous validation. The following architecture provides a production-ready foundation.
Step 1: Enforce TLS Everywhere
All in-transit traffic must be encrypted. This eliminates packet sniffing, man-in-the-middle attacks, and credential exposure on shared networks. Use TLS 1.3 exclusively and disable legacy cipher suites.
// tls-config-validator.ts
import { createServer as createHttpsServer } from 'https';
import { readFileSync } from 'fs';
import { Server } from 'http';
interface TLSConfig {
key: string;
cert: string;
ca?: string;
minVersion: 'TLSv1.3';
ciphers: string;
}
const SECURE_CIPHERS = 'TLS_AES_256_GCM_SHA384:TLS_CHACHA20_POLY1305_SHA256';
export function validateTLSConfig(config: TLSConfig): void {
if (!config.key || !config.cert) {
throw new Error('TLS key and certificate are required');
}
if (config.minVersion !== 'TLSv1.3') {
throw new Error('Only TLS 1.3 is permitted');
}
if (!config.ciphers.includes('AES_256_GCM')) {
throw new Error('Strong cipher suite required');
}
}
export function createSecureServer(handler: any, tlsConfig: TLSConfig): Server {
validateTLSConfig(tlsConfig);
return createHttpsServer({
key: readFileSync(tlsConfig.key),
cert: readFileSync(tlsConfig.cert),
ca: tlsConfig.ca ? readFileSync(tlsConfig.ca) : undefined,
minVersion: 'TLSv1.3',
ciphers: SECURE_CIPHERS,
honorCipherOrder: true,
}, handler);
}
Step 2: Implement Network Segmentation
Divide workloads into isolated security zones. Applications should only communicate with explicitly authorized services. Use declarative network policies rather than manual firewall rules.
// network-policy-generator.ts
interface NetworkPolicySpec {
namespace: string;
podSelector: Record<string, string>;
ingress: { from: Record<string, string>[]; ports: number[] }[];
egress: { to: Record<string, string>[]; ports: number[] }[];
}
export function generateNetworkPolicy(spec: NetworkPolicySpec): string {
const policy = {
apiVersion: 'networking.k8s.io/v1',
kind: 'NetworkPolicy',
metadata: {
name: `${spec.namespace}-policy`,
namespace: spec.namespace,
},
spec: {
podSelector: { matchLabels: spec.podSelector },
policyTypes: ['Ingress', 'Egress'],
ingress: spec.ingress.map(rule => ({
from: rule.from.map(match => ({ podSelector: { matchLabels: match } })),
ports: rule.ports.map(port => ({ protocol: 'TCP', port })),
})),
egress: spec.egress.map(rule => ({
to: rule.to.map(match => ({ podSelector: { matchLabels: match } })),
ports: rule.ports.map(port => ({ protocol: 'TCP', port })),
})),
},
};
return JSON.stringify(policy, null, 2);
}
Step 3: Deploy Mutual TLS (mTLS) for Service Authentication
Replace static API keys and bearer tokens with cryptographic identity verification. mTLS ensures both client and server authenticate each other before establishing a connection.
// mtls-auth-middleware.ts
import { Request, Response, NextFunction } from 'express';
import { TLSSocket } from 'tls';
export function requireMTLS(req: Request, res: Response, next: NextFunction): void {
const socket = req.socket as TLSSocket;
if (!socket.getPeerCertificate || Object.keys(socket.getPeerCertificate()).length === 0) {
res.status(403).json({ error: 'Client certificate required' });
return;
}
const cert = socket.getPeerCertificate();
if (!cert.valid_to || new Date(cert.valid_to) < new Date()) {
res.status(403).json({ error: 'Client certificate expired' });
return;
}
req.clientCert = cert;
next();
}
declare global {
namespace Express {
interface Request {
clientCert?: any;
}
}
}
Step 4: Automate Security Group Enforcement via IaC
Cloud security groups must be defined as code, validated in CI, and applied through declarative deployments. Manual console edits bypass audit trails and introduce drift.
Step 5: Centralize Certificate Lifecycle Management
Use automated certificate authorities (e.g., cert-manager, HashiCorp Vault, or AWS ACM) to handle issuance, rotation, and revocation. Manual certificate management guarantees expiration outages and increases attack surface.
Architecture Decisions & Rationale
- Declarative over imperative: Network policies defined in code enable version control, peer review, and automated drift detection. Imperative console changes cannot be audited or rolled back reliably.
- mTLS over static credentials: API keys leak through logs, environment variables, and client-side code. Cryptographic identities are bound to workloads, automatically rotated, and verifiable at the TLS layer without application-level token management.
- Centralized CA over self-signed: Self-signed certificates bypass chain validation and complicate revocation. A centralized CA provides consistent trust anchors, automated rotation, and compliance-ready audit trails.
- Shift-left validation: Network security must be validated during build and deploy phases, not post-deployment. TypeScript-based validators catch misconfigurations before they reach production.
Pitfall Guide
- Assuming internal traffic is trusted: Lateral movement accounts for 68% of successful breaches. Internal networks are not safe zones; every service-to-service connection must be authenticated and encrypted.
- Over-permissive cloud security groups: Rules like
0.0.0.0/0 or ::/0 on non-public services create unrestricted attack paths. Always apply least-privilege CIDR ranges and port restrictions.
- Hardcoding certificates or private keys in repositories: Source control history is immutable. Leaked keys enable immediate service impersonation. Use secret management systems and inject credentials at runtime.
- Ignoring DNS and egress filtering: Attackers use DNS tunneling and rogue egress connections for data exfiltration. Block unauthorized outbound traffic and enforce DNS resolution through trusted resolvers.
- Skipping certificate rotation automation: Expired certificates cause outages and force emergency manual interventions. Automated rotation reduces human error and maintains continuous trust.
- Treating network security as a one-time setup: Network topologies evolve with every deployment. Static policies become obsolete within weeks. Implement continuous validation and drift detection.
- Inadequate network flow logging: Without VPC flow logs, eBPF telemetry, or service mesh observability, breaches remain undetected until data is already exfiltrated. Log all connections and alert on anomalies.
Best Practices from Production:
- Enforce deny-by-default network policies. Allow only explicitly declared communication paths.
- Validate all network configurations in CI using schema checks and policy simulators.
- Separate management, data, and application traffic into distinct VLANs or service meshes.
- Rotate all cryptographic material on a fixed schedule, not just when compromised.
- Correlate network logs with identity and application telemetry for faster incident response.
Production Bundle
Action Checklist
Decision Matrix
| Scenario | Recommended Approach | Why | Cost Impact |
|---|
| Single-region monolith | Cloud security groups + TLS | Low complexity, sufficient isolation for limited service count | Low |
| Multi-service microservices | Service mesh with mTLS | Granular traffic control, automated policy enforcement, observability | Medium |
| Compliance-heavy (HIPAA/PCI) | Zero-trust microsegmentation + centralized CA | Audit-ready cryptographic identity, strict least-privilege enforcement | High |
| Serverless/event-driven | API Gateway + IAM + VPC endpoints | Eliminates direct network exposure, leverages managed auth | Low-Medium |
| High-frequency trading/low latency | eBPF-based network policies | Kernel-level filtering without proxy overhead, sub-microsecond enforcement | High |
Configuration Template
# network-policy.yaml
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: app-tier-policy
namespace: production
spec:
podSelector:
matchLabels:
app: payment-service
policyTypes:
- Ingress
- Egress
ingress:
- from:
- podSelector:
matchLabels:
app: api-gateway
ports:
- protocol: TCP
port: 8443
egress:
- to:
- podSelector:
matchLabels:
app: database-service
ports:
- protocol: TCP
port: 5432
- to:
- namespaceSelector:
matchLabels:
kubernetes.io/metadata.name: kube-system
ports:
- protocol: UDP
port: 53
---
# cert-manager-issuer.yaml
apiVersion: cert-manager.io/v1
kind: ClusterIssuer
metadata:
name: internal-ca
spec:
selfSigned: {}
---
apiVersion: cert-manager.io/v1
kind: Certificate
metadata:
name: payment-service-tls
namespace: production
spec:
secretName: payment-service-tls
duration: 2160h # 90 days
renewBefore: 360h # 15 days
issuerRef:
name: internal-ca
kind: ClusterIssuer
dnsNames:
- payment-service.production.svc.cluster.local
Quick Start Guide
- Initialize TLS validation: Add the
tls-config-validator.ts module to your build pipeline. Configure your HTTP/HTTPS servers to load certificates from a secret manager and enforce TLS 1.3 with the provided cipher suite.
- Apply deny-by-default policies: Deploy the
network-policy.yaml template to your cluster. Update podSelector and from/to labels to match your service topology. Verify with kubectl get networkpolicy -n production.
- Enable mTLS authentication: Integrate
requireMTLS middleware into your Express/Fastify servers. Configure your ingress controller or service mesh to request client certificates and validate the chain against your internal CA.
- Automate certificate rotation: Install cert-manager, apply the
ClusterIssuer and Certificate templates, and verify secret generation with kubectl get secret payment-service-tls -n production -o yaml.
- Validate and monitor: Run
kubectl audit or a policy simulator to confirm no unintended ingress/egress paths exist. Enable VPC flow logs or Cilium Hubble for real-time traffic visibility. Test breach containment by simulating lateral movement and measuring MTTC.