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.
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.
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.
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
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.
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.
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.
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.
/etc, /run and /usr/lib.systemd-resolved is active after the restart and DNSSEC tests match the intended policy.