This guide assumes that you already have a working BIND primary and secondary DNS pair. It focuses specifically on authenticating AXFR and IXFR zone transfers with TSIG.
TSIG uses a shared secret to authenticate DNS transactions between configured systems. It is different from DNSSEC, which signs zone data so that validating resolvers can verify DNS answers.
Tested on: Rocky Linux 10.2 (Red Quartz); BIND 9.18.33; sample zone
example.com; primary192.0.2.10; secondary192.0.2.20.
dnssec-policy and inline signing—not the HMAC key shown here.
Quick reference
| Task | Command or directive |
|---|---|
| Generate a new TSIG key once | tsig-keygen -a hmac-sha256 xfer-example.com > /etc/named/keys/xfer-example.com.key |
| Restore SELinux labels on the key | restorecon -RFv /etc/named/keys |
Validate named.conf on each server |
named-checkconf |
| Validate the primary zone file | named-checkzone example.com /var/named/example.com.zone |
| Restrict transfers on the primary | allow-transfer { key xfer-example.com; }; inside the zone |
| Associate the TSIG key with the primary | primaries { 192.0.2.10 key xfer-example.com; }; on the secondary |
| Reload BIND | systemctl reload named or systemctl reload named-chroot |
| Follow transfer logs | journalctl -u named -f or journalctl -u named-chroot -f |
| Test AXFR with TSIG | dig @192.0.2.10 example.com AXFR -k /etc/named/keys/xfer-example.com.key |
| Force a secondary retransfer | rndc retransfer example.com |
TSIG vs DNSSEC for BIND Zone Transfers
Many guides mix these terms because both involve keys. They solve different problems.
| Feature | TSIG | DNSSEC |
|---|---|---|
| Authentication target | DNS transactions between configured systems | DNS data returned to validating resolvers |
| Typical use | AXFR, IXFR, NOTIFY, dynamic updates | Zone signing and response validation |
| Key model | Shared secret | Public/private key pairs |
| Encrypts traffic | No | No |
| Used in this tutorial | Yes | No |
TSIG protects the authenticity and integrity of the zone transfer transaction. It does not hide transferred records from passive network observers. RFC 8945 identifies primary-to-secondary zone transfers as a common TSIG use case.
DNSSEC deployment on current RHEL-family systems involves zone signing, DNSSEC policy, key rollover, DS publication, and resolver validation—none of which replace TSIG for transfer authentication between your authoritative servers.
Lab Setup and Prerequisites
| Role | Hostname | IP address |
|---|---|---|
| Primary DNS | ns1.example.com | 192.0.2.10 |
| Secondary DNS | ns2.example.com | 192.0.2.20 |
| Zone | example.com | — |
The addresses above use the RFC 5737 documentation range. Replace them with your production addresses.
Before you add TSIG, confirm the baseline:
- BIND is installed and serving
example.comon the primary bind-utilsis installed on administrative hostsnamedornamed-chrootis running on both servers- TCP and UDP port 53 are permitted between the primary and secondary
- System clocks are synchronized through
chronyd - The secondary already receives the zone through the existing transfer configuration
If you still need the base replication layout, complete configure a BIND primary and secondary DNS server first. This page adds authentication on top of that working pair.
For a new lab, verify ordinary primary-to-secondary replication before adding TSIG. Do not temporarily permit unrestricted AXFR on an internet-facing server.
Clock skew matters because TSIG performs time validation. If transfers fail with a clocks-unsynchronized message, verify chronyd on both hosts before you regenerate keys.
Generate and Protect the TSIG Key
Generate the key once with tsig-keygen. It replaces the older dnssec-keygen -a HMAC-MD5 workflow and defaults to HMAC-SHA256 with a 256-bit secret suitable for inclusion in named.conf.
Create a protected directory for the TSIG key:
install -d -m 750 -o root -g named /etc/named/keysCreate the destination file with restrictive permissions before writing the secret:
install -m 640 -o root -g named /dev/null /etc/named/keys/xfer-example.com.keyGenerate the key directly into that file:
tsig-keygen -a hmac-sha256 xfer-example.com > /etc/named/keys/xfer-example.com.keytsig-keygen only when creating or intentionally rotating the key. Each run generates a different secret. Overwriting the file on only one server causes the primary and secondary keys to stop matching.
Display the generated BIND key block:
cat /etc/named/keys/xfer-example.com.keyExample structure:
key "xfer-example.com" {
algorithm hmac-sha256;
secret "REDACTED_BASE64_SECRET";
};The key name (xfer-example.com), algorithm (hmac-sha256), and secret must match on both servers. Treat the secret like a password: do not commit it to Git, paste it into tickets, or publish a real value in documentation screenshots.
Copy the same file to the secondary through SSH or another protected channel. Restore and verify the SELinux context on both servers:
restorecon -RFv /etc/named/keysls -lZ /etc/named/keys/xfer-example.com.keySample output:
-rw-r-----. 1 root named system_u:object_r:named_conf_t:s0 108 Jul 11 17:35 /etc/named/keys/xfer-example.com.keyThe key file should use the named_conf_t SELinux type on RHEL-family systems because it is part of the BIND configuration. named_cache_t is normally associated with writable secondary-zone locations such as /var/named/slaves/, not files under /etc/named/.
If the type is still incorrect after restorecon, compare the expected context:
matchpathcon /etc/named/keys/xfer-example.com.keySample output:
/etc/named/keys/xfer-example.com.key system_u:object_r:named_conf_t:s0Configure TSIG-Authenticated Zone Transfers
BIND still accepts the legacy keywords master, slave, and masters. This article uses primary, secondary, and primaries in examples because they match current documentation. The TSIG syntax is the same either way.
Configure the Primary DNS Server
Include the key once near the top of /etc/named.conf or in a dedicated snippet included from there:
include "/etc/named/keys/xfer-example.com.key";named-chroot installations, the service exposes selected host paths inside /var/named/chroot through bind mounts. If BIND reports that it cannot find the included key file, confirm that /etc/named is available through /etc/named-chroot.files and inspect the named-chroot journal.
Restrict transfers inside the authoritative zone block rather than globally when possible:
zone "example.com" IN {
type primary;
file "/var/named/example.com.zone";
allow-transfer { key xfer-example.com; };
also-notify { 192.0.2.20 key xfer-example.com; };
};allow-transfer { key xfer-example.com; }; requires AXFR and IXFR requests to use the TSIG key.
The optional also-notify entry below explicitly notifies the secondary and signs that NOTIFY message with the same key:
also-notify { 192.0.2.20 key xfer-example.com; };You can omit also-notify when the secondary has an NS record in the zone and ordinary automatic NOTIFY messages are sufficient. Retain it when the secondary is not represented by an NS record or when you intentionally want the explicit NOTIFY message to be TSIG-signed.
Do not assume that listing an IP address and a key in the same simple allow-transfer ACL requires both conditions:
allow-transfer { 192.0.2.20; key xfer-example.com; };That configuration can authorize a request by matching either ACL element. The key-only rule used in this guide makes possession of the TSIG secret the transfer requirement.
Configure the Secondary DNS Server
Include the same key file, then define the secondary zone with the TSIG key associated with the primary server address:
include "/etc/named/keys/xfer-example.com.key";
zone "example.com" IN {
type secondary;
file "slaves/example.com.zone";
primaries { 192.0.2.10 key xfer-example.com; };
allow-transfer { none; };
};Specifying the key in primaries causes the secondary's SOA queries and AXFR or IXFR requests to the primary to be TSIG-signed. Zone data is transferred from the primary to the secondary; the secondary sends the signed request.
Associating the key with the primary inside the zone definition is more precise than a global server { keys ...; }; block, which would apply the key to all communication with that address.
Legacy equivalent accepted by BIND:
zone "example.com" IN {
type slave;
file "slaves/example.com.zone";
masters { 192.0.2.10 key xfer-example.com; };
allow-transfer { none; };
};Set allow-transfer { none; }; on the secondary unless it should forward the zone to another authorized server.
Validate and Reload BIND
Validate syntax on each server before you reload the service. Run named-checkconf separately on the primary and secondary after editing each host. Both configurations must load the identical key name, algorithm, and secret.
Check the main configuration:
named-checkconfThe command exits silently with status 0 when the configuration is valid.
On the primary, check the zone file:
named-checkzone example.com /var/named/example.com.zoneSample output:
zone example.com/IN: loaded serial 2026071201
OKReload the running service. On a standard installation:
systemctl reload namedOn a chroot deployment:
systemctl reload named-chrootIf the reload command fails, inspect its output and the systemd journal. BIND normally continues using the previously loaded valid configuration, but the new TSIG configuration will not take effect.
Verify the Secure Zone Transfer
Confirm an Unsigned AXFR Is Rejected
Run the unsigned test from the secondary server or another host that has network access to the primary:
dig @192.0.2.10 example.com AXFRThe request should fail with REFUSED, followed by Transfer failed, because it does not contain the required TSIG signature.
Use the same source host for the signed test below. Testing both requests from the same host helps confirm that the difference is TSIG authentication rather than routing, firewall, or source-address rules.
Confirm a TSIG-Signed AXFR Succeeds
From the same host, repeat the request with the TSIG key:
dig @192.0.2.10 example.com AXFR -k /etc/named/keys/xfer-example.com.keyRun the command as root or another account that is permitted to read the protected key file. A successful AXFR prints the zone records. If authentication failed, dig reports BADKEY, BADSIG, or BADTIME before any useful zone data appears.
Update the Zone and Compare SOA Serials
Edit a harmless record on the primary and increment the SOA serial in /var/named/example.com.zone:
@ IN SOA ns1.example.com. hostmaster.example.com. (
2026071202 ; serialReload the primary zone:
rndc reload example.comOn the secondary, follow the service journal:
journalctl -u named -fOn a chroot deployment, substitute named-chroot for the unit name.
Sample log lines from a successful TSIG transfer:
zone example.com/IN: Transfer started.
transfer of 'example.com/IN' from 192.0.2.10#53: connected using 192.0.2.20#45678
zone example.com/IN: transferred serial 2026071202: TSIG 'xfer-example.com'
transfer of 'example.com/IN' from 192.0.2.10#53: Transfer completed: 1 messages, 9 records, 412 bytes, 0.004 secsThe TSIG 'xfer-example.com' line confirms the transfer was authenticated with your key name—not DNSSEC signing.
Compare SOA serials from both servers:
dig @192.0.2.10 example.com SOA +shortdig @192.0.2.20 example.com SOA +shortMatching serial numbers mean the secondary caught up. Query the changed record from the secondary to confirm the data itself replicated.
Check that the secondary database exists:
ls -l /var/named/slaves/Modern BIND may store secondary zone data in raw binary format depending on configuration. Do not assume the transferred file is always plain text.
If NOTIFY did not trigger a refresh, force a retransfer from the secondary:
rndc retransfer example.comrndc uses its own control key and is separate from TSIG.
Troubleshoot TSIG and Zone Transfer Errors
| Error or symptom | Likely cause | Check or recovery |
|---|---|---|
BADKEY or unknown key |
Key name differs | Compare key names in both include files and zone blocks |
BADSIG |
Secret or algorithm differs | Regenerate or securely recopy the key file |
BADTIME or clocks unsynchronized |
Time skew between servers | Verify chronyc tracking and timedatectl on both hosts |
Transfer failed or REFUSED |
allow-transfer mismatch |
Confirm the zone allows key xfer-example.com |
not authoritative |
Wrong server or zone definition | Check the primary zone type and file path |
| Secondary serial does not change | SOA serial not incremented | Bump the serial and reload the primary zone |
| Connection timeout | Firewall or routing issue | Verify TCP/UDP 53 and reachability between hosts |
| Permission denied on key file | Ownership, mode, or SELinux label | Check root:named, mode 640, run restorecon, confirm named_conf_t |
Permission denied while using dig -k |
Current shell user cannot read the protected key | Run the test as root or use a separately protected administrative copy |
| Could not find expected TSIG or unsigned response | One side expected a signed transaction but the other did not use the configured key | Check primaries, also-notify, and whether both servers loaded the key include |
| Secondary keeps old data | Transfer not triggered | Review NOTIFY in the journal or run rndc retransfer |
Practical diagnostics: journalctl -u named, named-checkconf, named-checkzone, SOA queries with dig, and a controlled dig ... AXFR -k keyfile test from the secondary.
For general BIND service problems outside TSIG, see configure a BIND DNS server with named chroot.
TSIG Security Best Practices and Limitations
- Use
hmac-sha256for new TSIG keys; avoid legacyhmac-md5andhmac-sha1. - Use a different TSIG key for unrelated server relationships where practical.
- Restrict access to the shared-secret file with
root:namedownership and mode640. - Transfer keys only through SSH or another protected channel.
- Rotate the key when a server or administrator with key access is compromised.
- Remove obsolete keys only after the replacement transfer succeeds.
- Do not confuse TSIG with
rndcauthentication—they protect different operations. - Do not confuse TSIG with DNSSEC zone signing.
- TSIG authenticates and integrity-checks transfers; it does not encrypt zone contents.
- When confidentiality is required and your BIND versions support it, evaluate network-layer protection or zone transfer over TLS in addition to TSIG.
Summary
TSIG lets a BIND primary accept zone transfers only from a secondary that possesses the matching shared secret. Generate the key once with tsig-keygen, store it in a protected include file on both servers, restrict allow-transfer on the primary zone, and associate the key with the primary address in the secondary zone definition.
Verify the control with named-checkconf on both hosts, journal logs showing TSIG 'key-name', and matching SOA serials after you increment the zone serial. For the base replication layout, start with configure a BIND primary and secondary DNS server. For signed authoritative answers to resolvers, follow your distribution's DNSSEC signing documentation separately from this transfer-authentication workflow.
References
- RFC 8945 — Secret Key Transaction Authentication for DNS (TSIG)
- ISC BIND 9 Administrator Reference Manual — tsig-keygen
- ISC BIND 9 Administrator Reference Manual — zone transfers
- Red Hat Enterprise Linux 10 — Configuring zone transfers among BIND DNS servers

