Add DNSSEC Trust Anchors with systemd.positive

Get a DNSSEC trust anchor wrong and you either break a signed zone outright or quietly weaken the validation you were trying to add. This guide adds a positive trust anchor file for systemd-resolved using the systemd.positive format, checks which file wins when names overlap, and verifies the resolver afterwards. Allow 15 to 20 minutes if you already have the correct DS record from the zone operator.

You need a root shell through sudo, a running systemd-resolved, and a trust anchor value obtained from a source you trust. This guide describes the installed systemd version 255.4-1ubuntu8.17. The manpage is named systemd.positive, but the same document also covers systemd.negative and the directories systemd-resolved uses.

1. Check the resolver before editing

Start with an unprivileged inspection. It records the current DNSSEC state and shows whether the configuration directories exist. A missing directory is not an error; a clean installation may have no local trust-anchor files.

$ resolvectl status
$ for d in /etc/dnssec-trust-anchors.d /run/dnssec-trust-anchors.d /usr/lib/dnssec-trust-anchors.d; do
>   printf '%s: ' "$d"
>   test -d "$d" && find "$d" -maxdepth 1 \( -type f -o -type l \) -printf '%f\n' | sort || echo absent
> done

Tip: Look for the DNSSEC line in resolvectl status and keep this output if you are troubleshooting a later change. It is a baseline, not proof that a new anchor will validate a particular zone.

2. Choose the file and precedence deliberately

Persistent administrator configuration belongs in /etc/dnssec-trust-anchors.d/. Runtime files belong in /run/dnssec-trust-anchors.d/ and suit temporary orchestration. Package-supplied files belong in /usr/lib/dnssec-trust-anchors.d/. The three directories are searched in that order, and if two files share a name, the earlier directory hides the later one completely.

Use a distinctive filename, such as corp-example.positive: a file is never merged with another copy of the same name. To disable a package file without deleting it, create an empty file with the same name in /etc/dnssec-trust-anchors.d/, or make that path a symlink to /dev/null. Both are administrative changes, so record them for the next person who investigates DNSSEC.

3. Add a positive trust anchor

A positive file contains one DS or DNSKEY resource record per line; the recommended form is DS. Its fields are the domain, class IN, record type, key tag, signature algorithm, digest algorithm and hexadecimal digest. A trailing dot on the domain is optional and equivalent to no trailing dot.

Warning: Do not install a made-up digest: it can make a signed private zone appear broken. Do not copy an unverified real digest either, since that weakens the trust decision it is meant to strengthen. Replace every angle-bracketed value below with the exact DS record supplied by the zone operator.

$ sudo install -d -m 0755 /etc/dnssec-trust-anchors.d
$ sudo tee /etc/dnssec-trust-anchors.d/corp-example.positive >/dev/null <<'EOF'
corp.example. IN DS <KEY-TAG> <ALGORITHM> <DIGEST-TYPE> <HEX-DIGEST>
EOF

Check the file as root and as a normal user: the first command catches permissions, the second confirms the visible text is what you intended.

$ sudo sed -n '1,5p' /etc/dnssec-trust-anchors.d/corp-example.positive
corp.example. IN DS <KEY-TAG> <ALGORITHM> <DIGEST-TYPE> <HEX-DIGEST>
$ test -r /etc/dnssec-trust-anchors.d/corp-example.positive && echo readable
readable

4. Protect the built-in root anchor

In the usual case, leave the internet root domain alone. If no positive trust anchor is defined for the root, systemd-resolved uses its built-in root key. Adding any root trust anchor disables that built-in key, so a copied example from an old document is not a safe way to refresh it.

Warning: If you genuinely need to manage the root anchor yourself, obtain the current value from the IANA Trust Anchor and Keys document, verify it through your change process, and install a valid . record; prefer a current DS record. Do not mix a guessed root record with a private-zone record merely to test the parser. The root anchor is security-sensitive, and a bad change can make ordinary signed lookups fail.

5. Add a negative trust anchor only for an exception

A negative file names a domain that becomes the root of a subtree where DNSSEC validation is disabled. It is meant for private, unsigned DNS trees not delegated from the public DNS hierarchy, not a general fix for a broken signed zone.

$ sudo tee /etc/dnssec-trust-anchors.d/private-zones.negative >/dev/null <<'EOF'
corp.example
lab.example
EOF

Every name affects that domain and its descendants, so keep the list as narrow as possible. Per-interface exceptions can instead be set with DNSSECNegativeTrustAnchors= in a systemd.network file, a different configuration path that should not be duplicated casually.

6. Restart and verify the effective state

After a file change, restart the resolver so the running service rereads its configuration. This briefly interrupts local name resolution, so do it in a maintenance window if other processes depend on the machine's resolver.

$ sudo systemctl restart systemd-resolved
$ systemctl is-active systemd-resolved
active
$ resolvectl status | sed -n '1,12p'

Checkpoint: For a positive anchor, test a name below the configured zone with your normal DNSSEC-aware test procedure and check the resolver logs if it fails. For a negative anchor, test only the intended private subtree, then confirm an unrelated signed public name still validates. A service that is merely active proves it started, not that your record is correct.

7. Recover from a bad change

Recovery: Before deleting anything, copy the file aside so the exact failed input is preserved:

$ sudo cp --preserve=all /etc/dnssec-trust-anchors.d/corp-example.positive /root/corp-example.positive.failed
$ sudo rm /etc/dnssec-trust-anchors.d/corp-example.positive
$ sudo systemctl restart systemd-resolved
$ systemctl is-active systemd-resolved
active

Removing a local positive root file lets the built-in root key apply again, provided no other root trust anchor remains in the three search directories. Removing a negative file restores the normal negative-anchor set only if no other negative file or per-interface setting covers the same name. Check all three directories before assuming the exception is gone.

Done means