Files
privatae-bastion/docs/host-on-this-machine.md
T
Privatae 77b7853ae1
ci / personal-data (push) Successful in 6s
ci / fuzz (push) Successful in 2m49s
ci / test (push) Successful in 3m7s
bastion 0.54.1
2026-10-21 23:39:13 +00:00

4.6 KiB

A Host on this machine

A Host with no platform (a customer's own server with the Host on it) pairs with a bastion on the same machine, so its threads can build and test code in sealed coder runs. Nothing about the walls changes: mutual TLS and the bearer on every lane, a CA this bastion pins, grants the Host signs and this bastion verifies on every operation, an anchored machine. What changes is who issues the certificates (the Host's own CA) and how the two talk: unix sockets in a directory both reach, /run/privatae-host/ (root, group privatae-host, 1770: the Host runs without privileges and makes its two sockets there, and the sticky bit keeps it from moving what root made; runs/ inside it is 0750 root, so only this bastion makes run sockets), instead of WireGuard through the relay.

socket served by what
/run/privatae-host/enroll.sock the Host pair redeems its token here (POST /bastion/enroll/redeem, the platform redeem's body)
/run/privatae-host/lane.sock the Host every lane, as over the tunnel to :8443
/run/privatae-host/runs/<run_id>.sock this bastion one coder run's control plane, for the owning pairing only

The commands an install script runs on such a machine, as root:

# 1. The bastion as the machine's service, in networked mode.
curl -fsSL https://privatae.ai/bastion/install.sh | sudo sh -s -- --networked
# 2. Pair with the Host over its enroll socket (the token comes from the Host).
sudo -H privatae-bastion pair --redeem-url unix:///run/privatae-host/enroll.sock <token>
# 3. Make the Host the anchor: from now on every coder run-up needs the
#    standing coder grant the Host signs.
sudo -H privatae-bastion claim-anchor --owner <name>
# 4. A way to approve at this machine: it is its own approval device.
privatae-bastion device-init                       # prints the pin-device line
sudo -H privatae-bastion pin-device <key it printed>
# 5. Coder runs of the workspace engine, from images built on this machine.
sudo -H privatae-bastion coders set --engines workspace --image-prefix localhost/privatae-harness/
sudo -H privatae-bastion coders on
sudo systemctl restart privatae-bastion

The one thing the owner does by hand: approve the Host's coder grant, once, on this machine's console (privatae-bastion ui, then Approvals). Until then every run-up is refused at the gate.

A unix:// redeem URL names an absolute socket path and nothing else: a host, a port or a relative path is refused before the token is read. The Host's answer names its CA, the lane socket and the runs directory, and both must be inside the directory of the enroll socket you named. The CA is pinned as the platform's is: it is the only root the lanes trust, the Host's lane certificate must carry the pairing's name, and a pair --replace that brings a different CA is refused.

The image is built on the machine and tagged <prefix>harness-workspace:<tag>; the Host names it <prefix>harness-workspace@<image ID>, the ID from docker image inspect --format '{{.Id}}'. Run-up takes an image that is present that way without a pull or any registry credential. Docker's classic image store keeps no repo digest for an image built or loaded locally, so there the run starts from the image ID, and only when the image with that ID carries a tag of the named repository.

A Host in a VM on this machine

A Host with no platform that runs in a VM on this machine shares no kernel and no directory with it. Its installer forwards two ports of the VM to this machine's loopback and hands over a pairing token with the Host's CA:

privatae-bastion pair --redeem-url https://127.0.0.1:8810/v1/local/redeem --host-ca host-ca.pem <token>
privatae-bastion run
port what
8810 pair redeems its token here (POST /v1/local/redeem, the platform redeem's body)
8811 every lane, as over the tunnel to :8443

The redeem and every lane go over TLS that trusts the --host-ca alone (no system roots) and checks the name host.cseries.internal on the Host's certificate; the lanes present this bastion's operator certificate, which the Host knows it by. The Host's answer must carry that same CA and name a lane on the host the redeem URL names. The CA is pinned for the pairing's life, as for a unix pairing. --host-ca goes with an https:// redeem URL only, and both are checked before the token is read.

Such a pairing has no WireGuard forwards (inference, PII, service slots) and no coder runs: a run's control plane is a tunnel port or a socket in a unix pairing's runs directory, and a TCP pairing has neither, so its run-up is refused before any container starts.