Jarl keeps a BIND 9.20 server's whole configuration (views, ACLs, TSIG keys, zones of every type, records, named.conf options) in SQLite and renders named.conf, keys.conf and zone files from it. Every change goes through one changeset pipeline: whole-configuration validation, named-checkconf -z and named-checkzone in a staging directory, atomic install, rndc reconfig/reload, serial verification with rndc zonestatus, and rollback if named does not load the change. Changes apply one at a time by default or are bundled and applied together. Applied changesets can be reverted. - jarld: the daemon with the REST API and an embedded web UI, plus import, adopt, check, resync, backup and local user recovery commands - jarl: the CLI, including ACME DNS-01 hooks for certbot and acme.sh - users with argon2id passwords and CSRF-protected sessions; hashed API tokens with granular grants and roles; an audit log - systemd unit, sysusers.d/tmpfiles.d files, Makefile - unit tests, integration tests against a real named, scripts/e2e.sh - docs/ guides, README and CHANGELOG Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
67 lines
2.4 KiB
Bash
Executable File
67 lines
2.4 KiB
Bash
Executable File
#!/usr/bin/env sh
|
|
# shellcheck disable=SC2034
|
|
dns_jarl_info='Jarl (BIND manager)
|
|
Publishes DNS-01 challenge records through the jarl CLI.
|
|
Install: copy this file to ~/.acme.sh/dnsapi/dns_jarl.sh, then
|
|
acme.sh --issue --dns dns_jarl -d example.com -d "*.example.com"
|
|
Options:
|
|
JARL_SERVER Jarl server URL, e.g. https://ns1.example.com:8053 (optional if the jarl CLI is configured)
|
|
JARL_TOKEN API token, ideally one with the "acme" role (optional if the jarl CLI is configured)
|
|
JARL_VIEW Only write into this view (optional; default every view that has the zone)
|
|
JARL_BIN Path of the jarl binary (optional; default "jarl")
|
|
'
|
|
|
|
dns_jarl_add() {
|
|
fulldomain=$1
|
|
txtvalue=$2
|
|
_jarl_setup || return 1
|
|
_info "Jarl: adding TXT record for $fulldomain"
|
|
if ! _jarl acme set --exact "$fulldomain" "$txtvalue"; then
|
|
_err "Jarl: could not add the TXT record for $fulldomain"
|
|
return 1
|
|
fi
|
|
return 0
|
|
}
|
|
|
|
dns_jarl_rm() {
|
|
fulldomain=$1
|
|
txtvalue=$2
|
|
_jarl_setup || return 1
|
|
_info "Jarl: removing TXT record for $fulldomain"
|
|
if ! _jarl acme unset --exact "$fulldomain" "$txtvalue"; then
|
|
_err "Jarl: could not remove the TXT record for $fulldomain"
|
|
return 1
|
|
fi
|
|
return 0
|
|
}
|
|
|
|
#################### private functions ####################
|
|
|
|
_jarl_setup() {
|
|
JARL_SERVER="${JARL_SERVER:-$(_readaccountconf_mutable JARL_SERVER)}"
|
|
JARL_TOKEN="${JARL_TOKEN:-$(_readaccountconf_mutable JARL_TOKEN)}"
|
|
JARL_VIEW="${JARL_VIEW:-$(_readaccountconf_mutable JARL_VIEW)}"
|
|
JARL_BIN="${JARL_BIN:-$(_readaccountconf_mutable JARL_BIN)}"
|
|
JARL_BIN="${JARL_BIN:-jarl}"
|
|
if ! command -v "$JARL_BIN" >/dev/null 2>&1; then
|
|
_err "Jarl: the jarl CLI ($JARL_BIN) was not found; set JARL_BIN"
|
|
return 1
|
|
fi
|
|
# Remember the settings for renewals.
|
|
[ -n "$JARL_SERVER" ] && _saveaccountconf_mutable JARL_SERVER "$JARL_SERVER"
|
|
[ -n "$JARL_TOKEN" ] && _saveaccountconf_mutable JARL_TOKEN "$JARL_TOKEN"
|
|
[ -n "$JARL_VIEW" ] && _saveaccountconf_mutable JARL_VIEW "$JARL_VIEW"
|
|
[ "$JARL_BIN" != "jarl" ] && _saveaccountconf_mutable JARL_BIN "$JARL_BIN"
|
|
return 0
|
|
}
|
|
|
|
_jarl() {
|
|
# jarl reads JARL_SERVER and JARL_TOKEN from the environment, and falls
|
|
# back to its own configuration file when they are empty.
|
|
if [ -n "$JARL_VIEW" ]; then
|
|
JARL_SERVER="$JARL_SERVER" JARL_TOKEN="$JARL_TOKEN" "$JARL_BIN" -q "$@" --view "$JARL_VIEW"
|
|
else
|
|
JARL_SERVER="$JARL_SERVER" JARL_TOKEN="$JARL_TOKEN" "$JARL_BIN" -q "$@"
|
|
fi
|
|
}
|