Защита бекапов с помощью ChatGPT4 — строим LastHope сервер
![d93fe6737cf677f9f8a8ca0228006eab.png](https://habrastorage.org/getpro/habr/upload_files/d93/fe6/737/d93fe6737cf677f9f8a8ca0228006eab.png)
Ситуация — два Hyper-V сервера, десяток виртуалок, на каждый Hyper-V установлен VBR CE, бекапы хранятся на соседних дисках + раз в неделю каталоги с бекапами синхронизируются со стареньким NetGear NAS.
Казалось бы — что тут может пойти не так?! Да все! Несмотря на то, что Hyper-V не в домене — сломать его по сети вполне реально, если злоумышленник попадет хотя бы на одну рабочую станцию (или подключится по WiFi). NetGear NAS уже устарел, прошивка содержит известные уязвимости. В общем бекапы не защищены и в случае атаки изнутри — шансы получить проблемы весьма велики.
Решение — делаем отдельный хакеро-защищенный NAS на базе Debian Linux 12 + iptables + скрипты от ChatGPT4.
Состав самодельного NAS
Берем 2 диска по 4 Тб, устанавливаем Linux Debian 12, диски организовываем согласно схеме через штатный CLI-TUI инсталлятор:
NAME MAJ:MIN RM SIZE RO TYPE MOUNTPOINTS
sda 8:0 0 3,6T 0 disk
├─sda1 8:1 0 1,9G 0 part /boot/efi
├─sda2 8:2 0 14,9G 0 part [SWAP]
├─sda3 8:3 0 74,5G 0 part
│ └─md1 9:1 0 74,4G 0 raid1 /
└─sda4 8:4 0 3,5T 0 part
└─vg1-disk2 253:0 0 3,5T 0 lvm /backup2
sdb 8:16 0 3,6T 0 disk
├─sdb1 8:17 0 1,9G 0 part
├─sdb2 8:18 0 14,9G 0 part [SWAP]
├─sdb3 8:19 0 74,5G 0 part
│ └─md1 9:1 0 74,4G 0 raid1 /
└─sdb4 8:20 0 3,5T 0 part
└─vg0-disk1 253:1 0 3,5T 0 lvm /backup1
Дополнительно проверяем загрузку с каждого диска (например, при загрузке ПК через F8).
Количество ядер и ОЗУ не сильно принципиально, сеть — 1 гбит/сек.
Дополнительные программы (относительно минимального Linux)
cifs-utils — нужно для автоматического монтирования SMB шары с бекапами на NAS-е
iptables-persistent — скрипт загрузки правил межсетевого экрана из файла /etc/iptables/rules.v4 при старте ОС
Автоматическое монтирование шары с бекапами
В файле /etc/fstab прописываем адрес шары:
//192.168.XXX.XXX/backup /mnt/nas164 cifs vers=1.0,credentials=/etc/keys164.fstab 0 0
В файле /etc/keys164.fstab прописываем учетные данные для аутентификации:
username=veeam
password=XXXXXXXXXXXXXXXX
Проверяем, что при перезагрузке у нас все подключается и монтируется:
Файловая система 1K-блоков Использовано Доступно Использовано% Cмонтировано в
udev 3960532 0 3960532 0% /dev
tmpfs 797040 952 796088 1% /run
/dev/md1 76255012 6106432 69351612 9% /
tmpfs 3985192 0 3985192 0% /dev/shm
tmpfs 5120 0 5120 0% /run/lock
/dev/mapper/vg1-disk2 3750348432 2720716580 991502352 74% /backup2
/dev/mapper/vg0-disk1 3750348432 1820983080 1891235852 50% /backup1
/dev/sda1 1947916 5972 1941944 1% /boot/efi
//192.168.200.164/backup 5812666536 1648055344 4164611192 29% /mnt/nas164
tmpfs 797036 0 797036 0% /run/user/0
Постановка задачи для ChatGPT4
Ура — мы готовы начать ставить задачи для нейронки:
Условие 1 — из NAS по расписанию вынимать только Full Backup файлы от Veeam (расширение .vbk) и раскладывать в каталоги /backup2 и /backup1
Условие 2 — сначала файлы должны копироваться на /backup2, при этом, нам нужно не более 3-х Full Backup файлов каждого объекта (виртуальной машины)
Условие 3 — если файлов на /backup2 стало больше 3-х — самый старый бекап перемещается на /backup1
Условие 4 — если на /backup1 файлов больше 2-х — удаляем самый самый старый бекап
Условие 5 — при всех операциях должно проверяться свободное дисковое пространство и чтобы скрипт не пытался забивать диск в ситуации, когда это заведомо провальная идея (места нет)
Условие 6 — хотим после выполнения скрипта получать отчет в Telegram, чтобы просмотреть, какие файлы не были тронуты, какие файлы скопированы с NAS, а какие файлы были перемещены из /backup2 в /backup1
Пишем подобное ТЗ нейронке (запрос был не один — было много уточнений в процессе) — на выходе получаем следующие результаты:
Основной скрипт, который будет реализовывать описанные выше условия:
#!/bin/bash
# Проверяем, что передано ровно три аргумента
if [ $# -ne 3 ]; then
echo "Ошибка: скрипту необходимо передать три каталога - исходный, каталог назначения и архивный каталог"
exit 1
fi
# Сохраняем аргументы в переменные
# Исходный каталог, где нужно искать файлы .vbk
SOURCE_DIR="$1"
# Каталог назначения на другом диске
DEST_DIR="$2"
# Архивный диск - для самых самых старых бекапов
ARCHIVE_DIR="$3"
# Максимальное количество файлов .vbk в каталоге назначения и архиве
MAX_FILES=2
# Проверка наличия каталогов назначения и архива
if [ ! -d "$DEST_DIR" ] || [ ! -d "$ARCHIVE_DIR" ]; then
echo "Каталог назначения или архивный каталог не существует"
exit 1
fi
# Функция для получения свободного места на диске в байтах
get_free_space() {
df -B1 "$1" | tail -1 | awk '{print $4}'
}
# Функция для удаления самого старого файла, если количество файлов в архиве превышает MAX_FILES
cleanup_archive() {
local count=$(ls -1 "$ARCHIVE_DIR"/*.vbk 2>/dev/null | wc -l)
if [ "$count" -gt "$MAX_FILES" ]; then
oldest_file=$(ls -1t "$ARCHIVE_DIR"/*.vbk | tail -1)
echo "Удаление самого старого файла в архиве: $oldest_file"
rm "$oldest_file"
fi
}
# Функция для перемещения самого старого файла в архив
move_oldest_file_to_archive() {
local count=$(ls -1 "$DEST_DIR"/*.vbk 2>/dev/null | wc -l)
if [ "$count" -gt "$MAX_FILES" ]; then
oldest_file=$(ls -1t "$DEST_DIR"/*.vbk | tail -1)
filesize=$(stat -c%s "$oldest_file")
free_space=$(get_free_space "$ARCHIVE_DIR")
if [ "$free_space" -ge "$filesize" ]; then
echo "Перемещение самого старого файла в архив: $oldest_file"
mv "$oldest_file" "$ARCHIVE_DIR"
cleanup_archive
else
echo "Недостаточно места в архиве для перемещения файла $oldest_file"
fi
fi
}
# Поиск и копирование файлов
for file in "$SOURCE_DIR"/*.vbk; do
# Проверка существования файлов .vbk в исходном каталоге
if [ ! -e "$file" ]; then
echo "Нет файлов .vbk в каталоге: $SOURCE_DIR"
exit 1
fi
# Получение имени файла
filename=$(basename "$file")
# Проверка существования файла в каталоге назначения
if [ ! -e "$DEST_DIR/$filename" ]; then
# Размер файла в байтах
filesize=$(stat -c%s "$file")
# Свободное место в каталоге назначения
free_space=$(get_free_space "$DEST_DIR")
# Проверка достаточности свободного места
if [ "$free_space" -ge "$filesize" ]; then
# Перемещение самого старого файла в архив, если файлов больше 2
move_oldest_file_to_archive
echo "Копирование файла $filename в $DEST_DIR"
cp "$file" "$DEST_DIR"
else
echo "Недостаточно места для копирования файла $filename. Требуется: $filesize байт, доступно: $free_space байт"
fi
else
echo "Файл $filename уже существует в $DEST_DIR"
fi
done
Далее тестируем скрипт, отлаживаем на разных ситуациях. Потом пишем уже сами второй скрипт, который будет последовательно делать описанные действия для всех каталогов всех бекапов (напоминаю, у нас 10-к виртуальных машин):
#!/bin/bash
/root/Scripts/copy-full-backup-vbk-v3.sh /mnt/nas164/HYPERV2/DC2/ /backup2/HYPERV2/DC2/ /backup1/HYPERV2/DC2/
/root/Scripts/copy-full-backup-vbk-v3.sh /mnt/nas164/HYPERV2/KSC14/ /backup2/HYPERV2/KSC14/ /backup1/HYPERV2/KSC14/
/root/Scripts/copy-full-backup-vbk-v3.sh /mnt/nas164/HYPERV/DC1/ /backup2/HYPERV/DC1/ /backup1/HYPERV/DC1/
/root/Scripts/copy-full-backup-vbk-v3.sh /mnt/nas164/HYPERV/ICINGA/ /backup2/HYPERV/ICINGA/ /backup1/HYPERV/ICINGA/
/root/Scripts/copy-full-backup-vbk-v3.sh /mnt/nas164/HYPERV/SUPPORT/ /backup2/HYPERV/SUPPORT/ /backup1/HYPERV/SUPPORT/
/root/Scripts/copy-full-backup-vbk-v3.sh /mnt/nas164/HYPERV/1C-LICENSE/ /backup2/HYPERV/1C-LICENSE/ /backup1/HYPERV/1C-LICENSE/
/root/Scripts/copy-full-backup-vbk-v3.sh /mnt/nas164/HYPERV/1C-SRV2/ /backup2/HYPERV/1C-SRV2/ /backup1/HYPERV/1C-SRV2/
/root/Scripts/copy-full-backup-vbk-v3.sh /mnt/nas164/HYPERV2/MAILSERVER/ /backup2/HYPERV2/MAILSERVER/ /backup1/HYPERV2/MAILSERVER/
/root/Scripts/copy-full-backup-vbk-v3.sh /mnt/nas164/HYPERV/DIRSERVER/ /backup2/HYPERV/DIRSERVER/ /backup1/HYPERV/DIRSERVER/
/root/Scripts/copy-full-backup-vbk-v3.sh /mnt/nas164/HYPERV2/FILESERVER/ /backup2/HYPERV2/FILESERVER/ /backup1/HYPERV2/FILESERVER/
Задаем еще один вопрос в ChatGPT4 (о скрипте, который будет отправлять файлик нам в Telegram) — получаем третий скрипт:
#!/bin/bash
# Запускаем проверку наличия и сравнения бекапов:
bash /root/Scripts/all-check.sh > /root/Scripts/backup-rotate-history.txt
# Замените 'TELEGRAM_BOT_TOKEN' на токен своего бота
TOKEN="41XXXXXXXXX:AAF7LKAw4iX0hwXhaUjXXXXXXXXXXXXXXXX"
# Замените 'CHAT_ID' на ID нужного чата
CHAT_ID="-19XXXXXXXX"
BACKUP_LIST="/root/Scripts/backup-rotate-history.txt"
if [ -n "$(cat /root/Scripts/backup-rotate-history.txt)" ]; then
curl -F chat_id=$CHAT_ID -F text="COMPANY-BCK-HISTORY" -F filename=backup-rotate-history.txt -F document=@$BACKUP_LIST https://api.telegram.org/bot$TOKEN/sendDocument
fi
Осталось все еще раз протестировать на тестовых наборах файлов и повесить третий скрипт в /etc/crontab:
30 10 1 * * root /root/Scripts/telegram-notification.sh
Защита NAS с Debian Linux от вторжения
В текущей схеме на Debian открыт только один порт — SSH (TCP/22). Используя iptables и iptables-persistent заполняем файл /etc/iptables/rules.v4 по типу такого:
root@lasthope:~/Scripts# cat /etc/iptables/rules.v4
# Generated by iptables-save v1.8.9 (nf_tables) on Tue Apr 16 14:39:19 2024
*filter
:INPUT ACCEPT [0:0]
:FORWARD ACCEPT [0:0]
:OUTPUT ACCEPT [0:0]
-A INPUT -s XX.XX.XX.XX/32 -i enp3s0 -p tcp -m tcp --dport 22 -j ACCEPT
-A INPUT -i enp3s0 -p tcp -m tcp --dport 22 -j DROP
COMMIT
# Completed on Tue Apr 16 14:39:19 2024
В принципе, если хочется еще большей паранойи — можно установить KnockD, закрыть SSH вообще. Также можно даже добавить OneTime последовательности для Port Knock. Или даже к SSH еще прикрутить F2A через телефон…
IP-ник, с которого мы будем входить по SSH и проверять сервер, тоже защищаем — отдельный ПК с Linux, открытых портов нет вообще, iptables блокирует все входящие соединения.
Естественно, стоит периодически проверять данный сервер (Linux NAS), обновлять пакеты (привет недавней уязвимости в OpenSSH), проверять сами бекапы (раз в квартал выкачиваем VBR, пробуем развернуть).
Если хочется еще большей защиты — покупаем USB HDD 3.0, выкачиваем архив, кладем в сейф…
P.S.
Резервное копирование — это регулярный повторяющийся процесс — нельзя один раз его настроить и не контролировать, не проверять, не тестировать и не улучшать.
Или Вы занимаетесь этим, или эта ситуация займется Вами — когда будет взлом и шифрование (с последующим вымогательством выкупа), либо сбои железа, ошибки персонала и т.п.
Всем удачи и жду Ваших решений и предложений по защите бекапов в комментариях!