Представим, что основной VPS скомпрометирован. Злоумышленник сидит под root и первым делом ищет, чем вы собираетесь откатываться. В конфигурации cron он находит строку запуска restic, рядом пароль репозитория и параметры доступа к удалённому хранилищу. Копии лежат на другом сервере, в другой локации, у другого провайдера. Звучит надёжно. Но если ключ, найденный на основном сервере, умеет удалять объекты в хранилище, то отдельный сервер лишь удлинил злоумышленнику путь на одну команду.

Эта статья про то, как не отдавать клиенту власть над всей историей. Клиент должен уметь одно: добавлять новые данные. Читать он должен ровно столько, сколько нужно для работы, а уничтожать прошлое не должен вовсе. Заодно разберём, где такое ограничение действительно обеспечивает restic, где его обязано обеспечить хранилище, как устроить доверенную очистку и что нужно иметь на руках, когда основного сервера больше нет.

Три разные власти над копиями

Обычно про резервные копии говорят как про одно действие: «сделать бэкап». Но у репозитория есть минимум три роли, и каждой нужен свой уровень прав.

  • Добавление. Клиент загружает новые данные и новый снимок (snapshot). Это единственное, что нужно ему каждую ночь.
  • Чтение. Нужно для восстановления и проверки. Отчасти оно нужно и при обычной записи: чтобы не загружать повторно уже сохранённые куски, программа должна знать, что в репозитории уже лежит.
  • Очистка. Удаление устаревших снимков и освобождение места. Это разрушительная операция по самой своей природе, ведь её смысл в том, чтобы данные исчезли.

Типичная ошибка состоит в том, что все три роли достаются одному ключу просто потому, что так проще настроить. Один пользователь, один пароль, одна строка в cron, которая сначала делает копию, а потом чистит старьё. Удобно ровно до первого инцидента: ключ, которому доверили очистку, получается и у атакующего.

Кому какое полномочие стоит выдавать
РольГде живётЧто может делатьЧто должно быть исключено
Клиент резервного копированияОсновной VPSДобавлять данные и снимкиУдалять и перезаписывать существующие объекты
Администратор очисткиОтдельная доверенная машинаЗапускать удаление снимков и освобождение местаХранение рабочих секретов на основном VPS
ВосстановлениеСвежий сервер или рабочая станцияЧитать репозиторий целикомЗависимость от чего-либо, что лежит только на потерянном сервере

Эта таблица описывает не настройку, а модель. Дальше нужно выяснить, кто технически способен её обеспечить.

Что запрещает restic, а что должно запрещать хранилище

Здесь легко ошибиться на самом первом шаге. Шифрование репозитория защищает содержимое от чтения тем, у кого нет пароля. Но оно ничего не говорит о том, кто вправе стирать файлы. Зашифрованный объект так же легко удалить, как открытый. Пароль репозитория отвечает на вопрос «кто может расшифровать», а не на вопрос «кто может удалить».

Поэтому режим «только добавление» (append-only) нельзя получить красивым именем пользователя вроде backup-writer или аккуратной строкой в конфиге клиента. Клиент сам себя не ограничит: на скомпрометированной машине атакующий просто запустит другую команду или обойдёт ваш конфиг. Ограничение обязана навязывать сторона, которая принимает данные. Она отказывает в удалении и перезаписи независимо от того, что попросил клиент.

Отсюда практическое следствие для выбора места хранения. Прежде чем строить схему, нужно найти в документации самого хранилища подтверждение, что в нём есть механизм запрета удаления для конкретного ключа или конкретного соединения. Если такого подтверждения нет, нельзя рассчитывать, что restic сам сделает хранилище «только на добавление». Это особенно важно для произвольного S3-совместимого сервиса: само слово «S3» ничего не гарантирует. У одних провайдеров есть версионирование объектов или блокировка удаления, у других политики доступа достаточно гибкие, у третьих набор прав по сути сводится к «читать и писать всё». Какие именно возможности есть у вашего, нужно проверять по документации провайдера и на тестовом бакете. Тест должен быть конкретным: зайти ключом клиента и попытаться удалить объект, который уже записан. Проверяйте и перезапись существующего объекта, потому что запрет удаления без запрета замены защищает вполовину.

Если же вы берёте собственный сервер на VPS, выбор шире: можно поставить на него хранилище, у которого режим «только добавление» входит в документированные возможности, и дать клиенту доступ только к нему. Тогда вы сами отвечаете за настройку и сами её проверяете. Конкретные ключи запуска и параметры берите из документации выбранного серверного компонента, а не из статей, написанных по памяти.

Чего append-only не даёт

Режим «только добавление» защищает историю от стирания. У него есть несколько оборотных сторон, и о них лучше знать заранее:

  • Конфиденциальность он не обеспечивает. Пароль репозитория лежит на основном сервере, иначе ночная копия не выполнится без человека. Значит, злоумышленник под root может расшифровать всё, что ему позволит прочитать хранилище. Разделение «писать» и «читать» на стороне хранилища возможно не везде; уточняйте у выбранного решения.
  • Место не освобождается. Если ничто не удаляется, репозиторий только растёт, и об этом придётся заботиться отдельно.
  • Он не отличает хорошие данные от испорченных. Если на сервере уже шифровальщик, то следующая ночная копия аккуратно сохранит зашифрованные файлы. История не потеряется, но в ней появятся плохие снимки, среди которых придётся искать последний чистый.

Штатная запись: что клиент делает каждую ночь

Посмотрим, как выглядит правильный ночной цикл в такой схеме. Клиент подключается к хранилищу ограниченным ключом. Он проверяет, что репозиторий доступен, загружает новые куски данных, затем записывает новый снимок. И всё. В его расписании нет ни удаления снимков, ни освобождения места, ни операций, которым нужен монопольный захват репозитория.

Это отличается от привычной практики, когда скрипт копирования заканчивается вызовом очистки по политике хранения. В нашей схеме очистка вынесена из скрипта осознанно. Если скрипт на основном VPS содержит вызов удаления, то ограниченный ключ его либо не выполнит (и скрипт будет каждую ночь падать с ошибкой), либо вы выдали ключу больше прав, чем собирались. Такое падение лучше воспринимать как сигнал о нарушении собственной модели, а не как повод расширить права.

Практические детали, которые стоит проговорить, когда вы пишете клиентский скрипт:

  1. Репозиторий инициализирует доверенный человек, а не ночной скрипт. Создание репозитория и первую проверку доступа проще сделать с административного ключа, а потом оставить на клиенте только ключ добавления.
  2. Теги и имя хоста должны быть стабильными. Это пригодится при очистке: по ним политика хранения группирует снимки. Если имя хоста нестабильно, очистка увидит несколько «разных» машин и применит политику к каждой отдельно.
  3. Код возврата копии нельзя игнорировать. Ночная задача, которая молча завершилась с ошибкой, хуже отсутствующей: вы будете считать, что копии есть. Результат стоит отправлять во внешний мониторинг, а не только в локальный журнал, который злоумышленник тоже может стереть.
  4. Время на клиенте влияет на историю. Снимок записывается со временем клиента. Об этом подробнее ниже, потому что на нём держится одна из неприятных атак на политику хранения.

Подробно, как поставить restic на VPS и первый раз инициализировать репозиторий, мы разбирали в статье «Как установить и настроить restic на VPS». Здесь предполагается, что базовая копия уже работает, а нас интересует разделение прав вокруг неё.

Нужен сервер под эту задачу?

Разверните VPS MAATRIX за пару минут: NVMe, AMD EPYC, root-доступ, локации Россия, США, Франция и Великобритания. Оплата картой РФ и по СБП.

АРЕНДОВАТЬ СЕРВЕР

Очистка: единственная опасная операция живёт отдельно

Теперь о том, что вы вынесли из клиента. В документации restic про удаление снимков описаны две разные операции: forget удаляет ссылки на снимки, а prune освобождает данные, которые больше не используются сохранёнными снимками (Restic: Removing backup snapshots). Это различие важно для нашей задачи вот чем. Пока вы не запускали освобождение места, сами данные физически лежат в репозитории, даже если ссылки на снимки уже убраны. Но рассчитывать на это как на защиту нельзя: после очистки данные пропадают, и вернуть их из репозитория уже не получится.

Чистить репозиторий должна машина, которую атакующий с основного VPS не достанет. Она может быть небольшим сервером без публичных сервисов, виртуальной машиной на вашей рабочей станции или отдельным VPS, где нет ничего, кроме административного ключа и задачи очистки. Главное требование: административный ключ хранения не лежит на основном сервере и не передаётся на него ни при каком обслуживании.

Сухой прогон перед каждым изменением

Документация описывает режим dry run, при котором показывается, что будет удалено, а репозиторий не меняется (источник). В схеме с доверенной очисткой это не вежливая опция, а рабочий инструмент: на доверенной машине каждое изменение политики хранения сначала запускается в сухом режиме, и человек смотрит на список. Вопросы, которые стоит себе задать, глядя на этот список:

  • Остаётся ли хотя бы один снимок, сделанный до подозрительной даты?
  • Нет ли среди снимков неожиданных хостов, тегов или путей?
  • Не исчезает ли слишком много снимков за один запуск по сравнению с обычным ритмом?

Сухой прогон полезен именно потому, что ограниченный клиент больше не может «испортить» политику, но может подбросить в репозиторий данные, которые политику обманут. Ниже о том, как это происходит.

Почему политика хранения сама по себе уязвима

В документации restic отдельно сказано, что для append-only репозитория есть угрозы, связанные с политикой удаления снимков. Этот случай подробно описан там, и вам стоит прочитать раздел целиком. Здесь приведу собственное рассуждение, как это может выглядеть на практике, чтобы объяснить, зачем нужен сухой прогон.

Допустим, политика звучит так: «хранить последние тридцать ежедневных снимков». Атакующий с ключом добавления не может удалить ваши старые снимки. Но он может записать много новых, например, сотню пустых или мусорных снимков с будущими датами или просто с короткими интервалами. Когда доверенная очистка применит политику «последние тридцать», именно эти фальшивые снимки займут тридцать мест, а ваши настоящие, сделанные до инцидента, окажутся «лишними» и будут удалены. Формально клиент ничего не удалял. Удалила ваша собственная очистка, выполняя вашу собственную политику.

Отсюда несколько правил для доверенной очистки:

  • Не запускайте очистку по расписанию вслепую. Пока вы не уверены, что основной сервер цел, автоматическая очистка может стать исполнителем чужого замысла. Запуск вручную после просмотра списка надёжнее, особенно после любого подозрения на инцидент.
  • Предпочитайте политику, которая не вытесняет старое новым слишком охотно. Правила вида «хранить помесячные снимки за год» устойчивее к всплеску мусорных записей, чем «хранить последние N». Конкретные ключи политики смотрите в документации.
  • Следите за числом снимков. Резкий рост количества снимков у одного хоста за сутки уже сигнал, даже если места ещё достаточно.

Освобождение места и расписание копирования

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

Освобождение места можно запускать реже, чем удаление ссылок: например, раз в несколько недель в согласованное окно, а ссылки убирать после ручной проверки списка. Выбор частоты зависит от скорости роста репозитория и от того, насколько вам важно быстро возвращать место.

Репозиторий, который только растёт

Если клиент ничего не удаляет, а очистка выполняется редко и вручную, то основным риском становится заполнение диска. Здесь нужна арифметика, и покажем её на условном примере: пусть ночная копия добавляет в репозиторий около двух гигабайт новых данных, а очистка проходит раз в месяц. Тогда между очистками репозиторий вырастет на шестьдесят гигабайт. Если на сервере хранения всего восемьдесят гигабайт и половина уже занята, запас кончится раньше следующего окна очистки. Числа условные, но порядок рассуждения универсален: свободное место должно покрывать рост между очистками с запасом, а не только текущее состояние.

Что в этой арифметике критично:

  1. Скорость роста нужно измерить на своих данных. Чужие цифры не годятся: дедупликация работает по-разному для базы данных, почтовых ящиков и медиа-архива. Сначала несколько недель наблюдайте реальный прирост.
  2. Порог тревоги ставится заранее. Оповещение при заполнении диска на определённую долю и отдельное при резком скачке дневного прироста. Скачок говорит о том, что что-то изменилось: появилась новая папка с данными или кто-то начал загружать мусор.
  3. Заполнение диска само по себе может быть атакой. Ключ добавления можно использовать, чтобы забить место, и тогда следующая честная копия не поместится. Если хранилище позволяет ограничивать квоту для ключа, это стоит сделать. Если нет, остаётся мониторинг и быстрая реакция.

Ресурсы здесь надо оценивать отдельно для хранения и для обслуживающей машины. Сервер хранения требует прежде всего дискового места и стабильной сети, а процессор и память ему нужны скромные. Обслуживающей машине очистки при больших репозиториях понадобится больше оперативной памяти и процессорного времени. Размеры тарифов ориентиром не служат: в линейке MAATRIX есть, например, Ba с 40 ГБ NVMe и Uab с 80 ГБ, но объём диска не равен обещанию ёмкости под ваш репозиторий. Считайте от прироста ваших данных, а не от красивых цифр в списке.

Контроль, который не живёт на основном сервере

Если мониторинг заполнения и свежести копий работает на том же основном VPS, то при компрометации его заглушат первым. Поэтому проверки лучше размещать на стороне хранения или на доверенной машине:

  • Возраст последнего снимка по каждому хосту. Если новейший снимок старше суток-полутора, значит, копия молчит. Это сигнал даже без признаков взлома.
  • Свободное место на сервере хранения. Порог и скорость убывания.
  • Число снимков за сутки. Сигнал от рассуждения про вытеснение: если вместо одного снимка за ночь появилось двадцать, это повод остановиться и смотреть.

Эти проверки не отвечают на вопрос «чисты ли данные в копии», зато быстро показывают, что с копированием что-то не так.

Когда основной сервер потерян: восстановление без него

Лучшая проверка схемы — воображаемый день, когда основного VPS нет. Диск недоступен, вход закрыт, образ вы ему не доверяете. Что у вас осталось? Ответ определяется тем, что вы заранее положили вне этого сервера. Минимум:

  • адрес репозитория и способ доступа к нему на чтение;
  • пароль репозитория, сохранённый в менеджере паролей или в запечатанной копии у доверенного человека;
  • учётные данные для чтения, которые не совпадают с ключом добавления с основного сервера;
  • исполняемый файл restic или точная инструкция, откуда его взять и какой версии;
  • заметки о том, что и куда восстанавливать: пути, владельцы, порядок запуска сервисов.

Особенно болезненно потерять пароль репозитория. Он есть на основном сервере, но если больше нигде, то при потере сервера все копии превращаются в аккуратно сохранённый шум. Храните его минимум в двух независимых местах.

Само восстановление удобно репетировать на чистом сервере. На VPS MAATRIX доступ root позволяет поставить нужные утилиты, а создание сервера после оплаты по публичному описанию занимает около пары минут, так что учебный стенд можно поднять на время и удалить. Ориентируйтесь на ту локацию, где будет лежать восстановленная система: в предложении перечислены UK, US, RU и FR, а наличие конкретного образа и операционной системы проверяется в форме заказа. Разместить рабочий сервер и сервер хранения в разных локациях полезно ради независимости от сетевых проблем, но сам факт аренды двух серверов не гарантирует, что они стоят на разном оборудовании, поэтому полагайтесь на разные площадки и разные учётные записи, а не на предположения.

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

  1. Поднимите чистый сервер, где нет ничего от основного.
  2. Установите restic и получите доступ к репозиторию только теми данными, что хранятся вне основного VPS.
  3. Посмотрите список снимков и найдите последний, который вы считаете чистым. Если был инцидент, выбирайте с запасом: снимки после даты взлома могут содержать закладки.
  4. Восстановите данные в отдельную папку, а не поверх системных путей, и сверьте важные файлы вручную: открывается ли база, читаются ли документы.
  5. Запишите, сколько это заняло времени и чего не хватило под рукой. Именно в этом списке и скрыты слабые места.

Для сервисов с базами данных восстановление файлов не равно восстановлению рабочей базы. Если вы копируете каталог живой базы без согласованного дампа, снимок может получиться в неконсистентном состоянии. Это рассуждение к restic как таковому не относится, но влияет на то, что считать успешной копией. Репетиция должна завершаться запуском приложения и проверкой данных, а не только сообщением об окончании восстановления.

Что остаётся в руках у потерянного сервера

Вернёмся к вопросу из начала. Основной сервер скомпрометирован, ключ клиента у атакующего. Что он может сделать с историей копий?

Если хранилище действительно навязывает режим «только добавление» и вы проверили это тестом, то он может следующее: добавить новые данные и новые снимки, в том числе мусорные; заполнить свободное место, если нет квоты; прочитать то, что хранилище ему разрешает читать, и расшифровать это имеющимся на сервере паролем. Всё это неприятно, и каждый пункт нужно закрывать отдельными мерами: мониторингом прироста, квотами, раздельными ключами чтения и записи там, где хранилище это умеет.

Чего он сделать не может: удалить или перезаписать уже сохранённые объекты и тем самым стереть историю до момента взлома. Не может он и запустить освобождение места, потому что административного ключа у него нет. Единственный путь к потере истории идёт через вас: через автоматическую очистку, которая применит политику к подброшенному мусору. Поэтому очистка вынесена на доверенную машину и проходит через сухой прогон.

Если же хранилище не подтверждает запрет удаления, ответ другой: потерянный сервер может стереть всё. Отдельное расположение и шифрование в этом случае не помогут, они лишь прячут содержимое, но не защищают от удаления. Тогда у вас два честных выхода: выбрать хранилище с документированным режимом защиты от удаления или держать административные операции полностью отдельно, предоставив клиенту другой механизм записи.

Это и есть модель прав. Клиент пишет, доверенная машина чистит, а восстановление опирается на то, что лежит вне основного сервера. Физически отдельный сервер хранения хорош как место для копий, но защитой становится только тогда, когда ему поручено отказывать клиенту в удалении.