# Baron SSO 전체 시스템 백업 및 복구 설계 ## 목적 Baron SSO의 전체 시스템 백업/복구는 CSV export/import의 확장판이 아니라, 서비스 저장소 전체를 일관된 시점으로 보존하고 복원하는 재해 복구 기능이다. 핵심 목표는 다음과 같다. - 사용자, 조직, 권한, RP, WORKS 연동 참조에 쓰이는 UUID를 그대로 보존한다. - Kratos identity subject와 Baron local user ID가 어긋나지 않게 복구한다. - Hydra/Keto/Oathkeeper 기반 인증/인가 상태를 서비스 가능한 수준으로 복원한다. - 복구 후 WORKS externalKey 기반 비교/동기화가 기존 연동과 이어지도록 한다. - 백업 산출물의 무결성, 보안, 복구 가능성을 검증 가능한 절차로 만든다. ## 배경과 결론 사용자 CSV는 `user_id`를 포함해 내보낼 수 있지만, 실제 사용자 계정의 주체 ID는 Kratos identity ID다. Kratos Admin API의 identity 생성 요청은 `id` 필드를 받지 않으므로, CSV import만으로 기존 사용자 UUID를 보장할 수 없다. 따라서 사용자 UUID 보존이 필요한 복구는 반드시 Kratos DB까지 포함한 full backup/restore로 처리해야 한다. CSV import는 운영 편의 기능으로 유지하되, 재해 복구나 WORKS 연동 보존 목적의 원장 복구 수단으로 간주하지 않는다. ## 백업 대상 ### 필수 저장소 | 대상 | 저장소 | 포함 이유 | 복구 필수 여부 | | --- | --- | --- | --- | | Baron 애플리케이션 DB | `baron_postgres` | users, tenants, user_login_ids, user_groups, api_keys, outbox, WORKS mapping, RP metadata 등 | 필수 | | Kratos DB | `ory_postgres`의 `ory_kratos` | identity UUID, credentials, verifiable/recovery addresses, sessions | 필수 | | Hydra DB | `ory_postgres`의 `ory_hydra` | OAuth2 clients, consent, token/session 관련 상태 | 필수 | | Keto DB | `ory_postgres`의 `ory_keto` | ReBAC relation tuple 원장 | 필수 | | Baron ClickHouse | `baron_clickhouse` | 감사 로그, 운영 추적 데이터 | 운영 정책상 필수 | | Ory ClickHouse | `ory_clickhouse` | Ory/Oathkeeper/Vector 계열 로그 | 운영 정책상 필수 | | 설정/비밀값 | `.env`, generated Ory config, WORKS private key, gateway/Oathkeeper config | 동일 환경 재기동과 외부 연동에 필요 | 필수 | ### 선택 저장소 | 대상 | 처리 원칙 | | --- | --- | | Redis | 로그인 pending state, cache, short code 등 휘발성 데이터다. full restore에서는 원칙적으로 제외하고 재시작 시 비운다. 무중단 이전 시나리오에서만 snapshot을 검토한다. | | 프론트 빌드 산출물 | 소스/이미지 태그로 재생성한다. 별도 보관은 배포 재현성을 위한 선택 항목이다. | | 로컬 개발 산출물 | reports, coverage, test-results 등은 백업 대상에서 제외한다. | ## 백업 산출물 형식 백업 단위는 압축된 디렉터리 또는 object storage prefix로 관리한다. ```text baron-sso-backup-YYYYMMDD-HHMMSSZ/ manifest.json checksums.sha256 postgres/ baron.dump ory_kratos.dump ory_hydra.dump ory_keto.dump globals.sql clickhouse/ baron_clickhouse/ ory_clickhouse/ config/ env.redacted env.encrypted ory/ gateway/ reports/ row-counts.json restore-readiness.json ``` `manifest.json`에는 최소한 다음 정보를 기록한다. - backup format version - 생성 시각, git commit, 이미지 태그 - 서비스별 DB schema/migration version - 각 dump 파일의 checksum, 크기, 생성 명령 버전 - 백업 모드: `offline`, `maintenance`, `online-best-effort` - 암호화 방식과 key id - 복구 대상 환경 제한: `same-env-only`, `staging-rehearsal`, `cross-env` ## Dump 대상별 복구 flow 및 영향도 `make dump`의 서비스 필터는 저장소별 복구 단위를 명확히 나누기 위한 운영 인터페이스다. 전체 재해 복구는 `DUMP_SERVICES=all`을 기본으로 하되, staging rehearsal이나 부분 장애 분석에서는 개별 대상을 분리해서 검증할 수 있다. ### 대상별 요약 | 서비스 필터 | 주요 dump 산출물 | 포함 데이터 | 복구 중요도 | 복구 영향도 | | --- | --- | --- | --- | --- | | `postgres` | `postgres/baron.dump` | Baron users, tenants, membership, user_login_ids, user_groups, RP metadata, API keys, WORKS mapping/outbox, Keto outbox, consent read model 등 | 필수 | Ory에 저장되지 않거나 조회가 불가능한 Baron control plane 데이터와 처리 상태를 담는다. 누락되면 사용자/테넌트/RP/WORKS 참조가 끊기고 Ory DB만 복구해도 서비스 의미가 깨진다. | | `ory-postgres` | `postgres/globals.sql`, `postgres/ory_kratos.dump`, `postgres/ory_hydra.dump`, `postgres/ory_keto.dump` | Kratos identity/credential/session, Hydra client/consent/token state, Keto relation tuple | 필수 | 인증 주체, OAuth2/OIDC 상태, ReBAC 권한 원장이다. Baron DB와 시점이 다르면 로그인/인가/consent 불일치가 발생한다. | | `clickhouse` | `clickhouse/baron_clickhouse/schema/*.sql`, `clickhouse/baron_clickhouse/data/*.native` | Baron audit_logs, RP usage event/aggregate 등 | 운영 정책상 필수 | 인증 자체를 막지는 않지만 감사 추적, 사용량 집계, 사고 분석 이력이 손실된다. | | `ory-clickhouse` | `clickhouse/ory_clickhouse/schema/*.sql`, `clickhouse/ory_clickhouse/data/*.native` | Oathkeeper/Ory/Vector 접근 로그 | 운영 정책상 필수 | Ory edge 접근 로그와 장애 분석 근거가 손실된다. 인증 원장은 Postgres에 있으므로 직접 로그인 기능 영향은 제한적이다. | | `config` | `config/env.redacted`, `config/generated-ory.*`, `config/gateway.*`, `config/compose/*` | 환경 변수 redacted snapshot, generated Ory config, gateway/Oathkeeper 설정, compose 파일 | 필수 | DB만 복구해도 secret/config가 맞지 않으면 Ory Stack, WORKS 연동, callback URL, gateway routing이 정상 기동하지 못한다. | ### `postgres`: Baron 애플리케이션 DB Dump flow: 1. `baron_postgres` 컨테이너 실행 상태를 확인한다. 2. `${DB_NAME:-baron_sso}`를 `pg_dump -Fc`로 `postgres/baron.dump`에 저장한다. 3. `pg_stat_user_tables` 기준 row count를 `reports/baron-postgres-row-counts.txt`에 기록한다. 4. `checksums.sha256`에 dump와 report checksum을 기록한다. Restore flow: 1. restore 전용 빈 Baron Postgres DB를 준비한다. 2. `make restore ... RESTORE_SERVICES=postgres CONFIRM_RESTORE=baron-sso`로 `pg_restore --clean --if-exists`를 실행한다. 3. 복구 후 backend migration 자동 실행은 금지하고, dump 시점의 schema version과 현재 binary가 호환되는지 먼저 확인한다. 4. Kratos identity와 Baron `users.id`의 참조 검증을 수행한다. 5. WORKS relay, Keto outbox relay는 post-restore 검증 전까지 재개하지 않는다. 영향도: - 사용자, 테넌트, 소속, RP metadata, WORKS mapping의 기준 원장이므로 full restore에서 가장 먼저 Baron/Ory 시점 정합성을 확인해야 한다. - Baron DB만 과거 시점으로 되돌리면 Kratos identity, Hydra consent, Keto tuple과 불일치할 수 있다. - WORKS mapping/outbox 상태가 과거로 돌아가면 외부 WORKS와 중복 upsert/delete 후보가 생길 수 있으므로 comparison dry-run이 필수다. 검증 포인트: - `users.id`와 Kratos `identities.id` 일치 - `tenants.parent_id`, membership, user group 참조 무결성 - RP metadata와 Hydra client 연결성 - WORKS mapping의 BaronResourceID 참조 유효성 ### `ory-postgres`: Kratos/Hydra/Keto DB Dump flow: 1. `ory_postgres` 컨테이너 실행 상태를 확인한다. 2. `pg_dumpall --globals-only`로 role/권한 정보를 `postgres/globals.sql`에 저장한다. 3. `${KRATOS_DB:-ory_kratos}`, `${HYDRA_DB:-ory_hydra}`, `${KETO_DB:-ory_keto}`를 각각 `pg_dump -Fc`로 저장한다. 4. 각 DB의 row count report를 `reports/ory_*-row-counts.txt`에 기록한다. Restore flow: 1. restore 전용 빈 Ory Postgres DB를 준비한다. 2. 필요 시 `globals.sql`을 먼저 적용한다. 3. Kratos, Hydra, Keto DB를 각각 복구한다. 4. migration은 자동 실행하지 않고, Ory binary version과 dump schema version을 확인한다. 5. Ory Stack을 backend보다 먼저 기동해 admin/public endpoint health를 확인한다. 영향도: - Kratos DB는 사용자 subject와 credential 원장이므로 누락되면 비밀번호, recovery/verifiable address, identity UUID 보존이 불가능하다. - Hydra DB는 client, consent, OAuth2 token/session 상태를 담으므로 누락되면 기존 RP 로그인/consent 상태가 재생성되거나 만료될 수 있다. - Keto DB는 ReBAC tuple 원장이므로 누락되면 사용자/테넌트/RP 권한 판단이 실패한다. - Ory DB만 복구하고 Baron DB가 맞지 않으면 identity는 있으나 Baron user가 없거나, Baron user는 있으나 identity가 없는 상태가 된다. 검증 포인트: - Kratos identity 수와 Baron users 수 비교 - Hydra client와 Baron RP metadata 비교 - Keto tuple subject/object가 복구된 사용자/테넌트/RP를 참조하는지 확인 - 대표 사용자 password login, 대표 RP OIDC login/consent smoke ### `clickhouse`: Baron ClickHouse Dump flow: 1. `baron_clickhouse` 컨테이너 실행 상태를 확인한다. 2. `system.tables`에서 Baron ClickHouse table 목록과 engine을 조회한다. 3. 일반 table은 `SHOW CREATE TABLE`과 `FORMAT Native` 데이터를 함께 저장한다. 4. view 계열 engine은 restore insert 위험을 피하기 위해 schema만 저장한다. 5. table별 row count를 `reports/baron_clickhouse-row-counts.txt`에 기록한다. Restore flow: 1. restore 전용 ClickHouse DB를 준비한다. 2. database를 생성한 뒤 table schema를 먼저 적용한다. 3. 일반 table의 `.native` 데이터를 insert한다. 4. materialized view나 view는 schema만 복구하고, 대상 table 데이터가 들어간 뒤 재계산/재생성 정책을 별도로 확인한다. 5. row count와 주요 기간의 min/max timestamp를 비교한다. 영향도: - Baron audit log와 RP usage 집계가 손실되면 보안 감사, 운영 추적, 사용량 화면의 신뢰도가 떨어진다. - 인증 기능 자체의 필수 원장은 아니지만, 사고 대응과 운영 증적 측면에서는 필수 백업 대상이다. - aggregate/materialized view는 원본 event table과 복구 순서가 맞지 않으면 중복 집계나 누락 집계가 생길 수 있다. 검증 포인트: - `audit_logs`, `rp_usage_events`, aggregate table row count 비교 - 주요 기간별 min/max timestamp 비교 - AdminFront/DevFront의 사용량 조회 smoke ### `ory-clickhouse`: Ory ClickHouse Dump flow: 1. `ory_clickhouse` 컨테이너 실행 상태를 확인한다. 2. Ory/Oathkeeper/Vector 계열 table schema와 일반 table data를 저장한다. 3. table별 row count를 `reports/ory_clickhouse-row-counts.txt`에 기록한다. Restore flow: 1. restore 전용 Ory ClickHouse DB를 준비한다. 2. schema를 적용한 뒤 일반 table data를 insert한다. 3. Vector/Oathkeeper 기동 후 신규 로그가 같은 table로 유입되는지 확인한다. 영향도: - Ory edge 접근 로그와 gateway 관측 자료가 손실된다. - 인증/인가 원장은 Postgres에 있으므로 서비스 기동 자체 영향은 제한적이다. - 보안 사고 분석, OIDC redirect 장애 분석, rate/anomaly 분석에는 영향이 크다. 검증 포인트: - Oathkeeper access log row count 비교 - Oathkeeper 경유 요청 후 신규 로그 유입 확인 - Vector pipeline 재기동 후 error log 확인 ### `config`: 설정 snapshot Dump flow: 1. `.env`가 있으면 secret 성격 key를 `REDACTED`로 치환해 `config/env.redacted`를 만든다. 2. `config/.generated/ory`, `gateway`, 주요 compose 파일을 tar snapshot 또는 file copy로 보존한다. 3. 실제 secret 원문은 1차 로컬 구현의 `env.redacted`에 포함하지 않는다. 운영 백업에서는 별도 암호화 산출물로 보관해야 한다. Restore flow: 1. `make restore ... RESTORE_SERVICES=config` 실행 시 운영 파일을 직접 덮어쓰지 않는다. 2. snapshot은 `config-restored/`에 풀어 운영자가 diff로 검토한다. 3. secret 원문은 승인된 secret manager 또는 암호화 백업에서 별도 복원한다. 4. `make validate-auth-config`, `make verify-auth-config`로 callback/redirect/gateway mapping을 검증한다. 5. Ory Stack과 gateway를 기동한 뒤 대표 callback과 OIDC flow를 확인한다. 영향도: - DB가 정상이어도 Hydra system secret, Kratos config, Oathkeeper rule, WORKS private key, callback URL이 맞지 않으면 서비스가 정상 동작하지 않는다. - `env.redacted`만으로는 운영 복구가 완성되지 않는다. 운영 복구용 secret은 별도 암호화 저장소가 필요하다. - config를 운영 파일에 바로 덮어쓰면 현재 환경의 도메인, callback, gateway rule을 깨뜨릴 수 있으므로 수동 검토가 기본이다. 검증 포인트: - `make validate-auth-config` - `make verify-auth-config` - gateway/Oathkeeper route smoke - WORKS credential dry-run 또는 외부 호출 차단 상태 검증 ### 제외 대상의 복구 영향 | 제외 대상 | 제외 이유 | 복구 후 영향 | 운영 대응 | | --- | --- | --- | --- | | Redis | cache, pending login, short code 등 휘발성 상태 | 진행 중인 login/link/short code flow가 만료되거나 재시작된다. | 사용자에게 재시도 안내, 서비스 기동 후 cache 재수렴 확인 | | 프론트 빌드 산출물 | 소스와 이미지 태그로 재생성 가능 | 기존 정적 파일을 그대로 보존하지 않는다. | 동일 commit/image tag로 재배포 | | 로컬 reports/coverage/test-results | 운영 원장이 아님 | 운영 서비스 영향 없음 | CI artifact나 별도 관측 저장소 기준으로 확인 | ### 전체 복구 순서와 의존성 Full restore는 다음 순서를 기본으로 한다. 1. restore 전용 빈 환경과 volume을 준비한다. 2. `config` snapshot을 `config-restored/`에 풀고 운영자가 secret/config 차이를 검토한다. 3. `ory-postgres`를 복구한다. 4. `postgres`를 복구한다. 5. `ory-clickhouse`와 `clickhouse`를 복구한다. 6. `make dump-verify`와 `make restore-verify`로 산출물 무결성을 확인한다. 7. `make validate-auth-config`, `make verify-auth-config`로 Ory/gateway 설정을 확인한다. 8. Ory Stack을 먼저 기동하고 Kratos/Hydra/Keto health를 확인한다. 9. backend와 app을 기동한다. 10. super admin login, 일반 사용자 login, 대표 RP OIDC login/consent를 확인한다. 11. WORKS comparison dry-run을 수행한다. 12. 대량 delete/upsert 위험이 없을 때 relay worker와 외부 동기화를 재개한다. 부분 복구는 원칙적으로 장애 분석 또는 rehearsal에서만 사용한다. 운영에서 특정 저장소만 과거 시점으로 되돌리면 cross-store 정합성이 깨질 수 있으므로, 실제 운영 restore는 같은 backup directory에서 나온 동일 시점의 산출물을 함께 적용하는 것을 기본으로 한다. Restore 입력과 report: - `make dump`, `make restore`, `make upload-cloud`는 기본적으로 Debian Trixie slim 기반 `baron-sso-backup-tools:local` 컨테이너에서 실행한다. - 호스트 요구사항은 Docker와 Docker socket 접근 권한으로 제한한다. `zstd`, `jq`, `curl`, `openssl`, `postgresql-client`, `docker-cli`는 backup-tools image에 포함한다. - `make restore BACKUP=`는 압축 해제된 백업 디렉터리를 입력으로 사용한다. - `make restore DUMP_FILE=.tar.zst`는 archive를 임시 디렉터리에 풀어 복구한다. - `BACKUP`과 `DUMP_FILE`은 동시에 지정하지 않는다. - restore report 기본 위치는 `BACKUP` 입력일 때 `/reports/restore-report.json`, `DUMP_FILE` 입력일 때 `reports/restore/-restore-report.json`이다. - restore report JSON이 생성되면 같은 경로에 `.md` 확장자의 Markdown 요약도 함께 생성한다. - `RESTORE_REPORT=`로 report 경로를 명시할 수 있다. - restore report는 checksum 검증, 서비스별 복구 대상, 복구 후 row count 비교, config snapshot copy 위치를 기록한다. - 외부 접속을 막은 상태에서 복구하려면 app/Ory serve/gateway를 먼저 중지하고 Postgres/ClickHouse/Redis만 기동해 restore를 수행한 뒤 검증 통과 후 Ory/backend/frontend를 순차 기동한다. ### 외부 분산 저장: WORKS Drive 업로드 로컬 dump가 끝난 뒤 같은 백업 디렉터리를 외부 저장소에 분산 보관하기 위해 `scripts/backup/upload_cloud.sh`를 사용한다. 현재 1차 대상은 WORKS Drive다. Upload flow: 1. `make dump BACKUP=...` 또는 `make dump-upload-cloud BACKUP=...`로 백업 산출물을 만든다. 2. `dump.sh`가 `reports/backup-report.md`를 생성한다. report에는 사용자 수, 테넌트 수, RP 수, Hydra client 수, WORKS 관련 row count, 서비스별 수행 시간이 Markdown 표로 기록된다. 3. `upload_cloud.sh`가 백업 디렉터리를 `baron-sso-backup-*.tar.zst`로 압축한다. 4. Drive API용 access token을 확인한다. - `WORKS_DRIVE_ACCESS_TOKEN`, `WORKS_DRIVE_ACCESS_TOKEN_FILE`, `WORKS_DRIVE_ACCESS_TOKEN_CMD`는 항상 최우선이다. - `WORKS_DRIVE_AUTH_MODE=auto` 기본값은 service account credentials가 완비되어 있으면 `WORKS_DRIVE_OAUTH_*` 서비스 계정 JWT 토큰 발급을 먼저 사용하고, 없으면 `WORKS_DRIVE_OAUTH_REFRESH_TOKEN` 갱신으로 fallback한다. - `WORKS_DRIVE_AUTH_MODE=service-account`는 service account JWT 토큰 발급을 강제한다. - `WORKS_DRIVE_AUTH_MODE=refresh-token`은 service account 설정이 있어도 refresh token 갱신을 강제한다. 5. WORKS Drive upload URL 생성 API를 호출한다. 6. 발급받은 upload URL에 multipart `Filedata`로 `.tar.zst` archive를 업로드한다. 7. `WORKS_DRIVE_UPLOAD_REPORTS=true`이면 대상 폴더 아래 `WORKS_DRIVE_REPORT_FOLDER_NAME` 하위 폴더를 찾거나 생성한 뒤 `reports/*.md`만 업로드한다. - 업로드 파일명은 `backup-report-YYYYMMDD-HHMMSSZ.md`처럼 업로드 시각을 붙인다. - `reports/cloud-upload.json`은 로컬 실행 기록이며 Drive 업로드 대상에서 제외한다. 8. 업로드 결과를 `reports/cloud-upload.json`에 기록한다. 대상 drive 선택: | `WORKS_DRIVE_TARGET` | 필요 변수 | 업로드 URL 생성 API | | --- | --- | --- | | `sharedrive` | `WORKS_DRIVE_SHARED_DRIVE_ID`, 선택 `WORKS_DRIVE_PARENT_FILE_ID` | `/v1.0/sharedrives/{sharedriveId}/files[/]` | | `mydrive` | 선택 `WORKS_DRIVE_USER_ID`, 선택 `WORKS_DRIVE_PARENT_FILE_ID` | `/v1.0/users/{userId}/drive/files[/]` | | `group` | `WORKS_DRIVE_GROUP_ID`, 선택 `WORKS_DRIVE_PARENT_FILE_ID` | `/v1.0/groups/{groupId}/folder/files[/]` | | `sharedfolder` | `WORKS_DRIVE_USER_ID`, `WORKS_DRIVE_SHARED_FOLDER_ID`, 선택 `WORKS_DRIVE_PARENT_FILE_ID` | `/v1.0/users/{userId}/drive/sharedfolders/{sharedFolderId}/files[/]` | 운영 주의: - 업로드 archive는 `.tar.zst`로 고정한다. `zstd`가 없으면 실패해야 한다. - Drive API는 `file` scope가 필요하다. - `WORKS_DRIVE_PARENT_FILE_ID`는 폴더 이름이나 경로가 아니라 WORKS Drive API가 반환하는 폴더 `fileId`여야 한다. - 계정 동기화용 `WORKS_ADMIN_OAUTH_*`와 백업 업로드용 `WORKS_DRIVE_OAUTH_*`는 용도가 다른 앱/키로 분리한다. - 운영 기본 경로는 Drive용 access token을 명시 주입하거나 service account JWT를 사용하는 방식이다. - refresh token을 재발급해 사용하는 경우 `make works-drive-refresh-token`을 사용한다. WORKS OAuth refresh token은 Authorization Code Flow에서 발급되며, WORKS Token 설정의 Refresh Token Rotation 상태에 따라 갱신 응답에 새 refresh token이 포함될 수 있다. - 기존 refresh token이 아직 유효하면 `make works-drive-refresh-token WORKS_DRIVE_TOKEN_GRANT=refresh-token`로 `.env`의 `WORKS_DRIVE_OAUTH_REFRESH_TOKEN`을 자동 갱신한다. - 기존 refresh token이 폐기되어 401이 발생하면 `WORKS_DRIVE_TOKEN_GRANT=print-authorize-url scripts/backup/refresh_works_drive_token.sh`로 출력된 URL을 브라우저에서 승인한 뒤, callback의 `code`를 `make works-drive-refresh-token WORKS_DRIVE_TOKEN_GRANT=authorization-code WORKS_DRIVE_AUTH_CODE=`에 전달한다. - callback URL 전체를 복사할 수 있으면 `WORKS_DRIVE_AUTH_CALLBACK_URL=`을 사용해도 된다. - 토큰 갱신 도구는 짧게 만료되는 access token을 `.env`에 저장하지 않고 refresh token과 `WORKS_DRIVE_AUTH_MODE=refresh-token`만 갱신한다. - 서비스 계정 JWT는 Drive 업로드 앱 정책에서 Drive scope 위임이 허용되고 Client ID, Service Account, Private Key가 같은 앱에서 발급된 조합일 때만 성공한다. - 파일 크기가 WORKS Drive 단일 파일 제한에 걸릴 수 있으면 `WORKS_DRIVE_MAX_SINGLE_FILE_BYTES` 또는 `WORKS_DRIVE_FORCE_SPLIT=true`로 split part 업로드를 사용한다. - Markdown report 업로드 기본 폴더명은 `reports`이며 `WORKS_DRIVE_REPORT_FOLDER_NAME`으로 바꿀 수 있다. - 외부 업로드 성공은 복구 가능성을 보장하지 않는다. 업로드 후에도 `make dump-verify BACKUP=...`와 restore rehearsal을 별도로 수행해야 한다. ## 백업 모드 ### 1. Offline backup 가장 안전한 모드다. 모든 writer를 중지한 뒤 dump한다. 순서: 1. gateway 또는 Oathkeeper에서 maintenance mode 활성화 2. backend, relay worker, vector 등 write producer 중지 3. Kratos/Hydra/Keto public/admin 요청 차단 또는 컨테이너 중지 4. Baron Postgres dump 5. Ory Postgres의 Kratos/Hydra/Keto DB dump 6. ClickHouse backup 7. 설정/비밀값 백업 8. checksum과 row count 생성 9. 서비스 재개 이 모드는 사용자 UUID, WORKS mapping, Keto relation, OAuth consent 상태의 일관성이 가장 좋다. ### 2. Maintenance backup 짧은 점검 모드에서 writer만 막고 read는 제한적으로 허용한다. 운영 기본 모드로 권장한다. 필수 조건: - 사용자 생성/삭제/수정 차단 - 테넌트/조직 변경 차단 - WORKS outbox relay 중지 - Keto outbox relay 중지 - OAuth client 변경 차단 ### 3. Online best-effort backup 무중단 스냅샷이다. 저장소가 여러 개라 cross-store 일관성을 보장할 수 없다. 감사 로그나 분석용 백업에는 가능하지만, 재해 복구용 원본으로는 사용하지 않는다. ## Postgres 백업 전략 Postgres는 논리 dump를 기본으로 한다. - `pg_dump -Fc` 형식 사용 - DB별 dump 파일 분리 - `pg_dumpall --globals-only`로 role/extension/권한 정보 별도 보관 - 백업 전후 row count와 핵심 UUID sample 기록 대상 DB: - Baron DB: `DB_NAME` - Kratos DB: `ory_kratos` - Hydra DB: `ory_hydra` - Keto DB: `ory_keto` 복구는 빈 DB에 `pg_restore --clean --if-exists`로 수행한다. 기존 운영 DB에 덮어쓰는 in-place restore는 금지한다. ## ClickHouse 백업 전략 ClickHouse는 감사 로그 성격이 강하므로 정책을 분리한다. - 재해 복구: ClickHouse native backup 또는 volume snapshot 사용 - 장기 보관: 파티션 단위 export 또는 object storage backup - 복구 검증: 날짜 파티션별 row count와 min/max timestamp 비교 ClickHouse 백업 실패가 인증 기능 복구를 막지는 않지만, 감사 로그 보존 정책상 별도 실패로 취급한다. ## Redis 처리 원칙 Redis는 기본적으로 백업하지 않는다. 복구 후 영향: - 로그인 pending flow 만료 - short code/link login flow 재시작 필요 - headless JWKS cache 재생성 - 세션 cache miss 발생 가능 Kratos/Hydra 자체 session/token 원장은 Postgres 쪽에 있으므로 Redis가 비어 있어도 서비스는 재수렴해야 한다. ## 설정과 비밀값 DB dump만으로는 복구가 불완전하다. 다음 항목은 암호화해서 함께 보관한다. - `.env` 또는 배포 환경 변수 - Ory generated config - Hydra system secret, cookie secret - Kratos courier/config secret - Keto config - Oathkeeper rules/config - WORKS Admin OAuth client private key - API gateway 설정 - object storage backup key id `env.redacted`는 검토용이고, 실제 복구에는 `env.encrypted`만 사용한다. ## 복구 절차 ### Full restore 기본 절차 1. 대상 환경을 새로 준비한다. 2. 모든 애플리케이션 서비스를 중지한다. 3. 기존 DB가 있으면 별도 보관 후 빈 DB를 만든다. 4. Postgres globals를 복구한다. 5. Baron DB를 복구한다. 6. Kratos/Hydra/Keto DB를 복구한다. 7. ClickHouse를 복구한다. 8. 설정/비밀값을 복호화해 배치한다. 9. migration은 자동 실행하지 않고 현재 dump의 schema version을 확인한다. 10. Ory Stack을 기동한다. 11. backend를 기동한다. 12. relay worker는 아직 켜지 않는다. 13. post-restore verification을 수행한다. 14. WORKS comparison dry-run을 수행한다. 15. 문제가 없을 때 relay worker와 외부 동기화를 재개한다. ### Post-restore verification 필수 검증: - Kratos identity 수와 Baron users 수 비교 - Baron `users.id`가 Kratos `identities.id`에 존재하는지 확인 - tenant parent tree 참조 무결성 확인 - `user_login_ids.user_id`, `user_login_ids.tenant_id` 참조 무결성 확인 - Keto relation subject/object가 복구된 사용자/테넌트를 참조하는지 확인 - Hydra client와 Baron RP metadata 참조 확인 - WORKS mapping의 BaronResourceID가 복구된 사용자/테넌트를 참조하는지 확인 - super admin 로그인 확인 - 일반 사용자 로그인 확인 - 대표 RP OIDC login/consent 확인 - WORKS comparison dry-run에서 externalKey 기준 대량 삭제/생성 후보가 없는지 확인 ## WORKS 연동 복구 정책 WORKS 자체 데이터는 Baron 백업으로 복구하지 않는다. Baron이 보존해야 하는 것은 WORKS와 연결되는 참조 키다. 필수 보존: - 사용자 UUID - 테넌트 UUID - WORKS resource mapping - WORKS outbox 처리 상태 - WORKS domain mapping/config 복구 직후 정책: - relay worker 자동 실행 금지 - comparison dry-run 먼저 실행 - externalKey 기준으로 Baron/WORKS가 매칭되는지 확인 - 대량 delete/upsert가 감지되면 동기화 중단 - 확인 후 필요한 사용자/조직만 재동기화 outbox는 복구 모드에 따라 처리한다. | 복구 모드 | outbox 정책 | | --- | --- | | 같은 운영 환경 재해 복구 | outbox 상태 보존, 단 relay 재개 전 dry-run 필수 | | staging rehearsal | outbox relay 비활성화, 외부 WORKS 호출 금지 | | cross-env migration | outbox는 보존하되 실행하지 않고 별도 remap 정책 필요 | ## CSV export/import의 위치 CSV는 다음 목적으로만 사용한다. - 운영자가 사용자/조직을 일괄 등록하거나 보정 - 일부 필드를 검토하기 위한 추출 - dry-run 입력 보조 자료 CSV는 다음 목적에 사용하지 않는다. - Kratos identity UUID 보존 복구 - 비밀번호/credential 복구 - OAuth consent/token/session 복구 - Keto relation 원장 복구 - WORKS mapping 원장 복구 ## 구현 계획 ### Phase 1: 백업/복구 스크립트와 문서화 Estimate Time: 3~5d - `scripts/backup/full-backup.sh` - `scripts/backup/full-restore.sh` - `scripts/backup/verify-backup.sh` - `scripts/backup/verify-restore.sh` - `manifest.json` 생성기 - checksum 생성 - row count report 생성 ### Phase 2: staging restore rehearsal Estimate Time: 3~5d - 백업 파일로 격리된 staging stack 복구 - Ory/Baron/Postgres/ClickHouse 복구 검증 - 로그인/OIDC/관리자 화면 smoke test - WORKS 외부 호출 차단 상태에서 comparison dry-run ### Phase 3: 운영 자동화 Estimate Time: 5~8d - 정기 백업 스케줄링 - 암호화 및 object storage 업로드 - retention 정책 - 실패 알림 - restore rehearsal 주기화 ### Phase 4: 관리 UI Estimate Time: 5~8d - backup 목록 조회 - backup 생성 요청 - restore readiness report 조회 - staging rehearsal 결과 조회 - 운영 restore는 UI에서 직접 실행하지 않고 승인 절차와 runbook으로 제한 ## 테스트 전략 ### 단위 테스트 - manifest 생성 검증 - checksum 검증 - row count report 비교 - restore readiness parser 검증 ### 통합 테스트 - fixture DB 생성 - full backup 실행 - 빈 DB로 restore - 핵심 테이블 row count 비교 - 사용자/테넌트 UUID 동일성 비교 - Kratos identity와 Baron user ID 일치 검증 ### E2E 테스트 - super admin 로그인 - 일반 사용자 로그인 - AdminFront 사용자 목록 조회 - UserFront 로그인 - 대표 RP OIDC 로그인 - WORKS comparison dry-run ### 실패 테스트 - 누락된 dump 파일 - checksum 불일치 - schema version 불일치 - 일부 DB만 복구된 상태 - Kratos identity는 있는데 Baron user가 없는 상태 - Baron user는 있는데 Kratos identity가 없는 상태 - WORKS mapping이 복구되지 않은 상태 ## 운영 정책 - 백업은 암호화하지 않은 상태로 저장하지 않는다. - 운영 restore는 빈 환경 또는 새 볼륨에만 수행한다. - restore 전 현재 운영 DB는 별도 snapshot으로 보존한다. - restore 후 WORKS relay는 수동 승인 전까지 비활성화한다. - 월 1회 이상 staging restore rehearsal을 수행한다. - schema migration 직전 수동 backup을 강제한다. ## 남은 결정 사항 - RPO/RTO 목표값 - 백업 저장 위치와 암호화 key 관리 방식 - ClickHouse 장기 보관 기간 - WORKS outbox replay 정책의 운영 기본값 - 운영 restore 승인자와 절차 - restore rehearsal 자동 실행 주기