Immutability (неизменяемость) для бэкапов — зрелая практика, которая заметно снижает риски потери данных. Даже если злоумышленник получил ключи или администратор ошибся, правильно настроенное WORM-хранилище (write once, read many) не даст стереть или переписать резервные копии до истечения срока хранения. В S3-мире это реализовано через Object Lock. Разберём технологию подробно, с упором на практику.
Зачем нужна иммутабельность бэкапов
Обычный контроль доступа защищает от большинства ошибок, но не от сценариев, когда у атакующего есть валидные ключи или он действует из-под скомпрометированного CI/CD. Стратегия immutable backups позволяет гарантировать, что критичные точки восстановления (restore points) нельзя сократить или удалить до заданной даты. Это особенно важно для:
- защиты от шифровальщиков и масс-удалений;
- соблюдения регуляторных требований к WORM-хранению;
- страховки от ошибок в скриптах ротации и политике Lifecycle;
- аудита и форензики (legal hold).
Главная идея: объект записывается один раз и до истечения срока удержания (retention) физически не может быть удалён или изменён. Это техническая, а не только организационная гарантия.
S3 Object Lock: как это устроено
Object Lock — расширение S3 API, которое требует включённого версионирования и применяется к версиям объектов. Важные особенности:
- Включается на уровне бакета при создании. В большинстве реализаций S3 включить Object Lock на уже существующем бакете нельзя — нужен новый бакет и миграция.
- Работает поверх версии объекта. Каждая версия может иметь индивидуальный срок удержания и/или флаг legal hold.
- Есть два режима удержания: Governance и Compliance. Плюс отдельный механизм — Legal Hold.
- Поддерживается «дефолтный» retention для бакета (удобно, если ваше приложение не проставляет заголовки на заливке).
Governance vs Compliance, плюс Legal Hold
Режимы задают строгость запрета изменения/удаления:
- Governance — мягкая неизменяемость. Удалить или сократить срок может только принципал с правом
s3:BypassGovernanceRetentionи явным указанием этого обхода в запросе. Для большинства корпоративных сценариев это достаточно строго, если права «bypass» нигде не выданы, а политики Deny закрывают лазейки. - Compliance — жёсткий WORM. Ни один принципал (включая root) не может сократить или снять удержание версии до наступления даты Retain Until. Это подходит под требования строгих регуляторов, но опасно при ошибочных настройках — вернуть назад нельзя.
- Legal Hold — отдельный флаг ON/OFF без даты окончания, блокирует удаление независимо от режима и дат. Обычно применяется адресно в ходе расследований и судебных разбирательств.
Практика показывает: для ежедневных бэкапов часто выбирают Governance, а для ежемесячных архивов — Compliance. Legal Hold используют точечно, по процессу.

Retention: срок удержания и его границы
Retention можно задать по умолчанию на бакете (например, 14 дней в Governance), а также на каждую заливку — через заголовки/параметры запроса (Mode и RetainUntilDate). Есть нюансы:
- Если задать retention меньше дефолтного бакета, большинство реализаций не позволят сократить (ошибка). Увеличить — можно.
- Для Compliance сократить или снять удержание невозможно в принципе; можно лишь увеличивать (продлевать).
- Время интерпретируется по серверному часовому поясу и RFC3339. Всегда используйте UTC и следите за синхронизацией времени клиента (NTP/chrony), иначе получите странные ошибки при заливке.
Включаем Object Lock: пошаговый план
Рекомендуем завести «песочницу» и отработать сценарии протоколом. Базовая последовательность:
- Спроектируйте политику хранения: какие классы бэкапов, сроки хранения и режимы (Governance/Compliance). Опишите это в runbook.
- Создайте новый бакет с Object Lock и включённым версионированием.
- Назначьте «дефолтный» retention (если приложение не проставляет самостоятельно).
- Настройте инструменты бэкапа на заливку с нужными заголовками Retention и/или Legal Hold.
- Проверьте невозможность удаления/сокращения срока под типовыми ролями.
- Добавьте Lifecycle-политику для очистки старых версий после истечения удержания.
- Включите аудит событий и мониторинг ошибок заливки/удаления.
Примеры команд S3 API (AWS CLI)
Создание бакета с Object Lock и версионированием:
aws s3api create-bucket --bucket my-backup-lock --object-lock-enabled-for-bucket
aws s3api put-bucket-versioning --bucket my-backup-lock --versioning-configuration Status=Enabled
Задаём дефолтный retention для бакета (например, 14 дней в Governance):
aws s3api put-bucket-object-lock-configuration --bucket my-backup-lock --object-lock-configuration '{"ObjectLockEnabled":"Enabled","Rule":{"DefaultRetention":{"Mode":"GOVERNANCE","Days":14}}}'
Загрузка объекта с явным retention и без legal hold:
aws s3api put-object --bucket my-backup-lock --key daily/2025-11-16.tar.zst --body ./2025-11-16.tar.zst --object-lock-mode GOVERNANCE --object-lock-retain-until-date 2025-12-01T00:00:00Z
Установка или снятие Legal Hold для конкретной версии:
aws s3api put-object-legal-hold --bucket my-backup-lock --key daily/2025-11-16.tar.zst --version-id <VersionId> --legal-hold Status=ON
Продление удержания на существующей версии (увеличить можно, сократить — нет):
aws s3api put-object-retention --bucket my-backup-lock --key daily/2025-11-16.tar.zst --version-id <VersionId> --retention Mode=GOVERNANCE,RetainUntilDate=2025-12-15T00:00:00Z
Если гоняете большие объёмы и считаете секунды, почитайте сравнение инструментов командной строки для S3 — s5cmd против AWS CLI.
Multipart upload и Object Lock
Для больших файлов (многогигабайтные архивы) используется multipart upload. Важный момент: параметры Object Lock нужно передать уже при создании multipart-сессии, чтобы итоговая версия получила удержание на этапе завершения:
aws s3api create-multipart-upload --bucket my-backup-lock --key weekly/2025-W46.tar.zst --object-lock-mode COMPLIANCE --object-lock-retain-until-date 2026-11-01T00:00:00Z
Далее — стандартные загрузки частей и завершение multipart. В проде добавьте проверку: скрипт должен валидировать, что получен VersionId, а у версии выставлены ожидаемые поля удержания.
Политики доступа: закрываем «дырки»
Иммутабельность легко испортить избыточными правами. Базовые принципы:
- Не выдавайте право
s3:BypassGovernanceRetentionникому, кроме чётко определённого break-glass процесса, и то — через временные токены и аудит. - Запретите сокращение удержания с помощью условных ключей
s3:object-lock-remaining-retention-daysиs3:RequestObjectTag(если используете теги для классов данных). - Разделите роли «заливка бэкапов» и «чтение/восстановление». Писателям не нужны удаления/листинг старых префиксов.
Пример политики, запрещающей уменьшать срок удержания и ставить обход Governance:
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "DenyBypassGovernance",
"Effect": "Deny",
"Action": ["s3:BypassGovernanceRetention"],
"Resource": ["arn:aws:s3:::my-backup-lock", "arn:aws:s3:::my-backup-lock/*"]
},
{
"Sid": "DenyShortenRetention",
"Effect": "Deny",
"Action": ["s3:PutObjectRetention"],
"Resource": ["arn:aws:s3:::my-backup-lock/*"],
"Condition": {
"NumericLessThan": {"s3:object-lock-remaining-retention-days": 7}
}
}
]
}
Подстройте значения под ваши SLO: например, минимум 14 дней для daily-класса. Если ваш бэкап-оркестратор крутится на VDS, вынесите IAM/учётки и ключи в отдельный vault, а доступ к ним ограничьте через временные токены.

Retention и Lifecycle: живут вместе, но по-разному
Object Lock запрещает удаление до истечения срока удержания. Lifecycle отвечает за автоматическую очистку и переход между классами хранения (Standard, архив и т. п.). Важные моменты:
- Правило Lifecycle «expire» не удалит защищённую версию, пока retention не истечёт. Это не ошибка — так задумано.
- Закладывайте буфер: срок Lifecycle делайте чуть больше, чем retention (например, на 1–3 дня), чтобы исключить гонки и проблемы с часовыми поясами.
- Переход в холодные классы совместим с Object Lock, но учитывайте RTO и стоимость «доставки» при тестах восстановления.
Репликация и DR: переносим иммутабельность
Если у вас есть межрегиональная репликация, обязательно включайте копирование полей Object Lock. На стороне назначения должен быть бакет с Object Lock и версионированием, а в политике репликации — опция копирования Object Lock. Иначе на целевой стороне объекты окажутся без удержания, и DR-план потеряет смысл.
Отдельный приём: делать вторую копию в Compliance на долгий срок, при этом рабочий бакет держать в Governance. Так вы получаете быстрый восстановительный контур и «архивный бункер» на случай худшего сценария.
Схемы префиксов и разбиение по бакетам
Чтобы не перегружать одну политику на всё, используйте отдельные префиксы и (часто лучше) отдельные бакеты под разные классы данных и сроки хранения. Несколько практических паттернов:
- Отдельный бакет на daily/weekly/monthly с собственным дефолтным retention и Lifecycle.
- Префиксы по датам:
daily/YYYY/MM/DD,weekly/YYYY-WW; это облегчает инвентаризацию и выборочные проверки. - Теги объектов для логического класса (prod, stage, critical), если ваши политики доступа учитывают теги.
Интеграция с инструментами бэкапа
Современные «бэкаперы» и утилиты синхронизации S3 в большинстве случаев умеют проставлять параметры Object Lock при загрузке или работать с дефолтным retention бакета. Рекомендации по внедрению:
- Если инструмент явно задаёт
ModeиRetainUntilDate— используйте это и храните значения в конфигурации. - Если нет — настройте дефолтный retention на бакете, а инструмент пусть просто загружает объекты.
- Всегда валидируйте после заливки: проверьте метаданные версии (режим и дату удержания). Автоматизируйте проверку в CI/CD.
- Проводите регулярные тесты восстановления, в том числе из «холодных» классов и из DR-региона.
Практические рецепты: восстановление и хранение с Restic/Borg — бэкапы в S3 c Restic и Borg, а для синхронизации и верификации — rclone: синхронизация и проверка.
Мониторинг и аудит
Что имеет смысл отслеживать и логировать:
- Ошибки заливки с параметрами Object Lock (InvalidRequest, AccessDenied, InvalidRetentionPeriod).
- События установки/изменения retention и legal hold. Включите аудит API и регулярно просматривайте аномалии.
- Инвентаризация S3 с полями Object Lock, чтобы убедиться, что свежие объекты имеют корректные значения.
- Время сервера и клиента (NTP/chrony) — рассинхронизация даёт трудноотлавливаемые ошибки по датам.
Стоимость и эксплуатационные эффекты
Иммутабельность повышает предсказуемость RPO/RTO, но имеет цену:
- Версионность хранит каждую версию до окончания удержания: объёмы растут. Планируйте бюджет на хранение.
- Удаления отложены, Lifecycle не удалит раньше срока — будут «хвосты» хранения.
- Архивные классы удешевляют хранение, но увеличивают время восстановления; балансируйте.
Типичные ошибки и как их избежать
- Создали бакет без Object Lock «на попробовать», а потом решили включить. В большинстве реализаций нельзя. Сразу создавайте новый бакет с Object Lock, реплицируйте данные по префиксу, переключайте клиентов.
- Выдали право
s3:BypassGovernanceRetentionширокой роли. Уберите избыточные права, используйте Deny и принцип наименьших привилегий. - Ставите Compliance «навсегда», а потом понимаете, что нужно раньше удалить по GDPR/внутренним политикам. Для Compliance назад дороги нет. Используйте Governance там, где нужна управляемость.
- Не учли часовые пояса: клиент пишет дату удержания «сегодня до полуночи», а сервер трактует иначе. Всегда задавайте UTC и ISO 8601.
- Multipart upload без передачи параметров Object Lock на старте — итоговая версия окажется без удержания. Передавайте параметры при создании multipart-сессии.
Проверка: «стреляем по ноге» в безопасной среде
Перед боевым включением полезно сделать мини-runbook тестов:
- Залить объект с Governance и 7-дневным retention.
- Попробовать удалить с обычной ролью — получить отказ.
- Попробовать сократить retention — получить отказ.
- Продлить retention — получить успех.
- Включить Legal Hold и снова проверить удаление — отказ.
- Снять Legal Hold — убедиться, что удаление всё ещё запрещено до даты удержания.
Зафиксируйте результаты в документе и приложите к процедуре включения.
Чек-лист внедрения
- Определены классы бэкапов, сроки retention и режимы (Governance/Compliance).
- Созданы отдельные бакеты с Object Lock и включённым версионированием.
- Назначен дефолтный retention там, где нужно.
- Инструменты бэкапа умеют проставлять retention или используют дефолт.
- Политики доступа исключают
bypassи сокращение удержания. - Репликация переносит Object Lock на целевой бакет.
- Lifecycle согласован с retention и имеет буфер.
- Включён аудит событий и регулярная инвентаризация.
- Проведены тесты восстановления, в том числе из «холодных» классов и DR.
Итоги
S3 Object Lock — не серебряная пуля, но мощный и относительно простой способ зафиксировать гарантию неизменяемости бэкапов. Ключ к успеху — аккуратный дизайн (разделение классов данных и бакетов), строгие политики доступа, обязательные тесты и мониторинг. Начните с Governance и дефолтного 14–30-дневного retention для ежедневных копий, добавьте Compliance для долгоживущих архивов — и вы закроете критичный класс рисков без драматичных изменений в приложениях.


