Статья
Тихий SSO через Keycloak и Kerberos
SAML с формой уже работал — довёл до входа без пароля: keytab в AD, маппинг по UPN и allowlist браузера на FQDN Keycloak.
Нужен был бесшовный вход в приложение с SAML 2.0: человек жмёт Войти через SSO и не видит форму Keycloak. Базовый SAML между SP и Keycloak и LDAP User Federation уже работали. Осталось научить браузер отдать Negotiate, а Keycloak — принять ticket.
Кто что делает
| Участник | Роль |
|---|---|
| Приложение | SP с SAML 2.0 |
| Keycloak | IdP |
| Active Directory | KDC + каталог |
| Браузер | Negotiate/Kerberos |
Порядок, который у меня работает: AD (SPN + keytab) → Kerberos в federation и browser flow → GPO allowlist → при необходимости UPN в AD.
Пример имён:
| Роль | Значение |
|---|---|
| SP | sp.example.com |
| Keycloak | keycloak.example.com |
| AD / KDC | ad.example.com |
| Kerberos realm | EXAMPLE.COM |
| Service account | keycloak-int |
| Principal | HTTP/keycloak.example.com@EXAMPLE.COM |
Что должно работать до Kerberos
- SAML между SP и Keycloak уже настроен: вход через SSO с формой Keycloak работает
- AD подключён как User Federation, пользователи находятся
- Клиентские машины в домене, DNS и TLS Keycloak доверенны
- Keycloak доступен по FQDN, что пойдёт в SPN
AD: учётка, SPN, keytab
Браузер просит TGS на HTTP/<FQDN-Keycloak>. Keycloak расшифровывает SPNEGO ключом из keytab. Без корректного SPN и keytab бесшовного входа нет.
Учётка службы, например keycloak-int: длинный пароль без истечения по политике, в Account включено This account supports Kerberos AES 256 bit encryption:
setspn -S HTTP/keycloak.example.com keycloak-int
setspn -Q HTTP/keycloak.example.com
setspn -Q должен вернуть ровно одну учётку. Дубликаты SPN — частая причина отката на NTLM и окна Windows Security. Синтаксис — HTTP/fqdn, регистр HTTP каноничный для браузерного SPNEGO.
ktpass `
-out C:\keycloak.keytab `
-princ HTTP/keycloak.example.com@EXAMPLE.COM `
-mapUser keycloak-int@example.com `
-pass "user_password" `
-crypto AES256-SHA1 `
-ptype KRB5_NT_PRINCIPAL
Realm в princ — UPPERCASE. ktpass фиксирует ключ учётки и часто ставит UPN service account в вид HTTP/keycloak.example.com@EXAMPLE.COM — этот UPN у keycloak-int потом не трогать, иначе keytab умрёт.
Keytab на хост Keycloak, например /opt/keycloak/keycloak.keytab, права только процессу Keycloak (chmod 440, нужный owner).
На ОС Keycloak
Установить krb5-user пакет:
apt update
apt install krb5-user
Создать и заполнить конфигурационный файл — /etc/krb5.conf:
[libdefaults]
default_realm = EXAMPLE.COM
dns_lookup_realm = false
dns_lookup_kdc = true
rdns = false
default_tkt_enctypes = aes256-cts-hmac-sha1-96 aes128-cts-hmac-sha1-96
default_tgs_enctypes = aes256-cts-hmac-sha1-96 aes128-cts-hmac-sha1-96
permitted_enctypes = aes256-cts-hmac-sha1-96 aes128-cts-hmac-sha1-96
[realms]
EXAMPLE.COM = {
kdc = ad.example.com
admin_server = ad.example.com
}
[domain_realm]
.example.com = EXAMPLE.COM
example.com = EXAMPLE.COM
Проверить работу keytab до настройки UI в Keycloak:
kinit -k -t /opt/keycloak/keycloak.keytab HTTP/keycloak.example.com@EXAMPLE.COM
klist
Пример успешного ответа:
Ticket cache: FILE:/tmp/krb5cc_0
Default principal: HTTP/keycloak.example.com@EXAMPLE.COM
Valid starting Expires Service principal
10/13/2026 04:07:36 10/13/2026 14:07:36 krbtgt/EXAMPLE.COM@EXAMPLE.COM
renew until 10/14/2026 04:07:35
Нужен TGT для HTTP/keycloak.example.com@EXAMPLE.COM. Если kinit падает — UI тоже не заработает: чинить SPN, AES, keytab или пароль.
Keycloak: federation и browser flow
В существующем LDAP/AD provider:
| Параметр | Значение |
|---|---|
| Allow Kerberos authentication | On |
| Kerberos realm | EXAMPLE.COM |
| Server principal | HTTP/keycloak.example.com@EXAMPLE.COM |
| Key tab | /opt/keycloak/keycloak.keytab |
| Kerberos principal attribute | userPrincipalName |

В ticket principal вида user@EXAMPLE.COM. Keycloak ищет в LDAP значение из Kerberos principal attribute:
userPrincipalName=user@example.com— находитsAMAccountName=userбез@realm— часто не находит → форма логина при живом ticket- пустой UPN в AD — маппинг тоже не сработает
Authentication → Flows → browser:
| Execution | Requirement |
|---|---|
| Cookie | Alternative |
| Kerberos | Alternative |
| Identity Provider Redirector | Alternative |
| forms → Username Password Form | Alternative / Required внутри forms |

Порядок сверху вниз: Cookie → Kerberos → … → forms. Kerberos только Alternative: нет ticket — fallback на форму. Required вне домена сломает вход.
Клиент: GPO / реестр Chromium
Даже при живом keytab браузер по умолчанию не отдаёт доменные credentials любому сайту. Нужно в allowlist браузеров указать — FQDN Keycloak. Value data будет без https://. Это лучше раздавать через GPO → Computer Configuration → Preferences → Windows Settings → Registry → New → Registry Item.
После применения на клиенте выполнить — gpupdate /force, перезапустить браузеры и проверить:
- Edge —
edge://policy - Chrome —
chrome://policy - Yandex —
browser://policy
Google Chrome
Создать два Registry Item:
Computer Configuration
Preferences
Windows Settings
Registry
New → Registry Item
Первый item:
Action: Update
Hive: HKEY_LOCAL_MACHINE
Key Path: SOFTWARE\Policies\Google\Chrome
Value name: AuthNegotiateDelegateAllowlist
Value type: REG_SZ
Value data: keycloak.example.com
Второй item:
Action: Update
Hive: HKEY_LOCAL_MACHINE
Key Path: SOFTWARE\Policies\Google\Chrome
Value name: AuthServerAllowlist
Value type: REG_SZ
Value data: keycloak.example.com
Microsoft Edge
Создать два Registry Item:
Computer Configuration
Preferences
Windows Settings
Registry
New → Registry Item
Первый item:
Action: Update
Hive: HKEY_LOCAL_MACHINE
Key Path: SOFTWARE\Policies\Microsoft\Edge
Value name: AuthNegotiateDelegateAllowlist
Value type: REG_SZ
Value data: keycloak.example.com
Второй item:
Action: Update
Hive: HKEY_LOCAL_MACHINE
Key Path: SOFTWARE\Policies\Microsoft\Edge
Value name: AuthServerAllowlist
Value type: REG_SZ
Value data: keycloak.example.com
Yandex Browser
Создать два Registry Item:
Computer Configuration
Preferences
Windows Settings
Registry
New → Registry Item
Первый item:
Action: Update
Hive: HKEY_LOCAL_MACHINE
Key Path: SOFTWARE\Policies\YandexBrowser
Value name: AuthNegotiateDelegateAllowlist
Value type: REG_SZ
Value data: keycloak.example.com
Второй item:
Action: Update
Hive: HKEY_LOCAL_MACHINE
Key Path: SOFTWARE\Policies\YandexBrowser
Value name: AuthServerAllowlist
Value type: REG_SZ
Value data: keycloak.example.com
Итог
Бесшовный вход — это цепочка на стороне IdP и клиентов: один SPN и живой keytab, маппинг по userPrincipalName, Kerberos в browser flow как Alternative и allowlist браузера на FQDN Keycloak. Когда kinit -k с keytab проходит, а SSO всё ещё с формой — я сначала смотрю UPN и GPO, а не ACS.
Метод подходит любому SP с SAML 2.0. После базовой интеграции на стороне приложения обычно больше ничего не нужно: Kerberos/SPNEGO крутится на Keycloak, AD и браузере.