Шифрування резервних копій Docker: захист секретів без порушення відновлення

Було корисно?

Найгірший час дізнатися, що ваші резервні копії «захищені», — під час відновлення. Другий за гіркістю час — під час аудиту, коли хтось спокійно питає, чому дампи виробничих баз даних лежать в об’єктному сховищі у відкритому вигляді з часовою міткою в імені файлу.

Docker полегшує доставку додатків. Він же робить простим зберегти не те, що потрібно, зашифрувати не в тому місці й виявити, що процес відновлення залежить від секрету, який жив лише на щойно втраченої машині. Це посібник для людей, які керують продуктивними системами і хочуть шифрування, що переживе реальні катастрофи — включно з людськими помилками.

Спочатку модель загроз, потім інструменти

«Зашифруйте резервні копії» — це не вимога; це нечітке бажання. Вимоги мають бути конкретними:
хто не повинен читати резервні копії, які відмови ви можете терпіти і як ви будете відновлювати, коли половина інфраструктури в вогні, а інша половина чекає на зміни за процедурою контролю.

Почніть із трьох поширених моделей загроз:

  • Компрометація хмарного сховища: витік облікових даних, неправильна політика бакета або недобросовісний внутрішній обліковий запис.
    Шифрування має завадити читанню даних навіть після ексфільтрації.
  • Вимагач / зломник на хості: атакуючий може читати локальні файли й, можливо, ваші скрипти резервного копіювання.
    Шифрування може допомогти або ні залежно від того, де зберігаються ключі.
  • Помилка оператора: найпоширеніше. Хтось завантажує «тимчасовий» дамп у спільне місце або змінює ключі без плану відновлення.
    Шифрування має зменшувати зону ураження, а відновлення має залишатися рутинною операцією.

Для Docker-середовищ операційна істина така: ви не «робите резервні копії Docker». Ви робите резервні копії даних за контейнерами і достатньо метаданих, щоб відтворити їх. Шифрування повинно охоплювати артефакт, який ви реально зберігаєте й переміщуєте — не лише диск, не лише транспорт і точно не «десь у стеку, де ми припускаємо шифрування».

Цікаві факти та історичний контекст

  • Факт 1: Ранні unix-методи резервного копіювання вважали стрічки «фізичною безпекою». Шифрування було рідкісним, бо стрічка зберігалася в запечатаному шафі — до першої помилки.
  • Факт 2: GPG (1990-ті) став стандартом «зашифрувати файл» для опсів, бо працював офлайн і на різних платформах, а не тому, що був простим.
  • Факт 3: Багато «невдач з шифруванням резервних копій» насправді — це відмови в доступності ключів: шифротекст нормальний; відновлення не може розшифрувати вчасно.
  • Факт 4: Компресія перед шифруванням — довгострокова найкраща практика, бо шифрування руйнує надмірність і робить компресію неефективною.
  • Факт 5: Поширення об’єктного сховища зробило «офсайтні бекапи» дешевими і звичними — але також випадкові публічні витоки стали регулярними заголовками індустрії.
  • Факт 6: Дедуплікація й шифрування давно в холодній війні: шифрування випадково рандомізує дані й може вбити ефективність dedupe, якщо не продумати дизайн.
  • Факт 7: Дивно багато команд все ще «зберігають контейнери» (образи) замість стану, а потім дивуються, чому база даних пуста після відновлення.
  • Факт 8: Ротація ключів старша за хмару. Складність завжди була в сумісності зі старими даними й передбачуваних ритуалах операцій.

Одна надійна перефразована ідея від Річарда Кука (інженерія стійкості): успіх і невдача часто походять від тієї самої повсякденної роботи; різниця — у контексті (парафраз).
Шифрування резервних копій — саме про це. Той самий конвеєр, що вас захищає, може і залишити вас у пастці — залежно від того, чи шлях відновлення був першокласною функцією.

Принципи: шифрувати, не ламаючи відновлення

1) Шифруйте артефакт, який ви зберігаєте, а не машину, яку б хотіли мати

Шифрування диска (LUKS, шифрування EBS у хмарі, зашифровані датасети ZFS) — хороша гігієна. Але резервні копії призначені для перенесення. Ви копіюватимете їх на інші машини, інші бакети, інші регіони, можливо — на ноутбук під час інциденту. Отже шифрування має «подорожувати» разом із резервною копією.

2) Шлях відновлення — це продукт

Якщо для розшифровки потрібен VPN до мертвого дата-центру — ви зробили пастку. Відновлення має працювати з чистого старту: новий хост, мінімальний набір інструментів, ключі доступні через контрольований, але доступний процес.

3) Віддавайте перевагу простим крипто-робочим процесам над хитромудрими

Складні ієрархії ключів і власні envelope-схеми можуть бути правильними й водночас нереально відновлюваними о 03:00.
Більшість команд працює краще з:

  • Один файл на артефакт резервної копії
  • Компресія, потім шифрування (потоково для великих об’єктів)
  • Шифрування на отримувача (без загальних паролів)
  • Документоване і протестоване отримання ключів

4) Розділяйте конфіденційність та цілісність, але перевіряйте обидва

Сучасні режими шифрування (і інструменти як age) забезпечують автентифіковане шифрування: конфіденційність плюс цілісність.
Проте треба перевіряти контрольну суму артефакту і тестувати розшифровку та відновлення. Німе корупцію краще виявити заздалегідь.

5) Плануйте втрату ключа, а не лише його крадіжку

Більшість організацій одержимі запобіганням крадіжці й ігнорують втрату. Втрата — це шлях до «ідеально безпечних» бекапів, які не можна відновити. Ваше керування ключами має мати:

  • Принаймні два незалежні шляхи відновлення (наприклад, два оператори або vault + break-glass)
  • Документовану ротацію
  • Логи доступу
  • Регулярні тренування з відновлення

Що робити резервні копії в Docker (і чого не треба)

Контейнери — це «cattle»; томи й зовнішні системи — це «pets», яких насправді потрібно зберігати. У термінах Docker ваш обсяг резервного копіювання зазвичай:

  • Іменовані томи (наприклад, каталог даних Postgres, завантаження додатків)
  • Bind mounts, де зберігається стан (уважно з правами й дрейфом шляхів)
  • Логічні дампи баз даних (pg_dump, mysqldump) або фізичні бекапи (pg_basebackup, xtrabackup)
  • Стан конфігурації: docker-compose.yml, env-файли (але ставтесь до секретів обережно), конфіги зворотного проксі
  • Секрети: не в git, зазвичай не в резервній копії, якщо немає окремої історії захисту

Часто люди помилково роблять резервні копії:

  • Шарів/образів контейнерів (їх можна відтворити; ще й образи можуть містити секрети, якщо ви неакуратно працюєте)
  • /var/lib/docker повністю (можливо, але крихке між версіями/драйверами зберігання; і це велике)
  • Кешів часу виконання (марнотратно і сповільнює відновлення)

Думка: робіть резервні копії даних і відновлювального визначення розгортання. Якщо ваше відновлення залежить від копіювання стану демонa Docker між хостами, ви вже домовляєтеся з хаосом.

Де шифрувати: у спокої, в польоті чи в конвеєрі

Шифрування транспорту (TLS)

Необхідно, але недостатньо. TLS захищає дані в дорозі, але кінцева точка все одно бачить відкритий текст. Якщо бакет буде скомпрометований пізніше, TLS не допоможе.

Шифрування на стороні сховища (SSE)

Серверне шифрування в стилі S3 (SSE-S3 або SSE-KMS) корисне, особливо для відповідності вимогам і щоб зменшити вплив «неправильного бакета». Але це означає, що провайдер зберігання може розшифрувати, і об’єкт зберігається в формі, яку можна розшифрувати, маючи відповідні повноваження. Це не end-to-end.

Клієнтське шифрування (шифрувати перед завантаженням)

Це стандартна рекомендація, якщо потрібно «тримати секрети в безпеці». Ви шифруєте артефакт локально і завантажуєте шифротекст. Навіть якщо сховище буде скомпрометоване, атакуючий отримає лише зашифровані бінарні об’єкти.

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

Вибір криптоінструментів: age, GPG, OpenSSL, S3 SSE

age: нудний у правильному сенсі

age — сучасний інструмент шифрування файлів, спроектований так, щоб ним було складно неправильно користуватися. Шифрування на отримувача просте, вихід детерміністичний для роботи, і він менш «містичний», ніж GPG.
Використовуйте його, коли потрібен чистий робочий процес і не потрібна повна екосистема PGP.

Випадок використання: щоденні зашифровані tar-архіви, потокові дампи баз даних, офсайтні копії.

GPG: потужний, але з гострими краями

gpg всюди і підтримує складне керування ключами. Також має борг складності: моделі довіри, keyring-и, pinentry, поведінка агента та людське непорозуміння.

Випадок використання: коли в організації вже є PGP-розповсюдження ключів і потрібна сумісність.

OpenSSL: гнучкий, але ним легко себе вбити

OpenSSL може шифрувати файли з паролем, але робочі процеси на основі пароля систематично зловживаються:
спільні секрети, слабкі паролі, паролі вбудовані в скрипти тощо. Якщо ви використовуєте OpenSSL, застосовуйте сучасні режими AEAD і тримайте паролі поза списками процесів і історією shell.

Серверне шифрування: добрий базовий рівень, не кінець історії

SSE корисне, особливо SSE-KMS з сильними межами IAM і логами аудиту. Але для сценаріїв «компрометації облікового запису хмари» клієнтське шифрування — сильніший підхід.

Жарт 1: Якщо ваш ключ для шифрування резервних копій знаходиться в тому ж бакеті, що й бекапи, ви не побудували безпеку — ви побудували тематичну квест-кімнату.

Керування ключами так, щоб не з’їло ваш вихідний вікенд

Виберіть модель ключів, якою ви зможете оперувати під стресом

Мета не «ніхто ніколи не може розшифрувати». Мета — «лише уповноважені можуть розшифрувати, і вони можуть зробити це під час інциденту без імпровізацій».

Рекомендовані патерни

  • Шифрування на отримувача (рекомендовано): age-recipients або GPG-публічні ключі. Шифруйте для кількох отримувачів
    (наприклад, ключ команди ops + break-glass ключ). Без спільних паролів. Немає єдиного вузького місця в людях.
  • Break-glass ключ офлайн: надрукований QR у сейфі або процес експорту, захищений HSM, залежно від вашого середовища.
    Суть — незалежність від виробничого хоста.
  • Vault/KMS для розповсюдження ключів, не обов’язково для шифрування: зберігайте приватний ключ або обгорнутий data key у системі з жорстким контролем доступу й логами аудиту.

Чого уникати

  • Єдиний пароль, який ділять у чаті (тепер він є в бекапі чату теж)
  • Ключі, збережені на тому ж хості без додаткового захисту
  • Ротація ключів без плану повторного шифрування (ви це помітите під час відновлення)
  • «Ми завжди можемо запитати Олю» залежність (Оля йде у відпустку або звільняється)

Ротація ключів: робіть її, не ламаючи старі відновлення

Ротація потребує вікна сумісності. Тримайте старі приватні ключі доступними (під контролем), поки всі бекапи, зашифровані ними, не прострочаться. Якщо потрібно відкликати доступ, перешифруйте утримувані архіви і зафіксуйте, який ID ключа шифрував який об’єкт.

Практичні конвеєри зашифрованих бекапів (з шляхами відновлення)

Конвеєр A: знімок тому → tar → стиснення → age → завантаження

Це робочий кінь для випадків «іменований том містить файли». Не гарантує консистентності бази даних, якщо додаток змінює файли під час копіювання. Для баз даних надавайте перевагу нативним бекапам СУБД.

Конвеєр B: логічний дамп Postgres, стримінг і шифрування

Для багатьох організацій pg_dump — золота середина: консистентна знімка, переносима, і її можна стримити, щоб відкритий текст не з’являвся на диску. Потім шифруйте й відправляйте.

Конвеєр C: об’єктне сховище з SSE-KMS плюс клієнтське шифрування

Багаторівневий захист — нормальна практика. SSE-KMS дає контролі на стороні провайдера й логи аудиту; клієнтське шифрування дає гарант, що при компрометації бакета атакуючий отримає шифротекст.

Думки щодо шляху відновлення

Для кожного конвеєра задокументуйте:

  • Де зберігається зашифрований артефакт
  • Як його отримати (які облікові дані і хто ними володіє)
  • Як отримати ключ розшифровки (основний і break-glass)
  • Як перевірити цілісність (контрольна сума/підпис)
  • Як відновити у чистому Docker-середовищі

12+ реальних завдань: команди, виводи та рішення

Це ті перевірки, які ви виконуєте при побудові системи або при дебагу, чому відновлення повільне, не вдається або підозріло «успішне», але з пропущеними даними.
Кожне завдання включає: команду, що означає вивід, і рішення, яке ви приймаєте.

Завдання 1: Перелічити контейнери й визначити stateful

cr0x@server:~$ docker ps --format 'table {{.Names}}\t{{.Image}}\t{{.Status}}'
NAMES                 IMAGE                 STATUS
pg                     postgres:16          Up 3 days
app                    myco/app:2.8.1       Up 3 days
nginx                  nginx:1.25           Up 3 days

Значення: Шукаєте бази даних, файлові сховища, черги — все, що має стан.
Рішення: Позначте pg і, ймовірно, app як такі, що потребують бекапів понад простого перевидання образів.

Завдання 2: Перелічити томи й зіставити їх з контейнерами

cr0x@server:~$ docker volume ls
DRIVER    VOLUME NAME
local     pg_data
local     app_uploads
cr0x@server:~$ docker inspect pg --format '{{json .Mounts}}'
[{"Type":"volume","Name":"pg_data","Source":"/var/lib/docker/volumes/pg_data/_data","Destination":"/var/lib/postgresql/data","Driver":"local","Mode":"z","RW":true,"Propagation":""}]

Значення: pg_data — іменований том; бекап цієї директорії «в сирому вигляді» ризикує неконсистентністю, якщо база працює, або поки ви не зупините DB або не використаєте нативні бекапи.
Рішення: Використовуйте pg_dump або pg_basebackup замість простого tar-архівування pg_data під час роботи.

Завдання 3: Перевірити наявність Docker Compose і версійність

cr0x@server:~$ ls -l /srv/app/docker-compose.yml
-rw-r--r-- 1 root root 2481 Jan  2 09:41 /srv/app/docker-compose.yml

Значення: Ви можете відтворити стек. Без цього відновлення перетворюється на археологію.
Рішення: Зберігайте файли compose в контролі версій; тримайте секрети ззовні або використовуйте зовнішні сховища секретів.

Завдання 4: Підтвердити звідки приходять секрети (env змінні чи файли)

cr0x@server:~$ docker inspect app --format '{{range .Config.Env}}{{println .}}{{end}}' | grep -E 'PASSWORD|TOKEN|SECRET' || true
DATABASE_URL=postgres://app:REDACTED@pg:5432/app
JWT_SECRET=REDACTED

Значення: Якщо секрети живуть у env-змінних, вони можуть витікнути через діагностику, дампи аварій і надто «допоміжні» скрипти.
Рішення: Вирішіть, чи мають резервні копії містити секрети. Зазвичай: ні. Резервуйте дані; відновлюйте секрети окремим контрольованим шляхом.

Завдання 5: Створити пару ключів age (робоча станція оператора або захищений хост)

cr0x@server:~$ age-keygen -o /secure/keys/backup.agekey
Public key: age1k8t6y7z8n6k5m2p9k4d3s2q1w0e9r8t7y6u5i4o3p2a1s0d9f8g7h6j

Значення: Тепер у вас є публічний ключ отримувача (його можна поширювати) і приватний ключ (ставтеся як до break-glass артефакту).
Рішення: Зберігайте приватний ключ поза Docker-хостом і поза місцем зберігання бекапів. Шифруйте для кількох отримувачів, якщо можливо.

Завдання 6: Зашифрувати невеликий тестовий файл і перевірити розшифровку

cr0x@server:~$ printf "hello-restore\n" > /tmp/restore-test.txt
cr0x@server:~$ age -r age1k8t6y7z8n6k5m2p9k4d3s2q1w0e9r8t7y6u5i4o3p2a1s0d9f8g7h6j -o /tmp/restore-test.txt.age /tmp/restore-test.txt
cr0x@server:~$ age -d -i /secure/keys/backup.agekey -o /tmp/restore-test.out /tmp/restore-test.txt.age
cr0x@server:~$ cat /tmp/restore-test.out
hello-restore

Значення: Ключ дійсний, інструменти працюють, і розшифровка не є «проблемою майбутнього себе».
Рішення: Впровадьте встановлення age в середовище відновлення або тримайте відомий робочий статичний бінарний файл доступним.

Завдання 7: Стримити дамп Postgres і зашифрувати його (без відкритого файлу на диску)

cr0x@server:~$ docker exec -i pg pg_dump -U postgres -d app --format=custom | age -r age1k8t6y7z8n6k5m2p9k4d3s2q1w0e9r8t7y6u5i4o3p2a1s0d9f8g7h6j -o /backups/app_pg.dump.age
cr0x@server:~$ ls -lh /backups/app_pg.dump.age
-rw-r--r-- 1 root root 192M Jan  3 01:00 /backups/app_pg.dump.age

Значення: Ви отримали зашифрований артефакт. Дамп пройшов через pipe; хост не зберіг відкритий текст на диску.
Рішення: Використовуйте стримінг для великих чутливих бекапів; зменшуйте проблему «залишків відкритого тексту».

Завдання 8: Перевірити, що можна розшифрувати та відновити дамп у чистій базі

cr0x@server:~$ docker run --rm -d --name pg-restore -e POSTGRES_PASSWORD=restore -p 5433:5432 postgres:16
d4b2f8f15c65f6b6f8b0b76d1cc9d9d2a2b0a6f0d3f0d8f9a1c2b3d4e5f6a7b8
cr0x@server:~$ age -d -i /secure/keys/backup.agekey /backups/app_pg.dump.age | pg_restore -h 127.0.0.1 -p 5433 -U postgres -d postgres --clean --if-exists
Password:

Значення: Це доводить шлях відновлення від початку до кінця, а не тільки шифрування.
Рішення: Зробіть це регулярним прогоном. Якщо ви не можете відновити в чистий інстанс, у вас не бекапи — у вас артефакти.

Завдання 9: Зробити бекап не-DB тому tar + стиснення + шифрування

cr0x@server:~$ docker run --rm -v app_uploads:/data:ro -v /backups:/out alpine:3.20 sh -c "cd /data && tar -cf - . | gzip -1" | age -r age1k8t6y7z8n6k5m2p9k4d3s2q1w0e9r8t7y6u5i4o3p2a1s0d9f8g7h6j -o /backups/app_uploads.tgz.age
cr0x@server:~$ file /backups/app_uploads.tgz.age
/backups/app_uploads.tgz.age: age encrypted file

Значення: Ви створили переносний зашифрований архів файлових даних.
Рішення: Для файлових томів це підходить. Для баз даних не робіть цього під час роботи DB, якщо у вас немає механізму забезпечення консистентності.

Завдання 10: Відновити зашифрований tarball у новий пустий том

cr0x@server:~$ docker volume create app_uploads_restore
app_uploads_restore
cr0x@server:~$ age -d -i /secure/keys/backup.agekey /backups/app_uploads.tgz.age | gunzip -c | docker run --rm -i -v app_uploads_restore:/restore alpine:3.20 sh -c "cd /restore && tar -xvf - | head"
./
./avatars/
./avatars/u123.png
./docs/
./docs/terms.pdf

Значення: Дані відновлюються і потрапляють у Docker-том.
Рішення: Спочатку відновлюйте в том для перевірки, а потім підміняйте. Прямі відновлення в живі томи — шлях від маленького інциденту до великого.

Завдання 11: Завантажити зашифровані бекапи в S3-сумісне сховище і підтвердити статус SSE

cr0x@server:~$ aws s3 cp /backups/app_pg.dump.age s3://prod-backups/app_pg/2026-01-03/app_pg.dump.age --sse aws:kms
upload: backups/app_pg.dump.age to s3://prod-backups/app_pg/2026-01-03/app_pg.dump.age
cr0x@server:~$ aws s3api head-object --bucket prod-backups --key app_pg/2026-01-03/app_pg.dump.age --query '{Size:ContentLength,SSE:ServerSideEncryption,KMS:SSEKMSKeyId}'
{
    "Size": 201326592,
    "SSE": "aws:kms",
    "KMS": "arn:aws:kms:us-east-1:111122223333:key/REDACTED"
}

Значення: Об’єкт — шифротекст від клієнтського шифрування, і додатково захищений SSE-KMS.
Рішення: Тримайте SSE увімкненим. Воно не замінить клієнтське шифрування, але додає запобіжники й сліди аудиту.

Завдання 12: Згенерувати й зберегти маніфест контрольних сум для перевірки цілісності

cr0x@server:~$ sha256sum /backups/app_pg.dump.age /backups/app_uploads.tgz.age > /backups/manifest.sha256
cr0x@server:~$ cat /backups/manifest.sha256
2f9e0f1c0a8c5d4b3e2a1f0e9d8c7b6a5f4e3d2c1b0a9e8d7c6b5a4f3e2d1c0b  /backups/app_pg.dump.age
9a8b7c6d5e4f3a2b1c0d9e8f7a6b5c4d3e2f1a0b9c8d7e6f5a4b3c2d1e0f9a8b  /backups/app_uploads.tgz.age

Значення: Ви можете виявити корупцію або часткові передачі до того, як намагатися відновити.
Рішення: Зберігайте маніфест поруч з бекапами (і бажано також у окремій системі логів). Перевіряйте перед розшифровкою великих файлів.

Завдання 13: Перевірити, що розмір віддаленого об’єкта відповідає локальному перед відновленням

cr0x@server:~$ aws s3 ls s3://prod-backups/app_pg/2026-01-03/app_pg.dump.age
2026-01-03 01:02:11  201326592 app_pg.dump.age

Значення: Розмір відповідає очікуваному; це не гарантія, але ловить очевидні усічення.
Рішення: Якщо розмір не збігається, зупиніться. Досліджуйте передачу, баги multipart upload, правила життєвого циклу або корупцію на стороні сховища.

Завдання 14: Перевірити політику життєвого циклу/незмінності (опір вимагачам)

cr0x@server:~$ aws s3api get-bucket-versioning --bucket prod-backups
{
    "Status": "Enabled"
}
cr0x@server:~$ aws s3api get-object-lock-configuration --bucket prod-backups
{
    "ObjectLockConfiguration": {
        "ObjectLockEnabled": "Enabled",
        "Rule": {
            "DefaultRetention": {
                "Mode": "GOVERNANCE",
                "Days": 30
            }
        }
    }
}

Значення: Версіонування і object lock зменшують ймовірність, що атакуючий (або скрипт) видалить вашу єдину хорошу копію.
Рішення: Якщо можете увімкнути незмінність — зробіть це. Шифрування захищає конфіденційність; незмінність — існування.

Завдання 15: Підтвердити, що середовище відновлення має потрібні інструменти перед початком

cr0x@server:~$ age --version
age 1.2.0
cr0x@server:~$ pg_restore --version
pg_restore (PostgreSQL) 16.1
cr0x@server:~$ docker --version
Docker version 24.0.7, build afdd53b

Значення: Сумісність інструментів — класична причина відмов відновлення, особливо з утилітами відновлення баз даних.
Рішення: Тримайте відомий робочий образ відновлення або рукопис із вказівкою версій. Не виявляйте невідповідності під час інциденту.

Швидкий плейбук діагностики

Коли зашифровані бекапи «повільні», або відновлення «зависає», зазвичай винне одне з чотирьох вузьких місць: CPU, диск, мережа або фаза застосування в базі даних.
Не гадайте. Перевіряйте в такому порядку і зупиняйтеся, щойно знайдете фактор, що обмежує.

1) Підтвердьте, що ви відновлюєте правильний артефакт (і він повний)

  • Перевірте, що розмір віддаленого об’єкта відповідає очікуванням.
  • Перевірте маніфест контрольних сум.
  • Рішення: якщо цілісність невідома, не починайте відновлення в живу ціль.

2) Визначте, яка фаза повільна: завантаження, розшифровка, розпакування чи застосування

  • Заміряйте час для кожного сегмента простими конвеєрами.
  • Рішення: оптимізуйте там, де реально витрачається час; шифрування часто не є головним підозрюваним.

3) Перевірте завантаження CPU і міфи про нестачу ентропії

  • Сучасні системи рідко «чекають ентропії» при звичайному використанні age/GPG; зазвичай CPU — підозрюваний.
  • Рішення: якщо CPU завантажений, розгляньте паралелізм або швидші налаштування стиснення, а не слабше шифрування.

4) Перевірте диск I/O і поведінку файлової системи

  • Цілі відновлення можуть бути повільніші за джерела, особливо при мережевому зберіганні.
  • Рішення: відновлюйте на швидке локальне сховище, а потім переміщуйте/приєднуйте, якщо можливо.

5) Для баз даних: фаза застосування домінує

  • pg_restore та створення індексів можуть перебити час завантаження/розшифровки.
  • Рішення: налаштуйте опції відновлення (jobs, maintenance settings) і перевірте WAL/checkpoint налаштування для середовища відновлення.

Поширені помилки (симптоми → причина → виправлення)

Помилка 1: «Decrypt failed: no identity found» під час відновлення

Симптоми: age відмовляється розшифрувати; відновлення заблоковано негайно.
Причина: Ви зашифрували для невірного отримувача, втратили приватний ключ або хост відновлення не має доступу до файлу identity.
Виправлення: Шифруйте для кількох отримувачів (ключ команди + break-glass). Зберігайте процедуру отримання identity в рукописі. Тестуйте розшифровку щотижня з невеликим артефактом.

Помилка 2: Бекапи є, але відновлення дає порожній стан додатка

Симптоми: Додаток піднімається після відновлення, але немає користувачів/файлів/даних.
Причина: Ви робили бекапи образів/compose, але не томів чи дампів БД; або відновили лише одну зі складових стану.
Виправлення: Визначте інвентар бекапів: БД + завантаження + конфіг. Проводьте відновлення, що перевіряє коректність на рівні додатка (а не тільки «контейнер запущено»).

Помилка 3: Зашифровані бекапи величезні й повільні у переміщенні

Симптоми: Вікна передачі пропадають; витрати на зберігання ростуть.
Причина: Шифрування без компресії витрачає місце; також бекап занадто багато (логи, кеші).
Виправлення: Стискайте перед шифруванням; виключайте некритичні шляхи; розгляньте нативну компресію БД або спеціальні формати.

Помилка 4: «Ми використовуємо SSE-KMS, тож ми в безпеці» (доки акаунт не скомпрометовано)

Симптоми: Аудит проходить, але модель загроз не в порядку; скомпрометований IAM-принципал може отримати і розшифрувати.
Причина: Покладання лише на серверне шифрування і віра в непохитність IAM.
Виправлення: Додайте клієнтське шифрування. Розглядайте компрометацію хмарного облікового запису як реальний сценарій, а не теоретичний.

Помилка 5: Шифрування на паролі, вбудованому в скрипти

Симптоми: Кожен, хто має доступ до скрипта, списку процесів або CI-логів, може розшифрувати бекапи.
Причина: Операційна зручність перемогла безпеку.
Виправлення: Перейдіть на шифрування для отримувачів. Якщо мусите використовувати паролі, отримуйте їх безпечно під час виконання і тримайте поза логами й історією shell.

Помилка 6: Tar-бекапи томів живих баз даних

Симптоми: Відновлення завершилося, але БД пошкоджена або неконсистентна; іноді «працює», але потім падає.
Причина: Захоплення файлової системи змінної бази без snapshot-ів або координації з БД.
Виправлення: Використовуйте pg_dump, pg_basebackup або механізми знімків, скоординовані з БД. Не tar-архівуйте живі каталоги БД.

Помилка 7: Ротація ключів ламає доступ до старих бекапів

Симптоми: Нові бекапи розшифровуються; старі — ні; вимоги зберігання створюють проблему.
Причина: Відмовилися від старих ключів без плану з урахуванням термінів зберігання.
Виправлення: Зберігайте старі ключі під суворим контролем, поки старі бекапи не прострочаться, або перешифровуйте утримувані архіви у рамках ротації.

Три корпоративні міні-історії з практики

Міні-історія 1: Інцидент через хибне припущення

Середня компанія працювала зі стеком Docker Compose: Postgres, веб-додаток і том для завантажень. У них були «зашифровані бекапи», бо VM-диск був зашифрований і S3-бакет вимагав SSE-KMS. Робота бекапів копіювала нічний pg_dump у бакет. Все проходило аудит. Усі спокійно спали.

Потім ключі доступу розробника до хмари витекли через неправильну конфігурацію CI-джоба. Атакуючий не мусив ламати шифрування. Маючи ті ключі, він перелічив бакет, скачав дампи і — оскільки IAM це дозволяв — завантажив їх. SSE-KMS виконало свою роль як задумано: воно розшифрувало для уповноваженого принципала.

Неправильне припущення команди було тонким: «серверне шифрування означає, що компрометація сховища не дозволить читати бекапи». Це правда лише якщо атакуючий не може стати принципалом, якого сервіс визнає. У хмарних середовищах компрометація облікових даних — ключова загроза.

Виправлення — клієнтське шифрування за ключами, недоступними для скомпрометованого оточення. Вони зашифрували дампи ключами отримувачів, що зберігалися поза хмарним акаунтом, і завантажили шифротекст. Атакуючий міг вкрасти об’єкти, але це було лише дорогим шумом.

Міні-історія 2: Оптимізація, що повернулась боком

Інша організація хотіла пришвидшити бекапи. Вони помітили, що компресія займає час, і вирішили «оптимізувати» — шифрувати спочатку, потім стиснути. Ідея звучала правдоподібно для нефахівців зі зберігання: «шифрування зменшить дані; компресія ще більше їх скоротить». Насправді це навпаки.

Їхні артефакти роздмухалися. Час передачі подвоївся. Витрати повільно зростали, поки фінанси не помітили. Час відновлення теж погіршився, бо треба було переносити більші об’єкти перед початком розшифровки та застосування.

Глибша проблема: вони також втратили будь-яку ефективність дедуплікації в нижчих шарах, бо шифрування зробило потік випадковим. Вони непомітно примусили «унікальні байти щодня», що системи зберігання інтерпретують як «будь ласка, стягніть плату за все».

Вони відкотилися до compress-then-encrypt з низьким рівнем компресії для стримінгу. Бекапи стали менші, передачі стабілізувалися, відновлення прискорилося, і ніхто більше не прикидався, що початкову зміну було «експериментом» (вона була).

Міні-історія 3: Нудна, але правильна практика, що врятувала день

Регульований бізнес розгорнув сервіси в Docker на парі хостів. Нічого надзвичайного. Вони робили одне непопулярне: щомісячний прогін відновлення.
Не таблиця. Реальне відновлення в тимчасове середовище, з чек-листом і часовими рамками.

Вони також мали два шляхи розшифровки: нормальний ключ у внутрішній системі секретів з RBAC і break-glass приватний ключ офлайн з документованою процедурою отримання, що вимагала двох людей. Це було дратівливо, що і вказує на те, що це працювало.

Під час інциденту — відмова сховища і складний ребілд хоста — вони виявили, що система секретів тимчасово недоступна через побічні мережеві роботи. Саме тут багато команд застрягає і починає імпровізувати. Вони не імпровізували. Вони викликали break-glass, розшифрували бекапи, відновили Postgres і завантаження, і повернули бізнес в роботу.

Після інциденту постмортем був спокійним. Не через удачу, а тому що шлях відновлення не був теоретичним. Він був пропрацьований, заміряний і навмисно нудний.

Жарт 2: Бекапи як парашути — якщо ви тестуєте їх тільки в лабораторії, ви все ще робите «дослідження», а не забезпечуєте безпеку.

Чек-листи / покроковий план

Покроково: впровадити зашифровані бекапи для Docker Compose стека

  1. Інвентар стану: перелічіть контейнери, томи, bind mount-и та зовнішні залежності (БД, об’єктні сховища).
    Визначте, що означає «відновлення закінчено» на рівні додатка.
  2. Виберіть основний метод бекапу для кожного компонента:

    • Postgres: pg_dump для портативності; pg_basebackup для швидшого відновлення великих баз (з більшою складністю).
    • Завантаження/файли: tar+gzip із тому.
  3. Виберіть інструмент і модель шифрування: рекомендується age; шифруйте для кількох отримувачів.
  4. Спроектуйте опіку за ключами: де зберігаються приватні ключі, хто має доступ і шлях break-glass.
  5. Реалізуйте стримінгові конвеєри: мінімізуйте відкритий текст на диску.
  6. Згенеруйте метадані цілісності: маніфести контрольних сум; за потреби підписуйте маніфести для сильної довірчості.
  7. Відправляйте поза сайтом: об’єктне сховище з версіонуванням і object lock, якщо доступно.
  8. Тестуйте відновлення: відновіть у свіжий контейнер/том, перевірте поведінку додатка й кількості записів.
  9. Плануйте прогони відновлення: щомісяця для критичних систем; щокварталу мінімум для менш критичних.
  10. Логування й оповіщення про відмови бекапу: «мовчазна відмова» — типовий стан для покинутих скриптів.

Операційний чек-лист: перед ротацією ключів

  • Перелічіть, які об’єкти бекапів зашифровані яким ключем (зберігайте ID ключів/отримувачів у метаданих).
  • Визначте терміни зберігання і переконайтеся, що старі ключі доступні, поки дані не прострочаться або не будуть перешифровані.
  • Виконайте відновлення за «старим ключем» тиждень перед ротацією.
  • Проведіть ротацію ключів, потім негайно зробіть відновлення за «новим ключем».
  • Оновіть рукопис, а не тільки код.

Чек-лист для інциденту: потрібно відновити зараз

  • Виберіть точку відновлення (RPO) і підтвердьте, що вона відповідає бізнес-потребам.
  • Отримайте артефакт і перевірте контрольну суму/розмір перед розшифровкою.
  • Отримайте ключ розшифровки основним шляхом; якщо заблоковано — викликайте break-glass.
  • Відновлюйте у чисті цілі (нові томи / новий екземпляр БД).
  • Підтвердіть на рівні додатка (логіни, кількість записів, критичні сценарії).
  • Тільки потім перемикайте трафік.

FAQ

1) Чи покладатися на шифрування диска (LUKS/EBS) для бекапів?

Ні. Використовуйте його, але не покладайтеся лише на нього. Шифрування диска захищає диск. Резервні копії переміщуються. Шифруйте сам артефакт бекапу, щоб захист «подорожував» разом із ним.

2) Чи достатньо серверного шифрування (SSE-KMS)?

Це сильний базовий рівень і часто обов’язковий, але це не end-to-end. Якщо атакуючий отримує доступ IAM, який дозволяє читання, SSE з радістю розшифрує для нього.
Додайте клієнтське шифрування для сценаріїв «компрометації акаунту/бакета».

3) age чи GPG для бекапів Docker?

Якщо починаєте з нуля, оберіть age. Він простіший і складніше ним користуватися неправильно. Використовуйте GPG, якщо в організації вже є PGP-розповсюдження ключів і операційна експертиза.

4) Де зберігати приватний ключ для розшифровки бекапів?

Не на Docker-хості і не поруч із бекапами. Зберігайте в контрольованій системі секретів з логами аудиту, а також офлайн-копію break-glass з документованою процедурою отримання.

5) Чи мають бекапи містити секрете додатку?

Зазвичай — ні. Зберігайте дані й конфігурацію, потрібну для повторного розгортання, а секрети відновлюйте з окремої системи. Якщо мусите робити бекап секретів, ставтеся до такого бекапу як до підвищеної чутливості і ізольовуйте доступ.

6) Як уникнути появи відкритого тексту на диску під час бекапу?

Стриміть: dump → compress → encrypt → upload. Pipe — ваш друг. Перевірте, що проміжні тимчасові файли не створюєте інструментами і що логи не фіксують чутливий вміст.

7) Чи захищають зашифровані бекапи від вимагачів?

Шифрування заважає несанкціонованому читанню; воно не запобігає видаленню або шифруванню атакуючим. Для опору вимагачам потрібна незмінність (object lock, версіонування, офлайн-копії) і сильні межі IAM.

8) Чому відновлення повільне, хоча шифрування «швидке»?

Тому що відновлення зазвичай домінують часом завантаження, розпакування або застосування в базі даних/перебудови індексів. Заміряйте кожну фазу. Оптимізуйте реальне вузьке місце, а не інструмент, якого підозрюєте.

9) Скільки отримувачів шифрування вибрати?

Принаймні двох: ключ команди ops (або сервісний ключ) і break-glass ключ для відновлення. Більше отримувачів дає гнучкість, але розширює коло тих, хто може розшифрувати, тому робіть це свідомо.

10) Чи можна зробити бекап /var/lib/docker і вважати справу зробленою?

Можна, але, швидше за все, не варто. Це велике, чутливе до версій і змішує кеші зі станом. Резервуйте томи і нативні артефакти баз даних; тримайте стан демонa Docker поза бекапами, якщо немає доведеної потреби.

Висновок: наступні кроки, які ви реально можете зробити

Якщо ви хочете зашифровані резервні копії Docker, які відновлюються чисто, перестаньте ставитися до шифрування як до пункту у чек-листі і почніть розглядати відновлення як фічу.
Практичний шлях:

  • Інвентаризуйте стан: томи, bind mount-и, бази даних і «приховані» залежності.
  • Для баз даних використовуйте нативні бекапи; для файлів — tar томів.
  • Стисніть, потім зашифруйте (стримінг де можливо).
  • Використовуйте шифрування на отримувача (age — надійний дефолт).
  • Тримайте ключі поза хостом; надайте break-glass шлях, незалежний і документований.
  • Робіть прогони відновлення регулярно і вимірювано.
  • Додайте незмінність/версіонування, щоб захистити існування бекапів, а не тільки конфіденційність.

Виконайте це, і ваше наступне відновлення не буде трилером. Це буде робота. Нудна робота. Найкраща.

← Попередня
Antennagate: коли тримання телефону стало заголовком
Наступна →
Ariane 5 і перетворення числа, яке знищило ракету

Залишити коментар