---
document_id: PLAI_PHASE1_BACKUP_RESTORE_REHEARSAL
schema_version: 1
status: PREFLIGHT_ONLY_BLOCKED_SAFE
production_backup_executed: false
restore_executed: false
production_changes_applied: false
---

# Phase 1 암호화 backup과 격리 복원 rehearsal

## 현재 판정

Phase 1 실행은 아직 허용하지 않는다. 읽기 전용 preflight 결과를 먼저 만족해야 한다.

현재 확인된 blocker:

- Primary A와 물리적으로 독립된 recovery node와 backup root가 지정되지 않았다.
- offline encryption recipient와 manifest signing key ID가 지정되지 않았다.
- 격리 restore host가 지정되지 않았다.
- Windows Server Backup CLI와 유효한 production backup scheduled task가 확인되지 않았다.
- `vssadmin list shadows`의 관리자 실행은 shadow entry를 반환하지 않았다.

이 상태에서 plaintext dump를 만들거나 Primary A의 다른 drive를 독립 backup으로 간주하지 않는다.

MongoDB Database Tools `100.17.0`과 age `1.3.1`은 이제 `D:\aisfor-chain\tools\resilience` 아래에만 준비돼 있다. 시스템 PATH는 변경하지 않았고 preflight가 실행 파일 경로와 SHA-256을 고정해 확인한다. age ZIP은 공식 release가 게시한 SHA-256과 일치했다. MongoDB의 별도 `.sha256` endpoint는 HTTP 403을 반환했으므로 공식 archive URL, 내려받은 ZIP hash, 개별 실행 파일 hash와 `--version` 결과를 함께 기록했다. 이 도구 준비 과정에서는 DB 연결, dump 생성, age identity 생성, backup 전송을 수행하지 않았다.

또한 `D:\aisfor-chain\data`와 `runtime` 전체를 일반 backup 대상으로 삼지 않는다. 이 경로에는 protected operator custody, 과거 env snapshot, validator/runtime key material과 activation authority가 섞여 있다. Phase 1 plan은 `ledger.json`, canonical network/genesis public identity 파일만 allowlist하고 key/approval 경로는 명시적으로 제외한다. validator key custody backup은 기존 별도 승인 gate를 계속 따른다.

## 준비 파일

- Plan template: `config/resilienceBackupPlan.example.json`
- Read-only preflight: `scripts/resilience-phase1-preflight.js`
- PC local hardware collector: `scripts/resilience-pc-inventory-readonly.js`
- Recovery candidate local-ledger check: `scripts/resilience-node-candidate-readiness.js`
- Portable tool manifest: `tools/resilience/tool-manifest.json`

preflight는 DB에 연결하지 않고, network request와 file write를 하지 않는다.

```powershell
Set-Location D:\aisfor-chain
node scripts\resilience-phase1-preflight.js
```

정상적인 현재 기대값은 `SAFE_BLOCKED_MISSING_PREREQUISITES`다. `required_tools`는 통과했고 현재 실패 항목은 `independent_destination_named`, `encryption_recipient_named`, `restore_host_named` 세 개다. 이는 failure가 아니라 backup 실행을 차단하는 안전 동작이다.

## PC local inventory 수집

각 PC에서 다음 명령은 local hardware만 stdout으로 출력한다. 파일 저장, server 전송, public egress 조회, environment/secret 읽기를 하지 않는다.

```powershell
node scripts\resilience-pc-inventory-readonly.js `
  --pc-name=Ellia-Main-01 `
  --owner-label=ellia `
  --site-label=site-a `
  --network-domain=PC_EGRESS_A
```

출력의 `operatorAssertionsRequired`는 운영자가 실제 UPS, auto boot, site/ISP 독립성, NAT/VPN reachability를 확인한 뒤 별도 승인 evidence에서 채운다. collector의 SHA-256은 무결성 비교용이지 운영자 서명을 대신하지 않는다. 이후 전송은 기존 PC Sync device authentication과 signed update gate를 통해서만 추가한다.

`logicalCpuVisibleToProcess`는 OS 전체 CPU 수가 아니라 collector process에 보이는 수다. volume health가 `UNKNOWN_NON_ADMIN`이면 용량은 수집됐지만 관리자 storage health 검사가 아직 필요하다는 뜻이다.

## backup 실행 전 승인 gate

다음 조건을 모두 만족해야 실제 dump/archive 작업을 별도 승인할 수 있다.

1. MongoDB Database Tools 공식 binary와 SHA-256 고정
2. `age` 공식 binary와 SHA-256 고정
3. recovery node의 signed local inventory와 독립 site 판정
4. recovery root의 실제 free space가 source 총량 + 30% 이상
5. offline age recipient 등록; private key는 Primary A에 두지 않음
6. manifest signing key ID와 custody owner 지정
7. plaintext temporary archive가 정상·실패 모두 즉시 제거되는 cleanup/rollback 설계
8. Mongo dump 시점과 file snapshot 시점의 consistency window가 RPO 5분 안에 들어오는지 계획
9. restore host가 production DNS/API, push, OpenAI, TRON, validator network에 route되지 않음
10. restore service profile에서 reward, settlement, proof auto-submit, push, deletion, auto-confirm, revocation retry worker가 모두 fence 상태

## backup artifact 규약

각 dataset은 다음 순서를 따른다.

```text
read-only source capture
  -> SHA-256 file manifest
  -> encrypted archive to offline public recipient
  -> ciphertext SHA-256
  -> recovery node copy
  -> source/copy hash comparison
  -> plaintext cleanup proof
```

manifest에는 relative path, bytes, mtime, SHA-256, dataset classification, capture window와 tool version을 넣는다. absolute user path, URI credential, secret, private key는 넣지 않는다.

PC Sync chunk 계층에는 plaintext나 raw DB dump가 아니라 암호화가 끝난 ciphertext만 전달한다. 기존 stored/verify/restore-upload 흐름과 chunk hash를 재사용하되 production user media와 backup encryption key를 같은 node에 보관하지 않는다.

## 격리 restore 순서

1. recovery node에서 ciphertext와 manifest hash 확인
2. production route가 없는 restore host에서 offline private key로 복호화
3. 별도 Mongo port 기본값 `37017`에 restore
4. standby profile로 각 service를 production과 다른 port에 기동
5. health/readiness, DB count, session 안전 재로그인, media hash를 확인
6. worker·push·external provider·chain submission·validator가 모두 비활성인지 확인
7. 측정 RPO/RTO와 restore proof hash 기록
8. rehearsal 종료 후 plaintext와 test credential을 승인된 retention 정책에 따라 제거

격리 restore 성공은 production failover 승격 승인이 아니다. DNS나 traffic 전환은 Phase 4의 fencing·operator gate가 별도로 통과한 후에만 수행한다.

## TLS와 자동 시작 보완사항

- `Start PM2 Apps` scheduled task의 최근 result는 0이었다.
- `Start Nginx` task의 최근 result는 1이었지만 Nginx process는 snapshot 당시 online이었다. reboot recovery 원인은 별도 rehearsal이 필요하다.
- win-acme renewal task는 존재하지만 최근 result가 `0xFFFFFFFF`였다.
- 핵심 certificate 만료일은 2026-09-19부터 2026-10-22 사이였다.

인증서 갱신 task의 실패 원인을 해결하기 전에는 TLS를 recovery-ready로 판정하지 않는다. 이 문서 작성 중 task 실행·인증서 갱신·Nginx reload는 수행하지 않았다.
