ZIM-НИЙ SAAALEЗимние скидки: до −50% на старт и −20% на продление
до 31.01.2026 Подробнее
Выберите продукт

2FA для SSH и sudo на Linux: TOTP через pam_google_authenticator без лишней боли

Практический гайд по внедрению TOTP-2FA в Linux через pam_google_authenticator: установка, создание секрета, настройка PAM и OpenSSH, безопасные исключения для CI/Ansible и проверенный план отката.
2FA для SSH и sudo на Linux: TOTP через pam_google_authenticator без лишней боли

2FA для SSH — один из самых практичных шагов в hardening: даже если пароль утёк или ключ оказался скомпрометирован, злоумышленнику всё ещё нужен второй фактор. Но в админской реальности важно внедрить 2FA так, чтобы не потерять доступ, не сломать автоматизацию и иметь понятный путь отката. Ниже — рабочая схема TOTP на Linux через pam_google_authenticator с аккуратным подключением к SSH и (опционально) к sudo.

Логика такая: сначала настраиваем TOTP для одного пользователя, потом включаем требование второго фактора в sshd и только после успешного теста думаем про 2FA для sudo.

Что именно настраиваем и какие есть режимы

TOTP — одноразовый код, который генерирует приложение-аутентификатор (Google Authenticator, FreeOTP, Aegis и т.п.) на основе общего секрета и времени. На сервере код проверяет PAM-модуль pam_google_authenticator.so. Секрет по умолчанию хранится в ~/.google_authenticator конкретного пользователя.

Для SSH чаще всего используют один из сценариев:

  • Ключ или пароль + TOTP: классический «два фактора» — сначала основной метод, затем код.
  • Только TOTP: обычно плохая идея, потому что вы теряете смысл «двух факторов» и усложняете аварийное восстановление.

Для sudo добавлять TOTP имеет смысл только с учётом кэша (timestamp) и исключений, иначе вы получите постоянные запросы кода на каждую команду.

Не включайте 2FA «для всех и сразу» без второго канала доступа. Правильная стратегия: держите открытую запасную сессию, имейте доступ к консоли и меняйте настройки поэтапно.

Предварительные меры безопасности: как не потерять сервер

Перед изменениями убедитесь, что у вас есть запасной способ доступа:

  • вторая открытая SSH-сессия под админом (не закрывайте до конца работ);
  • консоль провайдера/виртуализации (out-of-band);
  • резервный админский аккаунт и/или аварийный SSH-ключ.

Если у вас агрессивные таймауты, временно увеличьте LoginGraceTime в SSH, чтобы при первом тесте успеть ввести код. После настройки вернёте обратно.

Если сервер размещён на VDS, заранее проверьте доступность VNC/serial-консоли в панели: это самый быстрый способ вернуть доступ при ошибке в PAM/SSHD.

Пример настройки sshd_config и PAM для включения 2FA в SSH

Установка pam_google_authenticator

В Debian/Ubuntu пакет обычно называется libpam-google-authenticator, в RHEL-подобных — google-authenticator.

Debian/Ubuntu

sudo apt update
sudo apt install -y libpam-google-authenticator

Rocky/Alma/CentOS

sudo dnf install -y google-authenticator

Проверьте, что модуль на месте (путь зависит от дистрибутива):

sudo ls -la /lib/security/pam_google_authenticator.so
sudo ls -la /lib64/security/pam_google_authenticator.so
FastFox VDS
Облачный VDS-сервер в России
Аренда виртуальных серверов с моментальным развертыванием инфраструктуры от 195₽ / мес

Создаём TOTP-секрет пользователю

Генерацию секрета запускайте под тем пользователем, для которого включаете 2FA: файл секрета создаётся в его домашнем каталоге.

google-authenticator

Обычно безопасный набор ответов выглядит так:

  • Time-based tokens: y (TOTP)
  • Обновлять файл: y
  • Ограничить повторное использование: y
  • Окно верификации: лучше небольшое/по умолчанию; увеличивайте только если реально гуляет время
  • Rate-limiting: y

В процессе вы получите QR-код/секрет — добавьте его в приложение-аутентификатор. Scratch-коды сохраните отдельно (офлайн/в защищённом хранилище): это аварийный вход, если телефон потерян или недоступен.

Время на сервере должно быть синхронизировано

Если часы уезжают — коды начинают «не подходить». Проверьте NTP/chrony:

timedatectl status
chronyc tracking

Включаем 2FA в SSH через PAM (sshd + /etc/pam.d/sshd)

Здесь два шага: включить keyboard-interactive в sshd и подключить PAM-модуль в /etc/pam.d/sshd. Все изменения делайте с открытой запасной сессией.

Шаг 1: настройки sshd_config

Откройте /etc/ssh/sshd_config и убедитесь, что PAM включён, а keyboard-interactive разрешён:

UsePAM yes

KbdInteractiveAuthentication yes

ChallengeResponseAuthentication yes

Параметр ChallengeResponseAuthentication встречается в старых конфигурациях. Если OpenSSH его игнорирует — это нормально; главное, чтобы работал KbdInteractiveAuthentication.

Дальше задайте, что именно требуется для входа, через AuthenticationMethods.

Рекомендуемый базовый вариант (ключ + TOTP):

AuthenticationMethods publickey,keyboard-interactive

Если вам нужно временно разрешить и пароль + TOTP (например, на период миграции ключей), задайте несколько цепочек:

AuthenticationMethods publickey,keyboard-interactive password,keyboard-interactive

Если оставить просто publickey без keyboard-interactive, то при входе по ключу второго фактора не будет. Следите, чтобы в вашей схеме 2FA реально требовалась.

Шаг 2: подключаем pam_google_authenticator в /etc/pam.d/sshd

Откройте /etc/pam.d/sshd и добавьте правило в секцию auth так, чтобы оно срабатывало при интерактивной аутентификации (обычно — рядом с другими строками auth, до включений вроде @include common-auth).

Строгий режим (если файла секрета нет — вход запрещён):

auth required pam_google_authenticator.so

Мягкий режим для поэтапного внедрения (если файла нет — пропускаем TOTP):

auth required pam_google_authenticator.so nullok

nullok удобен, чтобы «раскатывать» по пользователям: тем, кто создал секрет, будет запрошен TOTP, остальные войдут по старой схеме. Для финального состояния чаще всего nullok убирают.

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

Перед перезапуском проверьте синтаксис:

sudo sshd -t

Перезапуск (зависит от дистрибутива, поэтому даю оба варианта отдельными командами):

sudo systemctl restart ssh
sudo systemctl restart sshd

Не закрывайте текущую сессию, пока не проверите вход в новой.

Исключения: как не сломать автоматизацию и аварийные входы

TOTP плохо сочетается с неинтерактивными сценариями: CI/CD, Ansible, бэкапы по SSH, мониторинг, rsync/scp без TTY. Вместо того чтобы «пытаться заставить бота вводить код», обычно выбирают одну из безопасных архитектурных развилок.

Подход A: отдельный порт или Match-блок без 2FA

Идея: основной SSH-вход требует 2FA, а для узкого набора источников (например, bastion/админская подсеть) делаете отдельное правило через Match в sshd_config, где допускаете другой метод.

Это удобно для автоматизаций, но требует дисциплины в firewall и строгого контроля IP-источников.

Подход B: отдельный пользователь для автоматизаций с минимальными правами

Практичный вариант: создаёте отдельного пользователя для бэкапов/деплоя, разрешаете вход только по ключу и ограничиваете возможности (без sudo, без shell, с ограниченными командами в authorized_keys). Тогда отсутствие TOTP не превращается в «дырищу», потому что права аккаунта изначально минимальны.

Подход C: включать TOTP только для части пользователей (группа)

Если хотите, чтобы 2FA требовалась, например, только для админов, удобная тактика — завести группу и в PAM включать модуль только для неё (через pam_succeed_if или эквивалентные механизмы). Базовая подготовка группы:

sudo groupadd -f ssh2fa
sudo usermod -aG ssh2fa youradmin

Дальше конкретная строка в PAM зависит от вашей PAM-цепочки и дистрибутива. Обязательно тестируйте на отдельной сессии и держите консольный доступ, потому что ошибкой в условии можно либо выключить 2FA, либо запереть себя.

Если нужна максимально предсказуемая модель: требуйте 2FA на bastion/jump-host, а к серверам пускайте только по ключам из закрытой сети. Так проще и для безопасности, и для эксплуатации.

Кстати, если вы переносите проекты на отдельный сервер под админские нужды, заранее продумайте миграцию так, чтобы не потерять доступ и не уронить сервисы: пригодится инструкция про перенос сайта без простоя.

Добавляем TOTP для sudo без самострела

2FA для sudo полезна, если вы боитесь сценария «злоумышленник получил shell пользователя и пытается повысить привилегии». Но sudo вызывается часто — если заставить вводить TOTP на каждую команду, жить станет очень тяжело.

Рабочий компромисс:

  • оставить кэширование sudo (timestamp) на 5–15 минут;
  • запрашивать TOTP только при «первом» sudo после истечения кэша;
  • не распространять 2FA на сервисные аккаунты и неинтерактивные сценарии.

Вариант: добавить pam_google_authenticator в /etc/pam.d/sudo

Обычно достаточно добавить строку в /etc/pam.d/sudo (а иногда отдельно в /etc/pam.d/sudo-i, если у вас активно используется sudo -i). После этого при запросе пароля sudo дополнительно спросит TOTP.

Для поэтапного включения:

auth required pam_google_authenticator.so nullok

После теста на себе можно убрать nullok для строгой политики админов.

Нюанс: неинтерактивные сценарии и отсутствие TTY

Часть задач выполняется без полноценного терминала (некоторые systemd-юниты, автоматизации). В таких случаях PAM не сможет запросить код и будет возвращать отказ, из-за чего «сломается не только sudo, а ваш пайплайн/обслуживание».

Практические правила:

  • не включайте 2FA на сервисных аккаунтах;
  • проверяйте, где реально нужен интерактив;
  • если 2FA для sudo обязательна, документируйте аварийный способ входа и отката.

Запрос пароля sudo и кода TOTP при включённой 2FA

Тестирование: чек-лист перед тем, как считать задачу закрытой

  1. Откройте новую SSH-сессию и убедитесь, что вход проходит только при наличии TOTP.

  2. Проверьте ваши инструменты (Ansible/rsync/CI) по выбранной схеме (исключение, отдельный пользователь или bastion).

  3. Один раз проверьте вход по scratch-коду и отметьте, что он израсходован.

  4. Проверьте sudo -v и поведение кэша sudo (например, после 10 минут).

  5. Посмотрите логи на предмет отказов PAM/SSH.

Где смотреть ошибки

Для SSH:

sudo journalctl -u ssh -n 200 --no-pager
sudo journalctl -u sshd -n 200 --no-pager
sudo journalctl -t sshd -n 200 --no-pager

Для случаев с sudo часто достаточно общего журнала:

sudo journalctl -n 200 --no-pager
FastFox SSL
Надежные SSL-сертификаты
Мы предлагаем широкий спектр SSL-сертификатов от GlobalSign по самым низким ценам. Поможем с покупкой и установкой SSL бесплатно!

Откат: что делать, если что-то пошло не так

Если вы потеряли SSH-доступ из-за 2FA:

  • зайдите через консоль провайдера/виртуализации;
  • откатите изменения в /etc/pam.d/sshd (удалите или закомментируйте строку с pam_google_authenticator.so);
  • если меняли AuthenticationMethods, временно верните более мягкую схему (например, только ключ);
  • проверьте sshd -t и перезапустите sshd.

Чтобы сбросить 2FA конкретному пользователю, обычно достаточно переименовать или удалить ~/.google_authenticator (учитывая, используете ли вы nullok и какие условия в PAM).

Практичные рекомендации по hardening вместе с 2FA

2FA лучше всего работает в связке с базовой гигиеной SSH:

  • отключайте парольный вход там, где можно жить только на ключах;
  • ограничивайте доступ по IP (firewall, bastion);
  • включайте разумные лимиты попыток и наблюдаемость (логи, алерты);
  • держите актуальные OpenSSH/PAM;
  • имейте аварийный доступ (консоль, второй админ, запасные ключи).

Частые проблемы и быстрые решения

Код не принимается, хотя я уверен, что ввожу правильно

Чаще всего виновато время. Проверьте синхронизацию (NTP/chrony) и убедитесь, что на телефоне включена автоматическая синхронизация времени.

Автоматизация зависает на вводе кода

Значит, вы потребовали TOTP там, где нет интерактива. Решение: отдельный пользователь с минимальными правами, Match-исключение, или перенос «интерактивного входа» на bastion с 2FA.

Страшно потерять телефон

Минимум — сохраните scratch-коды. Лучше — предусмотрите второй независимый способ восстановления (второе устройство или защищённый менеджер секретов) и регламент замены/ротации.

Итог

Связка TOTP + pam_google_authenticator даёт быстрый и понятный способ включить реальный второй фактор для SSH и при желании усилить sudo. Главное — внедрять поэтапно, с тестом в новой сессии, планом отката и продуманными исключениями для автоматизаций. Тогда 2FA будет работать как защита, а не как источник простоя.

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

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

Fail2ban 2025: защита от SSH brute force и nginx basic auth, настройка bantime/ignoreip и отладка OpenAI Статья написана AI (GPT 5)

Fail2ban 2025: защита от SSH brute force и nginx basic auth, настройка bantime/ignoreip и отладка

Fail2ban в 2025 всё так же спасает от перебора паролей: читает логи, находит ошибки входа и банит IP через фаервол. В статье — нас ...
SLO-мониторинг с node_exporter и blackbox_exporter: latency, доступность и error budget OpenAI Статья написана AI (GPT 5)

SLO-мониторинг с node_exporter и blackbox_exporter: latency, доступность и error budget

Пошагово собираем SLO-мониторинг на Prometheus: node_exporter для диагностики хоста и blackbox_exporter для внешних проверок. Счит ...
Миграция сайта с rsync и переключением без простоя: пошаговая схема для админов OpenAI Статья написана AI (GPT 5)

Миграция сайта с rsync и переключением без простоя: пошаговая схема для админов

Практичная схема переезда сайта почти без простоя с rsync: как подготовить новый сервер, выполнить первичную и финальную синхрониз ...