Files
platform-core/bootstrap/manual/k3s-secret-encryption-restore-drill.md

6.9 KiB

k3s Secret 암호화 복구 drill

이 문서는 승인된 k3s Secret hardening의 post recovery bundle을 실제 복구할 수 있는지 검증하고, 파기 확인 뒤 운영 host에 비민감 evidence를 등록하는 수동 진입점이다. 운영 server에서 restore를 실행하는 runbook이 아니며 서비스, datastore, backup 또는 Secret을 자동으로 변경하지 않는다.

승인과 책임 경계

  • 운영 장애 복구와 drill은 서로 다른 변경 승인으로 다룬다.
  • SQLite와 embedded etcd restore 명령은 이 저장소의 자동 실행 스크립트로 제공하지 않는다.
  • drill은 운영 host와 network, datastore, hostname이 격리된 일회용 VM/host에서 post bundle 복사본으로만 한다.
  • recovery bundle에는 복구·복호화에 필요한 자료가 함께 있으므로 bundle 전체를 Secret으로 취급한다. 경로, token/config 내용, payload, hash와 escrow 위치를 terminal 결과나 원장에 기록하지 않는다.
  • result만 반출하고 일회용 환경과 bundle 복사본을 파기한 뒤 운영 host에서 evidence를 등록한다.

backend별 수동 복구 기준

SQLite 장애 복구 순서는 k3s 중지, 현재 DB의 timestamp quarantine 이동, 같은 server token·config와 검증된 backup DB 복원, k3s 시작이다. 현재 DB를 즉시 삭제하거나 backup으로 덮어쓰지 않는다. 모든 단계는 별도 승인된 장애 runbook에서 사람이 대상과 rollback 지점을 확인한다.

embedded etcd는 현재 K3s 공식 --cluster-reset-restore-path snapshot 복구 절차를 사용한다. 단일 server와 다중 server 절차, token/config 일치 조건, reset 후 정상 시작 조건을 실행 시점의 공식 문서와 다시 대조한다. 보조 tutorial을 복구 권위로 사용하지 않는다.

일회용 환경의 격리 조건

복구 전에 다음 조건을 모두 만족시킨다.

  • 운영 server와 다른 hostname, network와 datastore를 사용한다.
  • hypervisor private switch 또는 network namespace에 default route와 upstream DNS가 없다.
  • 원본 운영 API/datastore로 향하는 route가 없다.
  • host firewall egress가 default-deny다.
  • LAN, Internet, Slack, AIStor와 운영 API 연결 시험이 모두 실패한다.
  • 복구된 workload/controller가 격리망 밖으로 통신할 수 없고 외부 host port를 열 수 없다.
  • 운영과 같은 정확한 k3s version, server token과 config를 post bundle 복사본에서 사용한다.

복구 뒤에는 다음을 확인한다.

  • k3s API ready
  • node Ready
  • encryption status가 Enabled/reencrypt_finished
  • server hash와 local integrity가 모두 일치
  • kubectl get secrets --all-namespaces -o json 조회가 오류 없이 완료
  • bundle metadata의 복구 전 전체 Secret object count와 복구 후 count가 일치
  • 위 격리 연결 시험을 다시 실행해 모두 실패

격리 조건과 live 검사가 모두 끝나기 전에는 result의 isolation=pass를 만들지 않는다.

세 mode 사용

모든 mode는 먼저 일반 사용자의 현재 kube context를 확정한다. 전체 script를 sudo로 실행하지 않는다. root 권한은 운영 host의 권위 파일 stat/read/install에만 좁게 사용되므로 필요하면 같은 terminal에서 사전에 sudo credential을 갱신한다.

격리 복구 host에서 post metadata와 결과 출력 위치를 직접 지정한다. 출력은 기존 파일을 덮어쓰지 않는다.

bash scripts/validate/k3s-secret-encryption-restore-evidence.sh \
  --emit-result --bundle-metadata BUNDLE_METADATA_FILE --output RESULT_FILE

script는 live API ready, node Ready, Enabled/reencrypt_finished, server hash, local integrity, version/backend와 Secret object count를 직접 검사한다. 수동 격리 시험을 마친 현재 context를 추가 확인한 뒤에만 result를 만든다. result에는 credential, 경로, 민감 filename이나 hash가 없고 destroyed도 없다.

결과 파일을 운영 host로 반입한 뒤 일회용 환경과 bundle 복사본을 먼저 파기한다. 그 다음 운영 host에서 등록한다.

bash scripts/validate/k3s-secret-encryption-restore-evidence.sh \
  --record --bundle-metadata BUNDLE_METADATA_FILE --result-file RESULT_FILE

--record는 post phase, metadata/result의 bundle-id·version·backend, 24시간 age와 운영 host 권위 post metadata의 일곱 field 전체를 확인한다. evidence 대상이 이미 있으면 중단한다. prompt에는 정확히 DESTROYED default를 입력한다. 파기하지 않았거나 확인할 수 없으면 등록하지 않는다.

Phase 4의 읽기 전용 gate는 다음과 같다.

bash scripts/validate/k3s-secret-encryption-restore-evidence.sh --check

--check는 exact evidence field, 현재 권위 bundle-id/version/backend, live reencrypt_finished와 local integrity, 30일 age, destroyed=confirmed를 모두 요구한다. 2026-08-09 live 전환은 Enabled/reencrypt_finished, hash·integrity·API·node 검사, post bundle 기록과 최신 marker 검증까지 통과했다. 그러나 격리 restore·파기 evidence가 아직 없고 lifecycle 자동화, off-host 복제와 암호화 escrow 검증도 미완료다. 따라서 실제 운영 --check는 아직 성공으로 기록하지 않으며, 이 gate들이 완료되기 전에는 관측성 Phase 4를 열지 않는다.

입력 파일 보안

외부 metadata/result는 현재 사용자 소유 regular non-symlink, mode 0600, non-empty여야 한다. parser는 exact allowlist KEY=VALUE 한 줄만 받아들이며 duplicate/unknown/empty key, control character, malformed line, trailing data, $(와 backtick을 거부한다. 파일을 shell로 source하거나 eval하지 않는다. 입력 실패는 어떤 privileged install도 수행하기 전에 종료한다.

result와 evidence는 같은 directory의 mode 0600 temporary file을 완성하고 exact field를 다시 검사한 뒤 기존 target을 덮어쓰지 않는 atomic install로 만든다.

실행 원장

완료된 live hardening의 비민감 정정은 2026-08-08 복구 명령 원장의 2026-08-09 addendum과 2026-08-09 로컬 정책 기록에 있다. 아래 표는 아직 수행하지 않은 격리 restore drill의 실행 원장 형식이며, 완료된 live hardening에 별도 Task 6 실행 runbook은 만들지 않았고, 이를 암시하지 않는다.

시각 사전 상태 backend backup 검증 명령 종료 코드 후속 상태

backup 위치, token/hash payload, 민감 파일 hash, encryption config 내용과 escrow 위치는 검증 완료 또는 미완료로만 쓴다. bundle-id, restore drill 시각과 pass/fail은 비밀값이 아니므로 기록할 수 있다.