1
0
forked from baron/baron-sso

Merge branch 'dev' into feature/staging-healthcheck-monitoring

This commit is contained in:
2026-06-09 13:57:37 +09:00
70 changed files with 4788 additions and 467 deletions

View File

@@ -77,6 +77,247 @@ baron-sso-backup-YYYYMMDD-HHMMSSZ/
- 암호화 방식과 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 projection 등 | 필수 | 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=<backup-dir>`는 압축 해제된 백업 디렉터리를 입력으로 사용한다.
- `make restore DUMP_FILE=<backup>.tar.zst`는 archive를 임시 디렉터리에 풀어 복구한다.
- `BACKUP``DUMP_FILE`은 동시에 지정하지 않는다.
- restore report 기본 위치는 `BACKUP` 입력일 때 `<backup-dir>/reports/restore-report.json`, `DUMP_FILE` 입력일 때 `reports/restore/<archive-name>-restore-report.json`이다.
- restore report JSON이 생성되면 같은 경로에 `.md` 확장자의 Markdown 요약도 함께 생성한다.
- `RESTORE_REPORT=<path>`로 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`
- fallback 1: `WORKS_DRIVE_OAUTH_REFRESH_TOKEN`으로 Drive 앱 access token 갱신
- fallback 2: `WORKS_DRIVE_OAUTH_*` 서비스 계정 JWT 토큰 발급
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[/<folderFileId>]` |
| `mydrive` | 선택 `WORKS_DRIVE_USER_ID`, 선택 `WORKS_DRIVE_PARENT_FILE_ID` | `/v1.0/users/{userId}/drive/files[/<folderFileId>]` |
| `group` | `WORKS_DRIVE_GROUP_ID`, 선택 `WORKS_DRIVE_PARENT_FILE_ID` | `/v1.0/groups/{groupId}/folder/files[/<folderFileId>]` |
| `sharedfolder` | `WORKS_DRIVE_USER_ID`, `WORKS_DRIVE_SHARED_FOLDER_ID`, 선택 `WORKS_DRIVE_PARENT_FILE_ID` | `/v1.0/users/{userId}/drive/sharedfolders/{sharedFolderId}/files[/<folderFileId>]` |
운영 주의:
- 업로드 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을 명시 주입하거나 `WORKS_DRIVE_OAUTH_REFRESH_TOKEN`으로 갱신하는 방식이다.
- 서비스 계정 JWT fallback은 Drive 업로드 앱 정책에서 Drive scope 위임이 허용된 경우에만 성공한다.
- 파일 크기가 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