0

I want to have an embedded device join a Linux based AD/DC domain. I have kerberos libraries (no executables) on the embedded device. I have an application on the embedded device that can successfully authenticate and access services on the domain as a client. What I also want to do is have the embedded device join the domain as a member, to acquire credentials, and to accept authentication requests from domain users.

I've been using the sample program gss-server from the kerberos src/appl/gss-sample directory as a model for integrating the server functionality to my application.

HINT: I posted my solution as an answer to this question.

I am missing an important piece. Before the embedded device can offer kerberos services, it must join the domain, which, as I understand it, involves a) creating a principal for the host, b) adding an entry into the device's keytab, and c) adding a corresponding entry on the domain controllers keytab. If I were running a full samba stack on my device, I would use something like samba-tool domain join or net ads join. I have looked at the code for samba-tool and net and they seem to do a lot more than I need or want. For the most part, I believe all I need to do is add the artifacts that allow the embedded device to authenticate with the DC. I really don't know if I'm going about this right and I don't believe I know all the steps. But here's what I believe I'm trying to do:

  • provision a computer on the DC
  • Export the keytab entry from the DC
  • Import the keytab entry on the emdedded device.

After doing the above three steps, presumably I could run gss-client/gss-server successfully. First question: Is that correct? And is it the way to do this? Second question: How do I import a keytab entry?

Maybe I don't need a keytab but rather instead of using gss_acquire_cred, I somehow export the credential from the DC and securely communicate it to the embedded device and then use gss_import_cred.

Does anyone know if I'm on the right track? Is there any sample code they know about that does this?

As some background, we have a commercial SMB client/server stack that runs on Android. We support both NTLM and Kerberos authentication for the client and just NTLM on the server. We are trying to upgrade the server to support Kerberos authentication as well.

  • Not the answer you are looking for, but your device must join AD, also it cannot accept authentication requests, that's the DC's job. – Rowland Penny May 01 '23 at 15:21

2 Answers2

0

it must join the domain, which, as I understand it, involves a) creating a principal for the host, b) adding an entry into the device's keytab, and c) adding a corresponding entry on the domain controllers keytab.

Yes, although it's not exactly a single "keytab" on the domain controller's side – it's setting the keys associated with the host principal's entry specifically. In AD, it means setting the (computer or user) account's password and letting it derive keys from that; then you locally use the same procedure to derive keys and store them in a keytab file.

For AD, you only need a true "computer" account if you want to accept Kerberos tickets for the services usually associated with one in AD, e.g host/ (SSH) or cifs/ (SMB). In many other cases, however, it is sufficient to create a "user" account and assign it 'servicePrincipalName' attribute with the particular service principal you want. For example, a web server accepting SPNEGO for HTTP/ can just as easily be tied to a "user" account.

Also note that in the case of Active Directory, it is impossible to actually "export a keytab" from the KDC, as that would be basically equal to retrieving an account's password hash. Instead, the process is reverse: you would set the account's password to a randomly generated value, then locally generate the keytab using the same password as input to the hashing algorithm.

If you want to do everything using Linux tools, the adcli tool (part of realmd) could be used to provision a computer account in Active Directory, as an alternative to samba-tool. It can create a keytab file if necessary, or you could provide it a strong and randomly-generated password for the computer account and use ktutil to manually generate a keytab for it.

However, adcli does not use any unusual RPC interfaces, so you could do the same using a generic LDAP client too – e.g. you could use python-ldap to create a user or computer account and set its password. Finally, could just have the AD admin pre-create an account and generate a keytab for you.

Second question: How do I import a keytab entry?

This depends very much on the Kerberos implementation that you're using, but in most cases there is no "import" procedure – the keytab file stays a keytab file, you just place it at the correct location (/etc/krb5.keytab being the traditional "system-wide" default on Unix-like systems).

Recent versions of MIT Krb5 and Heimdal have the "credential store" extension to the GSS API interface to acquire credentials from a specified path, so the "correct location" can be entirely up to you.

(In older versions, it needed to be done through raw libkrb5 APIs or by setting KRB5_KTNAME in the environment.)

Similarly, other Kerberos or GSSAPI implementations (e.g. the Java one) will generally let you load the server keys from a specified path.

user1686
  • 10,162
  • 1
  • 26
  • 42
  • Thanks. Some followups: You mention adcli can generate a keytab or use ktutil to manually generate it. I have used `adcli preset-computer --domain=mydomain.com myhost.mydomain.com -V cifs -W`. I also used --one-time-password option. I don't see that it created a keytab nor is there an option to do that. – Richard Schmitt May 01 '23 at 22:28
  • You then say I can use ktutil to create a keytab file. I assume that's by using add_entry followed by write_kt. When I try to create an entry as: `add_entry -password -p cifs/myhost@mydomain.com -k 1 -f` I get an error `add_entry: Client not found in Kerberos database while adding new entry`. What Client and what Kerberos database? I get what your saying is I would need to do this on both the DC and the computer. That was helpful. – Richard Schmitt May 01 '23 at 22:28
  • "cifs/myhost@domain.com" is the 'client' in question, "Kerberos database" is the KDC, as `-f` does an online request to the KDC (to learn what KDF salt it's using for that particular principal). So ideally you would create an account on the KDC first, assign it the SPN, and *then* do the `add_entry -f`. – user1686 May 02 '23 at 04:38
  • It's only `adcli join` that creates a keytab, `adcli preset-computer` doesn't (it just creates a placeholder). – user1686 May 02 '23 at 04:39
  • Also, to make sure, keytabs use raw Kerberos principals, not UPNs/SPNs, and the `@REALM` part of a principal name is **upper-case**, even in AD. – user1686 May 02 '23 at 04:51
  • Still couldn't get it to work. Guess I am too unfamiliar with kerberos. Here's what I've done: On the DC: ``` # kadmin.local kadmin.local: add_principal cifs/ubuntu@SPIRITCLOUD.APP kadmin.local: ktadd cifs/ubuntu@SPIRITCLOUD.APP kadmin.local: quit # ``` Did the same thing on member adding same password. Then ran gss-server with: ``` ./gss-server cifs/ubuntu ``` client with: ``` ./gss-client ubuntu cifs test ``` Get pretty far considering, but end up with: ``` GSS-API error initializing context: The ticket isn't for us ``` More to do. Thanks – Richard Schmitt May 04 '23 at 16:40
  • kadmin.local? What kind of software is the DC running? I thought you said it was AD? – user1686 May 04 '23 at 16:43
  • I was adding more to my comment, sorry. Updated now. Also thought it was markdown so ignore ticks. My DC is samba-ad-dc. – Richard Schmitt May 04 '23 at 16:46
  • It is markdown but (deliberately) very minimal markdown, so that people would edit relevant info into their main post instead. If you're using kadmin.local, I suppose that means you're using the mit-kdc version of Samba? What does `KRB5_TRACE=/dev/stderr ./gss-server...` (and the same with ./gss-client) say? Are you sure the client is acquiring a ticket for cifs/ubuntu exactly, and not e.g. for cifs/ubuntu.spiritcloud.app? (Kerberos on Unix does more client-side canonicalization than Windows clients would.) – user1686 May 04 '23 at 17:04
0

SOLUTION: This is what I did to get things to work.

  1. My DC is running samba-ad-dc. This assumes you already have a user configured on your DC. Use samba-tool to add a service principal for the service account and attach it to the user:
# samba-tool spn add cifs/myhost.mydomain.com@MYREALM MyUser

Where cifs is the name of my service, myhost.mydomain.com is the FQDN of my computer, MYREALM is the realm or domain name, and MyUser is the existing user that I want to attach the principal to.

  1. Generate a keytab with an entry for that service principal
# samba-tool domain exportkeytab cifs.keytab --principal cifs/myhost.mydomain.com@MYREALM

Where cifs.keytab is an arbitrary name of an output file that will contain the keytab and cifs/myhost.mydomain.com@MYREALM is the service principal I just added in step 1.

  1. Copy that keytab file to the member computer with the FQDN myhost.mydomain.com. There are three things I could do with this keytab file on the member. a) replace /etc/krb5.keytab with it, b) import the entires from it into /etc/krb5.keytab using the ktutil utilitity, or c) specify it as an argument to gss-server. I am opting for c.

  2. Log in as the user that the service principal we created in step 1 is attached to.

# kinit MyUser@MYREALM
  1. Run gss-server
# gss-server -keytab cifs.keytab cifs/myhost.mydomain.com@MYREALM

where cifs.keytab is the keytab file exported from the DC and copied over to the member computer and cifs/myhost.mydomain.com@MYREALM is the principal we created in step 1.

  1. Run gss-client
# gss-client myhost.mydomain.com cifs message

where myhost.mydomain.com is the FQDN of my member computer, cifs is the service name of the principal I created in step 1 and message is whatever message I want to transfer to my server.

Simple wasn't it? NOT! But with user1686's patient help, I was able to get through this. Thanks.