Security in Depth
Microbus stacks several independent security mechanisms, each addressing a different attack vector. This document is the layered map. Each section gives a short overview of one mechanism and points to deeper documentation where one exists. An operator workflow turns these mechanisms into a deployed reality.
Perimeter Security
NATS is a closed network. The framework expects the NATS broker to listen only on an internal port (typically :4222 on a private network or VPC), with no external exposure. The HTTP ingress proxy is the only bridge between external HTTP traffic and the bus. It is the fortified single point of entry.
Other microservices do not open inbound ports. Web handler endpoints are reached through the bus, not through their own listening sockets. There is no second entry point and no out-of-band path to bypass the ingress.
This means that everything else in the model assumes the attacker has either already gotten past the ingress or is a compromised peer on the bus. The HTTP ingress focuses on classic web-edge concerns: TLS termination, rate limiting, WAF rules, port filtering. The next section and Ports cover what the ingress enforces at the port level.
Port Firewall
Microbus assigns different security contexts to different internal ports. The HTTP ingress acts as a port-level firewall against inbound external traffic, admitting it only on the ports that are meant to be externally reachable.
- Public ports
:80and:443. External traffic can reach endpoints on these ports through the ingress. - Internal ports
:444,:417,:428. Used for internal-only endpoints, dedicated outbound events, and task endpoints. The ingress blocks external traffic on these ports in a production deployment (MICROBUS_DEPLOYMENT=PROD). - Control port
:888. Used for management and control endpoints. The ingress always blocks external traffic on:888, regardless of deployment mode. - Trust-root port
:666. Reserved for endpoints whose compromise would undermine framework guarantees. Ingress always blocks:666. Inbound callers are also gated by interservice ACL. See Trust-Root Endpoint Protection.
Endpoints declare which port they listen on. The combination of ingress port-block rules and per-microservice ACL grants makes “endpoint X is reachable from Y” a static, reviewable property of the deployed code and configuration, rather than a runtime convention enforced by middleware.
Bearer Token to Short-Lived Access Token Exchange
Users authenticate to Microbus with a long-lived bearer token issued by the bearer token service. The bearer token never travels deeper than the ingress. The ingress (or a similar wrapper microservice) exchanges the bearer token for a short-lived access token issued by the access token service, and only the access token propagates with the request through the bus.
The exchange happens at the gate. The bearer token’s broad capability surface (it represents the user’s general identity) does not make it onto the bus, where many microservices would otherwise see it. The access token’s lifetime is operator-tunable and is typically configured for seconds or minutes. Exfiltrating an access token mid-flight gives the attacker a very small replay window. Exfiltrating a bearer token is harder because it lives only at the edge.
This also creates a clean integration pattern with external identity providers. The ingress, or a dedicated IDP-bridge microservice, validates the external token and calls the access token service to mint an internal access token with claims derived from the external assertion. Downstream microservices see only the internal access token.
JWKS Pinning
Actor JWTs are short-lived signed tokens carrying user claims (roles, scopes, level, and so on). Every receiving microservice verifies the signature before trusting any claim. The verification step does not delegate to the JWT’s iss claim. Microbus pins the JWKS lookup to a hardcoded list of trusted issuers, the access token service and the bearer token service, and rejects tokens whose iss does not match the expected pinned hostname for the token type.
Without pinning, any peer who controls a hostname’s namespace could mint forged tokens, signed with their own keypair, and serve a fake JWKS endpoint at that hostname. A naive verifier would happily fetch the attacker’s public key and accept any claim. Pinning closes that attack at the verifier level.
The pinned list is fixed at two hostnames: access.token.core and bearer.token.core. Other hostnames cannot become trusted issuers, but the standard implementations behind these hostnames can be replaced with custom microservices that satisfy the same interface and register under the same hostnames. This keeps the issuer set explicit and reviewable in code, while still allowing operators to source claims from a different identity backend or adjust mint behavior when needed.
JWKS Pinning covers the attack this closes and the wrapper-microservice pattern for external IDPs in full.
Actor Claims Propagation
A request entering the bus carries an actor JWT that identifies the user on whose behalf the request is being made. The actor JWT propagates automatically across every downstream microservice call (via the Microbus-Actor header), so any microservice handling the request can ask whether the user is authorized to do this.
Endpoint authorization in Microbus is expressed declaratively through requiredClaims boolean expressions over the actor JWT’s claims. Examples: roles.admin or level>5 && !guest or iss!=''. The framework verifies the JWT signature, evaluates the expression, and rejects the request if the expression evaluates false.
Certified Caller Identity
Every request on the bus carries a broker-verified source identity. The NATS subject layout dedicates one segment to the source hostname, and the NATS broker pins each connected microservice to publish only under its own hostname. Receivers parse the segment off the inbound subject and trust it as broker-verified, with no reliance on the publisher’s headers.
This is valuable on its own, even without per-endpoint ACL enforcement. It means that:
- Audit logs and traces record an authenticated source per call, not a self-attested one.
- Per-caller rate limits are enforced against verified identity, not against a header an attacker can rewrite.
- An endpoint that wants to admit only a specific peer microservice can check
Microbus-From-Hostand trust the value. - A header-smuggling attack against
Microbus-From-Hostis impossible. The framework unconditionally overwrites the publisher-set header with the broker-verified value before any handler runs.
Interservice ACL
Each microservice’s .creds file carries an explicit allow-list of {host, port, method, path} tuples derived from its own source code. The allow-list is true to code: it grants exactly what the microservice actually invokes, at the granularity of the exact endpoint. The NATS broker rejects any message that does not match a rule.
Precise true-to-code interservice access control is designed primarily to harden against lateral exfiltration. A compromised microservice can only do what its own code was written to do and no more.
The combination of certified caller identity and a tight per-endpoint allow-list is strictly tighter than mTLS-style service mesh authentication. TLS authenticates the connection once, then allows the client to hit any endpoint on the destination. Interservice ACL authenticates every message and authorizes per endpoint.
Application Bundling as a Trust-Boundary Lever
Microbus distinguishes a microservice (a single unit with its own hostname and code) from an application (a deployable bundle composed of one or more microservices). The same set of microservices can be deployed as one large bundle, as several smaller bundles, or as one application per microservice. The choice is a security lever the operator controls.
Microservices in the same bundle share an OS process and address space, with the consequence that a compromised microservice has direct memory access to its bundled siblings. Cross-bundle traffic, by contrast, always rounds through NATS, picks up broker-enforced source identity and ACL enforcement, and has no shared-memory shortcut. Within a bundle, each microservice still opens its own NATS connection with its own .creds, so broker-side enforcement remains per-microservice even when an OS process is shared.
The recommended posture for trust-root microservices is to deploy each one as its own application. The cost is one extra OS process per trust root. The gain is that a compromise in any other application cannot reach memory inside the trust root, and a compromise of the trust root is bounded to the trust root’s own permission set.
Other candidates for isolation into their own application include microservices with broad ACL surface (such as the HTTP ingress proxy and Foreman), microservices holding sensitive data, and microservices subject to compliance audit.
Trust-Root Endpoint Protection
Port :666 is reserved for endpoints whose compromise would undermine the security of the deployment. Two foundational :666 endpoints are present in any Microbus deployment that uses the framework’s authentication model:
- The access token service’s
Mintendpoint issues new actor JWTs with arbitrary claims. - The bearer token service’s
Mintendpoint issues bearer tokens.
Optional services can also expose :666 endpoints for privileged operations. The framework’s shell service is one example: its Execute endpoint runs shell commands on the host, and is gated by the same ACL machinery. Application code may define its own :666 endpoints for role grants, privileged writes, and similar.
Two layers protect :666:
- HTTP ingress always blocks
:666. The HTTP ingress proxy refuses to forward inbound requests on:666regardless of deployment mode, plane, or claims. External traffic cannot reach a trust-root endpoint, ever. - Interservice ACL gates internal callers. Only callers whose code actually invokes a
:666endpoint get the corresponding ACL rule in their.creds. No call site, no permission. The NATS subject layout reserves a separate trust segment (danger) for:666traffic, so a broad “any safe port” allow rule cannot accidentally subsume a trust-root grant.
Putting a new endpoint on :666 is a deliberate choice with a deployment-time burden. Every upstream caller’s .creds must include the explicit :666 permission, and gencreds has to find a real call site in the caller’s source. Operators audit the trust-root surface in the per-microservice .creds contents. Running grep danger <hostname>_nats.creds enumerates every active trust-root grant for that microservice.
Why This Is Stronger Than HTTP
| Layer | HTTP (TLS + headers) | Microbus |
|---|---|---|
| Server identity | TLS verifies server certificate | NATS verifies broker’s certificate |
| Client/sender identity | App reads Authorization header (publisher-attested) | Broker pins source segment via the microservice’s signed .creds (broker-verified) |
| Authorization granularity | Per-route, app-layer (whatever middleware chooses) | Per {host, port, method, path} tuple, wire-layer, broker-enforced |
| Compromise blast radius | Shared TCP connection, app-layer demux | Each microservice has its own NATS connection, .creds, and ACL |
| Audit | Server-side logs of inbound headers (self-attested) | Broker logs of authenticated source per publish |
The shift is at the boundary. HTTP defers caller-identity verification to the application layer, where every microservice has to get it right. Microbus pushes it down to the NATS broker, where it’s verified once and every receiver can trust it. The added precision (endpoint-granular ACLs derived from code) means a compromised microservice cannot reach endpoints its own code does not already invoke, even on microservices it does call.
Defense Matrix
A summary of which attack categories are closed by which mechanism.
| Attack | Defended? | By |
|---|---|---|
| External HTTP attacker reaching an internal endpoint | Yes | Perimeter Security and Port Firewall |
| Bearer token exfiltration from inside the bus | Mitigated | The bearer-to-access-token exchange keeps bearer tokens at the edge; only short-lived access tokens cross the bus |
| External actor-token forgery | Yes | JWKS Pinning fixes the issuer at the access and bearer token services |
Application bugs in requiredClaims | No | The framework enforces what the expression says, not what was meant |
| Stolen actor JWT replay | Mitigated | Short-lived actor JWTs keep the replay window small |
Microbus-From-Host header smuggling | Yes | Certified Caller Identity overwrites with broker-verified source on receive |
| Per-caller rate-limit bypass via identity rotation | Yes | Certified Caller Identity broker-pins the source segment per connection |
| Audit log forgery | Yes | Certified Caller Identity makes all cross-service trace and log labels use verified source |
Microservice impersonation (forging the <src> segment) | Yes | Interservice ACL enforces broker-pinned source in the PUB ACL |
| Capability escalation beyond own code | Yes | Interservice ACL (true-to-code allow-list per microservice) |
.creds exfiltration (single-microservice blast radius) | Mitigated | Per-deploy rotation, .creds expiration, and explicit revocation |
| In-bundle compromise (same OS process) | No | Bundling collapses trust by definition. Split the high-risk microservice into its own application. |
| Trust-root invocation by uninvolved microservices | Yes | Trust-Root Endpoint Protection: only microservices whose code calls Mint (or another :666 endpoint) get the rule |
| Compromised NATS broker | No | The framework does not sign individual messages end-to-end |
How the Layers Compose
Each layer addresses a different attack surface, and a determined attacker has to defeat each one in turn:
- The perimeter keeps external HTTP traffic away from the bus.
- The port firewall narrows what inbound traffic can reach which endpoints, even after passing the perimeter.
- The bearer-to-access-token exchange limits the user-credential blast radius if the bus is reached.
- JWKS pinning prevents forged actor tokens from being accepted on the bus.
- Actor claim propagation ensures every endpoint can enforce per-user authorization uniformly.
- Certified caller identity lets every receiver trust the source of inbound requests.
- Interservice ACL bounds what a compromised microservice can do laterally.
- Application bundling lets the operator decide where trust boundaries fall in the deployment topology.
- Trust-root protection raises the bar on the few endpoints whose compromise would matter most.
No single layer is sufficient. Each closes a different attack vector, and the combination is what gives the framework’s overall security posture. Operational security is best-served by setting all of these up in a production deployment.