354 lines
11 KiB
Markdown
354 lines
11 KiB
Markdown
# Kerberos Server
|
|
|
|
MIT Kerberos V KDC + admin server container running on Ubuntu 26.04.
|
|
|
|
## Prerequisites
|
|
|
|
### DNS setup
|
|
|
|
Kerberos is sensitive to hostname resolution. The following DNS records must be in place before starting the container.
|
|
|
|
**Forward record** — resolves the KDC hostname to its IP address:
|
|
|
|
```dns
|
|
krb5.example.org. IN A 192.168.1.10
|
|
_kerberos._tcp.example.org. IN SRV 1 0 88 krb5.example.org.
|
|
_kerberos._udp.example.org. IN SRV 1 0 88 krb5.example.org.
|
|
_kerberos-adm._tcp.example.org. IN SRV 1 0 749 krb5.example.org.
|
|
_kpasswd._udp.example.org. IN SRV 1 0 464 krb5.example.org.
|
|
```
|
|
|
|
**Reverse record** — resolves the IP back to the hostname (required by some Kerberos operations):
|
|
|
|
```dns
|
|
10.1.168.192.in-addr.arpa. IN PTR krb5.example.org.
|
|
```
|
|
|
|
The container's hostname must match `KRB5_KDC_HOST` exactly — it is set via the `hostname:` field in the compose file.
|
|
|
|
**Note**: DNS-based KDC discovery (SRV records) is disabled for the server container in the generated configuration (`dns_lookup_kdc = false`), however it is required for clients to locate the KDC. The KDC hostname must be resolvable by clients via DNS or a local hosts file entry.
|
|
|
|
## Environment variables
|
|
|
|
| Variable | Default | Description |
|
|
|---|---|---|
|
|
| `KRB5_REALM` | `EXAMPLE.ORG` | Kerberos realm (uppercase) |
|
|
| `KRB5_DOMAIN` | `example.org` | DNS domain mapped to the realm |
|
|
| `KRB5_KDC_HOST` | *(required)* | FQDN of this KDC, used by clients and in service ticket names |
|
|
| `KRB5_MASTER_PASSWORD` | *(required on first start)* | Database master key — set once, cannot be changed without destroying the database |
|
|
| `KRB5_ADMIN_PRINCIPAL` | `admin` | Name of the bootstrap admin principal |
|
|
| `KRB5_ADMIN_PASSWORD` | *(required on first start)* | Password for `<admin>@<REALM>` |
|
|
|
|
Copy `env.example` to `~/app-data/kerberos/kerberos.env` and fill in real values before first run.
|
|
|
|
### Admin principal naming
|
|
|
|
By default the bootstrap principal is created as `admin@REALM` — a flat, UPN-style name. This is the value of `KRB5_ADMIN_PRINCIPAL` used verbatim.
|
|
|
|
MIT Kerberos also supports the traditional `primary/instance` convention, where the `/admin` instance signals administrative intent. If you prefer that style, set the full name in the variable:
|
|
|
|
```
|
|
KRB5_ADMIN_PRINCIPAL=slawek/admin
|
|
```
|
|
|
|
This creates `slawek/admin@REALM` and grants it full kadmin rights via the ACL. Either form works — it is purely a naming preference.
|
|
|
|
> **Important:** `KRB5_MASTER_PASSWORD` and `KRB5_ADMIN_PASSWORD` are only required on first start. Once the realm is initialised (the database file exists in the volume), these variables are not read and can be removed from the env file for enhanced security. The master password cannot be changed without wiping the `kerberos_data` volume and reinitialising the realm, which invalidates all issued tickets and keytabs.
|
|
|
|
## Build
|
|
|
|
```bash
|
|
./scripts/build.sh
|
|
```
|
|
|
|
## Run
|
|
|
|
```bash
|
|
./scripts/run-container.sh
|
|
```
|
|
|
|
The `kerberos_data` volume (`/var/lib/krb5kdc`) holds the realm database, configuration, and keytab. All files are written once on first start. On subsequent starts the container requires no environment variables — the persisted configuration is used as-is. Sensitive variables (`KRB5_MASTER_PASSWORD`, `KRB5_ADMIN_PASSWORD`) can be removed from the env file after the realm is initialised.
|
|
|
|
## Ports
|
|
|
|
| Port | Protocol | Service |
|
|
|---|---|---|
|
|
| 88 | TCP/UDP | KDC (ticket granting) |
|
|
| 464 | TCP/UDP | kpasswd (password changes) |
|
|
| 749 | TCP | kadmin (remote administration) |
|
|
|
|
## Client configuration
|
|
|
|
Pre-authentication is required (`+preauth` is set by default), so clients must supply a password or keytab — anonymous TGT requests are rejected.
|
|
|
|
The KDC hostname (`KRB5_KDC_HOST`) must be resolvable from every client machine via DNS or a local hosts file entry.
|
|
|
|
### Linux
|
|
|
|
Install the MIT Kerberos client tools:
|
|
|
|
```bash
|
|
sudo apt install krb5-user # Debian / Ubuntu
|
|
sudo dnf install krb5-workstation # Fedora / RHEL
|
|
```
|
|
|
|
Create `/etc/krb5.conf`:
|
|
|
|
```ini
|
|
[libdefaults]
|
|
default_realm = EXAMPLE.ORG
|
|
|
|
[realms]
|
|
EXAMPLE.ORG = {
|
|
kdc = kerberos.example.org
|
|
admin_server = kerberos.example.org
|
|
}
|
|
|
|
[domain_realm]
|
|
.example.org = EXAMPLE.ORG
|
|
example.org = EXAMPLE.ORG
|
|
```
|
|
|
|
```bash
|
|
kinit user@EXAMPLE.ORG # obtain a ticket
|
|
klist # verify
|
|
kdestroy # release
|
|
```
|
|
|
|
### macOS
|
|
|
|
Kerberos (Heimdal) is built into macOS — no installation required. It is interoperable with MIT KDCs.
|
|
|
|
Create `/etc/krb5.conf` with the same content as the Linux example above.
|
|
|
|
```bash
|
|
kinit user@EXAMPLE.ORG
|
|
klist
|
|
kdestroy
|
|
```
|
|
|
|
Acquired tickets are also visible in **Ticket Viewer** (`/System/Library/CoreServices/Ticket Viewer.app`).
|
|
|
|
For SSH with GSSAPI, add to `~/.ssh/config`:
|
|
|
|
```
|
|
Host *.example.org
|
|
GSSAPIAuthentication yes
|
|
GSSAPIDelegateCredentials yes
|
|
```
|
|
|
|
### Windows (standalone, not domain-joined)
|
|
|
|
Install **MIT Kerberos for Windows** (KfW) from [web.mit.edu/kerberos/dist](https://web.mit.edu/kerberos/dist/). The built-in Windows Kerberos provider (SSPI) is designed for Active Directory domain membership and is not suitable for standalone use against a custom KDC.
|
|
|
|
Create the configuration file at `%ProgramData%\MIT\Kerberos5\krb5.ini` (system-wide) or set the `KRB5_CONFIG` environment variable to point to a file of your choice:
|
|
|
|
```ini
|
|
[libdefaults]
|
|
default_realm = EXAMPLE.ORG
|
|
|
|
[realms]
|
|
EXAMPLE.ORG = {
|
|
kdc = kerberos.example.org
|
|
admin_server = kerberos.example.org
|
|
}
|
|
|
|
[domain_realm]
|
|
.example.org = EXAMPLE.ORG
|
|
example.org = EXAMPLE.ORG
|
|
```
|
|
|
|
Use the KfW **Network Identity Manager** GUI or the bundled command-line tools from a Command Prompt:
|
|
|
|
```cmd
|
|
kinit user@EXAMPLE.ORG
|
|
klist
|
|
kdestroy
|
|
```
|
|
|
|
## Managing principals
|
|
|
|
### Remote (kadmin)
|
|
|
|
`kadmin` connects to `kadmind` on port 749 from any machine with a valid `krb5.conf`. Authenticate as a principal with rights in `kadm5.acl`:
|
|
|
|
```bash
|
|
kadmin -p admin@REALM
|
|
```
|
|
|
|
With a keytab instead of a password prompt:
|
|
|
|
```bash
|
|
kadmin -p admin@REALM -k -t /path/to/admin.keytab
|
|
```
|
|
|
|
All commands below work identically in `kadmin` — replace `kadmin.local` with `kadmin -p admin@REALM`.
|
|
|
|
### Local (kadmin.local)
|
|
|
|
Exec into the running container — no authentication required, bypasses `kadmind` entirely:
|
|
|
|
```bash
|
|
container exec -it kerberos bash
|
|
```
|
|
|
|
### Principals
|
|
|
|
```bash
|
|
# List all principals (supports glob: "user*")
|
|
kadmin.local -q "listprincs"
|
|
|
|
# Inspect a principal
|
|
kadmin.local -q "getprinc user@REALM"
|
|
|
|
# Add a user principal
|
|
kadmin.local -q "addprinc user@REALM"
|
|
|
|
# Add a service principal (random key, no password)
|
|
kadmin.local -q "addprinc -randkey service/host.example.org@REALM"
|
|
|
|
# Change password
|
|
kadmin.local -q "cpw -pw newpassword user@REALM"
|
|
|
|
# Randomise key (invalidates existing tickets and keytabs)
|
|
kadmin.local -q "cpw -randkey service/host.example.org@REALM"
|
|
|
|
# Set expiry
|
|
kadmin.local -q "modprinc -expire '2027-01-01' user@REALM"
|
|
|
|
# Unlock after failed authentication lockout
|
|
kadmin.local -q "modprinc -unlock user@REALM"
|
|
|
|
# Delete a principal
|
|
kadmin.local -q "delprinc user@REALM"
|
|
```
|
|
|
|
### Keytabs
|
|
|
|
```bash
|
|
# Extract keytab (randomises the principal's key)
|
|
kadmin.local -q "ktadd -k /tmp/service.keytab service/host.example.org@REALM"
|
|
|
|
# Extract without randomising key (-norandkey, preserves existing tickets)
|
|
kadmin.local -q "ktadd -k /tmp/service.keytab -norandkey service/host.example.org@REALM"
|
|
|
|
# Remove keytab entries for a principal
|
|
kadmin.local -q "ktremove -k /tmp/service.keytab service/host.example.org@REALM all"
|
|
```
|
|
|
|
### Password policies
|
|
|
|
```bash
|
|
# Create a policy
|
|
kadmin.local -q "addpol -minlength 12 -minclasses 3 -maxlife '90 days' -maxfailure 5 default"
|
|
|
|
# Assign policy to a principal
|
|
kadmin.local -q "modprinc -policy default user@REALM"
|
|
|
|
# Inspect a policy
|
|
kadmin.local -q "getpol default"
|
|
|
|
# List policies
|
|
kadmin.local -q "listpols"
|
|
|
|
# Delete a policy (fails if any principal uses it)
|
|
kadmin.local -q "delpol default"
|
|
```
|
|
|
|
## SSH server configuration
|
|
|
|
SSH uses the `host/` service principal. The FQDN must match the result of forward DNS resolution of the server's hostname, and the IP must reverse-resolve to the same FQDN.
|
|
|
|
### Linux
|
|
|
|
Create the host principal and extract the keytab to the default location (run as `root` on the SSH server — the keytab is written to `/etc/krb5.keytab`, mode `0600`):
|
|
|
|
```bash
|
|
sudo kadmin -p admin@REALM -q "addprinc -randkey host/ssh-server.example.org@REALM"
|
|
sudo kadmin -p admin@REALM -q "ktadd host/ssh-server.example.org@REALM"
|
|
```
|
|
|
|
Add to `/etc/ssh/sshd_config` (requires `root`):
|
|
|
|
```
|
|
GSSAPIAuthentication yes
|
|
GSSAPICleanupCredentials yes
|
|
GSSAPIStrictAcceptorCheck yes
|
|
```
|
|
|
|
`GSSAPIStrictAcceptorCheck` verifies the server's identity against the keytab — keep it enabled. Reload sshd (requires `root`):
|
|
|
|
```bash
|
|
sudo systemctl reload sshd
|
|
```
|
|
|
|
**Login authorisation** — by default a principal is granted access if its realm matches `default_realm` and its name matches the local account. To grant additional principals access to an account, list them in `~/.k5login` (one principal per line):
|
|
|
|
```
|
|
alice@EXAMPLE.ORG
|
|
alice/admin@EXAMPLE.ORG
|
|
```
|
|
|
|
If `.k5login` is present it is authoritative — unlisted principals are denied even if the name matches. To make it additive rather than restrictive, set in `krb5.conf`:
|
|
|
|
```ini
|
|
[libdefaults]
|
|
k5login_authoritative = false
|
|
```
|
|
|
|
### Client connection
|
|
|
|
SSH will prefer public key authentication by default even when GSSAPI is available. To enforce Kerberos:
|
|
|
|
```bash
|
|
ssh -o GSSAPIAuthentication=yes -o PreferredAuthentications=gssapi-with-mic user@ssh-server.example.org
|
|
```
|
|
|
|
To make this permanent for a host in `~/.ssh/config`:
|
|
|
|
```
|
|
Host ssh-server.example.org
|
|
GSSAPIAuthentication yes
|
|
PreferredAuthentications gssapi-with-mic
|
|
```
|
|
|
|
On Windows (KfW) and macOS the same `ssh` flags apply. macOS additionally accepts `-K` as a shorthand for `GSSAPIAuthentication=yes`.
|
|
|
|
### Windows
|
|
|
|
`GSSAPIAuthentication` is available on **Windows Server 2022, 2025, Windows 10 (May 2021 Update), and Windows 11** only. Windows Server 2019 does not support it.
|
|
|
|
Install **MIT Kerberos for Windows** (KfW) on the SSH server — Windows OpenSSH uses it for GSSAPI when the machine is not domain-joined. Create the host principal and extract a keytab:
|
|
|
|
```bash
|
|
kadmin -p admin@REALM -q "addprinc -randkey host/win-server.example.org@REALM"
|
|
kadmin -p admin@REALM -q "ktadd -k /tmp/win-server.keytab host/win-server.example.org@REALM"
|
|
```
|
|
|
|
Copy the keytab to the Windows server and set `KRB5_KTNAME` in the system environment to its path, or place it at the KfW default (`%ProgramData%\MIT\Kerberos5\krb5.keytab`).
|
|
|
|
Add to `%ProgramData%\ssh\sshd_config`:
|
|
|
|
```
|
|
GSSAPIAuthentication yes
|
|
```
|
|
|
|
> The following directives are **not available** on Windows OpenSSH and must not be added: `GSSAPICleanupCredentials`, `GSSAPIStrictAcceptorCheck`, `KerberosAuthentication`, `KerberosTicketCleanup`.
|
|
|
|
Restart the `sshd` service after the change (requires an elevated PowerShell prompt):
|
|
|
|
```powershell
|
|
Restart-Service sshd
|
|
```
|
|
|
|
## OpenLDAP SASL/GSSAPI integration
|
|
|
|
1. Create the LDAP service principal and extract a keytab:
|
|
```bash
|
|
kadmin.local -q "addprinc -randkey ldap/ldap.example.org@REALM"
|
|
kadmin.local -q "ktadd -k /tmp/ldap.keytab ldap/ldap.example.org@REALM"
|
|
```
|
|
2. Copy the keytab into the OpenLDAP container at `/etc/ldap/ldap.keytab`.
|
|
3. Set `KRB5_KTNAME=/etc/ldap/ldap.keytab` in the OpenLDAP container environment.
|
|
4. Install `libsasl2-modules-gssapi-mit` in the OpenLDAP image and enable the `GSSAPI` SASL mechanism.
|