Досвід впровадження 2fa на linux з duosecurity
Варіанти налаштування
Як я й казав, тема 2fa для linux є дуже популярною, є багато рішень, які дозволяють це зробити.
Що добре у цьому методі? З'явилася підтримка з openssh4.4, тому ви навряд чи знайдете сервер, де не можна буде увімкнути відповідні налаштування. На цьому плюси насправді закінчуються. Мінусів набагато більше:
- якщо у вас включений tcpportforward, то виконати прокидання порту можна в обхід існуючих перевірок у бінарнику;
- все, що прописано в rc-файлі, буде виконано до ForceCommand, тому там можна прописати виконання exec sh і не підтверджувати щоразу вхід другим фактором;
- коли користувач буде підключатися до сервера через sftp або scp, він не побачить жодного запрошення, яке ви можете надрукувати у разі стандартного входу за допомогою ssh-клієнта. Тому зручність для користувача в цьому випадку практично зводиться нанівець.
Другий фактор через pam
Класичний сценарій є модифікацією конфіга/etc/pam.d/sshd, коли в самий початок поміщають потрібний модуль приблизно в такому форматі:
Але це не вирішує проблему, якщо аутентифікація виконується не на рівні pam'у, а виконується засобами самого sshd-сервера, наприклад, аутентифікація за ключами. Як же бути в такому разі?
Authentication Methods
На щастя, openssh починаючи з версії 6.2 зробили нативну підтримку другого фактора. Тепер за допомогою опціїAuthenticationMethodsможна перерахувати методи аутентифікації, які обов'язково повинні бути успішно пройдені для входу на сервер:
Приклад такої конфігурації:
Щож тут написано? Для успішної аутентифікації потрібно пройти одну з таких комбінацій:
- publickey+password
- або hostbased+publickey
а файліpam.d/sshdвказуєте:
Все досить просто. Але до тих пір, поки ви не захочете включити кілька методів аутентифікації, при цьому якщо один метод виконується на рівні самого sshd (publickey або kerberos), а інший - на рівні pam (той же password). Проблема полягає в тому, що і password і keyboard-interactive обробляються в тому самому pam-конфізі. Потрібно якось навчитися відокремлювати першу стадію аутентифікації від другої у разі такого конфігу sshd:
Я довго шукав вирішення цієї проблеми, і натрапив на опис того, як facebook зробили у себе другий фактор:
Коли безпечники з facebook розповідали про використання 2fa у себе, то вони посилалися на підметоди аутентифікації -Authentication Submethods. Це дозволяє обмежити автентифікацію заданим пристроєм. У підсумку колегам вдалося вказати аутентифікацію для keyboard-interactive саме через duo:
Але спроби знайти ці комміти чи потрібну версію openssh – 6.2p1 не увінчалися успіхом. Тож вирішено було вивчати проблематику далі.
Експерименти з налаштуванням pam
Тут ми знову згадуємо, що таке стек pam, і з якими опціями можна підключати модуль. Усі пам'ятають стандартні варіанти підключення в секції auth – required, requisite, sufficient, optional.
Але експерименти зкомбінування модулів тільки з цими опціями ні до чого не привели. Або у користувача будуть вимагати пароль навіть у разі аутентифікації за ключем, або можна буде обійти другий фактор повторним введенням пароля.
Та тоді ми починаємо налаштовувати pam більш тонко. До кожного результуючого статусу можна вказувати свій вплив на стек, зокрема. «пропускати» один або кілька модулів, що підключаються.
Наприклад, таким чином.
У себе при налаштуванні двофакторки через duosecurity ми зробили таку конфігурацію pam, тому що було помічено, що в разі неможливості інтерактивної взаємодії з користувачем модуль повертає самеPAM_ABORT. Тобто автентифікація починає виглядати так:
А конфіг pam.d/sshd стає таким:
Розглянемо, що відбувається у першому варіанті можливої аутентифікації - gssapi-with-mic,keyboard-interactive
Користувач логіниться по kerberos-тикету, далі потрібно пройти keyboard-interactive аутентифікацію. Модуль pam_duo успішно підключається, у разі успіху слід перехід наPAM_PERMIT, у всіх інших варіаціях - наPAM_DENY. Все досить просто.
Що буде, якщо вхід йде паролем. Відпрацьовує той самий стек pam-модулів, але pam_duo не може ініціалізуватися і повертаєтьсяPAM_ABORT. Т.к. у нас написаноabort=ignore, це ні на що не впливає, управління передається наступному модулю pam_unix. Якщо все добре, то йде перехід до другої стадії - keyboard-interactive, і повторюється описана вище механіка.
Так, начебто все ок. Але є нюанс.
pam_duo дозволяє задати додаткові налаштування – для кого потрібна автентифікація, а для кого – ні.
Ось приклад такої конфігурації:
І що ми з'ясували врезультаті тестування? Якщо користувач, згідно з прикладом, полягає в групі wheel, то модуль повернеPAM_SUCCESS, що досить логічно. Але це повернеться до спроби провести ініціалізацію модуля, тобто навіть на стадії password. Таким чином, знаючи логін такого користувача, можна не просто обійти другий фактор, а зайти в систему, навіть не знаючи пароль користувача. Загалом повний провал.
Також виявляємо другу особливість. Якщо змінювати налаштування не pam.d/sshd, а глобальні - password-auth, який зазвичай підключається в інших модулях, з'ясовується, що логін через локальну консоль відбувається з можливістю підключати модулі з інтерактивною взаємодією. Тобто перша стадія перевірки пропускається і одразу йде перевірка другого фактора, де, як ми пам'ятаємо, можна знати просто ім'я обліку з групами-виключеннями. Це також провал.
Доробка напилком
Нас цікавить функціяpam_sm_authenticate. У міру вивчення вихідних даних, знаходимо, що можна викликати функцію для взаємодії між модулем і програмою, яка викликає модуль (у нашому випадку це буде sshd):
Приблизно після 5 segfault (під час тестування та підключення виправленого модуля) з'ясовуємо, який з параметрів відрізнятиметься у разі password та keyboard-interactive. Тестування проводилося через спробу вивести пропуск із використанням зазначених функцій. Покажчик наrespу структуріpam_convдорівнюватиме 0, якщо це вдалося.
У результаті отримуємо модифікований вихідний код, який виконує дві функції - повертаєPAM_AUTHINFO_UNAVAILпри підключенні модуля в стадії password. І повертаєPAM_AUTHINFO_UNAVAIL, якщо ім'я сервісу відрізняється від sshd (для запобігання зазначеній вище ситуації з входом через локальну консоль):
Ну і для зручності встановлення на всі сервери збираємо пакет, наприклад, за допомогою того ж таки fpm.
Після встановлення модифікованого модуля потрібно внести останні зміни до pam.d/sshd:
У результаті якщо модуль підключається не на стадії keyboard-interactive, то повертатиметься відповідьPAM_AUTHINFO_UNAVAIL, яка обробляється в стеку. В інших варіантах буде перехід на pam_deny або pam_permit у разі успіху.
Також для тих облікових записів, які використовуються в сервісах і повинні входити по одному фактору, можна зробити окремі налаштування за допомогою параметраMatchв конфізі sshd.
Підсумовуючи скажу, що навіть дуже хороше рішення часто потрібно трохи доопрацювати напилком, щоб для користувачів це не стало таким:

Також готовий поділитися ще інформацією про двофакторну автентифікацію, наприклад, які граблі були в момент інтеграції або описати цікаві фічі провайдера duosecurity.