Score:2

How can I send DNS Resource Record updates from Linux to a Windows Active Directory DNS zone that only accepts secure updates?

in flag

My company has an existing Windows AD DNS zone that I do not directly manage (but i know the folks who do manage it). The zone will accept dynamic updates, but the updates must be "secure". I have a Linux box (it runs an IPAM system) from which I'd like to send arbitrary DNS updates to AD. How can this be done?

Score:3
in flag

First, a few assumptions:

  • You have an AD DNS server already operational. It has a zone configured which allows updates as long as the updates are secure.
  • You have some AD credentials with permissions to update the zone. I think perhaps the DNSAdmin group might be granted permission by default (not sure), so make your user is a member of that. It's best to use a service account with lowest possible privileges.
  • You have a Linux box from which to send updates. Your version of nsupdate supports the -g flag which enables GSS-TSIG.

Let's get started. We need to do some setup.

First, we need to get and configure the Kerberos 5 authentication backend.

  1. If you're on Ubuntu, the tools you need can be installed using apt install sssd-krb5 krb5-user. If you're on another distribution, check the comments to see if someone has indicated what packages you need.
  2. Next, we need to add the info for our AD. This is not DNS info, it's Kerberos info about how to get tickets. Use your favorite text editor to open the krb5.conf file; for Ubuntu that is /etc/krb5.conf.
  3. Under the [libdefaults] section, it would be wise to add an entry like this: default_realm = CORP.EXAMPLE.LOCAL. Not sure why, but the Realm seems to need to be uppercase.
  4. Under the [realms] section, we need to add the AD domain and the server (domain controllers) info. Follow this template. Again, make the realm name UPPERCASE.
[realms]
CORP.EXAMPLE.LOCAL = {
  kdc = ms-dc-01.corp.example.local:88
  kdc = ms-dc-02.corp.example.local:88
  admin_server = ms-dc-01.corp.example.local
  default_domain = corp.example.local
}

Ok, let's see if it works.

Next, we'll try to get a Kerberos ticket from AD by authenticating.

  1. Run the command kinit [email protected]. Hopefully it prompts you for a password. And hopefully nothing more.
  2. Having a problem getting kinit to accept your password? Try enabling trace output like this: KRB5_TRACE=/dev/stdout kinit .... Note that sometimes the username can cause CaSeSeNsItIvItY problems.
  3. See if you have a ticket. Run the command klist. Hopefully you see something similar to this. If you don't, go back one step and try reading the trace output.
Valid starting       Expires              Service principal
05/19/2023 17:22:42  05/20/2023 03:22:42  krbtgt/[email protected]
  1. Pause here for just a moment. What we did was ask AD for a Kerberos ticket by using our credentials. If the ticket was granted, it was placed into the client's cache. You are viewing the cache when you use klist. You probably ought not leave that in the cache for longer than you need to, since the cache can be read and used by root Linux users. You can terminate a ticket by using the kdestroy command.
  2. With that ticket, let's see if we can send a DNS update to the DNS server. Run the nsupdate command. This will give you a new command prompt waiting for instructions about what you'd like to do. Enter these commands:
gsstsig
server chicago-dns-14.corp.example.local
zone corp.example.local.
update add my-new-test-record.corp.example.local. 3600 A 1.1.1.1
show
send
quit

Note, some servers don't require the TTL parameter, some do. Shrug.

  1. Use your favorite DNS utility to ask the DNS server if it has the record: host -ta my-new-test-record.corp.example.local chicago-dns-14.corp.example.local
  2. You can now delete the record in a nearly-identical way. Run nsupdate again. Enter these commands:
gsstsig
server chicago-dns-14.corp.example.local
zone corp.example.local.
update delete new-server-test-record.corp.example.local. A 1.1.1.1
send

Note you do not need to include the TTL when deleting.

  1. Run kdestroy to delete your Kerberos ticket from the cache.

Cool, what's next?

Ok, so that was how to do it manually. Now, let's put the password into a keytab file so we don't have to type it each time, yet the password is also not saved in a clear text file for other users to read.

  1. Run the ktutil command. Type this:
addent -password -p [email protected] -k 0 -f
  1. Hopefully, you get prompted for your password. Then continue:
wkt username.keytab
quit
  1. Okay, so you hopefully have a keytab file now. This file contains a mostly-secure version of your password. I don't exactly know how, but it's kinda-sorta-encrypted in some way or other.
  2. Now that we have the keytab file, we can run kinit with some new parameters that let us avoid typing the password: kinit -kt username.keytab [email protected]
  3. Run a klist to see if you got a ticket.
  4. Run a kdestroy to tear down your ticket.

Ok, now let's see if we can make this a really complicated one-liner.

  1. Run the command:
kinit -kt username.keytab [email protected] && echo "gsstsig
server chicago-dns-14.corp.example.local
zone corp.example.local.
update delete new-server-test-record.corp.example.local. 3600 A 1.1.1.1
send" |nsupdate && kdestroy

I know this looks like more than one line, but the quotation on the first line makes Bash wait until you close the quote.

Can you script this?

Sure

#!/bin/bash

if [ $# == 3 ]; then
 if [ $1 == "add" ] ; then
  kinit -kt DnsAdministrator.keytab [email protected]
  echo "gsstsig
server chicago-dns-14.corp.example.local
zone corp.example.local.
update $1 $2.corp.example.local. 7200 A $3
send" |nsupdate
  kdestroy
 elif [ $1 == "delete" ] || [ $1 == "del" ] ; then
  kinit -kt DnsAdministrator.keytab [email protected]
  echo "gsstsig
server chicago-dns-14.corp.example.local
zone corp.example.local.
update $1 $2.corp.example.local. A $3
send" |nsupdate
  kdestroy
 else
  echo "<action> must be either add or delete."
 fi
else
 echo "There must be precisely 3 parameters: <action>, <record-name> and <ip-address>"
fi

And then use it like this:

./my-dns-script.sh add my-new-test-record 1.1.1.1

or

./my-dns-script.sh delete my-new-test-record 1.1.1.1
user1686 avatar
fr flag
The keytab is not encrypted, it's a PBKDF2 hash of the password. It is also _password-equivalent,_ in the sense that stealing the keytab is (almost) exactly as bad as stealing the original password and allows authenticating to any Kerberos-protected service – not just DNS, but LDAP, RPC, and so on. (Speaking of which, if you do in fact have "DNS administrator" rights, you could use samba-tool to manage MS DNS servers.) So it's not a good idea to leave the admin keytab lying around; at minimum it definitely needs to be chmodded to be non-world-readable exactly like if it was a password file.
user1686 avatar
fr flag
Aside from that: You don't need SSSD for manual updates – though it is capable of automatically running nsupdate with the _machine_ credentials to register itself in DNS, like Windows systems do, but all of the "manual" tooling comes from Krb5 and BIND. Generally you shouldn't need any krb5.conf edits either, as the KDC address can be automatically retrieved from DNS SRV (AD always has SRV records), and the admin_server is not used (AD doesn't even have a compatible admin_server anyway).
Semicolon avatar
jo flag
defintely use the machine's account credentials; there should be no reason to potentially expose or use any other account
user3629081 avatar
in flag
@Semicolon This is not a domain-joined machine. There is no machine account.
mangohost

Post an answer

Most people don’t grasp that asking a lot of questions unlocks learning and improves interpersonal bonding. In Alison’s studies, for example, though people could accurately recall how many questions had been asked in their conversations, they didn’t intuit the link between questions and liking. Across four studies, in which participants were engaged in conversations themselves or read transcripts of others’ conversations, people tended not to realize that question asking would influence—or had influenced—the level of amity between the conversationalists.