openmega.net

← Notes

Zero-trust access for a home lab

Tags: Security Zero Trust Networking Home Lab

A home lab grows in quiet increments. One self-hosted service becomes two, then five, then a dozen things to keep running. The easy path is to open a router port forward for each one. That makes every application a public address and every web server part of the exposed edge. Each forward is a decision saying that the service is ready for the open internet, whether it actually is or not.

What a zero-trust approach changes

Zero trust is not a product. It is a stance: treat every request as untrusted until the requester is identified, check that request against policy, and grant only what the task needs.

NIST's Zero Trust Architecture states the ground rules more precisely. There is "no implicit trust granted to assets or user accounts based solely on their physical or network location". Authentication and authorization are "discrete functions" performed "before a session to an enterprise resource is established". The architecture protects resources rather than network segments (NIST SP 800-207). CISA's Zero Trust Maturity Model puts the same point differently: the goal is least privilege access decisions made per request, with enforcement "as granular as possible" in a network assumed to be compromised (CISA, Zero Trust Maturity Model).

For a home lab, the practical expression is to put an access layer in front of published services and to reach the origin over a private path rather than a public one, an outbound tunnel opened by an agent inside the network being the usual way to build that path. Users can reach applications through a shared access-control service while each application keeps its own URL. The layer checks identity, applies policy, and forwards the request to the internal service. In that arrangement the router needs no inbound rule per application, and a new service joins through the existing layer instead of opening another public port. The tunnel is one way to build the private path, not a requirement of the model, and not every service suits it: a protocol the tunnel does not carry, or an application that wants its own public entry, needs a different route.

Two mechanisms that are easy to confuse

An outbound tunnel and an identity-aware access layer solve different halves of the problem. Neither one automatically supplies the other's controls.

The tunnel is a network path. The agent inside the network dials out to the provider, and traffic for the published service returns over that same connection, so the origin does not have to be reachable by an inbound connection from the internet. Cloudflare describes the model as "outbound-only", with the agent initiating the connection to the edge and no inbound ports opened on the origin (Cloudflare, Connect with Cloudflare Tunnel).

The access layer is the decision point. It evaluates policies to decide who may reach the application, checks identity against an identity provider, and evaluates configured identity and request conditions according to the provider's session and policy model (Cloudflare, Access policies).

A publicly routed tunnel without an access policy can make the application reachable by anyone. The tunnel itself does not authenticate those users, although the application may enforce its own authentication. Private-network tunnels have a different access model. For the public-hostname design discussed here, configure the access policy deliberately instead of assuming the tunnel makes the application private. An access layer without a tunnel still needs a route to the origin, and that route is not necessarily a port forward: a private connection offered by the same provider or another one, a site-to-site link, or an application hosted with the provider can all carry it. The tunnel is one option among several.

Where the public name points

Internal services keep their private addresses. In this design the public hostname resolves to the access layer or to the tunnel endpoint, and not to the address of the machine behind it, so the internal addressing is not published in that record. The behaviour belongs to this arrangement rather than to DNS as such: a split-horizon zone, an administrative interface given its own public name, or a record published for a host that also carries a private address can each expose internal addressing.

The agent is part of your estate

A tunnel is not a substitute for application security. A vulnerable web application behind a tunnel is still a vulnerable web application. It changes the network boundary, not the code or the configuration of what sits behind it. Keep patching, keep hardening, and keep application credentials strong.

The agent itself deserves the same care as any other critical component: keep it patched, restrict the routes it advertises, and read its logs.

Grant access per application rather than giving a remote user network-wide reach into the whole estate. A VPN that opens the entire home network to a remote session gives that session a path to every machine behind it, which is the opposite of least privilege. An access policy that names one application does not.

Policies that hold up in practice

Require a named identity for every user. Anonymous access and shared accounts defeat the point. Enable multi-factor authentication for every identity, without exceptions for convenience. Group users by purpose, and write one policy per group rather than one per person where the group shares a real access need.

A country-based rule can reduce unwanted attempts when you know access should come from a small set of places. Treat it as a supporting signal rather than a control on its own. Location is a poor indicator of intent: travel moves, mobile networks change, and shared exits are used by anyone. Blocking a country is no proof that an attacker is somewhere else.

Separate policies for administration tools and ordinary services. A dashboard used daily does not need the same controls as a router management page. Avoid publishing management interfaces unless there is a clear, documented need, and when you do, require the strongest authentication you can.

Operational habits that keep the model honest

Review access logs. A sign-in from an unexpected place, a user accessing an application they no longer need, or a service account used interactively are all useful signals. Review group membership at a regular cadence and remove access when a need ends. Projects finish. Guest accounts expire. Test identities get discarded.

Keep a recovery path that does not depend on the tunnel provider. If the provider has an outage, you should still be able to reach the underlying hosts through a local route. Keep that path narrow, authenticate it strongly, and use it often enough that you trust it under pressure.

For a small estate, this approach can reduce direct origin exposure and centralise access decisions. A new service is an entry in a policy file rather than a firewall rule on the edge. Public traffic meets one policy boundary. Applications stay private by default. The cost is the discipline to maintain the policy and the habits to review it, which for a home lab is a small and reasonable price.

Checklist