LogShield is one static binary. Put it between the clients (or your TLS terminator) and the application it protects, and make the application reachable only through it. A proxy that can be bypassed protects nothing.
| Topology | When | Notes |
|---|---|---|
| Same host, loopback upstream | Unpatchable single host (typical OT/ICS server) | Move the application to 127.0.0.1:<port>, give LogShield the old public port. Nothing else changes for clients. |
| Separate host or container | Appliance-style, fleets | Firewall the application so only LogShield can reach it. |
| Behind a TLS terminator | Existing nginx, HAProxy or load balancer | Terminate TLS there, forward to LogShield over a trusted network. See nginx example. |
| LogShield terminates TLS | No terminator available | Set tls_cert_file and tls_key_file (configuration). |
- Start in monitor mode (the default). Nothing is blocked; every verdict is logged and counted.
- Watch
logshield_requests_totaland the logs for a few days of real traffic. Anymaliciousverdict on traffic you recognise as legitimate is a false positive worth a report. - Switch
modetoblock. Considerblock_suspiciousonce you have seen what your traffic produces forsuspicious(see the hardened profile). - Alert on
blockedevents and on any rise insuspicious.
- systemd: examples/systemd/logshield.service. Runs as a dynamic unprivileged user with no capabilities, a read-only filesystem and a syscall filter;
systemd-analyze securityrates it 1.2 (OK). Binding a port below 1024 needsAmbientCapabilities=CAP_NET_BIND_SERVICE(and the same inCapabilityBoundingSet=), or listen on a high port and redirect. - Kubernetes: examples/kubernetes/logshield.yaml: non-root, read-only root filesystem, all capabilities dropped, probes on the admin listener, and a NetworkPolicy that makes LogShield the only way in.
- Container:
ghcr.io/turlafsb/logshield, distroless and non-root, published and signed with each release (verification). Pass the upstream asLOGSHIELD_UPSTREAM; the image listens on0.0.0.0:8080. Build one locally withmake docker.
- Fail closed.
on_error: closed(default) refuses requests when the engine cannot decide;openforwards them. Choose open only where availability outweighs the risk, and alert on it. - Admin listener.
admin_listenexposes/metrics,/healthzand/readyz. It is unauthenticated: bind it to loopback or an internal network only. - Sizing. The proxy adds well under a millisecond at typical load (load report);
max_in_flightbounds concurrency and excess requests get503. - Logs. Logs are JSON on stderr and defang
${, so a downstream Java log pipeline cannot be attacked through them (observability). - Upgrades. Replace the binary and restart. With a load balancer, set
drain_delayto its health-check interval so shutdown is graceful. - Validate before deploying.
logshield -check-config -config ...exits 0 or 2 and prints the effective configuration.
Patch Log4j (2.17.1 or later, or remove JndiLookup), or retire the host. See the threat model for what the proxy cannot see.