Skip to content

feat(tsig): key lookup, root-only secret and tsigKeyId in the queue - #97

Merged
0kaba0 merged 2 commits into
developfrom
feat/tsig-common
Oct 12, 2026
Merged

0kaba0 merged 2 commits into
developfrom
feat/tsig-common

Conversation

@0kaba0

@0kaba0 0kaba0 commented Oct 11, 2026 •

Copy link
Copy Markdown
Collaborator

Step 1 of 3 for #96 (TSIG-signed transfers from hosting panels). Owner decisions:

  • transfers allowed by key only;
  • the key is passed as one pair --tsig=[ALGORITHM:]KEY:SECRET (dig -y form); KEY is the label or full name shown in Settings › DNS; no default-key fallback, so the server always shows which key it uses;
  • no panel test servers: checks run on fixtures here and against real BIND/PowerDNS in containers in steps 2–3.

New, touches no tested path:

  • common/seconddns-tsig:
    • resolve --tsig=… [--write]: finds KEY via GET /api/user/tsig-keys with the panel's API key. An unknown key fails and lists the account's keys. An algorithm prefix must match the key. The secret is checked against the key's algorithm (base64, 32/64 bytes).
    • With --write it stores [tsig] key_id/key_name/algorithm/secret_file in seconddns.conf, and the secret in /etc/seconddns/tsig.secret (0600). The config stays 0644 because hooks read it as non-root. The secret is kept so a later step can put the key back when a panel rewrites its DNS config.
    • status: the key in use, whether the secret is stored, and whether the account still has the key under the same id.
    • check-secret, secret, clear.
  • seconddns_common.py: resolve_tsig_key, parse_tsig_pair, check_tsig_secret (appended).

Existing code, every touched line:

  • seconddns-queued: load_config reads [tsig] key_id. send_op create adds tsigKeyId only when it is set, and logs a 422 with the key id. Without [tsig] the request body is byte-identical (asserted).
  • */install.sh: one appended line fetching seconddns-tsig. */uninstall.sh: two appended lines removing it and the secret file.

Nothing calls seconddns-tsig yet. Steps 2 (BIND panels) and 3 (PowerDNS panels) add install.sh --tsig=…, seconddns-tsig enable/disable/restore and the DNS-server side.

Tests: test_tsig.sh (35 checks):

  • pair parsing: missing secret, wrong algorithm prefix, secret length against the key;
  • lookup: by label and full name, unknown key with the key list;
  • --write: section written; secret not in the config; file 0600; rest of the config and its mode kept; one section after a rewrite;
  • status: ok, recreated key, deleted key, off;
  • queue: tsigKeyId sent, 422 explained, body unchanged without [tsig].

test_queue.sh still 104/104. CI step added.

seconddns-tsig finds the account's TSIG key through the API (default or
by label), checks a secret against the key's algorithm, writes a [tsig]
section to seconddns.conf and the secret to /etc/seconddns/tsig.secret
(0600) so the key can be put back if the panel rewrites its DNS config.
With a [tsig] section, seconddns-queued creates zones with tsigKeyId;
without one the request is unchanged. Installers fetch the tool, the
uninstallers remove it and the secret file.
@0kaba0

0kaba0 commented Oct 12, 2026

Copy link
Copy Markdown
Collaborator Author

CHANGES REQUESTED at 57579e0, one point.

Verified: resolve finds the account's default key or the one with the given label through the panel's API key; check-secret validates base64 and the 32/64-byte length per algorithm, the same sizes the dashboard generates; --write rewrites only the [tsig] section (one section, rest of the file and its mode kept, atomic replace) and puts the secret in a root-only 0600 file that the world-readable config names; clear removes both; the queue adds tsigKeyId only when the section exists and the create body is byte-identical without it; a 422 with a key is explained in the log. Installers fetch or copy the new tool, uninstallers remove it and the secret; CI runs test_tsig.sh (24 checks, green). No attribution lines.

  1. seconddns-tsig resolve --write without --secret after an earlier write with one: the new [tsig] body has no secret_file, so the config stops naming the file while /etc/seconddns/tsig.secret stays on disk with the previous key's secret. From then on seconddns-tsig secret says "no TSIG secret stored" and clear leaves the file behind (only uninstall removes it); if the key id changed, the stored secret is the wrong key's anyway. The test's "rewrite replaces the key" row takes exactly this path and does not look at the file. Define it: a --write without --secret removes the stored secret file (or keeps the secret_file line only when the key id is unchanged), and add the row: write with secret, write again without, then secret and clear behave as documented.

PR 2 approach: agreed. In BIND allow-transfer is an OR-list, so removing our IPs and adding key "<name>"; makes our transfers key-only while other secondaries keep their address entries. Keep our IPs in also-notify, NOTIFY is unsigned. The container check (named-checkconf, AXFR with the key passes, from our IPs without the key refused) is the right evidence.

…tly, status

No default-key fallback: the key is named by its label or full name, so
the server later shows which key it uses. The pair follows dig -y; an
algorithm prefix must match the key. seconddns-tsig status reports the
key and whether the account still has it under the same id.
@0kaba0

0kaba0 commented Oct 12, 2026

Copy link
Copy Markdown
Collaborator Author

APPROVED at c69ef42.

The previous point is closed by construction: the key and its secret now arrive as one --tsig=[ALGORITHM:]KEY:SECRET pair (the dig -y form), so every --write stores the secret and names the file; the orphaned-secret path no longer exists, and clear removes section and file (row 5 checks both). Verified: the key is found by label or full name as shown in Settings › DNS, an unknown one is refused with the account's key list, a leading algorithm must match the key's, the secret is checked for base64 and the key's length; status reports the stored key, whether the secret is on disk, and exits non-zero when the account no longer has the key or has it under a new id. Queue behaviour unchanged from 57579e0. test_tsig.sh 35/35 in CI; no attribution lines. The secret on the installer command line has the same exposure as the existing --api-key= argument, so nothing new there.

Taking the label or name instead of the id was the right call; the id is not visible in the dashboard.

@0kaba0
0kaba0 merged commit b226288 into develop Oct 12, 2026
1 check passed
@0kaba0
0kaba0 deleted the feat/tsig-common branch October 12, 2026 11:36
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant