cert get: combined file for HAProxy, --local, saved NAME; cert list shows get and last download
- jarl cert get --combined PATH writes the key and full chain in one file
(mode 600, atomic), kept outside --dir so it can live in HAProxy's crt
directory; JARL_CERT_COMBINED for the hook. Turning it on, moving it or
removing it ('') applies from the files on disk and runs the hook.
- jarl cert get --local writes the combined file and runs the hook from
this host's files, without asking jarld.
- jarl cert saved NAME shows all of one certificate's settings.
- jarl cert list: USES "get" for certificates for other hosts, and a
PULLED column (last download, "(old)" while a host is behind). Owners
now see their own downloads (pulled_by), not only administrators.
- jarl cert get without a name refuses per-certificate flags.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
1 parent
3fb159cf4d
commit
42e79af678
9 files changed
+578
-76
No files matched your search
+1
-1
@@ -603,7 +603,7 @@ Administrators only. See [certificates.md](certificates.md#api).
|
||||
|
||||
| Method | Path | Body |
|
||||
|--------|------|------|
|
||||
| GET | `/certificates` | `certificates` (with `status`, `next_attempt`, `issuing_since`, `serving`, `files`) and `account` |
|
||||
| GET | `/certificates` | `certificates` (with `status`, `next_attempt`, `issuing_since`, `serving`, `files`, and for one obtained with `jarl cert get` `owner_id`, `owner` and `pulled_by`: every download for an administrator, the caller's own for the owner) and `account` |
|
||||
| POST | `/certificates` | `{"name", "domains", "uses", "challenge", "key_type", "comment"}`, or `{"name", "source": "file", "cert_file", "key_file", "uses"}`; `"issue": false` doesn't start obtaining it |
|
||||
| POST | `/certificates/check` | `{"domains", "challenge"}`: the route of each challenge |
|
||||
| GET, PATCH, DELETE | `/certificates/{name}` | |
|
||||
|
||||
+67
-13
@@ -274,6 +274,7 @@ export JARL_SERVER=https://jarl.adbraun.lol:8053 JARL_TOKEN=@/root/jarl.token
|
||||
jarl cert get mail -d mail.adbraun.lol -d smtp.adbraun.lol --hook 'systemctl reload postfix dovecot'
|
||||
sudo jarl cert schedule # a daily systemd timer runs 'jarl cert get'
|
||||
jarl cert saved # what this host has, and when it expires
|
||||
jarl cert saved mail # all of mail's settings
|
||||
```
|
||||
|
||||
* **Asking again** with the same names returns the certificate jarld has:
|
||||
@@ -286,12 +287,26 @@ jarl cert saved # what this host has, and when it exp
|
||||
expiry, when it was fetched). Each file is replaced at once, never
|
||||
half written. The key is checked against the certificate before
|
||||
anything is written.
|
||||
* **Saved settings**: the names, `--dir`, `--hook`, the server and the
|
||||
token are saved in `/etc/jarl/cert-get/NAME.json` (as root;
|
||||
`~/.config/jarl/cert-get` otherwise), readable only by their owner.
|
||||
`jarl cert get` without a name does every saved certificate. A token
|
||||
given as `@FILE` is saved as that reference, not copied. `jarl cert
|
||||
forget NAME` stops getting one (`--delete` deletes it on jarld too).
|
||||
* **A combined file** (`--combined PATH`): the key, then the full chain,
|
||||
in one file (mode 600), as HAProxy wants. See [HAProxy](#haproxy).
|
||||
* **Saved settings**: the names, `--dir`, `--combined`, `--hook`, the
|
||||
server and the token are saved in `/etc/jarl/cert-get/NAME.json` (as
|
||||
root; `~/.config/jarl/cert-get` otherwise), readable only by their
|
||||
owner. `jarl cert get` without a name does every saved certificate. A
|
||||
token given as `@FILE` is saved as that reference, not copied. `jarl
|
||||
cert saved NAME` shows them all (the token never). `jarl cert forget
|
||||
NAME` stops getting one (`--delete` deletes it on jarld too).
|
||||
* **Changing a setting**: run `jarl cert get NAME` with just that option
|
||||
(`--hook '...'`, `--combined PATH`, `--dir DIR`); the others stay.
|
||||
`--hook ''` removes the hook, `--combined ''` stops writing the
|
||||
combined file and deletes it. The run still asks jarld for the
|
||||
certificate, but downloads nothing while this host has the current one.
|
||||
A new or moved combined file is written from the files this host
|
||||
already has, and the hook runs.
|
||||
* **`--local`** doesn't ask jarld at all: it writes the combined file and
|
||||
runs the hook from the files this host has. Use it to apply a changed
|
||||
setting while jarld is unreachable, or to test a hook. New names still
|
||||
need jarld.
|
||||
* **Several Jarl servers on one host**: each server has its own
|
||||
certificate names, so two servers may both have a `proxy`. The host
|
||||
keeps one `proxy` per settings directory, though: asking another server
|
||||
@@ -299,12 +314,14 @@ jarl cert saved # what this host has, and when it exp
|
||||
holding another certificate's files. Choose another name or `--dir`, or
|
||||
pass `--replace` to take the name (or directory) over. A `--dir` that
|
||||
another saved certificate uses is always refused.
|
||||
* **The hook** runs with `sh` after new files are written, with
|
||||
`JARL_CERT_NAME`, `JARL_CERT_DIR`, `JARL_CERT_CERT`, `JARL_CERT_CHAIN`,
|
||||
`JARL_CERT_FULLCHAIN`, `JARL_CERT_KEY`, `JARL_CERT_DOMAINS`,
|
||||
`JARL_CERT_SERIAL`, `JARL_CERT_NOT_AFTER` and `JARL_CERT_RENEWED` (1 when
|
||||
it replaced an older certificate). If it fails, `jarl cert get` exits
|
||||
non-zero and runs it again next time. It has 5 minutes.
|
||||
* **The hook** runs with `sh` after new files are written or the
|
||||
combined file changes (and with `--local`), with `JARL_CERT_NAME`,
|
||||
`JARL_CERT_DIR`, `JARL_CERT_CERT`, `JARL_CERT_CHAIN`,
|
||||
`JARL_CERT_FULLCHAIN`, `JARL_CERT_KEY`, `JARL_CERT_COMBINED` (empty
|
||||
without `--combined`), `JARL_CERT_DOMAINS`, `JARL_CERT_SERIAL`,
|
||||
`JARL_CERT_NOT_AFTER` and `JARL_CERT_RENEWED` (1 when it replaced an
|
||||
older certificate). If it fails, `jarl cert get` exits non-zero and runs
|
||||
it again next time. It has 5 minutes.
|
||||
* **`jarl cert schedule`** (Linux with systemd, as root) writes
|
||||
`/etc/systemd/system/jarl-cert-get.service` and `.timer`, which run
|
||||
`jarl cert get` daily at a random time within the hour after midnight,
|
||||
@@ -314,7 +331,44 @@ jarl cert saved # what this host has, and when it exp
|
||||
**On the Certificates page**, the administrators see each certificate's
|
||||
owner and who downloaded it: the token, from where, when, and whether
|
||||
that host has the current certificate or hasn't fetched the renewed one
|
||||
yet. `jarl cert show NAME` says the same.
|
||||
yet. `jarl cert show NAME` says the same. The owner's own tokens see
|
||||
their own downloads there too. In `jarl cert list`, such a certificate's
|
||||
USES is `get`, and PULLED is the last download, with `(old)` while a host
|
||||
hasn't fetched the renewed one.
|
||||
|
||||
### HAProxy
|
||||
|
||||
HAProxy wants the key and the chain in one file. Give `jarl cert get` a
|
||||
`--combined` path outside `--dir`:
|
||||
|
||||
```sh
|
||||
jarl cert get proxy -d adbraun.lol -d '*.adbraun.lol' \
|
||||
--combined /etc/haproxy/certs/adbraun.lol.pem --hook 'systemctl reload haproxy'
|
||||
jarl cert get webmail -d webmail.adbraun.lol \
|
||||
--combined /etc/haproxy/certs/webmail.pem --hook 'systemctl reload haproxy'
|
||||
```
|
||||
|
||||
```
|
||||
frontend https
|
||||
bind :443 ssl crt /etc/haproxy/certs/
|
||||
```
|
||||
|
||||
HAProxy loads every file in a `crt` directory and picks one by SNI, so
|
||||
`/etc/haproxy/certs` should hold only combined files. Don't point `crt`
|
||||
at `--dir` (`/etc/jarl/certs/NAME`): HAProxy would try to load
|
||||
`cert.pem`, `privkey.pem` and `jarl-cert.json` there too, and refuse
|
||||
to start. A `--combined` path that would overwrite a file in a saved
|
||||
certificate's directory, or another certificate's combined file, is
|
||||
refused.
|
||||
|
||||
The combined file is mode 600, owned by the user running `jarl cert get`
|
||||
(root under the timer). HAProxy reads its certificates as root before it
|
||||
drops privileges, so that's fine.
|
||||
|
||||
To add a combined file to a certificate this host already has, run
|
||||
`jarl cert get proxy --combined /etc/haproxy/certs/adbraun.lol.pem`: it's
|
||||
written from the files on disk and the hook runs, with nothing
|
||||
downloaded.
|
||||
|
||||
## Security notes
|
||||
|
||||
|
||||
@@ -452,7 +452,10 @@ jarl cert export mail --part bundle # one part to stdout: fullc
|
||||
jarl cert get mail -d mail.adbraun.lol --hook 'systemctl reload postfix' # on another host: get, download, hook
|
||||
jarl cert get # every saved certificate (what the timer runs)
|
||||
jarl cert get proxy -s other --replace # take over a name saved here for another server
|
||||
jarl cert get proxy --combined /etc/haproxy/certs/proxy.pem # also key + chain in one file (HAProxy); '' stops it
|
||||
jarl cert get proxy --hook 'systemctl reload haproxy' --local # change a setting; apply it from this host's files, without jarld
|
||||
jarl cert saved # this host's certificates and their expiry
|
||||
jarl cert saved proxy # all of one certificate's settings (never the token)
|
||||
jarl cert forget mail [--delete] # stop getting it here
|
||||
sudo jarl cert schedule [--remove] # daily systemd timer for jarl cert get
|
||||
jarl cert delete ns1
|
||||
|
||||
Reference in new issue
Block a user