Plan disaster recovery, który już działał — tylko nie potrafiliśmy tego udowodnić
Prośba
CTO platformy tradingowej przesłał wypełniony kwestionariusz disaster recovery oraz zewnętrzną ocenę zgodności usługi kopii zapasowych AWS z zasadami prowadzenia dokumentacji SEC. Przekaz był jasny: „zanim urośniemy dalej, czy faktycznie jesteśmy zabezpieczeni na wypadek katastrofy?”
W kwestionariuszu były prawdziwe liczby. Odtworzenie produkcyjnej bazy: poniżej godziny, nie więcej niż 60 minut utraconych danych. Środowiska staging i dev: okno czterech godzin wystarczy. Proces break-glass ograniczony do trzech wskazanych osób. Alerty tylko na Slacku — bez pagera, bez eskalacji dyżurowej. Odpowiedź „dwa tygodnie” na pytanie o retencję typu tak/nie, dziwnie kontrastująca z raportem zgodności, który wciąż powoływał się na wieloletnie regulacyjne okresy przechowywania.
Oczywisty następny krok wyglądał tak: zbudować kopie zapasowe, które spełnią te liczby.
Śledztwo
Pierwszy przystanek: samo repozytorium infrastructure-as-code. Grep wszystkiego, co dotyczy kopii zapasowych.
$ grep -rl "aws_backup\|backup_vault\|backup_plan\|vault_lock" . (no matches)
Zero. Żadnych vaultów AWS Backup, żadnych planów, nic. Na papierze wyglądało to na budowę od zera.
Potem faktyczne konfiguracje baz danych opowiedziały inną historię. Każda instancja bazy, w każdym środowisku, miała te same trzy ustawienia:
multi_az = true backup_retention_period = 7 # days deletion_protection = true
multi_az = true daje automatyczny failover w zakresie 60–120 sekund. Natywne automatyczne kopie już dają odtwarzanie do punktu w czasie z dokładnością do pięciu minut. Policz to wobec liczb samego CTO — odtworzenie poniżej godziny i utrata danych poniżej 60 minut dla produkcji, poniżej 4 godzin i 24 godzin dla reszty — i deklarowane cele były już spełnione, dziś, bez żadnych własnych narzędzi.
To zmieniło całe ujęcie problemu. To nie było „nie mamy disaster recovery”. To było „mamy disaster recovery, tylko nie mamy retencji dłuższej niż tydzień, zapisów odpornych na manipulację, kopii w innym regionie, roli break-glass ani sposobu, żeby udowodnić cokolwiek z tego audytorowi”. Zupełnie inny i dużo ciekawszy problem.
Pierwsza mina: zabezpieczenie, które po cichu odrzuciłoby „oczywistą” poprawkę
Platforma uruchamiała węzły walidatorów dla bazowej sieci blockchain — infrastrukturę z materiałem kluczy prywatnych uznanym za zbyt wrażliwy, żeby kiedykolwiek opuścił konto. Zabezpieczenie typu defense-in-depth, wdrażane niezależnie i już częściowo aktywne, blokowało dokładnie te wywołania API do snapshotów i kopiowania, których potrzebuje narzędzie do kopii zapasowych — konkretnie dla wszystkiego oznaczonego jako infrastruktura walidatorów.
To znaczyło, że niedbale ustawiony wybór „kopiuj wszystko z tym wzorcem tagów” w najlepszym razie po cichu pominąłby wolumeny walidatorów przy poprawnym zakresie — albo co noc generowałby ścianę alertów o nieudanych jobach przy zakresie z wildcardem. Tak czy inaczej, poleganie na tym zabezpieczeniu jako cichej siatce bezpieczeństwa było złą decyzją. Wybór kopii potrzebował własnego, jawnego wykluczenia, określonego na własnych warunkach, a nie „kontrola innego zespołu nas uratuje”. Dwie niezależne warstwy, celowo nadmiarowe — ten sam kształt, którego istniejące prace nad bezpieczeństwem używały już gdzie indziej.
Druga mina: budowa vaultu w złym momencie
Przegląd niedawnej historii ujawnił coś obok, ale krytycznego: trwającą migrację włączającą szyfrowanie storage na produkcyjnej bazie, jeszcze nieprzełączoną. Żywa, obecnie obsługująca ruch instancja nadal była nieszyfrowana; zaszyfrowany zamiennik istniał równolegle, pusty, czekający.
Oto pułapka: jeśli postawisz niezmienny, odporny na manipulację vault kopii teraz i skierujesz go na żywą bazę, pierwszy „trwały, dowodnie nienaruszony” punkt odtworzenia, jaki powstanie, będzie snapshotem nieszyfrowanej bazy — dokładnie tego, co migracja szyfrowania ma wycofać. Zablokuj to, a zabetonujesz zły artefakt.
Poprawka nie była techniczna, tylko dotyczyła kolejności: najpierw dokończyć przełączenie na szyfrowanie, potem skierować plan kopii na zaszyfrowaną instancję. Gdyby uznano pokrycie kopiami za zbyt pilne, żeby czekać, wyjściem awaryjnym była budowa na obecnej instancji z jawnym komentarzem w konfiguracji „tymczasowe, zostanie przekierowane” — nigdy nie pozwolić, żeby cel po cichu przesunął się przez przełączenie.
Trzecia mina: „trwały” nie znaczy tego, co myślisz
Raport zgodności wskazywał konkretny mechanizm retencji odpornej na manipulację: funkcję blokady z dwoma trybami. Jeden jest odwracalny przez uprawnioną osobę, logowany, audytowalny. Drugi nie jest odwracalny — ani przez właściciela konta, ani przez wsparcie samego dostawcy chmury, gdy minie okres karencji. Żadna funkcja nie pozwala na uprzywilejowane usunięcie. Kropka.
Skoro własna odpowiedź CTO o retencji wyglądała na niepełną odpowiedź na pytanie typu tak/nie — „dwa tygodnie” obok powołań na wieloletnie regulacyjne okna przechowywania — włączenie nieodwracalnego trybu teraz, z jakąkolwiek liczbą, było zakładem, którego nikt nie mógłby cofnąć. Zablokuj dwa tygodnie, a okaże się, że prawdziwy wymóg to siedem lat? Przycisku cofnij nie ma.
Rekomendacja brzmiała więc: na razie wszędzie tryb odwracalny. Logowany, audytowany, za tym samym procesem break-glass co wszystko inne. To uprawnione, dające się obronić stanowisko w docelowych ramach zgodności — nie słabsza namiastka „prawdziwej” odpowiedzi. Po prostu nie jest tym nieodwracalnym i nie stanie się nim, dopóki liczba retencji i dokładne zbiory zapisów, które jej wymagają, nie wrócą od osoby, do której należy ta decyzja.
Czwarta mina: jedno słowo kryjące strukturalną niespodziankę
Kwestionariusz pytał o staging i dev jako o jeden koszyk, a odpowiedź CTO mówiła, że powinny „dzielić vault”. Brzmi rozsądnie, dopóki nie sprawdzisz: staging i dev żyją w dwóch osobnych kontach chmurowych. „Współdzielony vault” między dwoma kontami to problem współdzielenia między kontami — polityki dostępu, joby kopiowania między kontami — a nie „skieruj dwie rzeczy na ten sam współdzielony zasób w jednym koncie”. Nic takiego nie istniało jeszcze nigdzie w infrastrukturze.
Zamiast po cichu budować bardziej skomplikowaną wersję, bo sugerowało ją sformułowanie kwestionariusza, wróciło to jako otwarte pytanie: czy „współdzielony” naprawdę znaczy między kontami, czy dwa identycznie skonfigurowane vaulty — po jednym na środowisko — spełnią faktyczny zamiar prościej? Czasem najszybszy sposób na uniknięcie przeinżynierowania to po prostu zapytać, co znaczyło dane słowo.
Zwrot akcji: czego naprawdę wymagało „przetrwanie awarii regionu”
CTO wprost zaznaczył niepewność, czy środowisko produkcyjne musi przetrwać awarię całego regionu chmury, i skłaniał się ku „raczej nie”. Kusiło, żeby się po prostu zgodzić i iść dalej. Ale uczciwa analiza wylądowała gdzieś pośrodku:
Pełny failover — żywy klaster w gotowości i replika bazy w drugim regionie, gotowe od razu przejąć ruch — nie był wart budowy. Faktyczna gwarancja dostępności platformy pochodziła z dziesiątek niezależnie hostowanych węzłów walidatorów, rozproszonych całkowicie poza infrastrukturą firmy; awaria regionu nie położyłaby sieci, tylko własną warstwę aplikacji firmy. A utrzymywanie częściowego stosu aplikacji w drugim regionie, który i tak nie dosięgnie zdrowej wersji tego, od czego zależy, rozwiązuje pół problemu za realny, stały koszt.
Ale zatrzymanie się na zerowej ochronie między regionami zostawiało prawdziwą lukę: prawdziwa utrata danych w jednym regionie oznaczałaby, że znikają też same kopie. Tani środek: automatycznie kopiować punkt odtworzenia każdej kopii do drugiego regionu. Tylko koszt storage — bez zapasowej mocy obliczeniowej, bez sieci między regionami do utrzymania. Nie poprawia czasu odtworzenia (odtwarzanie do świeżo zbudowanej infrastruktury w nowym regionie jest wolne), ale sprawia, że katastrofa regionu jest „w końcu odtwarzalna”, a nie „nieodtwarzalna”. Ujęte jawnie jako gwarancja odtworzenia, a nie failoveru, żeby nikt nie pomylił tego z czymś mocniejszym, niż jest.
Ostatnia luka: nie ma przycisku „3 osoby muszą zatwierdzić”
Projekt break-glass zakładał, że trzy wskazane osoby muszą wyrazić zgodę, zanim ktokolwiek odtworzy lub usunie produkcyjną kopię. Okazuje się, że systemy tożsamości w chmurze w ogóle nie mają do tego wbudowanego mechanizmu — przyjęcie roli to akcja jednego podmiotu i koniec. Nie ma warunku „wymagaj N współpodpisujących” do skonfigurowania.
Odpowiedź znowu była proceduralna, a nie techniczna: ograniczyć politykę zaufania roli dokładnie do tych trzech osób, wymagać uwierzytelniania wieloskładnikowego przy każdym przyjęciu roli i wymagać udokumentowanej, zalogowanej zgody wszystkich trzech na kanale incydentu, zanim ktokolwiek faktycznie przyjmie rolę — audytowanej po fakcie w dzienniku aktywności platformy, a nie blokowanej technicznym mechanizmem. Teoretycznie słabsze niż prawdziwy system kworum (nic nie powstrzyma jednej osoby przed pominięciem czekania), ale zgodne z tym, jak procesy break-glass mają działać w praktyce, i bez budowania własnej infrastruktury zatwierdzeń dla czegoś, co jest w gruncie rzeczy procesem ludzkim.
Jedno napięcie zostało zgłoszone, a nie rozwiązane: wymaganie wszystkich trzech, bez wyjścia awaryjnego, oznacza, że odtworzenie jest całkowicie zablokowane, jeśli choćby jedna osoba jest nieosiągalna w czasie prawdziwego incydentu — co samo mogłoby przekroczyć jednogodzinny cel odtworzenia, który ta zasada miała chronić. To nie jest decyzja, którą zespół infrastruktury może podjąć sam; wróciło to do CTO jako otwarte pytanie.
Wnioski
W tym podejściu nikt nie napisał ani linii kodu infrastruktury. Całe ćwiczenie to śledztwo i ustalanie kolejności: sprawdzić, co jest dziś faktycznie prawdą, zanim cokolwiek zbudujesz, odróżnić „liczby są już spełnione” od „liczby nie są udowodnione” i nie pozwolić, żeby niejednoznaczna odpowiedź w kwestionariuszu, kuszący skrót albo nieodwracalne ustawienie zostały rozstrzygnięte założeniem.
Wzorzec, który da się uogólnić poza ten jeden przypadek:
- Kiedy ktoś pyta „czy jesteśmy zabezpieczeni”, sprawdź, czy bazowy mechanizm już spełnia deklarowany cel, zanim sięgniesz po nowe narzędzie — prawdziwa luka to często retencja, niezmienność albo dowód, a nie sama szybkość odtworzenia.
- Każde zabezpieczenie z trybem nieodwracalnym to drzwi tylko w jedną stronę — nigdy go nie przełączaj, dopóki liczba za nim nie jest faktycznie ustalona, nawet pod presją „po prostu wybierz coś na razie”.
- Słowo takie jak „współdzielony” w odpowiedzi interesariusza może kryć prawdziwą złożoność strukturalną (tutaj: między kontami kontra w jednym koncie). Zapytaj, zanim zbudujesz kosztowną interpretację.
- Jeśli zabezpieczenie już blokuje niebezpieczny przypadek, to siatka bezpieczeństwa, a nie projekt — twoje własne narzędzia nadal powinny mieć poprawny zakres na własnych warunkach.
- Kolejność ma takie samo znaczenie jak projekt: stworzenie trwałego zapisu złego stanu pośredniego (tutaj: nieszyfrowanego snapshotu) to błąd, który się nawarstwia, a nie skrót.