How to Put Authentication in Front of a Service That Ships Without It
Orchestration engines and internal tools often expose an API with no auth of their own. The reverse-proxy, mutual-TLS and allowlist patterns that add a front door without touching the application.
A surprising amount of infrastructure software ships with no authentication on its primary interface. Orchestration engines, metrics dashboards, message brokers, internal admin panels, and developer tools frequently assume that access control is somebody else's job, usually the network's. The open-source Conductor server is a clean example: its API has no built-in authentication, and the vendor's commercial product is where role-based access control and single sign-on live. When a service like that gains a remote code execution bug, the missing auth is what turns a serious flaw into an unauthenticated one that anyone who can reach the port can fire. Putting authentication in front of a service that ships without it is one of the highest-leverage controls you can add, and it is almost always your responsibility, not the software's.
Why This Keeps Happening
Software gets shipped without auth for understandable reasons. It was designed to run on a trusted internal network. It was built as a component to sit behind someone else's gateway. Adding an auth system is real work the maintainers deferred, or reserved for a paid tier. None of those reasons help you when the service ends up reachable, and services end up reachable constantly: a firewallFirewall🌐Security system that monitors and controls network traffic based on predetermined rules. change, a cloud migration that flattens a network, a Kubernetes ingress that exposes more than intended, a developer who ran it with a public bind address to debug something and never undid it. The CVE-2026-58138 exploitation wave, described in our news coverage of the Conductor RCE, worked precisely because vulnerable instances were reachable and unauthenticated at the same time.
The mistake is treating network location as an access control. Perimeter position is not authentication. Anyone who lands inside the network, through a phished laptop, a compromised neighbor service, or a misrouted ingress, inherits whatever the unauthenticated service offers.
The Reverse Proxy in Front
The workhorse pattern is to put an authenticating reverse proxyReverse Proxy🛡️A server that sits in front of one or more backend services, terminating client connections and forwarding requests to the backend. It is the standard place to add authentication, TLS and access control to a service that lacks its own, without modifying the application. directly in front of the service and make it the only path in. Nginx, Caddy, Traefik, or a cloud load balancer terminates the connection, enforces authentication, and only then forwards to the backend. Bind the backend itself to localhost or a private interface so the proxy is genuinely the sole route, not merely the intended one. This adds authentication without touching the application's code, which is exactly what you need when the application has no auth to configure.
What the proxy enforces depends on the service. For machine-to-machine APIs like an orchestration backend, mutual TLS is the strong option: only clients presenting a valid certificate get through, and there is no password to phish or spray. For human-facing consoles, front the service with an identity-aware proxy or SSO gateway that speaks OAuthOAuth🛡️An open standard authorization protocol that allows applications to access user resources without exposing passwords, using tokens instead of credentials. or OIDC against your identity provider, so access follows the same accounts, groups, and revocation as everything else. Even HTTP basic auth over TLS, backed by a real credential store, is a night-and-day improvement over nothing, because it moves the door from "open" to "needs a key."
Layering the Controls
Authentication at the proxy is the primary control, but it works best stacked. Network allowlisting comes first: restrict which source addresses can even reach the proxy, so a stolen client cert or credential is only useful from expected locations. This is the same discipline as inventorying and locking down the API surfaces on your network appliances, applied to internal software. Bind services to private interfaces by default and make public exposure a deliberate, reviewed exception rather than an accident.
Then enforce least privilegeLeast Privilege🛡️A design principle that grants each user, role, or process only the permissions it needs to do its job and no more. Applied to session roles in a remote-access tool, least privilege means a role that never moves files should not carry file-transfer permission. behind the door. If the service supports any notion of scoped tokens or roles, even coarse ones, use them so that an authenticated client can only do what it needs. Run the service itself as an unprivileged user in a constrained container, so that a code-execution bug behind your new auth layer still lands somewhere contained. Defense in depthDefense in Depth🛡️A security strategy using multiple layers of protection so that if one layer fails, other layers continue to provide security. matters here because your bolt-on auth is not part of the application's own logic; if the app has a second, undocumented port or an internal endpoint that bypasses the proxy, you want the blast radiusBlast Radius🛡️The full set of systems, data, and access an attacker can reach after compromising a given asset. Ranking assets by blast radius rather than by how exposed they are pushes high-reach systems like a firewall management console to the top of the priority list. already minimized.
A Short Checklist
Inventory every service you run and record, for each, what authenticates access to it. Any answer that amounts to "it's on the internal network" is a finding, not a control. For each unauthenticated service, decide the front door: mutual TLS for service-to-service, an SSO or identity-aware proxy for humans, credential-backed basic auth over TLS at minimum. Bind the backend to a private interface so the proxy cannot be skipped. Add a source-address allowlist. Confirm the service runs unprivileged and containerized. Finally, verify the new control by trying to reach the backend directly, from off the allowlist and without credentials, and confirming you cannot.
None of this makes a vulnerable service invulnerable. It removes the "unauthenticated" from "unauthenticated remote code execution," which is often the entire difference between a flaw an anonymous scanner weaponizes at scale and one that requires an attacker to already be somewhere they should not be. When a bug like the Conductor evaluator escape lands, understanding why a scripting sandbox is only as safe as its host-access policy tells you what went wrong inside the app; putting auth in front of it decides who ever gets to reach that flaw in the first place.