Новинка Виртуальный VDS сервер в Нидерландах от 390р
Выберите продукт

Dovecot 2.4 и Keycloak: OAuth2-вход в IMAP

Практическая инструкция по подключению Keycloak к Dovecot 2.4: от настройки конфиденциального OIDC-клиента и проверки access token до сопоставления email с почтовым ящиком и входа в IMAP через OAUTHBEARER или XOAUTH2.
Dovecot 2.4 и Keycloak: OAuth2-вход в IMAP

Dovecot 2.4 может принимать OAuth2 access token вместо пароля при IMAP-аутентификации. Клиент передаёт токен через SASL-механизм OAUTHBEARER или XOAUTH2, а Dovecot проверяет его у Keycloak и определяет имя почтового пользователя по атрибуту email.

В этой инструкции используется онлайн-проверка через endpoint introspection. Такой вариант проще локальной валидации JWT: Dovecot не требуется самостоятельно хранить открытые ключи и учитывать их ротацию. Кроме того, introspection позволяет получить актуальное состояние токена, включая признак active. Цена этого решения — сетевой запрос к Keycloak при каждой аутентификации.

Dovecot 2.4 и Keycloak: OAuth2-вход в IMAP

В Dovecot 2.4 OAuth-токены обрабатываются непосредственно механизмами OAUTHBEARER и XOAUTH2: отдельная OAuth2 passdb для такого входа больше не нужна. При этом существующая userdb остаётся необходимой, поскольку после проверки токена сервер должен найти домашний каталог, UID, GID и расположение почтового ящика пользователя. Подробнее — в документации Dovecot.

Что потребуется

  • Dovecot ветки 2.4 с доступом к изменению системной конфигурации;
  • работающий IMAP-доступ по TLS;
  • realm в Keycloak и права на создание клиентов;
  • пользователь Keycloak с заполненным email;
  • существующий почтовый пользователь, которого userdb Dovecot находит по этому email;
  • сетевой доступ от сервера Dovecot к HTTPS-интерфейсу Keycloak;
  • тестовый IMAP-клиент или утилита openssl.

Настройка требует административного доступа к Dovecot. На обычном виртуальном хостинге пользователь, как правило, не может включать SASL-механизмы или изменять системные службы. Для такой интеграции нужен VPS-сервер, выделенный сервер, контейнер с собственной конфигурацией Dovecot либо поддержка OAuth2 со стороны панели или провайдера.

FastFox VDS
Облачный VDS-сервер
Виртуальные серверы с быстрым запуском и гибкой конфигурацией от 390₽ / мес
Доступные локации
Россия Нидерланды

Перед изменениями проверьте фактическую версию и сохраните резервную копию конфигурации:

dovecot --version
cp -a /etc/dovecot /etc/dovecot.backup-before-keycloak

Путь /etc/dovecot типичен, но не универсален. Если Dovecot установлен из нестандартного пакета, запущен в контейнере или собран вручную, используйте реальный каталог конфигурации. Команда копирования также предполагает достаточные права.

До настройки OAuth2 убедитесь, что TLS для IMAP уже работает корректно. Проверку сертификата, SNI и защищённых IMAPS/POP3S-подключений разбирает материал о TLS в Dovecot.

Определяем адреса Keycloak

В примерах будут использоваться следующие условные значения:

  • адрес Keycloak — https://sso.example.com;
  • realm — mail;
  • идентификатор клиента — dovecot-imap;
  • почтовый пользователь — user@example.com;
  • IMAP-сервер — imap.example.com.

Заменяйте их своими значениями. Имя realm чувствительно к регистру и должно совпадать во всех URL.

Keycloak публикует параметры OIDC realm через discovery-документ:

https://sso.example.com/realms/mail/.well-known/openid-configuration

В нём можно проверить issuer, token_endpoint, introspection_endpoint и jwks_uri. Для рассматриваемой схемы особенно важны точный issuer и endpoint introspection. Стандартный путь последнего имеет вид:

https://sso.example.com/realms/mail/protocol/openid-connect/token/introspect

Endpoint introspection сообщает, активен ли переданный токен, и доступен только конфиденциальным клиентам. Поэтому клиент, чьи реквизиты использует Dovecot, должен иметь включённую клиентскую аутентификацию. Это соответствует описанию OIDC endpoints в документации Keycloak.

Откройте discovery URL в браузере или проверьте его с сервера Dovecot:

curl --fail --silent --show-error https://sso.example.com/realms/mail/.well-known/openid-configuration

Ошибка сертификата, DNS или соединения должна быть устранена до настройки Dovecot. Не используйте параметр -k и не отключайте проверку сертификата в рабочей среде: сервер будет отправлять Keycloak действующие токены и реквизиты конфиденциального клиента.

Создаём OIDC-клиент в Keycloak

Откройте административную консоль Keycloak, выберите нужный realm и перейдите в раздел клиентов. Названия отдельных элементов интерфейса могут немного различаться между выпусками Keycloak, но требуемые параметры остаются теми же.

  1. Нажмите создание нового клиента.
  2. Выберите протокол или тип клиента OpenID Connect.
  3. Укажите Client ID dovecot-imap.
  4. Включите Client authentication. Это делает клиента конфиденциальным и позволяет ему обращаться к introspection endpoint.
  5. Сохраните клиента.
  6. Откройте вкладку с реквизитами клиента и скопируйте Client secret.

Для самой проверки токена не требуются redirect URI, web origins или service account. Standard Flow понадобится только в том случае, если этот же клиент участвует в интерактивном Authorization Code Flow. Direct Access Grants нужен лишь для приведённого ниже CLI-теста с логином и паролем; в постоянной конфигурации его лучше не оставлять включённым без необходимости.

В рабочей архитектуре получение токена и его проверка могут обслуживаться разными клиентами. Например, настольному приложению назначают публичный OIDC-клиент без секрета, а Dovecot использует отдельного конфиденциального клиента для introspection. Секрет Dovecot нельзя передавать пользовательскому почтовому приложению.

Добавляем email в access token

Dovecot должен получить из результата проверки значение, однозначно соответствующее почтовому ящику. В этой инструкции таким значением служит claim email.

Сначала откройте пользователя Keycloak и убедитесь, что в его профиле заполнен email:

user@example.com

Затем проверьте настройки клиента и назначенные ему client scopes. Стандартный scope email должен быть доступен клиенту, а при запросе токена нужно запросить как минимум:

openid email

Если после этого claim отсутствует в access token или результате introspection, создайте для клиента OIDC protocol mapper со следующей логикой:

  • источник значения — пользовательское свойство email;
  • имя token claim — email;
  • тип claim — String;
  • добавление в access token — включено;
  • добавление в introspection response — включено, если такая отдельная настройка присутствует в используемой версии Keycloak.

Не следует подставлять в email отображаемое имя, логин без домена или произвольный псевдоним. Значение должно совпадать с ключом, по которому Dovecot находит реальный почтовый ящик.

Проверяем соответствие email и пользователя Dovecot

OAuth2 отвечает только за подтверждение личности. После успешной проверки Dovecot передаёт имя пользователя своей userdb. Поэтому до включения OAuth убедитесь, что текущая пользовательская база уже знает адрес:

doveadm user user@example.com

Успешный ответ обычно содержит UID, GID, домашний каталог и другие поля, зависящие от вашей схемы хранения. Ошибка unknown user означает, что проблема находится не в Keycloak: сначала нужно настроить существующую userdb — SQL, LDAP, passwd-file, системных или статических пользователей.

В статье предполагается прямое соответствие:

email в Keycloak = имя для входа в IMAP = ключ пользователя в userdb
user@example.com  = user@example.com       = user@example.com

Если ящики в Dovecot называются иначе, например только user, безопаснее привести обе системы к единому каноническому имени или выпустить отдельный claim с точным идентификатором ящика. Простого указания username_attribute = email недостаточно для произвольного преобразования адреса в другую внутреннюю учётную запись.

Особое внимание уделите регистру. Хотя доменная часть email регистронезависима, пользовательская база и файловая система могут воспринимать User@example.com и user@example.com как разные строки. Практичный вариант — хранить почтовые идентификаторы в нижнем регистре и выдавать их из Keycloak в том же виде.

Получаем тестовый access token

Для первичной проверки можно временно включить Direct Access Grants у созданного клиента. Это позволяет запросить токен командой curl, не настраивая браузерное перенаправление. Такой способ предназначен именно для контролируемого теста: он требует передачи пароля Keycloak token endpoint и может быть несовместим с обязательной многофакторной аутентификацией.

Не записывайте настоящий пароль и Client secret в историю команд на многопользовательском сервере. Для лабораторного окружения запрос выглядит так:

read -r -p 'Keycloak username: ' KC_USER
read -r -s -p 'Keycloak password: ' KC_PASSWORD
printf '\012'
read -r -s -p 'Client secret: ' KC_CLIENT_SECRET
printf '\012'

TOKEN_RESPONSE=$(curl --fail --silent --show-error -X POST -H 'Content-Type: application/x-www-form-urlencoded' --data-urlencode 'grant_type=password' --data-urlencode 'client_id=dovecot-imap' --data-urlencode "client_secret=${KC_CLIENT_SECRET}" --data-urlencode "username=${KC_USER}" --data-urlencode "password=${KC_PASSWORD}" --data-urlencode 'scope=openid email' 'https://sso.example.com/realms/mail/protocol/openid-connect/token')

ACCESS_TOKEN=$(printf '%s' "$TOKEN_RESPONSE" | jq -r '.access_token')
unset KC_PASSWORD
printf 'Token length: %s\012' "${#ACCESS_TOKEN}"

Команды предполагают наличие jq. Не выводите access token в общий журнал и не отправляйте его в сторонние JWT-декодеры: до истечения срока действия это полноценный секрет доступа.

Если Keycloak возвращает unauthorized_client, проверьте, включён ли Direct Access Grants. Ошибка invalid_client обычно указывает на неверный Client ID, секрет или режим клиентской аутентификации. invalid_grant может означать неверный пароль, обязательное действие в профиле пользователя, временную блокировку либо поток аутентификации, который нельзя выполнить через password grant.

Проверяем токен через introspection

До редактирования Dovecot убедитесь, что конфиденциальный клиент действительно может проверить токен:

curl --fail --silent --show-error -u "dovecot-imap:${KC_CLIENT_SECRET}" -H 'Content-Type: application/x-www-form-urlencoded' --data-urlencode "token=${ACCESS_TOKEN}" 'https://sso.example.com/realms/mail/protocol/openid-connect/token/introspect' | jq

В ответе должны присутствовать как минимум:

{
  "active": true,
  "email": "user@example.com"
}

Реальный ответ будет содержать и другие поля. Проверьте также iss и scope, если собираетесь ограничивать по ним Dovecot. Значение issuer нужно копировать точно, без добавления или удаления завершающего слеша.

Если active равно false, возможны истечение срока действия, отзыв токена, передача ID token вместо access token или выпуск токена в другом realm. Если токен активен, но email отсутствует, вернитесь к client scopes и protocol mapper.

Подключаем OAuth2 к Dovecot 2.4

Создайте отдельный конфигурационный файл в каталоге, который подключается основной конфигурацией Dovecot. Например, в пакетной установке это может быть файл /etc/dovecot/conf.d/90-keycloak-oauth2.conf. Не копируйте путь вслепую: сначала проверьте структуру своей установки.

Минимальная конфигурация для проверки токена через Keycloak:

auth_mechanisms {
  oauthbearer = yes
  xoauth2 = yes
}

oauth2 {
  introspection_mode = post
  introspection_url = https://dovecot-imap:CLIENT_SECRET_URLENCODED@sso.example.com/realms/mail/protocol/openid-connect/token/introspect

  force_introspection = yes
  active_attribute = active
  active_value = true
  username_attribute = email

  issuers {
    https://sso.example.com/realms/mail = yes
  }

  token_expire_grace = 30s
  openid_configuration_url = https://sso.example.com/realms/mail/.well-known/openid-configuration
}

Назначение параметров:

  • auth_mechanisms включает оба SASL-механизма. OAUTHBEARER стандартизован для OAuth2, а XOAUTH2 нужен для совместимости с клиентами, которые поддерживают только этот формат;
  • introspection_mode = post передаёт токен endpoint в теле POST-запроса;
  • introspection_url задаёт endpoint и реквизиты конфиденциального клиента;
  • force_introspection = yes заставляет выполнять introspection, что необходимо для надёжной проверки поля активности;
  • active_attribute и active_value требуют, чтобы Keycloak вернул active: true;
  • username_attribute = email выбирает email как имя почтового пользователя;
  • issuers разрешает токены только указанного realm;
  • token_expire_grace оставляет небольшую погрешность для часов и сетевой задержки;
  • openid_configuration_url позволяет Dovecot сообщать адрес OIDC-конфигурации в диагностическом ответе OAUTHBEARER.

Dovecot поддерживает для OAuth2 проверку через tokeninfo или introspection, а для JWT — локальную валидацию. Также доступны ограничения по issuer и scope и выбор атрибута имени пользователя.

Подключаем OAuth2 к Dovecot 2.4

Как безопасно записать Client secret

В URL используется HTTP Basic Authentication. Если секрет содержит @, :, /, %, # или другие зарезервированные символы, его необходимо URL-кодировать. Например, это можно сделать локально с помощью Python:

python3 -c 'import getpass, urllib.parse; print(urllib.parse.quote(getpass.getpass("Client secret: "), safe=""))'

Результат вставляется вместо CLIENT_SECRET_URLENCODED. Это не шифрование, а только корректное представление значения внутри URL.

Ограничьте чтение конфигурационного файла пользователями системы:

chown root:root /etc/dovecot/conf.d/90-keycloak-oauth2.conf
chmod 600 /etc/dovecot/conf.d/90-keycloak-oauth2.conf

В контейнере или при запуске Dovecot не от root владелец и способ передачи секрета будут другими. Главное требование — секрет не должен быть доступен непривилегированным пользователям и не должен попадать в публичные резервные копии.

Ограничение по scope

После успешного базового теста можно потребовать специальный scope, например imap. Сначала создайте или назначьте соответствующий client scope в Keycloak, получите новый токен и убедитесь, что introspection возвращает imap в поле scope. Только после этого добавляйте в блок oauth2:

scope {
  imap = yes
}

Не включайте ограничение до проверки токена: иначе корректные токены без этого scope будут отклоняться, а диагностика смешается с проверкой email и соединения с Keycloak.

Проверяем конфигурацию и применяем её

Сначала выполните синтаксическую проверку:

doveconf -n

Команда не должна сообщать о неизвестных параметрах, незакрытых блоках или ошибках разбора URL. Учтите, что полный вывод эффективной конфигурации может содержать секрет клиента. Не публикуйте его в тикетах и открытых журналах.

Если синтаксис корректен, перезагрузите Dovecot способом, принятым в вашей системе. Для systemd обычно используется:

systemctl reload dovecot

Если служба или пакет не поддерживает reload, потребуется контролируемый restart:

systemctl restart dovecot
systemctl status dovecot --no-pager

Не закрывайте административную сессию, пока не убедитесь, что IMAP снова слушает нужные адреса IPv4 и IPv6 и обычные пользователи могут подключаться. При ошибке восстановите резервную копию конфигурации и повторно запустите службу.

Проверьте, что сервер объявляет новые механизмы. Подключитесь к IMAPS:

openssl s_client -quiet -crlf -connect imap.example.com:993 -servername imap.example.com

В открывшейся сессии выполните:

a1 CAPABILITY

Ответ должен содержать AUTH=OAUTHBEARER и AUTH=XOAUTH2. Если их нет, проверьте, действительно ли изменённый файл включён основной конфигурацией и не переопределяется ли auth_mechanisms ниже по порядку.

Тестируем вход через XOAUTH2

XOAUTH2 передаёт имя пользователя и bearer token в строке с разделителями ASCII Control-A. Обычные символы \x01 вводить нельзя: нужны настоящие управляющие байты. Сформируйте Base64-строку в оболочке:

IMAP_USER='user@example.com'
XOAUTH2_B64=$(printf 'user=%s\001auth=Bearer %s\001\001' "$IMAP_USER" "$ACCESS_TOKEN" | base64 | tr -d '\012')

printf '%s\012' "$XOAUTH2_B64"

Скопируйте результат, снова подключитесь через openssl s_client и отправьте:

a1 AUTHENTICATE XOAUTH2

После ответа сервера + вставьте Base64-строку отдельной строкой. При успешной проверке ожидается ответ вида:

a1 OK Logged in

Точный текст после OK зависит от сборки и конфигурации. Проверьте доступ к ящикам:

a2 LIST "" "*"
a3 LOGOUT

При ошибке сервер может вернуть дополнительную Base64-строку с диагностикой. Чтобы корректно завершить неудавшийся SASL-обмен, отправьте пустую строку, после чего изучите ответ и журнал Dovecot.

Тестируем вход через OAUTHBEARER

OAUTHBEARER использует другой формат initial response. В него можно включить авторизационное имя, имя IMAP-хоста и порт:

IMAP_USER='user@example.com'
IMAP_HOST='imap.example.com'

OAUTHBEARER_B64=$(printf 'n,a=%s,\001host=%s\001port=993\001auth=Bearer %s\001\001' "$IMAP_USER" "$IMAP_HOST" "$ACCESS_TOKEN" | base64 | tr -d '\012')

printf '%s\012' "$OAUTHBEARER_B64"

В TLS-сессии выполните:

a1 AUTHENTICATE OAUTHBEARER

После приглашения + вставьте сформированное значение. Успешный результат снова начинается с помеченного ответа a1 OK.

Если сервер объявляет возможность SASL-IR, initial response можно передать в той же IMAP-команде:

a1 AUTHENTICATE OAUTHBEARER BASE64_VALUE

Двухшаговый вариант с ожиданием + удобнее для ручной диагностики и работает независимо от поддержки SASL-IR клиентом.

Что происходит при входе

  1. Почтовый клиент получает access token у Keycloak подходящим OIDC-потоком.
  2. Клиент открывает защищённое TLS-соединение с IMAP.
  3. Токен передаётся Dovecot через OAUTHBEARER или XOAUTH2.
  4. Dovecot отправляет токен в Keycloak introspection endpoint, а клиентские реквизиты — через HTTP Basic Authentication.
  5. Keycloak возвращает состояние токена и доступные claims.
  6. Dovecot требует active: true, проверяет issuer и извлекает email.
  7. Полученный email сопоставляется с именем IMAP-входа и передаётся userdb.
  8. Userdb возвращает параметры существующего почтового ящика, после чего создаётся IMAP-сессия.

Dovecot не получает пароль пользователя Keycloak и не обновляет access token. Получение и обновление токенов остаётся задачей почтового клиента или отдельного приложения. Настройка SMTP-аутентификации также выполняется отдельно и в эту схему не входит.

Типичные ошибки

Keycloak возвращает active: false

Убедитесь, что в introspection передаётся access token из того же realm. Не используйте ID token или refresh token вместо ожидаемого access token. Получите новый токен и проверьте системное время на обоих серверах.

В ответе нет email

Проверьте профиль пользователя, назначение scope email и protocol mapper. После изменения настроек нужно получить новый токен: уже выпущенный токен не приобретёт новые claims.

Проверка curl проходит, но Dovecot не соединяется с Keycloak

Запустите тестовый curl именно с почтового сервера. Проверьте DNS, маршрутизацию, исходящий TCP-порт 443, доверие к цепочке сертификатов и наличие промежуточных сертификатов. Если Keycloak доступен по IPv4 и IPv6, убедитесь, что оба опубликованных адреса действительно работают либо DNS не выдаёт недоступный адрес.

Keycloak отвечает invalid_client

Проверьте Client ID, секрет, включённую клиентскую аутентификацию и URL-кодирование секрета в конфигурации Dovecot. После ротации секрета старое значение сразу перестанет подходить.

Dovecot сообщает о несовпадении пользователя

Сравните три значения: имя, переданное в SASL, claim email и результат doveadm user. Они должны совпадать в ожидаемом формате. Частые причины — другой домен, регистр символов, алиас вместо основного адреса или отсутствие полного адреса в userdb.

Аутентификация успешна, но ящик не открывается

Это обычно проблема userdb, прав файловой системы, UID/GID или расположения почты. OAuth2 к этому моменту уже выполнил свою задачу. Проверьте вывод doveadm user user@example.com и доступ процесса Dovecot к почтовому хранилищу.

В CAPABILITY нет OAuth-механизмов

Проверьте эффективную конфигурацию через doveconf -n, порядок подключения файлов и версию Dovecot. Не переносите конфигурацию ветки 2.3 без проверки: в 2.4 изменена модель OAuth-аутентификации.

Токен работает через curl, но отклоняется после ограничения scope

Посмотрите фактическое поле scope в introspection response. Назначение client scope в административной консоли ещё не гарантирует, что нужное значение присутствует в конкретном токене: это зависит от типа scope и параметров запроса токена.

Журналирование и безопасная диагностика

На системе с systemd журнал службы можно смотреть так:

journalctl -u dovecot -f

В других окружениях используйте назначенный в конфигурации Dovecot файл журнала или механизм контейнерной платформы. На время диагностики можно увеличить детализацию аутентификации, но не включайте вывод паролей и секретов. Access token также не должен попадать в журнал: любой имеющий доступ к нему сможет использовать оставшееся время действия токена.

После завершения проверки:

  • отключите Direct Access Grants, если он включался только ради теста;
  • очистите переменные оболочки;
  • удалите временные файлы с токенами;
  • проверьте права на конфигурацию Dovecot;
  • при необходимости ротируйте тестовый Client secret;
  • оставьте доступ к introspection только по HTTPS;
  • ограничьте сетевой доступ к Keycloak средствами уже используемого файрвола, не заменяя его без анализа текущих правил.
unset ACCESS_TOKEN TOKEN_RESPONSE KC_CLIENT_SECRET XOAUTH2_B64 OAUTHBEARER_B64

Когда выбирать локальную проверку JWT

Dovecot 2.4 умеет локально проверять подписанные JWT по открытым ключам. Это сокращает количество запросов к Keycloak и позволяет продолжать новые IMAP-входы при кратковременной недоступности introspection endpoint. Однако администратору нужно правильно разместить ключи в словаре Dovecot, учитывать kid, алгоритм, azp и ротацию ключей. Загруженные ключи кэшируются, поэтому их обновление требует отдельной эксплуатационной процедуры.

Для первой интеграции с Keycloak онлайн-introspection обычно проще диагностировать: можно отдельно проверить тот же endpoint через curl и увидеть поля, на основании которых Dovecot принимает решение. Переходить на локальную валидацию имеет смысл после того, как выпуск токенов, email, issuer и пользовательская база уже согласованы.

Итоговая проверка

Рабочую конфигурацию можно считать завершённой, если выполняются все условия:

  • discovery URL Keycloak доступен с сервера Dovecot по доверенному HTTPS;
  • OIDC-клиент является конфиденциальным и имеет действующий секрет;
  • introspection возвращает active: true и корректный email;
  • doveadm user находит почтовый ящик по этому email;
  • doveconf -n принимает конфигурацию без ошибок;
  • IMAP CAPABILITY объявляет OAUTHBEARER и XOAUTH2;
  • вход с действующим токеном проходит обоими механизмами;
  • истёкший, отозванный или выпущенный другим realm токен отклоняется;
  • Direct Access Grants отключён, если он не нужен рабочему приложению;
  • Client secret и access token не доступны непривилегированным пользователям.

В результате Keycloak становится источником OAuth2-идентичности, а Dovecot продолжает отвечать только за IMAP и существующее почтовое хранилище. Связующим идентификатором служит email: Keycloak включает его в данные токена, Dovecot извлекает после introspection, а userdb сопоставляет с конкретным почтовым ящиком.

Поделиться статьей

Вам будет интересно

Dovecot IMAP на VDS: mail_location, TLS, quota и auth failed OpenAI Статья написана AI (GPT 5)

Dovecot IMAP на VDS: mail_location, TLS, quota и auth failed

Разбираем Dovecot IMAP на VDS с практической стороны: где хранить почту, как выбрать mail_location, включить TLS, настроить quota ...
Postfix postscreen на VDS: защита SMTP от ботов без лишних отказов OpenAI Статья написана AI (GPT 5)

Postfix postscreen на VDS: защита SMTP от ботов без лишних отказов

Postscreen помогает отсеять smtp bots ещё до передачи письма в smtpd. Разбираем, как включить его на VDS, подобрать мягкие проверк ...
CNAME apex, A record, ALIAS и ANAME: что выбрать для домена в 2026 OpenAI Статья написана AI (GPT 5)

CNAME apex, A record, ALIAS и ANAME: что выбрать для домена в 2026

CNAME в корне домена до сих пор вызывает споры: одни панели запрещают его, другие предлагают ALIAS или ANAME. Объясняем, чем отлич ...