This repository has no description
0

Configure Feed

Select the types of activity you want to include in your feed.

configs.crit: register routes over a unix socket

hermes-agent runs with ProtectSystem=strict and cannot write the
group-writable routes dir. crit now asks crit-routes.socket (group crit)
for a route; a root service picks the id, writes the route, regenerates
the nginx map and reloads nginx.

author
Hermes
committer
lassulus
date (Oct 13, 2026, 10:27 PM CEST) commit cbc63b38 parent 3ff0ee1d
+73 -23
+73 -23
configs/crit.nix
··· 8 8 # to the agent as instructions. Whoever can reach a daemon can steer an agent 9 9 # running here, so the ports are only open on retiolum. On the public side the 10 10 # random 10-char hostname (~51 bits, fresh per review, only on a wildcard cert 11 - # so it never shows up in CT logs) is the only protection. 11 + # so it never shows up in CT logs) is the only protection. Only members of 12 + # group crit can register a route (via /run/crit-routes.sock), and the 13 + # ids are generated by the root service, callers cannot choose them. 12 14 { 13 15 self, 14 16 config, ··· 21 23 # router nginx, neoprism proxies *.review.lassul.us here 22 24 routerPort = 7720; 23 25 domain = "review.lassul.us"; 24 - # one file per port, "<id> <port>", written by the wrapper 26 + # one file per port, "<id> <port>", written by crit-routes-register (root) 25 27 routesDir = "/var/lib/crit-routes"; 26 28 mapDir = "/run/crit-routes"; 29 + socket = "/run/crit-routes.sock"; 27 30 crit-unwrapped = self.inputs.llm-agents.packages.${pkgs.system}.crit; 28 31 29 32 # crit binds 127.0.0.1 on a random port by default. Bind all interfaces on a ··· 38 41 for p in $(${pkgs.coreutils}/bin/seq ${toString firstPort} ${toString lastPort}); do 39 42 if [ -z "$(${pkgs.iproute2}/bin/ss -Htln "sport = :$p")" ]; then 40 43 export CRIT_PORT=$p 41 - # Fresh unguessable hostname per daemon. Replacing the port's 42 - # route kills the link of whichever review used the port before. 43 - id=$(LC_ALL=C ${pkgs.coreutils}/bin/tr -dc a-z0-9 </dev/urandom | ${pkgs.coreutils}/bin/head -c 10) 44 - tmp=${routesDir}/.$p.$$ 45 - if printf '%s %s\n' "$id" "$p" >"$tmp" && ${pkgs.coreutils}/bin/mv -f "$tmp" ${routesDir}/"$p"; then 44 + # Fresh unguessable hostname per daemon, picked by the root 45 + # service. Replacing the port's route kills the link of 46 + # whichever review used the port before. 47 + id=$(printf '%s\n' "$p" | ${pkgs.socat}/bin/socat -t 10 - UNIX-CONNECT:${socket} 2>/dev/null) 48 + if [[ $id =~ ^[a-z0-9]{10}$ ]]; then 46 49 export CRIT_PUBLIC_URL="''${CRIT_PUBLIC_URL:-https://$id.${domain}}" 47 50 else 48 - ${pkgs.coreutils}/bin/rm -f "$tmp" 49 - echo "crit: cannot write ${routesDir} (not in group crit?), no public URL" >&2 51 + echo "crit: cannot register at ${socket} (not in group crit?), no public URL" >&2 50 52 fi 51 53 break 52 54 fi ··· 66 68 ]; 67 69 }; 68 70 69 - # Only well-formed routes make it into the nginx config: the routes dir is 70 - # writable by the agent. 71 + # Only well-formed routes make it into the nginx config. 71 72 crit-routes-map = pkgs.writeShellApplication { 72 73 name = "crit-routes-map"; 73 74 runtimeInputs = [ pkgs.coreutils ]; 74 75 text = '' 75 76 routes=$1 76 77 out=$2 78 + mkdir -p "$(dirname "$out")" 77 79 tmp=$(mktemp "$out.XXXXXX") 78 80 for f in "$routes"/*; do 79 81 [ -f "$f" ] || continue ··· 88 90 mv -f "$tmp" "$out" 89 91 ''; 90 92 }; 93 + 94 + # One connection of crit-routes.socket: reads a port, gives it a fresh 95 + # route and answers with the route's id. 96 + crit-routes-register = pkgs.writeShellApplication { 97 + name = "crit-routes-register"; 98 + runtimeInputs = [ 99 + pkgs.coreutils 100 + pkgs.util-linux 101 + crit-routes-map 102 + ]; 103 + text = '' 104 + routes=$1 105 + map=$2 106 + port=''' 107 + read -r -t 5 port || true 108 + if ! [[ $port =~ ^[0-9]{4}$ ]] || ((port < ${toString firstPort} || port > ${toString lastPort})); then 109 + echo "crit-routes-register: invalid port" >&2 110 + exit 1 111 + fi 112 + # tr dies of SIGPIPE once head has its 10 chars 113 + id=$(LC_ALL=C tr -dc a-z0-9 </dev/urandom | head -c 10) || true 114 + [[ $id =~ ^[a-z0-9]{10}$ ]] 115 + # concurrent registrations must not lose each other's map update 116 + exec 9<"$routes" 117 + flock 9 118 + printf '%s %s\n' "$id" "$port" >"$routes/.$port.tmp" 119 + mv -f "$routes/.$port.tmp" "$routes/$port" 120 + crit-routes-map "$routes" "$map" 121 + systemctl try-reload-or-restart nginx.service 122 + echo "$id" 123 + ''; 124 + }; 91 125 in 92 126 { 93 127 environment.systemPackages = [ crit ]; ··· 96 130 config.users.users.mainUser.name 97 131 "hermes" 98 132 ]; 99 - # no sticky bit: any crit user must be able to replace another's route 100 - systemd.tmpfiles.rules = [ "d ${routesDir} 2770 root crit -" ]; 133 + # root-only; tmpfiles also tightens the group-writable dir of before 134 + systemd.tmpfiles.rules = [ "d ${routesDir} 0700 root root -" ]; 101 135 102 - systemd.paths.crit-routes = { 103 - wantedBy = [ "paths.target" ]; 104 - pathConfig.PathChanged = routesDir; 136 + # A unix socket rather than a writable dir: connecting works for agents 137 + # under ProtectSystem=strict. The group controls who may register. 138 + systemd.sockets.crit-routes = { 139 + wantedBy = [ "sockets.target" ]; 140 + socketConfig = { 141 + ListenStream = socket; 142 + SocketUser = "root"; 143 + SocketGroup = "crit"; 144 + SocketMode = "0660"; 145 + Accept = true; 146 + }; 105 147 }; 106 - systemd.services.crit-routes = { 148 + systemd.services."crit-routes@" = { 149 + description = "Register a crit review hostname"; 150 + serviceConfig = { 151 + ExecStart = "${pkgs.lib.getExe crit-routes-register} ${routesDir} ${mapDir}/routes.map"; 152 + StandardInput = "socket"; 153 + StandardOutput = "socket"; 154 + StandardError = "journal"; 155 + }; 156 + }; 157 + # map from the routes of before the reboot, so nginx starts with one 158 + systemd.services.crit-routes-map = { 107 159 description = "Generate the nginx map of crit review hostnames"; 108 160 wantedBy = [ "multi-user.target" ]; 109 161 before = [ "nginx.service" ]; 110 - serviceConfig.Type = "oneshot"; 111 - script = '' 112 - mkdir -p ${mapDir} 113 - ${pkgs.lib.getExe crit-routes-map} ${routesDir} ${mapDir}/routes.map 114 - systemctl try-reload-or-restart nginx.service 115 - ''; 162 + serviceConfig = { 163 + Type = "oneshot"; 164 + ExecStart = "${pkgs.lib.getExe crit-routes-map} ${routesDir} ${mapDir}/routes.map"; 165 + }; 116 166 }; 117 167 118 168 # Routes <id>.review.lassul.us to the daemon's port. A daemon that has gone