Add a local unix socket for root on the server
jarld also listens on /run/jarl/jarl.sock (socket in jarl.yaml). Requests on it from root or jarld's own user need no token and act as an administrator; the kernel's SO_PEERCRED says who is connecting, and anyone else must send a token. The jarl CLI uses the socket when no server is configured, or with -s local, so 'sudo jarl status' works on the server with nothing set up and a lost token or password never locks root out. Changes are audited under the system user's name via "socket". The systemd unit creates /run/jarl (0750). Socket paths over 107 bytes are refused with a clear message. The docs explain the socket and what happens when a token is revoked. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
1 parent
f528c2aa9c
commit
cf49df0346
22 files changed
+570
-26
No files matched your search
@@ -28,6 +28,14 @@ change something (anything but GET/HEAD) must send it as `X-CSRF-Token`.
|
||||
`GET /auth/whoami` returns the user, the token (if any), the effective
|
||||
permissions and whether the caller is an administrator.
|
||||
|
||||
**The local socket**: on jarld's unix socket (`/run/jarl/jarl.sock`),
|
||||
requests from root or jarld's own user need no `Authorization` header and
|
||||
act as an administrator; other users must send a token:
|
||||
|
||||
```sh
|
||||
sudo curl --unix-socket /run/jarl/jarl.sock http://localhost/api/v1/status
|
||||
```
|
||||
|
||||
**HTTP Basic**, only on the lego `httpreq` routes (below): the username is
|
||||
the token's user and the password the API token.
|
||||
|
||||
|
||||
+24
@@ -46,6 +46,30 @@ file is `~/.config/jarl/config.yaml` (mode 0600), or `--config` /
|
||||
Get tokens from the web UI (Account → API tokens), from
|
||||
`jarl token create`, or from `jarld init --token` on the server.
|
||||
|
||||
### On the server itself
|
||||
|
||||
On the DNS server, root needs no setup at all:
|
||||
|
||||
```sh
|
||||
sudo jarl status
|
||||
sudo jarl record add adbraun.lol www A 192.0.2.10
|
||||
```
|
||||
|
||||
With no server configured, the CLI talks to jarld through its local unix
|
||||
socket, `/run/jarl/jarl.sock`, where root and the `jarl` user are
|
||||
administrators without a token ([permissions.md](permissions.md#the-local-socket)).
|
||||
The history and audit log show such changes as made by `root` via
|
||||
`socket`.
|
||||
|
||||
* `-s local` (or `JARL_SERVER=local`) uses the socket even when servers
|
||||
are configured, and `local` can be part of a list (`-s local,ns2`).
|
||||
`local` is reserved and can't be a configured server's name.
|
||||
* `JARL_SOCKET` points at another socket path.
|
||||
* A token given with `--token` or `JARL_TOKEN` is sent over the socket as
|
||||
well, and then its permissions apply.
|
||||
* Other users get a clear error ("only root and the jarl user can use
|
||||
jarld's local socket"); they configure a server and token as above.
|
||||
|
||||
### Several servers and groups
|
||||
|
||||
With more than one Jarl (say a primary and a secondary, each with its own
|
||||
|
||||
@@ -19,6 +19,7 @@ The CLI has its own small configuration file, described in [cli.md](cli.md).
|
||||
| Key | Default | Meaning |
|
||||
|-----|---------|---------|
|
||||
| `listen` | `["127.0.0.1:8053"]` | Addresses to listen on (`host:port`, several allowed). Keep these on localhost and management networks. |
|
||||
| `socket` | `/run/jarl/jarl.sock` | A local unix socket for the API. Requests on it from root or jarld's own user need no token and have administrator rights; anyone else must send a token ([permissions.md](permissions.md#the-local-socket)). The `jarl` CLI uses it when no server is configured. At most 107 bytes long; `""` turns it off. If it can't be created, jarld logs a warning and serves the network addresses only. |
|
||||
| `tls.cert_file`, `tls.key_file` | (empty: plain HTTP) | PEM certificate chain and key. Both or neither. The files are rechecked every 10 minutes and on SIGHUP (`systemctl reload jarl`), so renewed certificates are used without a restart. |
|
||||
| `trusted_proxies` | `[]` | Addresses or prefixes of reverse proxies whose `X-Forwarded-For` and `X-Forwarded-Proto` (or `Forwarded: proto=`) headers are believed. Needed for correct client IPs in the audit log and for rate limiting behind a proxy, and for knowing that a proxied request came over HTTPS (the session cookie's Secure flag, `acme.httpreq`). From other addresses these headers are ignored. |
|
||||
| `session.lifetime` | `12h` | A web session ends this long after login... |
|
||||
|
||||
+7
-2
@@ -227,10 +227,15 @@ Open `https://<management-address>:8053/` and log in as `admin`.
|
||||
|
||||
## 9. Set up the CLI
|
||||
|
||||
The CLI can run on the server or on any machine that can reach jarld.
|
||||
On the server itself, root needs nothing: `sudo jarl status` and every
|
||||
other command use jarld's local socket without a token
|
||||
([cli.md](cli.md#on-the-server-itself)).
|
||||
|
||||
On other machines, or as an ordinary user, give the CLI a server and a
|
||||
token:
|
||||
|
||||
```sh
|
||||
jarl config set server https://ns1.adbraun.lol:8053 # or http://127.0.0.1:8053 on the server
|
||||
jarl config set server https://ns1.adbraun.lol:8053
|
||||
jarl config set token # paste the token from 'jarld init' at the prompt
|
||||
jarl status
|
||||
jarl zone list
|
||||
|
||||
+49
-1
@@ -7,6 +7,7 @@
|
||||
| People in the web UI | Username + password → session cookie | argon2id password hashes. The session cookie is HttpOnly and SameSite=Strict and lasts 12h (2h idle). Every change also needs the session's CSRF token, which the UI sends in `X-CSRF-Token`. Changing a password logs out the user's other sessions. |
|
||||
| CLI, scripts, certbot | API token: `Authorization: Bearer jarl_...` | Shown once at creation, stored hashed. Optional expiry. Revocable. Last use time and IP are recorded. |
|
||||
| lego / Traefik (`httpreq`) | HTTP Basic: the token's user and the API token | Only on `/api/v1/acme/httpreq/...`, only when `acme.httpreq.enabled` is set, and by default only over HTTPS ([acme.md](acme.md)). The token's grants apply as usual. |
|
||||
| Root on the server, with the CLI | jarld's local socket (`/run/jarl/jarl.sock`): no token | `sudo jarl ...` with no server configured. The kernel tells jarld which system user is connecting; root and the `jarl` user are administrators, anyone else must send a token. Audited as the system user (e.g. `root`) via `socket`. See [The local socket](#the-local-socket). |
|
||||
| Root on the server | `jarld` subcommands (`init`, `user`, `import`, `adopt`, `check`, `resync`, `backup`) | Work directly on the database. They are for bootstrapping and recovery, and are audited as "local". |
|
||||
|
||||
API tokens are how you give a script, a tool or a person limited access:
|
||||
@@ -161,9 +162,56 @@ In the web UI, the **Rotate** button next to each token asks how long the
|
||||
old secret should keep working and how long the token should last, then
|
||||
shows the new secret once.
|
||||
|
||||
## The local socket
|
||||
|
||||
jarld also listens on a unix socket, `/run/jarl/jarl.sock` (`socket` in
|
||||
jarl.yaml; systemd creates `/run/jarl`). It serves the same API, but a
|
||||
request on it without a token is trusted by **who sent it**: the kernel
|
||||
reports the connecting process's user (`SO_PEERCRED`), and
|
||||
|
||||
| Connecting user | Without a token | With a token |
|
||||
|--|--|--|
|
||||
| root | administrator | the token's permissions |
|
||||
| `jarl` (jarld's own user) | administrator | the token's permissions |
|
||||
| anyone else | refused (401) | the token's permissions |
|
||||
|
||||
This gives root nothing it doesn't already have: root can read Jarl's
|
||||
database, run `jarld user token` and edit named.conf directly. What it adds
|
||||
is convenience and a way back in: on the server, `sudo jarl status` and
|
||||
every other command work with nothing configured and no token stored in a
|
||||
file, even after every token has been revoked and every password
|
||||
forgotten.
|
||||
|
||||
* The socket file is mode 0600 in a 0750 directory owned by `jarl`, so
|
||||
other users can't even connect; the user check doesn't depend on that.
|
||||
* Changes made this way are in the history and audit log under the system
|
||||
user's name (`root`) with `socket` as the method. That name isn't a Jarl
|
||||
user, so it has no tokens of its own: `sudo jarl token create laptop
|
||||
--user admin` makes one for a real user.
|
||||
* The CLI uses the socket only when no server is configured at all, or
|
||||
with `-s local`, so a configured server is never silently swapped for
|
||||
the local one ([cli.md](cli.md#on-the-server-itself)).
|
||||
* Turn it off with `socket: ""` in jarl.yaml.
|
||||
|
||||
## Recovering access
|
||||
|
||||
On the server, as root or the `jarl` user:
|
||||
Revoking a token never locks you out: tokens and web sessions are
|
||||
separate. Revoking the token your CLI uses stops only the programs that
|
||||
use it; you stay logged in to the web UI with your password, with all your
|
||||
rights, and can make a new token under Account → API tokens. Jarl also
|
||||
refuses to delete, disable or demote the last administrator.
|
||||
|
||||
On the server, root can always use the CLI through the local socket,
|
||||
without a token:
|
||||
|
||||
```sh
|
||||
sudo jarl whoami
|
||||
sudo jarl token create laptop --user admin # a new token for admin
|
||||
sudo jarl user update admin --password # a new password
|
||||
```
|
||||
|
||||
The `jarld` subcommands work even when jarld isn't running. As root or the
|
||||
`jarl` user:
|
||||
|
||||
```sh
|
||||
sudo -u jarl jarld user list
|
||||
|
||||
Reference in new issue
Block a user