Files
abrown38andClaude Opus 5.5 7b3f0f764c The web UI's certificate from Let's Encrypt, through Jarl
tls.acme names the certificate and jarl: the Jarl server and a token that
may only write the challenge record. Steward gets the certificate with
DNS-01 (lego), writing the record through Jarl's API into every view that
has the zone, renews it with a third of its lifetime left and swaps it
in without a restart. A check runs before every order: Jarl, the zone,
the token's permission, a test record, the zone's name servers, public
resolvers, clean-up; each step says what to fix. Staging by default.

With a certificate, each listener serves HTTPS and plain HTTP on one port
(redirecting plain HTTP, except from the server itself).

steward cert / cert check / cert renew, Server -> Certificate in the web
UI, GET /certificate, POST /certificate/check|renew. docs/certificates.md
and docs/jarl.md (the Jarl user and the token's grant).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-14 15:46:36 +01:00

3.3 KiB

Connecting Steward to Jarl

Steward uses Jarl, the BIND manager, for its DNS records. In this version that means one thing: the DNS-01 challenge for the web UI's certificate (certificates.md). Registering clients' names is planned to use the same connection.

Steward talks to Jarl's REST API with an API token. Give it a user of its own, with only the permission it needs.

1. A user for Steward, in Jarl

On the Jarl server, make a user without a password. It can't log in to Jarl's web UI, only use its tokens. Grant it the challenge record of Steward's own name, and nothing else:

jarl user create steward --no-password --comment "Steward on dhcp01" \
    --grant "records:write zones=adbraun.lol names=_acme-challenge.dhcp.adbraun.lol types=TXT"

Use your zone for adbraun.lol, and the name Steward's web UI is reached by for dhcp.adbraun.lol (tls.acme.domain). The grant lets the token add and remove TXT records at exactly _acme-challenge.dhcp.adbraun.lol:

  • nothing else in the zone (names=);
  • no other record type (types=TXT);
  • no other zone (zones=).

It can see that the zone exists, which it needs to find it, but it can't read the zone's other records.

Why not something wider:

  • Jarl's acme role (records:write names=_acme-challenge.* types=TXT) would let the token publish challenges for any name in any zone, and so obtain certificates for all of them. Steward needs only its own name.
  • Your own account's token would carry all your permissions, and Steward's certificate would stop renewing the day your account changes. A user per program keeps the two apart, and the audit log shows steward/... for what Steward did.

If the challenge name is a CNAME into a zone kept for challenges, such as _acme-challenge.dhcp.adbraun.lol CNAME dhcp.acme.adbraun.lol., grant the target instead: zones=acme.adbraun.lol names=dhcp.acme.adbraun.lol.

2. The token

Make the token, and copy it to the Steward server into a file only the steward user can read:

jarl token create dhcp01 --user steward -q > steward.token          # on the Jarl server, or with the jarl CLI anywhere
scp steward.token dhcp01:
ssh dhcp01 'sudo install -m 0600 -o steward -g steward steward.token /etc/steward/jarl.token && rm steward.token'
rm steward.token

A token file is better than putting the token in steward.yaml: the configuration file is readable by the steward group, and gets copied around more readily.

You can give the token an expiry (--expires 365d). Rotate it in Jarl with jarl token rotate ID --grace 1d, then put the new secret in the file and restart stewardd within the grace period. Since the certificate is renewed every couple of months, nothing breaks while you do.

3. Steward's settings

In /etc/steward/steward.yaml:

jarl:
  server: https://dns.adbraun.lol:8053
  token_file: /etc/steward/jarl.token
  # ca_cert: /etc/steward/jarl-ca.pem   # if Jarl's certificate isn't from a public CA

Then restart stewardd (systemctl restart steward). Steward needs to reach Jarl's API over the network: Jarl's listen must include an address Steward can reach, ideally over HTTPS.

steward cert check (certificates.md) tests the connection, the token's permission, and that the record reaches the internet.