kdc

package module
v0.1.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Sep 12, 2026 License: BSD-3-Clause Imports: 22 Imported by: 0

README

kdc

Issue Kerberos tickets from a go-authn/directory, in Go, with no cgo.

srv, err := kdc.New(kdc.Config{
    Realm:    "EXAMPLE.ORG",
    People:   people,          // sqldir, hcldir — anything holding passwords
    Services: keytab,          // krbtgt/REALM, and a key per service
})
go srv.ServeUDP(pc)
go srv.ServeTCP(ln)

This is the issuing half. go-authn/krb5 is the accepting half, and a service that only verifies tickets needs this package not at all.

⛔ What can and cannot back a realm

A KDC must decrypt the client's pre-authentication with that person's long-term key. It follows that only a source holding the password can back one: sqldir and hcldir can, and a Verifier — a bind against somebody else's LDAP, or a hash comparison — cannot, however well it answers "is this the right password".

That is a property of Kerberos rather than a limitation here. This package refuses at configuration time, so an operator is told before the first kinit rather than after.

What it implements

AS-REQ and TGS-REQ, over UDP and TCP, with encrypted-timestamp pre-authentication required.

Not implemented: cross-realm referrals, PKINIT, FAST, renewable or postdated tickets, and any kadmin protocol. Keys come from the directory and from a keytab, and they change where they live.

The judge

MIT's own kinit and kvno. No MIT KDC is involved — the keytab is built in Go and only the client is borrowed, which is the point: a realm judged by a client it did not write.

go test ./...          # KDC_REQUIRE_JUDGE=1 turns a missing MIT into a failure

The tests also pin the refusals a real client never triggers: a timestamp under the wrong key, one from an hour ago, a three-byte cipher, a service asked for straight from an AS-REQ, and a realm backed by a verifier.

Licence

BSD-3-Clause.

Documentation

Overview

Package kdc issues Kerberos tickets from a go-authn/directory.

It is the other half of github.com/go-authn/krb5, which accepts them. A service that verifies tickets needs no KDC and should not import this; a site that wants its own realm, backed by the same people its LDAP and its NFS already know, does.

What it can and cannot be backed by

A KDC must DECRYPT the client's pre-authentication with that person's long-term key. It follows that only a directory source holding the PASSWORD can back one: sqldir and hcldir can, and a directory.Verifier — a bind against somebody else's LDAP, or a hash comparison — CANNOT, however well it answers "is this the right password".

That is a property of Kerberos rather than a limitation here, and this package refuses at configuration time rather than at the first kinit.

What it implements

AS-REQ and TGS-REQ over UDP and TCP, with encrypted-timestamp pre-authentication required. It does not implement cross-realm referrals, PKINIT, FAST, renewable or postdated tickets, or a kadmin protocol: keys come from the directory and from a keytab, and change where they live.

Index

Constants

This section is empty.

Variables

View Source
var (
	// ErrNoRealm reports a configuration with no realm name.
	ErrNoRealm = errors.New("kdc: no realm")
	// ErrNoPeople reports one with nowhere to look up users.
	ErrNoPeople = errors.New("kdc: no directory")
	// ErrNoServices reports one with no keytab, which means no krbtgt key
	// and therefore nothing to sign a TGT with.
	ErrNoServices = errors.New("kdc: no keytab")
	// ErrNoTGTKey reports a keytab without krbtgt/REALM@REALM. A KDC without
	// it can authenticate somebody and then have nothing to hand them.
	ErrNoTGTKey = errors.New("kdc: the keytab has no krbtgt key for this realm")
)

Errors a configuration can have.

View Source
var ErrClosed = errors.New("kdc: server closed")

ErrClosed is returned by ServeUDP and ServeTCP after Close.

View Source
var ErrNotAPerson = errors.New("kdc: not a user principal")

ErrNotAPerson reports a principal that is not a single name — a service like nfs/host asking for a TGT of its own. Services authenticate from a keytab, not from this directory.

Functions

This section is empty.

Types

type Config

type Config struct {
	// Realm is the realm name, conventionally the DNS domain in capitals.
	Realm string

	// People is where users come from. It must publish passwords; see the
	// package comment for why a verifier cannot serve Kerberos.
	People directory.Source

	// Services holds the keys for service principals, including the
	// krbtgt/REALM@REALM this KDC issues its own tickets under. It is the
	// same file a service like an NFS server reads, which is the point: one
	// keytab, two readers, no third place for a key to drift.
	Services *keytab.Keytab

	// Lifetime caps a ticket. Zero means ten hours, which is MIT's default.
	Lifetime time.Duration

	// MaxSkew is how far a client's clock may be from this one. Zero means
	// five minutes, which is what every Kerberos implementation assumes.
	MaxSkew time.Duration

	// Logf, when set, is told why a request was refused.
	//
	// It exists because the protocol cannot say: a client is given an error
	// CODE, and "pre-authentication failed" covers a wrong password, a wrong
	// salt, a clock an hour out and a malformed message. Only this side can
	// tell them apart, and only to an operator.
	//
	// ⛔ It is never given a password, a key, or a decrypted anything.
	Logf func(format string, args ...any)
}

Config describes one realm.

type Server

type Server struct {
	// contains filtered or unexported fields
}

Server answers Kerberos requests for one realm.

The zero value is not usable; use New.

func New

func New(cfg Config) (*Server, error)

New checks a configuration and returns a server for it.

It refuses a realm it could not serve — no keytab, no krbtgt key, a directory that publishes no passwords — rather than starting and failing at the first kinit, where the error reaches a person who cannot fix it.

func (*Server) Close

func (s *Server) Close() error

Close stops the server and drops what it is serving.

func (*Server) ServeTCP

func (s *Server) ServeTCP(ln net.Listener) error

ServeTCP answers connections. Each carries a four-byte length in front of every message, which UDP does not (RFC 4120 §7.2.2).

func (*Server) ServeUDP

func (s *Server) ServeUDP(pc net.PacketConn) error

ServeUDP answers datagrams. It is the transport a client tries first: MIT's kinit sends UDP and falls back to TCP only when the reply does not fit or the KDC says so.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL