В новой статье говорим про безопасность в Linux: как настроить и что важно учитывать в процессе. Дополнительно разбираем PAM и модули аутентификации, рассматриваем iptables.
За основу взят один из уроков нашего практического курса «Администрирование Linux Мега».
![](https://habrastorage.org/getpro/habr/upload_files/41e/491/681/41e4916815c1768c485fc4e8b4c8975e.jpg)
PAM: модули, флаги, sudoers
PAM — модульная система аутентификации пользователя. Программы могут попросить её произвести аутентификацию пользователя любым доступным методом и абстрагироваться от самого процесса. PAM сделает всё самостоятельно и отдаст результат программе.
PAM используется везде, где требуется аутентификация пользователя или проверка его прав. Например, при подключении через SSH или FTP, а также при повышении привилегий через команду sudo.
Модули PAM находятся в директории lib/security для старых операционных систем типа CentOS и в директории /usr/lib/x86_64-linux-gnu/security для современных ОС вроде последних релизов Ubuntu.
Конфигурационные файлы PAM — в директории /etc/pam.d.
![](https://habrastorage.org/getpro/habr/upload_files/71d/e47/797/71de47797d8c950ca1efe9386d8a5b1f.jpg)
Конфиги модулей — в директории /etc/security.
Типы модулей:
auth — аутентификация пользователя. Проверяют, точно ли пользователь является тем, за кого себя выдает.
account — проверка возможности доступа к серверу. Уточняют, может ли пользователь в данный момент получить доступ к сервису или службе.
password — обновление механизма аутентификации. Отвечают за обновление пароля пользователя.
session — действия при входе. Открываются и закрываются в рамках идентификации, блокируют действия пользователя и производят очистку после завершения его сессии.
Помимо модулей есть флаги контроля:
Required — указанный модуль должен успешно отработать. Остальные модули будут запущены при неудаче, исполнение продолжится по конфигу.
Requisite — указанный модуль должен успешно отработать. Остальные модули не будут запущены при неудаче, исполнение конфига тут же прекратится.
Sufficient — если указанный модель отработает успешно, весь сервис будет считаться доступным. При неудаче этого модуля будут выполняться следующие, стоящие в конфиге после него.
Optional — результат модуля не имеет значения, если этот модуль единственный.
Include — подключить содержимое другого конфига PAM.
Ещё есть sudoers — конфигурационные файлы, в которых описано, каким пользователям разрешено повышать свои привилегии при помощи команды sudo. В Linux-системах обычно действует правило, которое разрешает всем участникам группы voCentOS или sudo в Ubuntu повышать свои привилегии для любых действий.
Основный конфигурационный файл sudoers находится по пути /etc/sudoers, а дополнительные конфиги в /etc/sudoers.d/. Для редактирования правила sudo лучше использовать команду visudo. Она автоматически проверяет синтаксис, и, если там есть ошибки, тут же сообщает о них.
Меры защиты SSH-сервера
SSH-сервер — основная точка входа на сервер. В целях безопасности вы можете закрыть его за VPN. Но для большей защиты рекомендуется предпринимать дополнительные меры:
Перевести с SSH на нестандартный порт — самая простая, но в то же время самая слабая мера защиты. Злоумышленник может просканировать ваш сервер на предмет открытых портов и выяснить, какой из них слушает SSH. С её помощью вы можете избавиться от бесконечного брутфорса, который преследует на стандартном 22-м порту.
Запретить вход под пользователем root параметром PermitRootLogin. Мера эффективна в сочетании с хорошо настроенной конфигурацией sudoers и SELinux, где у пользователей и их процессов нет доступа к опасным командам. Даже при входе злоумышленника на сервер он не сможет серьёзно навредить системе, так как это невозможно без root-прав.
Запретить вход по паролю параметром Password/Authentication в config-е SSH-сервера. Данная мера спасает от брутфорса и утечки паролей пользователей. Если приватный ключ зашифрован паролем, взломать его практически невозможно, даже если код сольют.
Настроить двухфакторную аутентификацию через SSH. Пользователь сможет подключиться к серверу только, если правильно введёт пароль, приватный ключ или одноразовый код, меняющийся каждые 30 секунд.
К сожалению, ни один из перечисленных серверов не даёт 100% гарантии защиты — почти везде есть уязвимости. Чтобы максимально обезопасить себя, рекомендуется применять все четыре способа. В сумме эти меры добавляют вашей системе очков прочности при взломе.
От теории к практике
Перейдём в терминал на Ubuntu и попробуем настроить двухфакторную аутентификацию через Google Authenticator. Для начала установим пакет apt install libpam-google-authenticator:
root@vm:/home/zaqwer# apt install libpam-google-authenticator
После запуска команды вам зададут несколько вопросов, которые позволят настроить двухфакторную аутентификацию на сервере:
1. Хотите ли вы, чтобы аутентификация была основана на текущем времени? Ответ: да.
![](https://habrastorage.org/getpro/habr/upload_files/442/da3/984/442da3984597b79fab3a936419a06d30.png)
На экране отобразится QR-код — отсканируйте его через Google Authenticator на телефоне. В приложении добавится новый аккаунт и сгенерируется одноразовый пароль. В терминале появятся одноразовые emergency-коды на случай, если вы потеряете доступ к мобильному устройству.
2. Хотите ли вы создать файл с конфигом Google Authenticator для текущего пользователя. Ответ: да. Создастся файл /root/.google.authenticator.
3. Хотите ли вы, запретить несколько использований одного и того же токена аутентификации. Ответ: да. В противном случае по одному и тому же одноразовому коду можно будет войти несколько раз, а это небезопасно. Вы запрещаете многократное использование токена — теперь можно зайти в систему под одним пользователем не чаще, чем раз в 30 секунд до следующей генерации кода. И по умолчанию двухфакторная аутентификация может принять только 3 одноразовых кода: предыдущий код, текущий и следующий.
4. Хотите ли вы повысить количество принимаемых кодов до 17? Например, у вас будут храниться 8 предыдущих кодов, один текущий и ещё 8 будущих. Это не самая лучшая ситуация, поскольку у злоумышленника появляется огромный запас времени, чтобы завладеть кодом. Ответ: нет.
5. Хотите ли вы включить rate-limiting? Ответ: да. Это спасёт вас от брутфорса двухфакторной аутентификации.
Вы ответили на все вопросы, теперь займёмся SSH-сервером — сделаем так, чтобы он работал через Google Authenticator. Откройте файл /etc/pam.d/sshd для настройки PAM-модулей:
root@vm:/home/zaqwer# vim /etc/pam.d/sshd
Здесь уже есть какие-то настройки по умолчанию:
![](https://habrastorage.org/getpro/habr/upload_files/0f4/298/f97/0f4298f976d556b878ff33de0a404e03.png)
В конце файла допишите две строки. В первой тип модуля — auth required, имя модуля — pam_google_authenticator.so и параметр — nullok. Во второй тип модуля — auth required и модуль — pam_permit.so.
![](https://habrastorage.org/getpro/habr/upload_files/82c/e49/4d2/82ce494d2418be086db2447d070b7a87.png)
Затем перейдите в конфиг SSH-сервера:
root@vm:/home/zaqwer# vim /etc/ssh/sshd_config
И включите параметр ChallengeResponseAuthenticaton в yes (это нужно, чтобы у нас запросили одноразовый пароль):
![](https://habrastorage.org/getpro/habr/upload_files/80d/3e9/beb/80d3e9beb3f4c99d23909841f140c68f.png)
Сохраните изменения и перезапустите SSH-сервер:
root@vm:/home/zaqwer# systemctl restart sshd
Теперь попробуем подключиться к серверу. Посмотрим на IP-адрес:
root@vm:/home/zaqwer# ip a
![](https://habrastorage.org/getpro/habr/upload_files/e62/970/408/e62970408866fbc0640e07bba32ccf0f.png)
[zaqwer@archlinux~]$ ssh root@192.169.0.236
![](https://habrastorage.org/getpro/habr/upload_files/769/1e3/28d/7691e328d5b2cf722f369ea1b1d91f83.png)
Видим, что нас всё ещё пускают без двухфакторной аутентификации. Это происходит, потому что настроен вход по ключу, а для SSH-аутентификации он перезаписывает все опции аутентификации по умолчанию. И считается, что ключа достаточно. Система предложит ввести одноразовый пароль только в том случае, если вы попытаетесь войти по паролю.
Теперь нужно сделать так, чтобы и при использовании ключа запрашивался разовый пароль. Для этого возвращаемся в конфиг SSH-сервера:
root@vm:/home/zaqwer# vim /etc/ssh/sshd_config
Добавляем метод AuthenticatonMethods и пишем в нём publickey, password publickey и keyboard-interactive:
![](https://habrastorage.org/getpro/habr/upload_files/f22/525/1f1/f225251f1decab78e99d1c186ba416b8.png)
Сохраняем изменения и выходим. У нас отвалилась аутентификация по ключу — теперь каждый будет запрашиваться пароль, даже если у нас есть SSH-ключ. Чтобы у нас не спрашивали пароль, если есть SSH-ключ, нужно ввести команду:
root@vm:/home/zaqwer# vim /etc/pam.d/sshd
И закомментировать строчку:
![](https://habrastorage.org/getpro/habr/upload_files/f1b/0b2/a9e/f1b0b2a9e1461762da02cc75f0356d1c.png)
Это позволит отключить стандартную unix-аутентификацию при доступе через SSH. Аутентификация будет происходит только средствами SSH-сервера, то есть при помощи ключа.
Перезапускаем SSH-сервер ещё раз, подключаемся обратно, и у нас запрашивают одноразовый пароль:
![](https://habrastorage.org/getpro/habr/upload_files/4d1/c75/a26/4d1c75a26ec61fb46f6a9965c7d81c26.png)
Вводим пароль одноразовый, но нас по какой-то причине не пускают. Чтобы разобраться, в чём проблема, идём в /var/log/auth.log — сюда пишутся данные об аутентификации. Видим, что PAM получил пустой пароль:
![](https://habrastorage.org/getpro/habr/upload_files/28a/293/d00/28a293d007415bd2dee6dbe9858141b8.png)
Идём в конфиг SSH-сервера:
root@vm:/home/zaqwer# vim /etc/ssh/sshd_config
И видим, что PermitRootLogin отключен:
![](https://habrastorage.org/getpro/habr/upload_files/02c/3c6/a7d/02c3c6a7d8b1322395d1af2a183c26b4.png)
Пишем PermitRootLogin yes, снова перезапускаем наш SSH-сервер и пробуем подключиться заново. Мы попадаем в систему по одноразовому паролю — отлично, всё работает.
![](https://habrastorage.org/getpro/habr/upload_files/ab1/8e2/06d/ab18e206d03f7ebd065d79451e30cd5f.png)
Зададим пароль для root и попробуем раскомментировать строчку в PAM d, которую мы закомментировали, чтобы включить стандартную аутентификацию через средства unix:
root@vm:~# passwd
New password
Retype new password
passwd: password updated successfully
Снова перезапустим sshd, разлогинимся и попробуем подключиться. Теперь у нас спрашивают пароль:
![](https://habrastorage.org/getpro/habr/upload_files/ed7/177/eb6/ed7177eb685a934d77905f4086e141bd.png)
Посмотрим в лог аутентификации:
root@vm:/home/zaqwer# tail -f /var/log/auth.log
![](https://habrastorage.org/getpro/habr/upload_files/182/7b2/46a/1827b246ad28ec4fb749fc5af51b99b8.png)
Попробуем подключиться — вводим пароль и одноразовый код. Теперь нас впустили в систему.
![](https://habrastorage.org/getpro/habr/upload_files/457/fe4/292/457fe4292fdd99473ee8b69b5ceaf705.png)
И если мы посмотрим в log аутентификации, то увидим, что всё в порядке: мы вошли по паролю.
Iptables: что это и как работает
Iptables — это программа, которая компилирует и фильтрует трафик на сервере. С её помощью можно ограничить доступ к входящим портам или ограничить исходящий трафик по каким-то правилам. Она нужна, чтобы обеспечить безопасность на уровне сити и не оставлять открытых портов.
Конфигурация iptables состоит из цепочек правил. Все пакеты пропускаются через определенную для них последовательность цепочек и при прохождении пакетом цепочки к нему последовательно применяются все правила этой цепочки. Поэтому при использовании iptables стоит отключать другие межсетевые экраны, чтобы не случилась путаница с правилами.
Что важно помнить про iptables:
ограничивает доступ на уровне сети;
конфигурация состоит из цепочек правил;
управляется командой iptables.
Перейдём в терминал и узнаем, как iptables работает.
Посмотреть все текущие правила мы можем командой iptables-save:
root@vm:/home/zaqwer# iptables-save
Мы видим дефолтные цепочки, но не видим никаких правил:
![](https://habrastorage.org/getpro/habr/upload_files/66e/e2e/4e4/66ee2e4e4f000848db25e35b48a24d4e.png)
Ещё один вариант, как посмотреть правила с их номерами строк и дополнительной информацией:
root@vm:/home/zaqwer# iptables --line-numbers -L -v -n
Сейчас нет правил ни в одной из цепочек, поэтому все поля пустые:
![](https://habrastorage.org/getpro/habr/upload_files/902/fa7/f66/902fa7f665f8d0965befce8e71628013.png)
Начнём с добавления правила, которое будет разрешать все локальные подключения через интерфейс lo:
root@vm:/home/zaqwer# iptables -A INPUT -I lo -j ACCEPT
-A — чтобы добавить правила в конец цепочки;
INPUT — цепочка, в которую добавляем.
-i — чтобы указать интерфейс lo;
-j — чтобы указать, что дальше делать с трафиком;
ACCEPT — принимаем все подключения по локальной сети.
Запускаем и смотрим в правила:
![](https://habrastorage.org/getpro/habr/upload_files/651/87f/136/65187f13640b9f3af9bf94db9633262a.png)
Теперь разрешим icmp-пакеты, которые отправляются командой ping:
root@vm:/home/zaqwer# iptables -A INPUT -p icmp -j ACCEPT
Смотрим правила: теперь их два, как мы и хотели:
![](https://habrastorage.org/getpro/habr/upload_files/cf9/ffb/a81/cf9ffba8149156dc5ee09ef57c2fce2c.png)
Подготовимся к тому, чтобы полностью запретить входящий трафик на сервер. Для этого нужно разрешить получение пакетов в соединениях, которые мы сами и установили:
root@vm:/home/zaqwer# iptables -A INPUT -m conntrack --ctstate ESTABLISHED, RELATED -j ACCEPT
-m — ключ, который определяет критерий, по которому мы идентифицируем пакеты;
сonntrack — этот самый критерий и подсистема ядра, которая отслеживает состояние сетевых соединений;
--ctstate — ключ, указывающий состояние соединений;
RELATED и ESTABLISHED — типы соединений.
Теперь откроем порты, начнём с SH:
root@vm:/home/zaqwer# iptables -A INPUT -m tcp -p tcp --dport 22 -j ACCEPT
--dport — ключ для указаний порта;
22 — порт, на котором работаем SH, поэтому я указываю 22 и –j ACCEPT.
Мы разрешили всё, что нужно. Теперь давайте запретим всё, что мы не разрешили:
root@vm:/home/zaqwer# iptables -A INPUT -p tcp -j REJECT
tcp — пакеты, которые мы ключом -j отправляем в цепочку REJECT.
Точно так же запретим протокол utp:
root@vm:/home/zaqwer# iptables -A INPUT -p utp -j REJECT
![](https://habrastorage.org/getpro/habr/upload_files/95c/ef5/516/95cef5516fb118538745955b66efba78.png)
Проверим наш список правил:
![](https://habrastorage.org/getpro/habr/upload_files/163/72d/f62/16372df62b66d35483c99e41f3e5cf71.png)
Пятое и шестое правила запрещают нам входящие подключения, которые мы не разрешили.
Теперь поставим правило на определённую строку. Для этого:
меняем ключ -A, на ключ -I;
пишем цепочку и номер строки — INPUT 5;
указываем порт — 80;
добавляем ключ -s, если хотим разрешить порт только тем, кто пришёл из локальной сети;
указываем сеть, с которой будем принимать, — 192.168.0.0/24.
root@vm:/home/zaqwer# iptables -I INPUT 5 -m tcp --dport 80 -s 192.168.0.0/24 -j ACCEPT
Теперь пятое правило — это уже разрешение 80-го порта для нашей локальной сети.
![](https://habrastorage.org/getpro/habr/upload_files/f17/cfd/84d/f17cfd84dc36acbce714a0c43b9b6a5d.png)
Если понадобится удалить какое-то правило, воспользуйтесь командой iptables -D:
root@vm:/home/zaqwer# iptables -D INPUT -s 192.168.0.0/24 -p tcp -m tcp --dport 80 -j ACCEPT
На этом всё: мы обсудили, что модульная система аутентификации пользователя и где она используется, разобрали меры защиты SSH-сервера, а также рассказали об основных принципах работы iptables.
Комментарии (15)
onix74
19.10.2022 13:45+7Запретить вход под пользователем /root/ параметром PermitRootLogin
Во-первых , что за пользователь такой "/root/"? Что за слеши в имени?
Во-вторых, ставим это в рекомендации, но сами игнорируем и во всех примерах с libpam-google-authenticator ломимся на сервер именно под рутом. Красавцы, чо!
Плюс к этому — какие-то пробелы в ненужных местах (например,ssh root@ 192.169.0.236
), верхний регистр в имени файла (vim /etc/ssh/sshd_conFig
), в котором этого быть не должно...
Попадается вторая статья одного автора за день и второй раз — непрофесионализм.
Горшочек, не вари!!!iig
20.10.2022 08:32Что за слеши в имени? ... какие-то пробелы в ненужных местах ... верхний регистр в имени файла
А вдруг так и надо? Чтобы нельзя было просто скопировать непонятные заклинания? </s>
Moraiatw
20.10.2022 20:49Запретить вход по паролю параметром Password/Authentication в config-е SSH-сервера
Всегда интересовало, чем ключ лучше 20-символьного пароля?
Тем, что в отличии от пароля он хранится в виде файла и может быть похищен?
iig
21.10.2022 10:28чем ключ лучше
Много чем.
Одной учетной записи можно сопоставить сколько угодно ключей. Каждому ключу можно прописать дополнительные ограничения. Приватный ключ можно подпереть паролем. Можно засунуть в агент авторизации.
А 20 символьный пароль тоже будет храниться в виде файла ;)
erty3
iptables в 2022 это актуальненько конечно. Во всех основных дистрибутивах он уже deprecated де-юре. Де-факто его не рекомендовали к использованию уже года четыре.
RHEL 9, Debian 11, etc...
laminar
И чем же его заменили? Уж не firewalld ли, которой совершенно неожиданно ... обертка для iptables
ogost
по ссылке же есть: nftables
mpa4b
В чём профит nftables? Насколько правила, им заданные, работают быстрее чем iptables? А если у меня в iptables 1000 подсеток для блокировки, nftables с ними же будет быстрее или как?
Semy
Google?
Судя по описанию - должно стать быстрее. На мой взгляд, самое лучшее, что он предлагает - это настройка всего в одном месте (iptables и ip6tables (и ebtables до кучи), что бесило невероятно!).
karabanov
Если в кратце то да. Это примерно, как глоток холодной воды в пустыне.
PS
<dushnila_mode>
Фирвол это netfilter, а iptables - это утилита для его настройки
</dushnila_mode>
karabanov
firewalld - это обёртка для утилиты iptables