[Samba] GSS-TSIG DNS update fails (BIND9_DLZ/SAMBA_INTERNAL), kea-dhcp-ddns
Anton Shevtsov
shevtsovay at basealt.ru
Mon Aug 3 05:16:06 UTC 2026
1. Samba_dlz GSS-TSIG DNS update fails on GSS security-context reuse
(Kea DHCP-DDNS): "spnego update failed" (BIND9_DLZ)
2. "replayed in wrong direction" (SAMBA_INTERNAL)
Hello,
I am running an AD DC on ALT Linux and using ISC Kea DHCP-DDNS
(kea-dhcp-ddns / libddns_gss_tsig) to perform secure GSS-TSIG dynamic DNS
updates against the DC. I have hit what looks like a GSS-TSIG interop
problem on the Samba side that only manifests when the DNS client
(Kea's D2) REUSES an already-established GSS security context for more
than one DNS UPDATE. A single update on a freshly negotiated TKEY key
succeeds; the second and subsequent updates that reuse the same key are
rejected by Samba.
I would appreciate confirmation whether this is a known limitation/bug in
samba_dlz (and in the SAMBA_INTERNAL DNS server), and whether there is a
supported way to make it accept multiple GSS-TSIG-signed updates over a
reused context.
====================================================================
1. Environment / software versions
====================================================================
OS: ALT Linux (p11)
Samba: samba-4.21.9-alt3.p11.1 (AD DC, built against Heimdal,
samba-dc ships
libheimbase-private-samba.so / libheimntlm-private-samba.so,
spec built with "separate_heimdal_server"))
BIND: bind-9.18.49 (used for BIND9_DLZ)
Kea: 3.2.0 (kea-dhcp4, kea-dhcp-ddns, libddns_gss_tsig)
-- also reproduced with Kea 3.0.3, upgrade did not change it
Kerberos on Kea side: MIT libkrb5 1.21.3 (Kea is linked against MIT krb5)
So the setup crosses two Kerberos implementations:
- initiator (Kea D2 / libddns_gss_tsig): MIT krb5 1.21.3
- acceptor (Samba AD DC): Heimdal (Samba internal)
DC FQDN: dc1.new.alt (192.168.180.10)
Realm: NEW.ALT
DHCP client principal: kea-dhcp at NEW.ALT (member of DnsAdmins)
DNS service principal: DNS/dc1.new.alt at NEW.ALT
====================================================================
2. Relevant configuration
====================================================================
--- Kea kea-dhcp-ddns.conf (hook parameters) ------------------------
"hooks-libraries": [{
"library": "/usr/lib64/kea/hooks/libddns_gss_tsig.so",
"parameters": {
"client-principal": "kea-dhcp at NEW.ALT",
"client-keytab": "FILE:/etc/kea/kea-dhcp.keytab",
"credentials-cache":"FILE:/tmp/krb5cc_d2",
"tkey-lifetime": 3600,
"rekey-interval": 2700,
"retry-interval": 30,
"fallback": false,
"gss-replay-flag": true,
"gss-sequence-flag": true,
"servers": [{
"id": "dns-dc",
"ip-address": "192.168.180.10",
"port": 53,
"server-principal": "DNS/dc1.new.alt at NEW.ALT"
}]
}
}]
(kea-dhcp4 uses "ddns-conflict-resolution-mode": "no-check-without-dhcid"
because samba_dlz does not support the DHCID record type; with DHCID in
the update the whole transaction is rejected. That part is understood and
not the subject of this report.)
--- smb.conf [global] (BIND9_DLZ case) ------------------------------
[global]
realm = NEW.ALT
workgroup = NEW
server role = active directory domain controller
netbios name = DC1
ad dc functional level = 2016
server services = -dns # internal DNS disabled, BIND9_DLZ used
--- /etc/bind/options.conf (relevant) -------------------------------
tkey-gssapi-keytab "/var/lib/samba/bind-dns/dns.keytab";
listen-on { 127.0.0.1; 192.168.180.10; };
====================================================================
3. Case A: BIND9_DLZ backend
====================================================================
Behaviour: the FIRST DNS UPDATE performed on a freshly negotiated
GSS-TSIG key SUCCEEDS (forward A + PTR are written). Any subsequent
update that REUSES the same TSIG key is rejected with
"samba_dlz: spnego update failed" / REFUSED (RCODE 5).
--- 3.1 First update on a fresh key -> OK ---------------------------
named:
samba_dlz: allowing update of signer=kea-dhcp\@NEW.ALT
name=client1.new.alt tcpaddr=192.168.180.10 type=A
key=2906485250.sig-dc1.new.alt/160/0
...: updating zone 'new.alt/IN': deleting rrset at 'client1.new.alt' A
...: updating zone 'new.alt/IN': adding an RR at 'client1.new.alt' A
192.168.180.128
samba_dlz: added rdataset client1.new.alt '... A 192.168.180.128'
samba_dlz: committed transaction on zone new.alt
... (PTR update likewise committed) ...
kea-dhcp-ddns:
KEY_LOOKUP_FOUND ... key '2906485250.sig-dc1.new.alt.'
GSS_TSIG_VERIFIED GSS-TSIG verify succeeded.
DHCP_DDNS_ADD_SUCCEEDED ... successfully added the DNS mapping
--- 3.2 Second update, SAME key reused -> REFUSED -------------------
(~21 minutes later, rekey-interval had not elapsed, so D2 reused the
same key '2906485250')
named:
samba_dlz: spnego update failed
client @0x... 192.168.180.10#36408/key kea-dhcp\@NEW.ALT:
updating zone 'new.alt/IN': update failed: rejected by secure
update (REFUSED)
kea-dhcp-ddns:
KEY_LOOKUP_FOUND ... key '2906485250.sig-dc1.new.alt.'
GSS_TSIG_VERIFIED GSS-TSIG verify succeeded. <-- Kea side is happy
DHCP_DDNS_FORWARD_ADD_REJECTED ... rejected a DNS update request ...
RCODE: 5
DHCP_DDNS_ADD_FAILED ... Event: UPDATE_FAILED_EVT
Note that Kea reports "GSS_TSIG verify succeeded" for the response, i.e.
the initiator side is fine; the rejection comes entirely from
"samba_dlz: spnego update failed" during ssumatch/secure-update
verification of the *request* on a reused context.
There is also a periodic variant seen during key rotation, where the
TKEY negotiation itself fails to verify:
kea: TKEY_EXCHANGE_FAILED_TO_VERIFY ... response failed to verify
kea: GSS_TSIG_NEW_KEY_SETUP_FAILED ... response received but not signed
====================================================================
4. Case B: SAMBA_INTERNAL backend (same DC, DNS given back to Samba)
====================================================================
Switched with: samba_upgradedns --dns-backend=SAMBA_INTERNAL
(removed "server services = -dns", stopped bind)
Behaviour: WORSE than BIND9_DLZ. Here even the FIRST update on a fresh
key is rejected. On the initiator (Kea/MIT) side the response MIC
verification fails:
kea-dhcp-ddns:
KEY_LOOKUP_FOUND ... key '1751334962.sig-dc1.new.alt.'
GSS_TSIG_VERIFY_FAILED GSS-TSIG verify failed: gss_verify_mic failed
with GSSAPI error:
Major = 'A token had an invalid Message Integrity Check (MIC)'
(393216),
Minor = 'Packet was replayed in wrong direction' (100002).
DHCP_DDNS_FORWARD_ADD_RESP_CORRUPT ... received a corrupt response from
the DNS server, 192.168.180.10 port:53, while adding forward address
mapping for FQDN, client1.new.alt.
DHCP_DDNS_ADD_FAILED ... Event: NO_MORE_SERVERS_EVT
This "Packet was replayed in wrong direction" appears with ALL
combinations of the Kea GSS flags:
gss-replay-flag / gss-sequence-flag = true/true, false/true, false/false
i.e. it is not fixed by toggling replay/sequence protection on the
initiator. It is the MIC of the Samba *response* that MIT krb5 refuses to
verify.
====================================================================
5. What we have already ruled out (initiator side is clean)
====================================================================
- server-principal is correct (DNS/dc1.new.alt at NEW.ALT); manual updates
work (see below).
- kea-dhcp at NEW.ALT is a member of DnsAdmins; authorization is not the
problem (samba_dlz prints "allowing update ... signer=kea-dhcp at NEW.ALT"
in case A before it commits the first update).
- credentials cache is healthy (klist shows valid TGT and
DNS/dc1.new.alt service ticket).
- A full MIT KRB5_TRACE of the Kea D2 process shows a completely clean
Kerberos exchange: AS-REQ/AS-REP, TGS for DNS/dc1.new.alt at NEW.ALT
(result 0/Success), "Creating authenticator", "Read AP-REP" — no error
on the initiator side.
- Manual "nsupdate -g" using the SAME principal (kinit -k -t
/etc/kea/kea-dhcp.keytab kea-dhcp at NEW.ALT; nsupdate -g) ALWAYS succeeds
(add and delete), against the same DC, same zone, same name.
The crucial difference between working nsupdate and failing Kea:
* nsupdate establishes a FRESH GSS context (fresh TKEY) for basically
every operation — one context, one message.
* Kea's libddns_gss_tsig negotiates a TKEY key once and REUSES the same
GSS security context for many DNS UPDATE messages until the key
expires (tkey-lifetime / rekey-interval).
So the failure is strongly correlated with GSS security-context REUSE:
"one key = one successful update". The first message on a context is
accepted; the next message signed under the same context is rejected by
Samba ("spnego update failed" for BIND9_DLZ; MIC "wrong direction" on the
response for SAMBA_INTERNAL).
====================================================================
6. Questions
====================================================================
1. Is samba_dlz (and the SAMBA_INTERNAL DNS server) expected to accept
multiple GSS-TSIG signed DNS UPDATEs over a single, reused GSS
security context, or is a fresh TKEY negotiation required per update?
2. Is "samba_dlz: spnego update failed" on the 2nd+ update over a reused
context a known bug, and is there a fix or target version?
3. For the SAMBA_INTERNAL case, the initiator (MIT krb5 1.21.3) rejects
the MIC of Samba's response with minor 100002 "Packet was replayed in
wrong direction". Is this a known MIT<->Heimdal GSS interop issue on
per-message tokens, and is there a recommended Samba build/config?
4. Is there any server-side setting to relax/disable the per-message
replay/sequence checking that appears to break context reuse?
I can provide full unredacted logs, KRB5_TRACE output, and pcaps of the
TKEY/UPDATE exchange on request.
Thank you,
Anton
More information about the samba
mailing list