# Kerberos - сетевой single sign-on _Протоколы · LinuxLab Knowledge Base_ **TL;DR:** Kerberos - SSO-система с тикетами на временной криптографии. Один раз вводишь пароль (`kinit`), получаешь TGT, дальше KDC выдаёт service tickets в обмен. Основа AD и FreeIPA. ## Зачем Kerberos Решает фундаментальную проблему многосервисной сети: пользователь не должен вводить пароль каждый раз заново; пароль не должен ходить по сети; сервер должен быть уверен, что юзер, именно тот, за кого себя выдаёт. Kerberos с 1988 (MIT, проект Athena) даёт этот SSO. Сегодня: - **Active Directory**, Kerberos с самого начала AD; krb5 + LDAP через MS-расширения - **FreeIPA**, RHEL'овский SSO-стек: Kerberos + 389-DS + DNS + CA - **NFSv4 sec=krb5p**, единственный production-grade auth для NFS в multi-user environment - **SSH GSSAPI**, проксирование Kerberos-аутентификации - **Hadoop/Kafka secure mode**, krb для service-to-service auth Не для интернет-сервисов общего пользования (там OIDC/OAuth2 правит), но в корпоративном datacenter, стандарт. ## Главные понятия | Термин | Что | |--------|-----| | **Realm** | административный домен (типично UPPERCASE имя домена: `EXAMPLE.COM`) | | **Principal** | identity внутри realm: `alice@EXAMPLE.COM` (user) или `host/server.example.com@EXAMPLE.COM` (service) | | **KDC** | Key Distribution Center, сервер выдаёт тикеты. Состоит из AS + TGS | | **AS** (Authentication Service) | первичная аутентификация, выдаёт TGT | | **TGS** (Ticket Granting Service) | в обмен на TGT выдаёт service tickets | | **TGT** | Ticket Granting Ticket, главный тикет, на ~10 часов | | **Service Ticket** | "пропуск" к конкретному сервису, на минуты-часы | | **Keytab** | файл с долгосрочными ключами для service-principals (без пароля) | Все ключи, **симметричные**. Это и сила (быстрая криптография), и ограничение (KDC должен знать ключи всех принципалов). ## Поток аутентификации Упрощённо: ``` Client KDC (AS+TGS) Service │ │ │ │ AS-REQ (I'm alice@EXAMPLE.COM) │ │ ├─────────────────────────────────────►│ │ │ AS-REP (TGT, encrypted with │ │ │ alice's password-derived key) │ │ │◄─────────────────────────────────────┤ │ │ [client decrypts → if pw correct] │ │ │ │ │ │ TGS-REQ (TGT + "I want service │ │ │ nfs/file.example.com") │ │ ├─────────────────────────────────────►│ │ │ TGS-REP (service ticket, │ │ │ encrypted with service's key) │ │ │◄─────────────────────────────────────┤ │ │ │ │ │ AP-REQ (service ticket) │ │ ├─────────────────────────────────────────────────────────►│ │ AP-REP (mutual auth, optional) │ │◄─────────────────────────────────────────────────────────┤ ``` Главное: **пароль идёт только в первом сообщении** (и то, не пароль напрямую, а ключ из него). Дальше ходят тикеты. ## Принципалы Формат: ``` primary[/instance]@REALM alice@EXAMPLE.COM ← user host/server.example.com@EXAMPLE.COM ← service "host" (для SSH/SCP) nfs/server.example.com@EXAMPLE.COM ← NFS-сервис HTTP/web.example.com@EXAMPLE.COM ← Apache/Nginx с SPNEGO alice/admin@EXAMPLE.COM ← привилегированный alice ``` Service-принципалы названы по схеме `service/fqdn@REALM`, где `service`, известный тип (`host`, `HTTP`, `nfs`, `ldap`, `ftp`). ## Установка MIT Kerberos на Linux ```bash # Сервер (KDC) apt install krb5-kdc krb5-admin-server # Debian/Ubuntu dnf install krb5-server krb5-server-ldap # RHEL # Клиенты apt install krb5-user # Debian/Ubuntu dnf install krb5-workstation # RHEL ``` `/etc/krb5.conf`: ```ini [libdefaults] default_realm = EXAMPLE.COM dns_lookup_realm = false dns_lookup_kdc = true # KDC через SRV-записи ticket_lifetime = 24h renew_lifetime = 7d [realms] EXAMPLE.COM = { kdc = kdc1.example.com kdc = kdc2.example.com admin_server = kdc1.example.com } [domain_realm] .example.com = EXAMPLE.COM example.com = EXAMPLE.COM ``` KDC требует **точно синхронизированное время** (max skew ~5 минут): без NTP/chrony Kerberos падает с `Clock skew too great`. ## Daily commands ```bash kinit alice # запросить TGT (введёт пароль) klist # показать тикеты в кэше klist -e # с типом шифрования kdestroy # очистить cache kpasswd # сменить пароль # Из keytab без интерактива kinit -k -t /etc/krb5.keytab host/server.example.com # Renew TGT (если в lifetime) kinit -R ``` Cache по дефолту в `/tmp/krb5cc_$UID` (FILE-based) или Keyring/KCM на современных дистро. ## Keytab, для сервисов Сервисы (sshd, nfs, http) не могут запрашивать пароль. Их долгосрочные ключи лежат в **keytab** (binary файл): ```bash # Создать service principal на KDC kadmin.local -q "addprinc -randkey nfs/server.example.com" # Экспортировать в keytab kadmin.local -q "ktadd -k /etc/krb5.keytab nfs/server.example.com" # На клиенте использовать ktutil > read_kt /etc/krb5.keytab > list -e # Версия keytab klist -kt /etc/krb5.keytab ``` Keytab, **секрет**. Mode 600, owner = root (или сервисный юзер). Утечка = захват сервиса. ## Поддержка ядра: KEYRING / KCM Раньше тикеты лежали в файле `/tmp/krb5cc_$UID`. Современные дистро используют: - **KEYRING**, хранение в kernel keyring, изоляция per-namespace - **KCM** (Kerberos Cache Manager), daemon, удобно для multi-user + collection of caches (несколько realm'ов одновременно) Конфигурируется через `default_ccache_name = KEYRING:persistent:%{uid}`. ## SSH через GSSAPI/Kerberos Зашёл `kinit` один раз, `ssh server.example.com` не спросит пароль: Сервер: ``` # /etc/ssh/sshd_config GSSAPIAuthentication yes GSSAPICleanupCredentials yes ``` Клиент: ``` # ~/.ssh/config Host *.example.com GSSAPIAuthentication yes GSSAPIDelegateCredentials yes # форвардить TGT на сервер ``` С `GSSAPIDelegateCredentials yes`, сервер получит копию твоего TGT, сможет от твоего имени дальше ходить (на NFS/другие SSH). ## MIT Kerberos vs Heimdal vs AD | Признак | MIT | Heimdal | Microsoft AD | |---------|-----|---------|--------------| | Lineage | референс | независимая реализация | проприетарная | | На Linux default | RHEL/Fedora/Debian | FreeBSD, Samba (старо) | через samba/realmd | | Active dev | да | замедлилась | да | | Совместимость с AD | хорошая | хорошая | родной | Большинство Linux-документации подразумевает MIT. ## Когда что-то пошло не так - **`Clock skew too great`**, KDC и клиент разошлись по времени больше чем на `clockskew` (default 5min). Включи [[chrony-and-ntp|chrony]]. - **`KDC has no support for encryption type`**, клиент запрашивает DES/RC4, KDC выключил их (security update). Обнови `default_tgs_enctypes`/ `default_tkt_enctypes` на современные (aes256-cts). - **`Cannot find KDC for requested realm`**, DNS SRV не настроен, либо `dns_lookup_kdc = false` без явного `kdc =` в `[realms]`. - **`Permission denied (gssapi-with-mic)`** в SSH, нет TGT (`klist` пуст), либо service-principal `host/server@REALM` отсутствует на KDC, либо keytab сервера устарел. - **`KRB_AP_ERR_TKT_EXPIRED`**, service-ticket истёк по таймауту. `kinit -R` обновит TGT, новые service-tickets подтянутся. - **Keytab перестал работать после смены пароля принципала** KVNO (key version number) увеличился. Перевыпусти keytab: `ktadd -k /etc/krb5.keytab service/host`. - **`Server not found in Kerberos database`**, service-principal не создан на KDC; либо запрос идёт по неправильному hostname (mismatched DNS vs principal `host/`). ## Команды ```bash kinit alice@EXAMPLE.COM ``` Запросить TGT - первое что делает юзер за день ```bash klist -e ``` Тикеты в кэше с типом шифрования - проверить что есть и не истёк ```bash kinit -k -t /etc/krb5.keytab nfs/server.example.com ``` Получить TGT из keytab без интерактива - для сервисов ```bash kadmin.local -q 'listprincs' | head ``` Все principals в локальном KDC - инвентаризация ```bash kadmin.local -q 'ktadd -k /tmp/svc.keytab svc/host.example.com' ``` Экспорт service-principal в keytab для деплоя на сервис ```bash klist -kt /etc/krb5.keytab ``` Содержимое keytab: principals и их KVNO ```bash kvno nfs/server.example.com ``` Запросить service-ticket вручную - проверить что KDC выдаёт ## См. также - [LDAP - directory services основы](/kb/ldap-basics.md) - [PAM - Pluggable Authentication Modules](/kb/pam.md) - [SSH - secure shell](/kb/ssh.md) - [SSH hardening - закрытие сервера](/kb/ssh-hardening.md) - [NFS - сетевая файловая система](/kb/nfs.md) - [RADIUS - аутентификация для сети, VPN, Wi-Fi](/kb/radius.md)