Waystone Panel

Updates

Stage 3b: Waystone now builds its own game servers

Posted

In Stage 3a, Waystone learned to start and stop a Minecraft server. There was a catch: I had to set that server up by hand first, including its user, its folder and its systemd unit. As of Stage 3b, that's no longer true. One request now gives a game server everything it needs to exist on a machine.

What happens when you provision a server

The agent sends one small request: a server ID, the name of a runtime (java25) and a heap size. That's all it can send. It can't pass paths, user names or unit names, because Waystone works all of those out itself from the ID. On the other side:

  • The server gets its own Linux account. It's a system account with no home directory and no login shell, named after a hash of the server ID. Every game server runs as a different user, so one server can't read another's files.
  • Waystone writes a systemd unit from a template. The template hard-codes the sandbox: no capabilities, a read-only system, private /tmp and devices, and a memory limit of the heap plus 1 GB.
  • systemd creates the server's data folder, owned by that account and closed to everyone else (mode 0750). Waystone's own code never changes file ownership.

Run the same request again and nothing changes. The answer is simply changed: false. And Waystone never takes over anything it didn't create: an account or unit file that looks like someone else's is refused, not overwritten.

Two privileged services, each with one job

Creating Linux accounts needs root, and the obvious shortcut would have been to give the Stage 3a helper more power. We didn't. Instead:

  • The runtime helper is unchanged. It still only starts, stops and inspects servers, and it can't write a single file.
  • A new provisioning service runs the same program in a different role. The only place it may write is the systemd unit directory.
  • Accounts are created by the system's own useradd, in a short-lived sandboxed unit with no capabilities. It's the only process in the whole design that can write to /etc, and only for that one command.

Each service refuses the other's job. We checked that on the machine: the runtime helper rejects provisioning, the provisioner rejects start and stop, and both refuse root itself. Both score 1.3 ("OK") in systemd-analyze security.

We're also honest about the limits. Anything that can write systemd units is effectively root on that machine, so these sandboxes exist to contain mistakes, not to stop an attacker who has already broken in. The real boundary sits in front of them: the agent isn't root, only the agent can reach these services, and the requests are small and strictly typed.

Terminal session: provisioning a new server ID reports "changed: true", and repeating it reports "changed: false". getent and the useradd journal show the new system account with no home directory and a nologin shell. The generated unit file sets the server's user, state directory, Java command line, MemoryMax=3072M and an empty CapabilityBoundingSet. Running the same request as root is refused as an unauthorized caller. systemd-analyze rates both waystone-helper and waystone-provisioner 1.3 OK, and ps shows the Java process running as the server's own account with parent PID 1. Username and hostname are redacted.

It plays

To close the stage, I gave a freshly provisioned server the Minecraft 26.3 jar and EULA. It started in 2.4 seconds, ran as its own account under systemd rather than as a child of the agent, and I joined it from my client.

We also settled an open question from Stage 2. A normal stop does save the world. I broke some blocks, stopped the server well before any autosave could run, and they were still broken after the restart. Minecraft just doesn't say so in its log.

What's next

For this test I copied the jar in by hand. Stage 3c removes that step: a small worker, running as the server's own user, will download and verify the jar, accept the EULA and write the settings. After that, a game server goes from nothing to joinable without anyone touching the machine.

Newer: Stage 3c-1: Waystone can now manage Minecraft server filesOlder: First Minecraft server started through the real agent path