Ситуация - два 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.

Резервное копирование - это регулярный повторяющийся процесс - нельзя один раз его настроить и не контролировать, не проверять, не тестировать и не улучшать.

Или Вы занимаетесь этим, или эта ситуация займется Вами - когда будет взлом и шифрование (с последующим вымогательством выкупа), либо сбои железа, ошибки персонала и т.п.

Всем удачи и жду Ваших решений и предложений по защите бекапов в комментариях!

Комментарии (18)


  1. adron_s
    06.07.2024 05:32
    +1

    Хорошая статья, особенно понравилось понимание проблем с безопасностью HyperV. Вопрос к автору: а почему просто не перевести всю виртуализацию на ProxMox?


    1. Dorlas Автор
      06.07.2024 05:32

      Компания не моя, там и с освоением HyperV проблемы, до Proxmox им пока далеко (понимания)... Но надеюсь когда нибудь их скиллы (админов) подрастут и до таких технологий!


      1. werter_l
        06.07.2024 05:32

        Это что ж за компания такая? :)

        P.s. Proxmox, ceph, zfs, pfsense и все-все-все https://forum.netgate.com/topic/163435/proxmox-ceph-zfs-pfsense-и-все-все-все-часть-2/


        1. Dorlas Автор
          06.07.2024 05:32

          Любая компания, чья деятельность не связана с IT, и у которой нет понимания важности IT ))))


  1. NikaLapka
    06.07.2024 05:32

    Нужно было или сразу ставить собственника перед фактом, что нужен отдельный компьютер, который будет забирать, получать бэкапы, или никак больше. При этом настройки не так уж и важны, т.к. тут масса вариантов, начиная от запущенного .cmd файла в цикле.

    И позвольте дать совет, если Интернет безлимитный, то ночью можно ещё всё выгружать в какое-нить облако, благо 1Тб сейчас по скидки от того же маил.ру(1045 руб\год) выходит дешевле использования HDD.


    1. pfsenses
      06.07.2024 05:32

      В облако можно как выгружать, так и удалять с него. Так что проблему оно не очень решает. Да и терабайт - это вообще ни о чем. Разве что для совсем микро бизнеса.


      1. werter_l
        06.07.2024 05:32

        Можно развернуть minio - там есть Object Locking. C ним просто так удалить не получится.

        MinIO Object Locking https://min.io/docs/minio/linux/administration/object-management/object-retention.html

        Using MinIO with Veeam https://min.io/docs/minio/linux/integrations/using-minio-with-veeam.html


        1. pfsenses
          06.07.2024 05:32

          Если есть доступ к ОС, где он развернут, удалить данные проблем не составит.

          Ну и не уверен, что MinIO будет работать с указанным выше диском от мейла/Яндекса/etc.

          Уж лучше использовать уже готовые предложения от сервис провайдеров. Которые презентуют напрямую S3.


  1. kalapanga
    06.07.2024 05:32
    +6

    И при чём здесь ChatGPT4? Очередной кликбейт. С таким же успехом статью можно назвать "Защита бекапов с помощью Google", "Защита бекапов с помощью Васи Пупкина", "Защита бекапов с помощью такой-то матери". В статье практически только в одном месте нужно подставить имя помощника и всё.Удалите из статьи упоминание ChatGPT - это не повлияет ни на что.


  1. dimsoft
    06.07.2024 05:32

    Не решена главная задача - злоумышленник всё ещё может попасть по сети и испортить бекапы.

    Вариант:

    1) Отдельная NAS ZFS которая не управляется по сети

    2) Ежедневные снепшоты ZFS


    1. Dorlas Автор
      06.07.2024 05:32

      Расскажите, как можно по сети попасть на Linux, который не принимает никакие соединения (TCP/UDP) ?


      1. dimsoft
        06.07.2024 05:32

        В статье прописан вход по ssh

        -A INPUT -s XX.XX.XX.XX/32 -i enp3s0 -p tcp -m tcp --dport 22 -j ACCEPT


        1. Dorlas Автор
          06.07.2024 05:32

          А также отдельно сказано, что можно закрыть вообще, открывать только по Port Knock и т.д. В чем претензия, не пойму )


  1. foxb
    06.07.2024 05:32
    +1

    VEEAM имеет версию для Linux. Почему бы не использовать ее для управления резервными копиями вместо скриптов? Это также добавит функциональность иммутабилити.


    1. pfsenses
      06.07.2024 05:32

      Консоль Veeam пока только на винде.

      Есть репозитории, прокси, агенты.

      Ну и локальный immutable, при наличии доступа к хосту, где расположен репозиторий, на самом деле не очень immutable.


  1. Johan_Palych
    06.07.2024 05:32

    Просто для информации:
    https://wiki.debian.org/iptables
    NOTE: iptables was replaced by nftables starting in Debian 10 Buster
    Осталась минимальная альтернатива iptables-legacy
    Развернуть минимальный Debian 12 (Bookworm) на отдельный диск(желательно SSD NVMe) и поставить OMV 7.x(OpenMediaVault). Пул для nas - любые диски.
    Удобнй web interface и много плагинов. Легкий порог вхождения для одминов локалхостов этой фирмы.
    https://github.com/orgs/OpenMediaVault-Plugin-Developers/repositories
    Ручна установка на Debian:

    wget https://github.com/OpenMediaVault-Plugin-Developers/installScript/raw/master/install
    chmod +x install
    sudo ./install -n


    1. werter_l
      06.07.2024 05:32
      +1

      Truenas scale тогда. Оч удобная админка + возможность установки приложений одним кликом (apps).


      1. Dorlas Автор
        06.07.2024 05:32

        Я не знаю, как без скрипта обеспечить на TrueNAS или на OMV тот алгоритм выгрузки VBR, как мне написал GPT4 ИИ...чтобы из кучи файлов, среди которых Full, инкременты и метаданные, вытаскивались только VBK (Full Backup), копировались куда нужно, хранились в нужном количестве и ротировались по дискам.
        А если это можно только скриптом реализовать, зачем мне лишние сервисы и консоли? Все это может увеличивать "поле атаки".