Тема 02

Офлайн-профиль узла: состав, проверка, ротация

Офлайн-профиль узла: состав, проверка, ротация

Тема 1 закончилась перечнем требований: что должно сохраниться, в каком сценарии и на какое время. Перечень отвечает на вопрос «что обязано работать», но ничего не говорит о том, чем именно это обеспечивается. Следующий слой — средства: набор файлов, образов, документов и данных, которые должны оказаться под рукой в момент, когда внешних источников больше нет.

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

Второе правило — offline-first как проектная установка, а не как режим работы. Система проектируется так, чтобы быть работоспособной без внешних ресурсов, а внешние ресурсы её ускоряют, но не включают. Разница видна на одном примере: справочник, доступный только через поиск в интернете, при отказе сети недоступен полностью; справочник, лежащий локально и обновляемый из интернета, при отказе сети остаётся работоспособным, просто устаревшим. Первый вариант — не offline-first, второй — да.

Тема построена так. Сначала профиль определяется как артефакт и раскладывается по слоям, считается его объём. Затем вводится машиночитаемый манифест с подписью — то, что делает профиль проверяемым. Третий раздел посвящён проверке чужих артефактов, которые попадают в профиль: образов Debian и репозиториев пакетов, а также тому, как сроки действия подписей и ключей ведут себя при долгом офлайне. Четвёртый раздел — правило трёх копий, ротация и печатная часть, пятый — носители и их механизмы отказа, шестой — процедура проверки и паритетные архивы. Числа темы либо вычисляются скриптами лабораторной работы на данных читателя, либо цитируются с указанием места в источнике; у каждого есть идентификатор в реестре docs/CLAIMS.md.

Что такое офлайн-профиль и сколько он занимает

Профиль как артефакт, а не как папка

Офлайн-профиль (англ. offline profile) — это поименованный, версионированный и проверяемый набор средств, достаточный для установки, настройки, эксплуатации и восстановления узла без обращения к внешним источникам. Каждое слово в определении работает.

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

Достаточный: профиль покрывает требования из темы 1. Если требование говорит, что в сценарии Б нужно сохранить уровень 2 на 72 часа (условие C-01-02), профиль содержит всё, что для этого нужно: образ системы, пакеты локального зеркала, конфигурации сервисов, документацию по их восстановлению. Для сценария В, где узел 336 часов живёт без топлива и связи (условие C-01-03), к этому добавляется требование, которого нет в коротких сценариях: всё, у чего есть срок действия, — подписи репозитория, сертификаты, ключи — должно пережить эти две недели. Этому посвящён третий раздел.

Без обращения к внешним источникам: ни один элемент не требует скачивания в момент использования. Это не значит, что профиль не обновляется, — значит, что обновление происходит заранее и контролируемо (тема 7).

Разница между профилем и папкой видна на примере дистрибутива 1. Образ сетевой установки Debian 13 «trixie» с именем вида debian-13.N.0-amd64-netinst.iso — элемент профиля: у него есть имя, версия в имени файла, опубликованный разработчиком файл контрольных сумм и подпись этого файла. Папка linux_backup_old, содержимое которой никто не помнит, — не элемент профиля, пока для неё не составлено описание, не посчитаны суммы и не проведена хотя бы одна проверка восстановления.

Почему подготовка — это процедура

Подготовку к автономной работе часто понимают как закупку: купить побольше флешек, внешний диск, повербанк. Закупка создаёт ощущение готовности, но не готовность: она отвечает на вопрос «что есть», а не на вопрос «что работает».

Инженерная подготовка строится как процедура с обратной связью: сценарий задаёт требование, требование задаёт средство, средство проходит проверку, результат проверки записывается. Если проверка не пройдена, средство не засчитывается, даже если физически присутствует. Процедура повторяется при каждом обновлении профиля и по календарю ротации. Так же устроено планирование непрерывности в NIST SP 800-34: стратегия резервирования считается частью плана только вместе с процедурой её испытания и поддержания в актуальном состоянии 6.

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

Слои профиля

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

СлойСодержимоеЧастота обновленияСпособ проверки
Установкаобразы ОС, загрузочный комплектпри выходе точечного выпуска ОСзагрузка в виртуальной машине
Пакетысрез зеркала, зависимостипо графику ротацииустановка из зеркала в чистой среде
Драйверы и прошивкипрошивки устройств, драйверыпри смене оборудованияприменение на тестовом экземпляре
Прикладное ПОпортативные сборки, установщикипо мере надобностизапуск и базовая операция
Документациясправочники ZIM, man, даташитыпо графику ротациипоиск известного фрагмента
Данныекарты, базы справочниковпо мере надобностиконтрольная сумма и открытие
Восстановлениеаварийная система, диагностикавместе с образами ОСпрогон процедуры восстановления
Ключи и довериеоткрытые ключи, сертификаты, списки отзывапо сроку действияпроверка подписи и срока
Описьманифест, суммы, подписьпри каждом изменениисверка скриптом

Слой «Опись» — не дополнение, а то, что превращает остальные восемь слоёв в артефакт. Без него профиль остаётся набором файлов, о котором нельзя сказать ничего определённого. Пользовательские данные — документы, базы, конфигурации с историей изменений — в профиль не входят: их копирование и восстановление — предмет темы 9. Профиль восстанавливает узел до работоспособного состояния, копии данных возвращают ему содержимое.

Слои офлайн-профиля и их проверка
Восемь слоёв содержимого и девятый — опись: у каждого слоя своя частота обновления и свой способ проверки; опись подписана ключом, который хранится вне профиля

Отдельного пояснения требует слой документации. Справочник, доступный без сети, — это не PDF-файл на диске, а база с полнотекстовым поиском, потому что PDF без индекса бесполезен ровно тогда, когда нужен. Готовое решение — архивы ZIM, читаемые программой Kiwix 11; на них же построены автономные сборки вроде Internet-in-a-Box. Для инженерных задач этого курса важнее другое: ZIM-архив — обычный файл, у него есть контрольная сумма, его можно проверить скриптом и положить на два носителя, то есть он удовлетворяет определению элемента профиля, а «сайт, открытый в браузере» — нет. Развёртывание локальных сервисов, которые читают эти архивы, — тема 8.

Сколько это занимает места

Объём профиля — первое ограничение, с которым сталкивается проект, и первое число, которое надо посчитать, а не угадать. Расчёт делается по слоям: сумма размеров образов, зеркала, документации и данных плюс запас на рост. Единого «типичного» объёма не существует: разброс между профилем «только установка и man» и профилем с полным энциклопедическим ZIM-архивом составляет больше порядка, поэтому диапазон из книги здесь хуже собственного расчёта.

Расчёт выполняет скрипт лабораторной работы size_estimate.py. Он ничего не знает о реальных образах: размеры слоёв задаются по фактическим файлам или по листингу каталога загрузки, а скрипт складывает, добавляет запас и делит на ёмкость носителя. Пример ниже — допущения автора для профиля с крупным справочником: образы установки 4700 МБ, аварийная система 700 МБ, срез зеркала 8000 МБ, документация 110 000 МБ, карты 4000 МБ, запас 20 %.

python3 size_estimate.py --os 4700 --rescue 700 --mirror 8000 --docs 110000 \
    --maps 4000 --slack 20 --media-gb 128 --copies 3 --read-mbs 100
слои, МБ: os=4700, rescue=700, mirror=8000, docs=110000, maps=4000, other=0
сумма слоёв:            127400 МБ
с запасом 20 %:        152880 МБ = 152.88 ГБ
носителей по 128 ГБ:     2 на копию, 6 на 3 копии
полная проверка SHA-256: 0.42 ч (25 мин) на копию при 100 МБ/с, 1.27 ч на все копии
запись при 12 пересборках в год: 1.835 ТБ
допущения: размеры слоёв и скорость заданы вручную; ФС, паритет и мелкие файлы не учтены

Разберём вывод до последней цифры (запись C-02-05). Сумма слоёв: 4700 + 700 + 8000 + 110 000 + 4000 = 127 400 МБ. С запасом 20 %: 127 400 × 1,2 = 152 880 МБ, то есть 152,88 ГБ в десятичных единицах, в которых указывается ёмкость носителей. На носитель 128 ГБ такой профиль не помещается, нужно два носителя на копию: 152,88 / 128 = 1,19, округление вверх даёт 2; на три копии — 6 носителей. Если бы справочник был в двадцать раз меньше, профиль уложился бы в один носитель на копию, и число носителей уменьшилось бы вдвое: решение о составе справочника — это решение о бюджете.

Строка о проверке (запись C-02-06) — главное следствие расчёта для эксплуатации. Полная проверка SHA-256 требует прочитать каждый байт: 152 880 МБ / 100 МБ/с = 1528,8 с = 0,42 ч на одну копию и 1,27 ч на три. Скорость 100 МБ/с — допущение, а не измерение: внешний диск с интерфейсом USB 2.0 физически не может её дать, а SSD с USB 3.x даст больше. Последняя строка — годовой объём записи при ежемесячной пересборке профиля: 152,88 ГБ × 12 = 1,835 ТБ (запись C-02-07). К ней вернёмся при разговоре о ресурсе SSD.

Чего расчёт не учитывает, скрипт печатает сам: служебные области файловой системы и округление до кластера, объём паритета (его добавляют в --other), падение скорости на мелких файлах и на диске с черепичной записью. Все эти поправки увеличивают итог, поэтому расчёт — нижняя граница.

Манифест профиля

Зачем машиночитаемое описание

Человекочитаемая опись («на диске лежат образ системы, зеркало и справочники») не проверяется скриптом. Машиночитаемый манифест проверяется. Разница принципиальна: проверка, которую нельзя автоматизировать, не выполняется регулярно, а проверка, которая не выполняется регулярно, обнаруживает повреждение тогда, когда оно уже мешает.

Манифест профиля (англ. profile manifest) — файл, описывающий состав профиля, версии, хеши, источники и процедуры обновления и отката. Минимальный набор полей:

  • name — имя профиля;
  • version — версия в формате, допускающем сравнение;
  • date — дата сборки;
  • items — список элементов, каждый с путём, размером, хешем SHA-256 и источником;
  • signature — имя файла отсоединённой подписи манифеста;
  • update — описание процедуры обновления;
  • rollback — описание процедуры отката.

Формат — JSON или YAML; выбор не влияет на свойства, влияет только на удобство инструментов. В курсе используется JSON, потому что он разбирается стандартной библиотекой Python без дополнительных зависимостей.

Формат и пример

Манифест небольшого профиля, созданный командой manifest.py init, выглядит так (значения хешей и размеров здесь иллюстративные; настоящие дают sha256sum и stat):

{
 "name": "polygon-offline",
 "version": "1.0.0",
 "date": "2026-10-20T09:00:00Z",
 "items_count": 2,
 "total_bytes": 1048697,
 "items": [
  {
   "path": "install/debian-13-amd64-netinst.iso",
   "size": 1048576,
   "sha256": "7c49a4ff7d8d9088faa2027a6d8f59d8c3e7d7e0e7523b43f3afdd78c18c816e",
   "source": "https://cdimage.debian.org/debian-cd/current/amd64/iso-cd/"
  },
  {
   "path": "docs/man-mount.txt",
   "size": 121,
   "sha256": "…",
   "source": "local"
  }
 ],
 "signature": "manifest.sig",
 "update": "заменить элементы, пересобрать манифест, подписать, проверить на тестовом узле",
 "rollback": "переключить ссылку current на предыдущий каталог версии и проверить его манифест"
}

Пути в манифесте — относительные: абсолютный путь привязывает профиль к точке монтирования одной машины. Сам манифест и его подпись в список items не входят: манифест не может содержать собственный хеш, это логический круг. Поэтому sha256sum, запущенный по всем файлам каталога, насчитает на один файл больше, чем записано в манифесте, — это расхождение ожидаемо и проверяется в лабораторной работе.

Подпись манифеста и цепочка доверия

Хеш защищает от случайного повреждения, но не от подмены: тот, кто заменил файл, заменит и хеш в манифесте. Защита от подмены — подпись.

Манифест подписывается закрытым ключом; открытая часть хранится на узле отдельно от профиля. Проверка подписи выполняется до того, как содержимое профиля признано годным. Это простейшая цепочка доверия: доверяем ключу, ключ подтверждает манифест, манифест подтверждает файлы. В курсе подпись выполняется средствами openssl — пакет уже есть в учебной среде, а отсоединённая подпись RSA с SHA-256 проверяется одной командой:

openssl genpkey -algorithm RSA -pkeyopt rsa_keygen_bits:3072 -out ~/polygon/keys/profile-priv.pem
openssl req -x509 -key ~/polygon/keys/profile-priv.pem -out profile-cert.pem \
    -days 365 -subj "/CN=polygon-profile"
openssl dgst -sha256 -sign ~/polygon/keys/profile-priv.pem -out manifest.sig manifest.json
openssl x509 -in profile-cert.pem -pubkey -noout > profile-pub.pem
openssl dgst -sha256 -verify profile-pub.pem -signature manifest.sig manifest.json
Verified OK

Сертификат X.509 здесь нужен не ради инфраструктуры открытых ключей, а ради одного поля — срока действия notAfter. У «голого» открытого ключа срока нет, у сертификата есть, и это делает видимым вопрос, который иначе забывается: доживёт ли доверие к профилю до конца сценария. Полная инфраструктура открытых ключей, выпуск сертификатов и отзыв — предмет курса «Криптографические методы защиты информации» (темы 10, 14, 15); подпись репозитория пакетов своим ключом и её проверка APT — тема 7.

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

Версия и откат

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

Простая и работающая схема: каждый выпуск профиля хранится целиком в отдельном каталоге с версией в имени; манифест ссылается на элементы относительными путями; переключение версии — смена символической ссылки current. Откат — переключение ссылки обратно и проверка манифеста предыдущей версии. Схема не требует специальных инструментов и работает на любой файловой системе с символическими ссылками; на FAT32 и exFAT ссылок нет, и там та же схема реализуется файлом CURRENT с именем каталога.

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

Проверка чужих артефактов: образы, репозитории, сроки

Образ Debian: сумма, подпись, отпечаток

Профиль собирается из своих файлов и из чужих артефактов — образов, пакетов, архивов ZIM. Для своих файлов цепочка доверия начинается с собственного ключа; для чужих её надо продолжить до ключа издателя. Debian публикует рядом с образами файл SHA256SUMS и его отсоединённую подпись SHA256SUMS.sign; порядок проверки описан на странице проекта 2:

  1. Получить открытый ключ, которым подписан SHA256SUMS, и сверить его отпечаток с опубликованным.
  2. Проверить подпись SHA256SUMS.sign над SHA256SUMS.
  3. Сверить SHA-256 образа со строкой в SHA256SUMS.

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

Ключи Debian, которыми подписываются образы, входят в пакет debian-keyring (файл /usr/share/keyrings/debian-role-keys.gpg; в новых версиях пакета расширение может быть .pgp). Если на машине, где собирается профиль, уже стоит Debian, этот пакет пришёл из архива, подпись которого проверил APT, — цепочка доверия продолжается от ключа архива. Проверка без сети и без импорта ключа в личную связку:

gpgv --keyring /usr/share/keyrings/debian-role-keys.gpg SHA256SUMS.sign SHA256SUMS
sha256sum --check --ignore-missing SHA256SUMS
gpgv: Signature made …
gpgv:                using RSA key DF9B9C49EAA9298432589D76DA87E80D6294BE9B
gpgv: Good signature from "Debian CD signing key <debian-cd@lists.debian.org>"
debian-13.N.0-amd64-netinst.iso: OK

Отпечаток в выводе сверяется со страницей проверки образов Debian; на момент написания там опубликован ключ «Debian CD signing key» с отпечатком DF9B 9C49 EAA9 2984 3258 9D76 DA87 E80D 6294 BE9B (запись C-02-12) 2. Сверять надо со страницей, а не с этим текстом: учебник — не источник доверия. Если пакета debian-keyring нет, ключ импортируется с сервера keyring.debian.org командой gpg --keyserver keyring.debian.org --recv-keys и тот же отпечаток сверяется вручную. Записанный на бумаге отпечаток — часть печатной части профиля: по нему можно проверить образ на машине, где нет ни сети, ни Debian.

Ключ --ignore-missing нужен, потому что в SHA256SUMS перечислены все образы каталога, а загружен обычно один. Без него sha256sum сообщит об отсутствующих файлах и завершится с ошибкой, хотя проверяемый образ цел.

Подписи репозитория и поле Valid-Until

Пакеты из архива Debian проверяются иначе: подписан не каждый пакет, а файл Release (или InRelease, где подпись встроена), в котором перечислены хеши индексов Packages, а в индексах — хеши пакетов. Подробно цепочка «ключ архива → Release → Packages → .deb» описана в руководстве администратора Debian 4 и строится заново на собственном ключе в теме 7. В Debian 13 APT проверяет подписи OpenPGP программой sqv из проекта Sequoia, а не gpgv, но смысл проверки не изменился.

Для автономного узла важно поле Valid-Until, которое есть в Release-файлах части наборов, например у архива обновлений безопасности. Оно задаёт момент, после которого APT перестаёт принимать файл, даже если подпись верна: apt update сообщает, что Release-файл истёк (is expired), и не применяет обновления из этого источника 3. Механизм защищает от атаки заморозки: без него злоумышленник мог бы бесконечно подсовывать клиенту старый, правильно подписанный срез архива с известными уязвимостями.

Для узла, который неделями живёт без сети, тот же механизм работает против владельца. Локальное зеркало, снятое перед уходом в офлайн, содержит Release-файлы с Valid-Until в будущем; через некоторое время это будущее наступает, и APT перестаёт принимать зеркало, хотя в нём не изменился ни один байт. Если срок жизни файла меньше длительности сценария — для сценария В это 336 часов (условие C-01-03), — зеркало откажет посреди автономии. Синтетический Release-файл лабораторной работы подобран именно так. Проверка выполняется до ухода в офлайн:

grep -E '^(Date|Valid-Until):' /var/lib/apt/lists/*_InRelease
python3 valid_until.py samples/Release.synthetic --now 2026-10-20T12:00:00Z --hours 336

Отключение проверки — допустимое, но осознанное решение. APT позволяет отключить её глобально (apt -o Acquire::Check-Valid-Until=false update или строка Acquire::Check-Valid-Until "false"; в apt.conf) и для одного источника (check-valid-until=no в однострочном формате sources.list, Check-Valid-Until: no в формате deb822) 3. Второй вариант лучше: защита от заморозки снимается только с локального зеркала, источник которого и так находится под контролем владельца. Решение записывается в журнал узла вместе с причиной и датой, когда его нужно отменить. Альтернатива без отключения проверки — переподписать локальное зеркало своим ключом с собственным сроком действия (тема 7).

Сроки ключей и часы узла при долгом офлайне

У ключей тоже есть срок. Ключи архива Debian выпускаются с датой истечения; список и даты видны командой gpg --show-keys по файлу связки из /usr/share/keyrings/ (в Debian 13 файлы связок могут иметь расширение .pgp). Подпись ключом, срок которого истёк к моменту проверки, APT не принимает. Для профиля, который хранится годами, это означает: связка ключей архива — такой же элемент с датой годности, как батарейка часов, и проверяется по графику ротации.

Собственный сертификат подписи профиля подчиняется тому же правилу. Скрипт лабораторной работы manifest.py verify --horizon-hours 336 проверяет не только подпись, но и то, что сертификат будет действовать весь горизонт сценария: сертификат, выпущенный на 7 суток, проверку подписи проходит, а проверку горизонта 336 часов — нет. Это намеренно сделанный провал, который показывает, что «подпись верна» и «профилю можно доверять до конца автономии» — разные утверждения.

Все сроки сравниваются с часами узла. Если часы реального времени ушли вперёд или сбросились после разряда батарейки, действительный Release-файл окажется «истёкшим» или «ещё не наступившим», а сертификат — недействительным. Поэтому синхронизация времени без сети (тема 8) — не удобство, а условие работы проверок этого раздела.

Воспроизводимый срез: snapshot.debian.org

Сервис snapshot.debian.org хранит состояния архива Debian на каждый момент публикации и отдаёт их по адресу с меткой времени, например https://snapshot.debian.org/archive/debian/20261001T000000Z/. Для профиля это способ собрать срез зеркала, который можно воспроизвести позже: две сборки профиля с одной меткой времени дают одинаковый набор пакетов. Release-файлы в таких срезах почти всегда истёкшие, и источник подключается с check-valid-until=no — по той же логике, что и локальное зеркало.

Влияние на ротацию прямое. В график ротации добавляются три проверки, которых нет у «просто файлов»: ближайшее Valid-Until в локальном зеркале, срок сертификата подписи профиля, сроки ключей архива в связке. Каждая сравнивается не с сегодняшней датой, а с датой плюс длительность самого длинного сценария: профиль, который истечёт на десятые сутки сценария В, не готов к сценарию В.

Правило трёх копий, ротация и печатная часть

3-2-1 в офлайн-исполнении

Правило трёх копий формулируется так: три копии данных, два разных типа носителя, одна копия вне основного места. Оно пришло не из стандарта, а из практики; в известной формулировке его популяризировал Питер Крог в книге об управлении цифровыми архивами фотографов 5. Стандарты планирования непрерывности требуют того же по существу — резервных копий и хранения вне площадки 6, — но число «3-2-1» в них не задают.

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

Раскладка для офлайн-профиля: копия 1 — рабочий диск узла, используется ежедневно; копия 2 — внешний носитель рядом с узлом, но не в том же корпусе, для восстановления при отказе рабочего диска; копия 3 — носитель другого типа в другом помещении, для восстановления при потере места. Три копии на одном столе не считаются тремя копиями: пожар, вода и кража забирают их одновременно. Это учёт корреляции отказов, и он входит в проверку профиля отдельным вопросом «что если это место недоступно».

Правило трёх копий и механизмы отказа носителей
Копии разнесены по типам носителей и по местам: у каждого типа свой механизм отказа, и два разных типа не отказывают по одной причине

Ротация по графику

Ротация — проверка копий, замена носителей и пересборка профиля по расписанию. Без расписания ротация не происходит: она делается «когда вспомнится», то есть не делается. Расписание привязывается к календарю, а не к событиям, потому что события («когда сломается») происходят после того, как ротация была нужна.

Ротация — это три независимых процесса, которые часто смешивают. Проверка целостности отвечает на вопрос «файл не испорчен» и требует чтения всех данных. Обновление содержимого отвечает на вопрос «профиль ещё актуален» и требует источника обновлений, то есть сети. Перезапись носителя отвечает на вопрос «носитель ещё жив» и определяется ресурсом носителя и показаниями SMART (тема 9). Смешение приводит к типичной ошибке: профиль регулярно копируется на новые носители, но ни разу не сверялся с манифестом, и копирование размножает уже испорченный файл.

Минимальный график для личного узла, принятый в лабораторной работе: сверка манифеста — раз в месяц, восстановление из паритета и загрузка образа в ВМ — раз в квартал, сроки сертификатов, Valid-Until и печатная часть — раз в полгода, решение о замене носителей и проверка расходников — раз в год. Это не норма, а исходная точка: период проверки ограничен её стоимостью, а стоимость считается по формуле из первого раздела. Каждая ротация оставляет запись: дата, что проверялось, ожидание, результат, что заменено. Запись ведётся в том же журнале, что и обслуживание (тема 13).

Сроки годности расходников

Профиль — это не только файлы. В нём есть физические элементы со сроком годности, и они тоже входят в график ротации: элементы питания часов реального времени и измерительных приборов, термопаста и флюс для ремонта (тема 6), герметики и изолента, аккумуляторы фонарей и повербанков. Свинцово-кислотные и литий-ионные аккумуляторы при хранении саморазряжаются и требуют периодического подзаряда; электролитические конденсаторы в запасных блоках питания после долгого хранения могут потребовать формовки.

Числа для этих сроков курс не приводит: они зависят от изготовителя и партии и указаны на упаковке или в паспорте конкретного изделия. Правило процедурное: при закладке в профиль срок годности записывается в rotation.csv вместе с датой следующей проверки, а не держится в памяти. Вывод из строя носителей, уходящих из ротации, — отдельная операция: данные с них удаляются по категориям очистки (clear), уничтожения данных (purge) или физического разрушения (destroy) из NIST SP 800-88 Rev. 2 7, и «удалить файлы» ни одной из этих категорий не является.

Печатная часть

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

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

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

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

Носители и их механизмы отказа

Жёсткие диски: CMR и SMR

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

Важнее для профиля способ записи. В диске с обычной записью (англ. conventional magnetic recording, CMR) дорожки не перекрываются, и любую из них можно перезаписать независимо. В диске с черепичной записью (англ. shingled magnetic recording, SMR) дорожки частично накладываются друг на друга, как черепица; это повышает плотность, но перезапись одной дорожки требует перезаписать всю полосу соседних. Диски SMR, которые скрывают это от системы (англ. drive-managed SMR), принимают запись в буферную область и переписывают полосы в фоне. Пока буфер не заполнен, диск ведёт себя как обычный; при длительной случайной записи — восстановлении RAID-массива, работе базы данных — буфер переполняется, и скорость записи падает на порядки, а массив может счесть диск отказавшим.

Для профиля из этого следует различение ролей. Копия профиля пишется последовательно и целиком при пересборке и в остальное время только читается, поэтому SMR-диск для копии 2 или 3 приемлем, а его недостатки проявятся лишь в виде долгой первой записи. Для рабочего диска узла, на котором работают сервисы и базы, и для участия в RAID нужен CMR. Тип записи указывается в паспорте модели; если он не указан, диск считается SMR до проверки.

SSD и флеш-память: ресурс TBW и хранение без питания

У твердотельного накопителя два разных ограничения, и путать их — типичная ошибка. Ресурс записи (англ. endurance) задаётся в терабайтах записанных данных (англ. terabytes written, TBW) и расходуется при записи. Срок хранения без питания (англ. data retention) — время, в течение которого обесточенный накопитель сохраняет данные: заряд в ячейках флеш-памяти постепенно утекает, и тем быстрее, чем выше температура и чем сильнее изношены ячейки.

Стандарт JEDEC JESD218 задаёт требования к обоим ограничениям для двух классов накопителей; они сведены в таблицу классов и требований (Table 1 стандарта) 8. Для класса client (ноутбуки, настольные машины) накопитель, израсходовавший паспортный ресурс TBW, должен сохранять данные без питания 1 год при 30 °C (запись C-02-01). Для класса enterprise требование другое: 3 месяца без питания при 40 °C (запись C-02-02) — серверный накопитель рассчитан на круглосуточную работу под питанием, а не на хранение на полке. Оба требования относятся к накопителю в конце ресурса; новый накопитель хранит данные дольше, но стандарт этого не гарантирует, и для расчёта профиля берётся гарантированное значение.

Ресурс записи для профиля почти никогда не ограничение: при ежемесячной пересборке профиля из первого раздела записывается 1,835 ТБ в год (запись C-02-07), и это число сравнивается с TBW из паспорта своего накопителя. Ограничение — хранение: SSD класса client, лежащий в ящике как копия 3, по стандарту гарантирует сохранность 1 год при 30 °C (C-02-01), и поэтому график ротации предусматривает включение и полное чтение такой копии чаще, чем раз в год. Флешки и карты памяти не относятся ни к одному классу JESD218 и не имеют гарантированного срока хранения вовсе; они годятся для переноса, но не для копии, на которую рассчитывают.

Оптика и лента: M-DISC и LTO

Оптические диски однократной записи хранят данные в регистрирующем слое, и срок хранения определяется химией этого слоя. В обычных записываемых дисках слой органический (краситель) и деградирует от света и тепла. Диски M-DISC используют неорганический слой, в котором запись выполняется физическим изменением материала; изготовитель заявляет срок хранения в сотни лет по результатам ускоренного старения. Заявление изготовителя — не измерение для конкретной партии, и в курсе это число не используется; используется качественное свойство: механизм отказа оптики не связан ни с электроникой, ни с магнетизмом, ни с утечкой заряда, поэтому оптика хорошо дополняет диск или SSD. Ограничения: для записи M-DISC нужен привод с его поддержкой, ёмкость одного диска — десятки гигабайт, и профиль из первого раздела занял бы несколько дисков.

Магнитная лента LTO (англ. Linear Tape-Open) — носитель для больших архивов: картридж LTO-9 вмещает 18 ТБ без сжатия (запись C-02-10) 14. Лента хранится долго и дёшева в пересчёте на терабайт, но у неё два ограничения, существенных для автономного узла. Первое — привод: он дорог, и сам является элементом профиля со своим ресурсом; без исправного привода картридж — не копия. Второе — совместимость поколений: привод читает только ограниченное число предыдущих поколений картриджей (таблица совместимости опубликована консорциумом LTO 14), и архив на ленте устаревшего поколения требует хранить и устаревший привод. Файловая система LTFS позволяет работать с картриджем как с каталогом, но доступ остаётся последовательным. Для личного узла лента почти всегда избыточна; она уместна, когда профиль измеряется десятками терабайт.

Тип носителяЧем ограничен ресурсМеханизм отказа при храненииРоль в профиле
HDD CMRмеханика, циклы парковкизаклинивание механики после простоярабочий диск, копия 2
HDD SMRмеханика; медленная случайная записьто жекопия 2 или 3, не RAID
SSD clientTBWутечка заряда: 1 год при 30 °C в конце ресурса (C-02-01)копия 1 или 2, с регулярным включением
Флешка, картане нормированутечка заряда, срок не гарантированперенос, не копия
Оптика M-DISCоднократная записьхимия слоя; нужен приводкопия 3 для небольших слоёв
Лента LTOпривод и поколениенужен совместимый приводархив десятков терабайт

Вывод из таблицы один: профиль не может опираться на носитель одного типа, каким бы надёжным он ни считался. Требование «два разных типа носителя» существует потому, что механизмы отказа у них разные и не коррелируют: заряд в SSD утекает независимо от состояния механики HDD.

Файловые системы для переноса

Носитель профиля должен читаться на той системе, которая окажется под рукой. Это ограничивает выбор файловой системы сильнее, чем соображения производительности.

Файловая системаСовместимостьОграниченияКогда уместна
FAT32максимальная, включая прошивки и загрузку UEFIфайл не больше 4 ГиБ − 1 байт (C-02-08), нет прав и журналараздел EFI, прошивки, мелкий обмен
exFATWindows, macOS, Linuxнет журнала, риск при извлечении без размонтированиябольшие файлы, перенос между системами
NTFSWindows; Linux — чтение и запись драйвером ядра ntfs3; macOS — чтениезакрытая спецификация форматаноситель, который будет читаться в Windows
ext4LinuxWindows и macOS без дополнительного ПО не читаютрабочий диск и копии внутри Linux-узлов
ISO 9660 с Rock Ridgeмаксимальная для образовтолько чтениеобразы дисков

Ограничение FAT32 следует из формата: размер файла хранится в записи каталога 32-битным полем, поэтому файл не может быть больше 4 294 967 295 байт, то есть 4 ГиБ − 1 байт (C-02-08) 13. Образ установки или ZIM-архив больше этого предела на FAT32 одним файлом не помещается, и это главный довод за exFAT на носителе переноса.

Запись в NTFS из Linux выполняет встроенный драйвер ядра ntfs3, входящий в ядро с версии 5.15 (C-02-09) 12; монтирование — mount -t ntfs3. Старый драйвер ntfs-3g работает в пространстве пользователя через FUSE и остаётся запасным вариантом, если ядро собрано без ntfs3. Для профиля это значит, что NTFS-носитель, подготовленный на Windows, читается и обновляется на узле без дополнительных пакетов, но проверку целостности после записи из Linux всё равно выполняют сверкой манифеста.

Практическое правило: профиль, который должен читаться на любой машине, держится на двух носителях — один с exFAT для совместимости, второй с ext4 для целостности и прав. Это и есть «два разных типа» не только по железу, но и по формату. Отдельно о кириллице в путях: на exFAT и FAT32 с длинными именами имена хранятся в Unicode, и современные системы читают их корректно; проблемы возникают в прошивках, в архиваторах с неверной кодировкой и там, где путь передаётся через промежуточный инструмент. Для профиля, который должен открываться где угодно, безопаснее латиница в именах файлов и каталогов, а кириллица — внутри документов.

Проверка профиля и паритетные архивы

Четыре уровня проверки

Проверка профиля — не «файл открылся». Открытие проверяет только то, что файл читается, и ничего не говорит о его целостности и пригодности. Полная проверка состоит из четырёх уровней:

  1. Наличие и целостность. Каждый элемент из манифеста существует, его размер и SHA-256 совпадают с записанными, подпись манифеста верна и действует на горизонте сценария. Проверяется скриптом; время пропорционально объёму профиля.
  2. Читаемость формата. Файл открывается программой своего типа: образ монтируется, архив распаковывается, база справочника выполняет поисковый запрос.
  3. Восстановление после повреждения. Для файлов с паритетом — намеренное повреждение и восстановление. Для копий — восстановление на чистый носитель.
  4. Пригодность к использованию. Средство выполняет свою функцию: образ загружается в виртуальной машине и доходит до приглашения; установщик устанавливает систему; справочник находит известный фрагмент.

Уровни 1 и 2 выполняются при каждой проверке. Уровни 3 и 4 — по календарю, потому что они дороги по времени. Проверка, которая не может провалиться, ничего не проверяет, поэтому на уровне 3 повреждение вносится намеренно, а на уровне 1 намеренно портится один файл и подменяется манифест — скрипт обязан это заметить.

Паритет: как устроен par2

Контрольная сумма обнаруживает повреждение, но не исправляет его. Для исправления служит избыточное кодирование: блоки восстановления, записанные рядом с данными. Инструмент par2 (пакет par2 в Debian и Ubuntu) реализует формат PAR 2.0 10: файл режется на блоки одинакового размера, и по ним вычисляются блоки восстановления кодом Рида — Соломона над полем Галуа GF(2^16) (запись C-02-11) 9.

Главное свойство кода Рида — Соломона: R блоков восстановления позволяют восстановить любые R повреждённых или потерянных блоков данных, независимо от того, где они расположены. Набор с избыточностью 10 % восстанавливает повреждение до 10 % блоков в любой комбинации. Стоимость — те же 10 % места плюс небольшие служебные пакеты и время на вычисление, которое для поля GF(2^16) заметно на больших файлах. Формат хранит в каждом файле .par2 описание исходных файлов с их хешами, поэтому par2 repair находит и переименованный, и частично повреждённый файл.

Паритет не заменяет вторую копию. Он чинит частичное повреждение файла на живом носителе, но бесполезен, если носитель отказал целиком: блоки восстановления лежат на том же носителе. Его место — между сверкой манифеста, которая обнаруживает порчу, и восстановлением из другой копии, которое дороже.

Граница учебного паритета

В лабораторной работе используется учебный скрипт parity.py, и важно не принять его за par2. Он реализует не код Рида — Соломона, а простейший XOR-паритет по группам: блоки по 1024 байта раскладываются по G группам по правилу «блок i попадает в группу i mod G», и для каждой группы хранится XOR всех её блоков. Число групп равно числу блоков, умноженному на избыточность. Для файла карты учебного профиля размером 512 КиБ при избыточности 20 % получается 512 блоков и 102 группы, то есть паритетные данные занимают 102 КиБ — 19,9 % файла (запись C-02-03).

У XOR-схемы ровно одно уравнение на группу, а значит, в каждой группе восстанавливается не больше одного повреждённого блока. Пять повреждённых блоков в пяти разных группах восстанавливаются; два повреждённых блока в одной группе — нет, хотя повреждено меньше. Блоки одной группы отстоят друг от друга на G блоков: при 102 группах — на 102 КиБ, а паритетные данные занимают 19,9 % файла (C-02-03). Поэтому опыт «повреждение сверх паритета» в лабораторной работе делается двумя повреждениями со смещениями, отличающимися ровно на 102 КиБ, а не пятью случайными: случайные повреждения почти всегда попадают в разные группы и успешно чинятся. Код Рида — Соломона в par2 с той же избыточностью эти два повреждения восстанавливает.

Граница учебного XOR-паритета
Блоки раскладываются по группам по кругу; один повреждённый блок в группе восстанавливается, два — нет. Код Рида — Соломона такого ограничения не имеет
паритет: 512 блоков по 1024 Б, 102 групп (блок i -> группа i mod 102)
паритетные данные: 104448 Б = 19.9 % файла
файл паритета: data/map-region.pmtiles.parity.json, 244313 Б = 46.6 % файла

Третья строка вывода показывает расхождение, которое легко принять за ошибку: файл паритета занимает 46,6 % данных при заданных 20 % (запись C-02-04). Объяснение — формат, а не избыточность. Учебный скрипт хранит паритет в JSON в шестнадцатеричном виде, где каждый байт записан двумя символами: 104 448 байт паритета превращаются в 208 896 символов, это 39,8 % файла. Ещё 6,6 % дают SHA-256 каждого из 512 блоков: 64 символа хеша плюс кавычки и разделитель — 68 байт на блок, 34 816 байт всего. По этим хешам скрипт находит, какие блоки повреждены, — в par2 ту же роль играют контрольные суммы блоков в служебных пакетах, записанные в двоичном виде. Вывод общий: заявленная избыточность — это доля паритетных данных, а занимаемое место зависит ещё и от формата, и считать его надо по факту.

Автоматизация проверки

Проверка, выполняемая вручную, выполняется нерегулярно. Проверка, выполняемая скриптом, выполняется по расписанию. Поэтому процедура уровня 1 оформляется как скрипт и запускается таймером systemd (тема 7): сверить манифест с файлами, проверить подпись и горизонт сертификата, проверить Valid-Until локального зеркала, записать отчёт с датой и результатом.

python3 manifest.py verify profile --cert profile-cert.pem --horizon-hours 336 \
  && python3 manifest.py check profile \
  && python3 valid_until.py mirror/dists/trixie-security/InRelease --hours 336
echo "код возврата: $?"

Отчёт сохраняется, потому что история проверок — доказательство того, что процедура существует. Ненулевой код возврата должен быть виден: таймер, который молча пишет «ошибка» в журнал, который никто не читает, проверкой не является. Регламент реакции на неуспех — тема 13.

Что эта модель не учитывает

  • Стоимость времени. Расчёт C-02-06 даёт время чтения при заданной скорости (0,42 ч на копию в примере), но не время подключения носителей, монтирования и разбора отчёта. На практике это добавочная работа человека, и при большом числе носителей она становится главной статьёй: следствие — проверки копий 2 и 3 сдвигаются, если их не вписать в календарь.
  • Человеческий фактор при ротации. Ротацию выполняет человек, а человек пропускает шаги под усталость. Скрипт и rotation.csv уменьшают пропуски, но не устраняют их; следствие — копия, которую «проверяли», может оказаться непроверенной.
  • Повреждение самого паритета и манифеста. Учебный паритет и манифест лежат на том же носителе, что и данные. Повреждённый файл паритета даёт ложное «не восстанавливается», повреждённый манифест — ложное «расхождение». Подпись обнаруживает второе, но не первое.
  • Старение форматов и программ. Файл, читаемый сегодня, может стать нечитаемым из-за исчезновения программы. Профиль снижает риск, включая средства чтения, но они тоже стареют; следствие — уровень 2 проверки нужно повторять при обновлении ОС.
  • Реальные сроки хранения носителей. Числа JESD218 (C-02-01: 1 год при 30 °C; C-02-02: 3 месяца при 40 °C) — минимальные требования стандарта для накопителя в конце ресурса при заданной температуре, а не прогноз для конкретного экземпляра. Хранение при более высокой температуре сокращает срок, и модель этого не считает.
  • Согласованность копий. Три копии, обновлённые в разное время, содержат разные версии. Модель требует версионирования, но не решает, какая версия основная при расхождении; это решается регламентом (тема 13).
  • Доверие к первому ключу. Цепочка доверия начинается с ключа, отпечаток которого сверен один раз. Если сверка была выполнена с подменённой страницы или по подменённой бумаге, вся цепочка подтверждает подмену.
  • Юридические ограничения. Часть программ лицензионно ограничивает копирование, и профиль, собранный без учёта этого, может оказаться непригодным к использованию. Свободное ПО это ограничение снимает.

Итоги темы

Офлайн-профиль — поименованный, версионированный и проверяемый набор средств, достаточный для работы узла без внешних источников. Отличие профиля от папки с файлами — манифест: машиночитаемое описание с хешами и подписью превращает набор файлов в артефакт, который можно проверить скриптом, сравнить с прошлой версией и откатить. Объём профиля считается по слоям, и от него зависят число носителей и стоимость проверки в часах: в примере темы 152,88 ГБ, 6 носителей на три копии (C-02-05) и 0,42 ч чтения на копию (C-02-06).

Чужие артефакты проверяются цепочкой до ключа издателя: для образа Debian это SHA256SUMS, его подпись и сверенный отпечаток ключа. При долгом офлайне у этой цепочки появляется измерение времени: Valid-Until в Release-файлах, сроки ключей архива и сертификата профиля. Профиль готов к сценарию, только если всё, у чего есть срок, переживает длительность сценария, а отключение проверки срока — осознанное и записанное решение для конкретного источника.

Правило 3-2-1 в офлайн-исполнении требует трёх копий, двух типов носителя и одной копии в другом месте, причём третья копия — физический носитель. Носители различаются механизмами отказа: механика HDD и черепичная запись SMR, утечка заряда в SSD с гарантированным по JESD218 сроком — 1 год при 30 °C для класса client (C-02-01) и 3 месяца при 40 °C для класса enterprise (C-02-02), химия слоя у оптики, привод и поколение у ленты. Поэтому требуется два разных типа, а не один самый надёжный.

Проверка профиля имеет четыре уровня, и проверка, которая не может провалиться, ничего не проверяет. Паритет чинит частичное повреждение в пределах своей схемы: код Рида — Соломона в par2 — любые R блоков, учебный XOR — не больше одного блока в каждой из 102 групп учебного файла при паритете 19,9 % его объёма (C-02-03); граница схемы обнаруживается опытом, а не чтением документации. Печатная часть — последний уровень, работающий тогда, когда электроника недоступна.

Следующая тема переходит к энергии — ресурсу, без которого остальные слои профиля бесполезны, потому что их не на чем прочитать.

Литература

  1. Debian GNU/Linux Installation Guide (Debian 13 «trixie»). — Debian Project, 2025. https://www.debian.org/releases/trixie/installmanual
  2. Verifying authenticity of Debian images. — Debian Project. https://www.debian.org/CD/verify
  3. sources.list(5), apt.conf(5). Справочные страницы APT, Debian 13. https://manpages.debian.org/trixie/apt/sources.list.5.en.html
  4. Hertzog R., Mas R. The Debian Administrator's Handbook. — Freexian. https://debian-handbook.info/
  5. Krogh P. The DAM Book: Digital Asset Management for Photographers. 2nd ed. — O'Reilly Media, 2009.
  6. NIST Special Publication 800-34 Rev. 1. Contingency Planning Guide for Federal Information Systems. — National Institute of Standards and Technology, 2010. https://csrc.nist.gov/pubs/sp/800/34/r1/upd1/final
  7. NIST Special Publication 800-88 Rev. 2. Guidelines for Media Sanitization. — National Institute of Standards and Technology, 2025. https://csrc.nist.gov/pubs/sp/800/88/r2/final
  8. JEDEC JESD218B. Solid-State Drive (SSD) Requirements and Endurance Test Method. — JEDEC Solid State Technology Association, 2016.
  9. Nahas M., Clements P., Nettle P., Gallagher R. Parity Volume Set Specification 2.0. — 2003. https://parchive.github.io/doc/Parity%20Volume%20Set%20Specification%20v2.0.html
  10. par2cmdline. PAR 2.0 compatible file verification and repair tool. https://github.com/Parchive/par2cmdline
  11. Kiwix. Offline reader for ZIM archives. https://www.kiwix.org/
  12. NTFS3. The Linux Kernel documentation. https://docs.kernel.org/filesystems/ntfs3.html
  13. Microsoft Extensible Firmware Initiative FAT32 File System Specification. Version 1.03. — Microsoft, 2000.
  14. LTO Program. LTO generations and compatibility. https://www.lto.org/