Linux

Вход по ключу в SSH

Помимо использования SSH на не стандартном порту (не панацея), лучше усилить защиту используя вход по ключу. Пару ключей SSH сложнее взломать по сравнению с обычным паролем. Содержимое ключей генерируется с использованием алгоритмов, что затрудняет его перебор. Доступ может получить только машина, на которой находится закрытый ключ.

Аутентификация с открытым ключом никогда не показывает серверу содержимое закрытого ключа. В случае компрометации сервера локальная машина останется в безопасности. 

Тк в течении 2023 года появлялись научные статьи о возможной компрометации алгоритма RSA, для генерации ключа мы будем использовать алгорим использующий эллиптические кривые. На машине Linux (Хост А или Б) выполните следующую команду:

ssh-keygen -t ecdsa -b 521

Далее нажимаем просто клавишу Enter. Либо можно задать имя для ключевой пары или добавить пароль.

Добавление пароля к закрытому ключу добавляет многофакторную аутентификацию.

Выполняем действия на машине на которую хотим заходить по SSH (Хост Б), в корневой директории пользователя если нет папки .ssh, то ее необходимо создать:

cd ~
mkdir .ssh

Копируем содержимое публичного ключа (my_key.pub) и добавляем его содержимое в файл домашней директории пользователя root authorized_keys в папке .ssh пример команды ниже, для удобства можно использовать удобный вам текстовый редактор (в нашем случае публичный ключ был скопирован на Хост Б):

cat my_key.pub >> .ssh/authorized_keys

Либо операцию выше можно выполнить с помощью другой команды:

ssh-copy-id -i /root/.ssh/my_key root@<Хост Б>

Теперь на Хосте Б нужно поменять конфиг сервиса sshd, чтобы по SSH по паролю вход был запрещен:

vi /etc/ssh/sshd_config

Раскомментируем/Добавляем следующие строки:

PasswordAuthentication no 
PermitEmptypasswords no 

Получем следующее:

image.png

Выходим из редактирования с сохранением (для vi потребуется отдельная статья, чтобы узнать как оттуда выйти - шутка).

Перезапускаем службу сервиса SSH на Хосте Б:

systemctl restart sshd.service

Теперь на Хост Б можно зайти из машины, где присутсвует закрытый ключ, пример команды подключения с ключом на Linux системах:

ssh -i my_key root@<Хост Б>

А при попытке входа по паролю на Хост Б будет возникать подобная ошибка:

image.png

Запрет доступа с УЗ root и служебные УЗ

Прежде чем запретить доступ для root создадим отдельного пользователя admin с домашней директорией и с доступом по SSH по ключу (ключ необходимо предварительно сгенерировать см. эту статью):

useradd -m admin
usermod -aG sudo admin
passwd admin
su admin
mkdir /home/admin/.ssh
cat ssh_key.pub >> /home/admin/.ssh/authorized_keys
chown -R admin:admin /home/admin/.ssh
chmod 700 /home/admin/.ssh
chmod 600 /home/admin/.ssh/authorized_keys

Проверяем возможность входа пользователем admin.

Запретим вход по SSH пользователю root, для этого нужно поменять конфиг сервиса sshd:

vi /etc/ssh/sshd_config

Находим или добавляем (если такой строки нет) следующие строки:

PermitRootLogin no

Выходим из редактирования с сохранением.

Перезапускаем службу сервиса SSH:

systemctl restart sshd.service

Далее сбрасываем пароль для УЗ root:

sudo passwd -l root

 

Служебные УЗ

УЗ без возможности входа в систему

Такие УЗ могут потребоваться например для проброса портов или SSH туннелирования и т.д. Ниже пример создания такой УЗ:

useradd -m portfwd
passwd portfwd
usermod -s /sbin/nologin portfwd

 

Создание УЗ для удаленных бекапов по SCP

На исходной Linux машине, откуда будут забираться бекапы, необходимо создать отдельную специальную УЗ с доступом в определенную папку, в нашем случае это папка /backup куда складываются локальные бекапы:

adduser --home /backup user_back; chown user_back:user_back /backup; chmod 744 /backup

Далее необходимо создать пару ключей для беспарольного входа по этой УЗ:

sudo -u user_back ssh-keygen
# Добавить значение из созданного файла *pub в authorized_keys в домашней директории пользователя user_back
nano /backup/.ssh/authorized_keys

Закрытый ключ (без расширения pub) необходимо скопировать на удаленный хост, который будет использоваться для доступа к исходной машине. Далее для копирования можно использовать следующую команду (где 2222 порт SSH):

/usr/bin/scp -i /root/.ssh/user_back_key -P 2222 user_back@source.server:/backup/local-backup.tar.gz /source_server_backup/source-server-backup_$(date +"%d%m%Y").tar.gz

Для автоматизации можно добавить эту команду в планировщик задач CRON:

crontab -e

Для бекапа каждое воскресенье в 00:00 нужно добавить следующую запись в конец файла:

0 0 * * 0 /usr/bin/scp -i /root/.ssh/user_back_key -P 2222 user_back@source.server:/backup/local-backup.tar.gz /source_server_backup/source-server-backup_$(date +"%d%m%Y").tar.gz

Для собстевнного расписания можно использовать этот ресурс https://crontab.guru/ 

Чтобы удалять архивы старше 30 дней, можно в планировщик также добавить следующую команду:

find /source_server_backup/*.gz -type f -mtime +30 -delete

Настройка fail2ban (защита от брутфорса)

Fail2ban служба в Linux которая по log–файлам приложений может обнаружить злоумышленника и заблокировать его IP адрес. Программа умеет бороться с различными атаками на все популярные *NIX–сервисы, такие как Apache, Nginx, Guacamole, sshd, Exim, Postfix и другие. В данной статье мы будем защищать службу SSH.

Установка:

apt-get -y install fail2ban

Включаем автозапуск и запускаем:

systemctl enable fail2ban
systemctl status fail2ban
systemctl start fail2ban

Правим конфиг файл:

cp /etc/fail2ban/jail.conf /etc/fail2ban/jail.local
vi /etc/fail2ban/jail.local

Содержимое файла jail.local:

[DEFAULT]
bantime  = 1d
findtime  = 4h
maxretry = 2

[sshd]
enabled = true
mode = aggressive
port = 2222
# incremental banning:
bantime.increment = true
# default factor (causes increment - 1h -> 1d 2d 4d 8d 16d 32d ...):
bantime.factor = 24
# max banning time = 6 week:
bantime.maxtime = 6w
logpath = %(sshd_log)s
backend = %(sshd_backend)s

В конфиге выше fail2ban смотрит порт 2222 службы ssh, будет блокировка на 1 день источника подключения в случае 2 неверных попыток ввода в течение 4 часов, блокировка инкрементальная, в случае если этот же источник повторит неверные действия - блок на 2 дня и так до максимального срока блокировки до 6 недель.

Перезапуск службы для применения новой конфигурации:

systemctl restart fail2ban


Проверка журнала fail2ban:

less /var/log/fail2ban.log

Подсчет количества блокирововк по журналу:

cat /var/log/fail2ban.log | grep "\[sshd\] Ban" | wc -l

Просмотр заблокированных IP-адресов:

fail2ban-client status | grep "Jail list" | sed -E 's/^[^:]+:[ \t]+//' | sed 's/,//g'

Разблокировка адреса:

fail2ban-client set YOURJAILNAMEHERE unbanip IPADDRESSHERE

Разрешение доступа по гео с iptables

Устанавливаем необходимые пакеты:

apt-get -y install iptables-persistent
apt-get -y install ipset

Для постоянности работы ipset необходимо создать службу /etc/systemd/system/ipset-persistent.service:

[Unit]
Description=ipset persistent configuration
Before=network.target

# ipset sets should be loaded before iptables
# Because creating iptables rules with names of non-existent sets is not possible
Before=netfilter-persistent.service
Before=ufw.service

ConditionFileNotEmpty=/etc/iptables/ipset

[Service]
Type=oneshot
RemainAfterExit=yes
ExecStart=/sbin/ipset restore -exist -file /etc/iptables/ipset
# Uncomment to save changed sets on reboot
# ExecStop=/sbin/ipset save -file /etc/iptables/ipset
ExecStop=/sbin/ipset flush
ExecStopPost=/sbin/ipset destroy

[Install]
WantedBy=multi-user.target
RequiredBy=netfilter-persistent.service
RequiredBy=ufw.service

Включаем нашу службу:

systemctl daemon-reload
systemctl enable ipset-persistent.service
systemctl restart ipset-persistent.service

Создаем новую зону содержащую российские подсети:

ipset create "RU_zone" hash:net
for IP in $(wget -O - https://www.ipdeny.com/ipblocks/data/countries/ru.zone); do ipset add "RU_zone" $IP; done

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

ipset -L RU_zone | less

Для персистентности подсетей сохраняем и подгружаем их из файла:

ipset save > /etc/iptables/ipset
ipset restore < /etc/iptables/ipset

Сохраняем текущие правила iptables:

iptables-save > /root/rules.v4

Добавляем разрешение в нужном месте (определите его самостоятельно) доступа по гео в сохраненном файле /root/rules.v4:

-A INPUT -p tcp -m set --match-set RU_zone src -m tcp --dport 22000 -j ACCEPT

Для персистентности правил сохраняем их:

cp /root/rules.v4 /etc/iptables/rules.v4

Применение новых правил iptables:

iptables-restore < /etc/iptables/rules.v4

 

Полезная утилита для мониторинга работы iptables - iptstate

 

Команды по Linux Hardening (Харденинг)

Статья со временем будет пополняться

Запрос пароля при каждом выполнении sudo:

echo "Defaults timestamp_timeout=0" >> /etc/sudoers

Вход в систему под УЗ root запрещен: 

sudo passwd -l root

Планировщик задач crontab недоступен для всех, кроме владельца:

chown root:root /etc/crontab
chmod og-rwx /etc/crontab
chown root:root /etc/cron.hourly/
chmod og-rwx /etc/cron.hourly/
chown root:root /etc/cron.daily/
chmod og-rwx /etc/cron.daily/
chown root:root /etc/cron.weekly/
chmod og-rwx /etc/cron.weekly/
chown root:root /etc/cron.monthly/
chmod og-rwx /etc/cron.monthly/
chown root:root /etc/cron.d/
chmod og-rwx /etc/cron.d/

Защищаем системные разделы /home, /tmp, /var/tmp, /dev/shm от хранения и выполнения вредоносных программ с них, отредактируйте или добавьте строчки в файле /etc/fstab:

tmpfs /tmp tmpfs defaults,rw,nosuid,nodev,noexec,relatime 0 0
tmpfs /dev/shm tmpfs defaults,noexec,nodev,nosuid,seclabel 0 0

Отключите сбор телеметрии ОС:

sudo apt purge -y ubuntu-report popularity-contest apport whoopsie
sudo apt autoremove -y
sudo apt-get autoclean

Блокировка источников динамическим листом IP с UFW

Устанавливаем необходимые пакеты:

apt-get -y install ipset

Создаем блок лист:

ipset create "IP_ipsum4_block" hash:ip

Добавляем туда значения от общедоступных фидов IPsum (агрегационный фид level 4 - very low false positives) и сохраняем в файл /etc/ipset.rules:

ipset flush "IP_ipsum4_block"; for IP in $(wget -O - https://raw.githubusercontent.com/stamparm/ipsum/master/levels/4.txt); do ipset add "IP_ipsum4_block" $IP; done; ipset save > /etc/ipset.rules

Добавляем ежедневное обновление фидов с crontab (для редактирования планировщика: crontab -e):

0 0 * * * ipset flush "IP_ipsum4_block"; for IP in $(wget -O - https://raw.githubusercontent.com/stamparm/ipsum/master/levels/4.txt); do ipset add "IP_ipsum4_block" $IP; done; ipset save > /etc/ipset.rules

Для восстановления ipset при перезагрузке зайдите в CRON:

crontab -e

Добавьте запись и выйдите с сохранением:

@reboot ipset restore < /etc/ipset.rules; ufw reload
Переустановка UFW
sudo apt-get purge --auto-remove ufw
sudo apt-get install ufw
sudo ufw allow 22/tcp
sudo ufw enable
sudo ufw reload

Далее добавим правило в UFW:

sudo nano /etc/ufw/before.rules

Добавьте следующее значение до COMMIT:

# block by ipsum4 src IPs
-A ufw-before-input -m set --match-set IP_ipsum4_block src -j DROP

image.png

Перезапустите UFW:

sudo ufw reload

Убедитесь, что правило применяется (добавленная запись должна появиться в списке вывода):

sudo iptables -S ufw-before-input