Files
jarl/docs/permissions.md
T
abrown38andClaude Opus 5.5 6b44b92975 Add an httpreq endpoint for lego and Traefik
jarld can now answer lego's httpreq DNS provider
(POST /api/v1/acme/httpreq/present and /cleanup), so lego and Traefik
publish DNS-01 challenges with only environment variables, without the
jarl CLI. lego's username and API token arrive as HTTP Basic auth,
accepted on these routes only.

The endpoint is off by default (acme.httpreq.enabled) and HTTPS-only by
default: jarld's own TLS, or a trusted proxy that says so with
X-Forwarded-Proto or Forwarded (the last value counts). Plain HTTP can be
allowed from loopback only or everywhere. GET /api/v1/acme/httpreq shows
how jarld sees a request, to check a proxy setup.

jarl acme and the endpoint share their code in internal/acme. Documented
in docs/acme.md, configuration.md, api.md and permissions.md.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-08 13:48:47 +00:00

5.6 KiB

Users, tokens and permissions

Ways to authenticate

Who How Notes
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). The token's grants apply as usual.
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: a token restricted with grants (below) can, for example, only change TXT records under _acme-challenge in one zone. TSIG keys, on the TSIG keys page, are something else: shared secrets that BIND servers use to authenticate each other (zone transfers, NOTIFY); they don't give access to Jarl.

Failed logins are rate limited: 8 per username and 20 per client IP within 15 minutes. Failed token attempts count against the IP too. Every attempt is in the audit log.

A user without a password (--no-password) is a service account. It can't log in to the web UI and is used only through its tokens, which suits certbot, CI jobs and backups.

Grants

A user's permissions are a list of grants. Administrators (admin: true) may do everything, and only they can manage users, see everyone's tokens and run resync.

A grant is written as:

RESOURCE:ACCESS [zones=PATTERNS] [views=PATTERNS] [names=PATTERNS] [types=TYPES]
Resource Covers
zones zone definitions (create, delete, SOA, TTL, view) and zone options
records records in primary zones
views views and view options
acls ACLs
tsig TSIG keys (write is needed to see a secret)
options server options, top-level statements, the defaults for new zones, jarl check
audit everyone's audit events and changesets (without it, users see only their own)
stats query statistics, including client addresses and the names they look up (read only)
* all of the above

ACCESS is read or write (write includes read). Filters narrow a grant. Each takes comma separated patterns where * and ? are wildcards, and a missing filter matches everything:

  • zones=adbraun.lol,*.adbraun.lol: zone names, without the final dot
  • views=internal: view names (_default means zones outside any view)
  • names=_acme-challenge.*: record owner names, as FQDNs without the final dot
  • types=TXT,CNAME: record types

Examples:

*:read                                                    read everything
records:write zones=lab.adbraun.lol                       edit records in one zone
zones:write zones=*.lab.adbraun.lol                       create/delete zones below lab
records:write zones=adbraun.lol views=internal            only the internal copy of a split zone
records:write names=_acme-challenge.* types=TXT           ACME challenges anywhere
records:write zones=acme.adbraun.lol types=TXT            only TXT records in a dedicated ACME zone

A user who may see some records of a zone may also see that the zone exists (its name and type), but not its other records.

Roles

Roles are ready-made grant lists. Choosing a role copies its grants, which you can then edit.

Role Grants
readonly *:read (includes statistics)
dns-editor zones:write, records:write, views:read, acls:read, options:read
operator *:write (everything except user management)
acme records:write names=_acme-challenge.* types=TXT
jarl user create alice --role dns-editor
jarl user update alice --grant "records:write zones=adbraun.lol" --grant "zones:read"   # replaces all grants
jarl user update alice --role readonly

Tokens

Every token belongs to a user, and every token request acts as that user. The audit log shows the user and the token name.

  • A token without grants has all of its user's permissions, and they follow the user: if the user loses a permission, so does the token.
  • A token with grants is restricted to them. Effective permission is user grants ∩ token grants: a token can never do more than its user. Admin rights don't pass through a restricted token.
  • A restricted token can create further tokens, but only ones no wider than itself.
  • Disabling or deleting a user stops all their tokens at once.
jarl token create laptop                                  # full rights of the user, no expiry
jarl token create ci --grant "records:write zones=lab.adbraun.lol" --expires 90d
jarl token create certbot --user certbot --role acme       # admin: a token for another user
jarl token list --all
jarl token revoke 12

In the web UI: Account → API tokens (your own) and Users → user → Tokens (admin).

Recovering access

On the server, as root or the jarl user:

sudo -u jarl jarld user list
sudo -u jarl jarld user passwd admin          # set a new password and re-enable the account
sudo -u jarl jarld user add --admin rescue    # a new administrator
sudo -u jarl jarld user token admin cli       # a new API token for a user