fix(nano): make the installer work on EL10 and stop serving hasJoined to the world
Deploying `felis nano` to a real Rocky Linux 10 host surfaced four defects that no local check could see. Fixed together because they all sit on the same path from `curl|bash` to a running felis-nano.service. * docker killed the nano install on EL10. `acquire_nano_binary` pulled in docker purely to build the binary; on Rocky 10.2 the docker-ce el10 rpms install but dockerd refuses to start, so the install died at `systemctl enable --now docker`. nano needs one static binary, not an image, so the docker dependency is gone: fetch_source -> install_go_toolchain (pinned FELIS_GO_VERSION, default 1.26.4, amd64/arm64) -> build_nano_binary. * the built binary could not be exec'd by systemd (203/EXEC). The Go linker renames its output out of $TMPDIR, and a same-filesystem rename carries the source SELinux label, so `go build -o /usr/local/bin/felis` produced a binary labelled user_tmp_t rather than bin_t. root is unconfined and could run it by hand, which is what made this look fine, but the DynamicUser service could not. build_nano_binary now stages the output and installs it as a fresh file so the policy type transition labels it bin_t, with restorecon as a belt. * re-running the installer did not converge. `systemctl enable --now` is a no-op on an already-active unit, so a rebuilt binary was installed while the old process kept running. Now enable + restart. * the Velocity wiring comment in cmd/felis/nano.go was wrong. authlib appends /session/minecraft/hasJoined itself, so -Dmojang.sessionserver takes the base URL only, as the installer has always printed. Also bind to loopback by default. hasJoined is unauthenticated by protocol -- authlib speaks the vanilla sessionserver dialect and sends no token -- so a public bind is an open auth relay: anyone can point their own proxy at it and spend this host's egress IP on Mojang until Mojang rate-limits it and the operator's own players stop getting in. It is not an identity bypass (a caller still needs a serverId hash bound to their own server key, which the upstream Yggdrasil validates), but it is someone else's traffic on your address. FELIS_NANO_LISTEN and the -listen flag now default to 127.0.0.1:8081, which a same-host Velocity reaches unchanged; serving an off-host proxy is an explicit opt-in. configure_nano_firewall no longer opens a port for a loopback bind, and summary_nano prints the real bind address plus the relay warning. Verified on the target host: installs with no docker present, service active, binary labelled bin_t, `ss` shows LISTEN 127.0.0.1:8081, an external request is unreachable, and an in-host request returns 204 with the login logged. BREAKING CHANGE: felis nano defaults to 127.0.0.1:8081 instead of 0.0.0.0:8081. A Velocity proxy on another machine must now set FELIS_NANO_LISTEN (or -listen) to a reachable address, and should allow that port only from the proxy's IP.
This commit is contained in:
2 files changed
+110
-20
No files matched your search
+10
-3
@@ -5,8 +5,11 @@ package main
|
||||
// full Felis control plane (no k3s, no Postgres, no DB). It reads [[auth_source]] from
|
||||
// felis.toml, leads with Mojang as the code-owned identity anchor (正版优先), and serves the
|
||||
// vanilla sessionserver hasJoined endpoint. Point Velocity at it with
|
||||
// -Dmojang.sessionserver=http://<this-host>:8081/session/minecraft/hasJoined
|
||||
// and authlib verifies logins against Mojang plus every configured third-party source.
|
||||
// -Dmojang.sessionserver=http://127.0.0.1:8081
|
||||
// — the base URL only: authlib appends /session/minecraft/hasJoined itself. Then it
|
||||
// verifies logins against Mojang plus every configured third-party source. Serving a
|
||||
// proxy on another host means binding off-loopback with -listen; see the flag below for
|
||||
// why that is an explicit opt-in and not the default.
|
||||
//
|
||||
// This is the no-database delivery of the identical brain `felis api` mounts through its
|
||||
// route table (internal/api.HasJoinedHandler). `felis setup --nano` / the bootstrap nano
|
||||
@@ -35,7 +38,11 @@ func cmdNano(args []string, stdout, stderr io.Writer) int {
|
||||
fs := flag.NewFlagSet("nano", flag.ContinueOnError)
|
||||
fs.SetOutput(stderr)
|
||||
cfgPath := fs.String("config", "/etc/felis/felis.toml", "path to felis.toml (reads [[auth_source]])")
|
||||
listen := fs.String("listen", ":8081", "listen address for the hasJoined endpoint")
|
||||
// Loopback default: hasJoined carries no auth token (authlib speaks the vanilla
|
||||
// sessionserver protocol), so a public bind is an open auth relay — anyone can point
|
||||
// their proxy at it and spend this host's egress IP on Mojang. A same-host Velocity
|
||||
// reaches 127.0.0.1; serving an off-host proxy is an explicit -listen opt-in.
|
||||
listen := fs.String("listen", "127.0.0.1:8081", "listen address for the hasJoined endpoint")
|
||||
if err := fs.Parse(args); err != nil {
|
||||
return 2
|
||||
}
|
||||
|
||||
Reference in new issue
Block a user