All posts

Windows-Style SSO on Linux — No Domain Join Required

Kerberos · SSO · Linux

Windows-Style SSO on Linux — No Domain Join Required

Domain join gets a machine a computer account. It turns out a user ticket never needed one at all.

Your domain-joined Windows box logs into internal web apps silently. Kerberos ticket, SPNEGO handshake, done — you never see a login form. The question was whether a Linux machine that AD has never heard of can pull off the same trick.

It can. Domain join is for machine accounts. A user ticket needs three things: a Kerberos client, five lines of config, and your password. Here’s the whole journey, including the two places I face-planted.

The setup

shell
sudo apt install krb5-user

Then /etc/krb5.conf:

/etc/krb5.conf
[libdefaults]
    default_realm = EXAMPLE.COM
    dns_lookup_kdc = true
    dns_lookup_realm = true
    rdns = false

That’s it. No KDC addresses hardcoded — AD publishes its domain controllers in DNS, and the client finds them on its own:

shell
dig +short SRV _kerberos._tcp.example.com
# 0 100 88 dc01.example.com.
# 0 100 88 dc02.example.com.

(Internal DNS only. Public resolvers know nothing. On VPN, check resolvectl status before blaming Kerberos.)

Bonus AD fact: every DC is simultaneously KDC, password server, and admin/LDAP endpoint. The MIT-Kerberos distinction between kdc and admin_server? Collapses. Any DC does everything.

Getting a ticket — and face-plant #1

First attempt:

shell
kinit myuser@example.com

Result: a blank line. No prompt, no error, nothing. Just a cursor staring back at me. Pressing Enter produced another blank line. Great software.

The problem: everything after @ is a Kerberos realm, and realms are UPPERCASE. example.com looks like the domain — it looks like my email, even — but to Kerberos it’s an unknown realm, and instead of saying so it just… sulked.

The fix is almost insulting:

shell
kinit myuser
Password:

Leave out the realm entirely and default_realm from krb5.conf kicks in. Suddenly there’s an actual, visible Password: prompt — that’s how you know you’re talking to the right realm. Type the password (input is hidden, sudo-style), Enter, and:

shell
klist
# Default principal: myuser@EXAMPLE.COM
# krbtgt/EXAMPLE.COM@EXAMPLE.COM   valid ~10h

A krbtgt entry means you hold a TGT. You are now, cryptographically speaking, logged into the domain.

If kinit ever misbehaves again, this shows exactly what it’s doing — DNS lookups, which DC it contacts, where it dies:

shell
KRB5_TRACE=/dev/stdout kinit myuser

Face-plant #2: “Unable to locate package nc”

Wanted to check whether port 88 was even reachable. apt install nc — no such package. On Debian/Ubuntu it’s called netcat-openbsd. Or skip the install entirely, bash has networking built in:

shell
timeout 3 bash -c 'cat < /dev/null > /dev/tcp/dc01.example.com/88' && echo OPEN || echo CLOSED

Teaching the browser

Windows browsers negotiate automatically because they trust the intranet zone. Linux browsers trust nobody until told otherwise:

Firefoxabout:confignetwork.negotiate-auth.trusted-uris.example.com

Chrome/Chromium/etc/opt/chrome/policies/managed/kerberos.json:

/etc/opt/chrome/policies/managed/kerberos.json
{ "AuthServerAllowlist": "*.example.com" }

curl — because of course curl can do it:

shell
curl --negotiate -u : https://internal-app.example.com/

Open an internal site. It logs you in. Silently. On a machine that isn’t in the domain.

Extremely satisfying.

The fine print

  • Clocks: Kerberos allows ~5 min skew. Keep NTP running or nothing works and the errors won’t tell you why.
  • Use FQDNs: the hostname must match the service’s SPN. IPs and random aliases fall back to NTLM or fail.
  • Tickets expire (~10h). Re-kinit daily, or automate with k5start, a keytab, or sssd + KCM.
TL;DR

krb5.conf with an UPPERCASE realm → kinit myuser → browser allowlist. Three steps, zero domain join, and the same silent ticket dance Windows has been doing behind your back all along.

And if kinit ever greets you with a blank line instead of Password: — check your realm. It’s shouting-case or nothing.

Comments (0)

No comments yet. Be the first!

Write a Comment