Saphan StudioDocs
Security/Egress control

How it works

The door that judges each connection, and the wall that makes the door the only way out, on each kind of machine.

Egress control has two parts, and a run needs both.

  • The door judges. Every connection the run opens reaches the door first; the door checks the destination against the run's policy and the hard floor, and either connects it or refuses it.
  • The wall makes the door the only way out. Without it, an agent could simply ignore the door and dial the network directly. The wall is enforced by the operating system, so the agent needs no cooperation and cannot opt out.

The three carries

Which wall a run gets depends on where it runs. There are three, and each is chosen automatically.

carryused onhow it works
the network wallLinux machines, local or reached over sshThe run is placed in its own network namespace. Its TCP connections on the policy's ports are redirected by the kernel into the door, which reads the original destination and judges it. Name resolution inside the namespace answers only for names the policy lists; other TCP is reset and other UDP rejected. The agent needs no proxy setting.
the CONNECT doormacOS machines, local or reached over sshThe macOS sandbox denies the run all network access except one local port where the door listens. The agent is handed that address as its HTTP(S) proxy, and the door judges each CONNECT.
the container bridgea container run on the local machine, under the saphan-agent harnessThe same network wall as on Linux, raised inside the container's own namespace.

On a machine reached over ssh, the door runs on that machine, beside the run, so the decision is made where the connection would leave from.

What each machine needs

A machine carries the wall only when its record says it can. That record is written by measuring the machine, never by typing a value: saphan machine probe-confinement performs the act on the host itself and records the result. See Preparing a machine.

machinecarried when its record shows
local Linuxthe netns rung. If the kernel then refuses to make the namespace routable, the run fails before the agent starts, and when AppArmor is the cause it prints the remedy
remote Linuxthe netns rung and netns-redirect = yes, with landlock confinement
macOSthe seatbelt-network-deny rung, with seatbelt confinement
local containernetns-redirect = yes on the host, and run.harness = saphan-agent

⚠ A machine that has never been probed carries nothing. A run placed on it is refused, not run open: an unmeasured machine is treated as a machine that cannot enforce.

Before the run starts

When a run is dispatched, the engine decides which carry the target machine can provide. If none can, the run is refused before anything is spawned — no model call, no cost — with the marker EGRESS-CLOSED-DEFAULT-REFUSED and a message that names the lane, what was measured and the fix. See When something is refused.

Model traffic and the guardrail

When a run is recorded by the guardrail, the guardrail sits between the agent and its model provider. In one configuration the model hosts are then sealed — only the registered guardrail process can reach them, so the agent cannot talk to its model without passing through the guardrail. All of these must hold:

  • the run is on a Linux network wall — local, or a remote Linux machine whose measured rung is netns;
  • under the legacy harness and the engine's own jail (not container or vendor confinement);
  • the run is judged by its backend's baseline; a run dispatched with --egress-policy is not sealed.

Anything else the run is allowed — a package registry, for example — still goes through the door as usual. Everywhere else the agent is pointed at the guardrail but not forced through it, and the run still gets its full egress policy. When a seal is attempted, the run record says whether it held and, if not, why.

Which runs are not walled

runwhy
a run dispatched with --egress-open "<reason>"an explicit, recorded decision to open that one run's network
a proc runit has no model and no network wire, so there is nothing to judge
a container run whose permission class grants no networkthe container already has no network at all

Every other run is judged.

On this page