Удостоверителят показва нов шестцифрен код, VPN го отхвърля, а същият код се проверява успешно, когато го тествате от собствената си обвивка. Тази разлика е цялата история. PAM модул, който не може да отвори тайната за записване, връща отказ, който изглежда еднакво с грешен код, а средата на услугата, която скрива домашните директории, е честа причина за това. Преди да разхлабите каквото и да е разрешение, решете в коя от три ситуации сте.

Кой от три провала е това?

Първият е тайна, която модулът изобщо не може да прочете. Вторият е тайна, която може да прочете, но не може да обнови. Третият е код, който наистина е грешен, обикновено заради дрейф на часовника или повторно използвана стойност.

Разделете ги, като прочетете журнала на услугата и системния журнал за удостоверяване за един неуспешен опит, после потвърдете коя PAM услуга зарежда плъгинът и кой ред на модула използва тази услуга. Общото съобщение за неуспешно удостоверяване не ги различава, нито успешен ръчен тест, защото вашата обвивка не е средата на услугата.

Изгледът на файловата система на юнита е обичайният виновник, когато само услугата се проваля.

systemctl show -p ProtectHome -p ProtectSystem -p ReadWritePaths [email protected]
ls -l /var/lib/vpn-otp/*/.google_authenticator 2>/dev/null | head -n 20

Вариант A: преместете тайната извън домашната директория

Когато услугата скрива /home и предпочитате да запазите тази защита, съхранете тайната някъде, където тя може да я види. Модулът приема път secret= и акаунт user=, който извършва файловите операции, което позволява на централно хранилище да обслужва много самоличности.

Това е спретнатият вариант и той изисква най-много внимание, защото споделеното хранилище прави една директория границата за сигурност на всеки акаунт.

auth required pam_google_authenticator.so secret=/var/lib/vpn-otp/${USER}/.google_authenticator user=vpn-otp

Проверете три неща, преди да му се доверите: акаунтът съществува, работният процес на модула може да премине към него и файловете са негови с ограничителни режими. Не използвайте ~ или път с домашна променлива заедно с user= и не изключвайте проверките за собственост на модула, за да проработи даден път. Запазете етапа с паролата и останалата част от стека непокътнати.

Вариант B: оставете файла и отворете път

Ако тайната трябва да остане в домашната директория на потребителя, юнитът се нуждае от изглед, който включва тази една директория, без да разкрива всяка домашна директория на хоста. Drop-in може да добави тясно ограничено монтиране под изолирана домашна директория.

Това запазва собствеността за всеки потребител като модел, на цената на промяна в юнита, която трябва да се преглежда при всяка промяна на пясъчника.

Две ограничения се пропускат лесно. Път само за четене, добавен под директория, която пясъчникът крие, не я разкрива, защото родителят просто не е там. И монтирането трябва да е записваемо, ако модулът трябва да обновява състояние, което въвежда следващия вариант. Запишете drop-in като отделен файл, вместо да редактирате пакетирания юнит под /usr/lib, така че надграждане на пакет да не го отмени тихо.

Вариант C: запазете пясъчника и поправете записите на състоянието

Четенето на тайната е само половината от удостоверяването. Модулът може да презаписва информация за отклонение на времето, защита срещу повторение или брояч, а файл, който минава проверката за четене, все още може да се провали при запис.

Този провал изглежда като лош код при следващия опит, а не при този, затова се бърка с дрейф на часовника.

Дайте му собствена записваема директория и насочете пътя на тайната там, вместо да правите цялата домашна директория записваема. Потвърдете собственика на директорията, свободното пространство на файловата система и дали юнитът ограничава записите другаде. След това тествайте два последователни входа, защото вторият доказва пътя за запис, а първият доказва само четенето.

Проверявайте като услугата, а не като себе си

Всяка важна проверка трябва да се изпълнява в пясъчника на юнита с идентичността на юнита.

Команда, която успява като root, ви казва, че файлът съществува, и нищо друго. Входът през истинската услуга ви казва дали модулът може да прочете тайната, да я използва и да запише обратно нужното.

Накрая, запазете изискването непокътнато. Добавянето на опция за празна парола, приемането на откази само за четене или премахването на пясъчника биха премахнали симптома чрез промяна на политиката. Потребител, който е длъжен да представи код, трябва да бъде отхвърлен и когато тайната е недостъпна.

Подобни статии