[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