feat(gateway): htpasswd Basic auth — close #1010

Replaces the earlier PAM+binary approach with nginx's built-in
`auth_basic` module. No new binary, no new systemd service, no PAM.

New option `services.hyperhive.gateway.auth`:
- `enable` — off by default
- `htpasswdFile` — host path to an htpasswd file (required when enable)
- `realm` — WWW-Authenticate realm string (default "hyperhive");
  restricted to `strMatching "[^\"$]*"` to prevent nginx config injection

When enabled:
- the parent directory of `htpasswdFile` is bind-mounted read-only
  into the gateway container at `/run/gateway-auth/`
- the `"/"` proxy location gets `auth_basic` + `auth_basic_user_file`

Create credentials: `htpasswd -Bc /path/to/file alice` (BCrypt).
See `docs/gateway.md` ("HTTP Basic auth") for the full setup guide.
This commit is contained in:
atlas 2026-06-01 22:50:04 +02:00
commit 25d2951d1e
7 changed files with 128 additions and 532 deletions

View file

@ -339,3 +339,44 @@ the nginx config get custom error pages. Other gateway routes
(forge / matrix / fluffychat) get nginx defaults — extending the
custom-error pattern there is a separate follow-up.
## HTTP Basic auth
`services.hyperhive.gateway.auth.enable = true` gates every request to
the main vhost (`_`) behind HTTP Basic auth. nginx's built-in `auth_basic`
module validates credentials; no extra service or host-side daemon is
required.
**Setup:**
```nix
services.hyperhive.gateway.auth = {
enable = true;
htpasswdFile = "/etc/hyperhive/gateway.htpasswd";
# realm = "hyperhive"; # optional, default shown
};
```
Create the htpasswd file on the host:
```sh
# Create new file with first user (BCrypt, recommended):
htpasswd -Bc /etc/hyperhive/gateway.htpasswd alice
# Add subsequent users:
htpasswd -B /etc/hyperhive/gateway.htpasswd bob
```
The file must be readable by the `nginx` user inside the container
(`chmod 0644`). The module bind-mounts the file's parent directory
read-only into the container at `/run/gateway-auth/`; nginx reads
`/run/gateway-auth/<filename>`.
**What is not gated:** per-agent UI routes emitted into `agents.conf`
(served under `/agent/<name>/`) inherit no auth from `/` — nginx
applies `auth_basic` per-location. Full per-agent coverage is a
follow-up.
**Realm:** the `WWW-Authenticate: Basic realm="..."` string browsers
display in the credential dialog. Defaults to `"hyperhive"`. Must not
contain `"` or `$`.