12 KiB
Production Personnel Dataset Backup and Staging Restore Design
Estimate Time
Estimate Time: 2.5d
목적
프로덕션의 "인력정보" 관련 데이터만 주기적으로 백업하고, 스테이징에 복구해 운영 데이터에 가까운 검증 환경을 구축한다. 이 기능은 재해 복구용 full backup이 아니라 staging rehearsal용 논리 데이터셋 이관 기능이다.
기존 make dump/make restore는 저장소 단위 full backup을 목표로 한다. 이번 기능은 Hydra와 RP 정보를 제외해야 하므로 저장소 단위 필터인 DUMP_SERVICES=postgres,ory-postgres만으로는 충분하지 않다. 별도의 dataset profile을 두어 테이블/행/민감값을 명시적으로 제한해야 한다.
정책 전제
- Ory Stack은 identity, authorization, OAuth/OIDC 상태의 SoT다.
- Backend DB의
users는 Ory에 저장되지 않거나 Ory API만으로 조회하기 어려운 Baron 운영 read model이다. - Hydra client, consent, token/session state와 Baron RP metadata는 이번 데이터셋 대상이 아니다.
- staging restore는 운영 복구가 아니므로 production credential/session을 그대로 들고 오지 않는다.
- Wiki는 사용 중이지만, 정책 업데이트 초안은
docs/문서로 남기고 사람이 검토 후 Wiki에 반영한다.
제안 인터페이스
기존 백업 명령을 유지하면서 dataset profile을 추가한다.
make dump DUMP_SERVICES=postgres,ory-postgres DUMP_DATASET=personnel DUMP_MODE=maintenance
make restore RESTORE_SERVICES=postgres,ory-postgres RESTORE_DATASET=personnel CONFIRM_RESTORE=baron-sso
make restore-plan RESTORE_DATASET=personnel BACKUP=backups/baron-sso-backup-YYYYMMDD-HHMMSSZ
운영 자동화에서는 production에서 full backup만 만들고, staging에서 받은 full backup을 personnel dataset으로 필터링한 뒤 복구한다.
# Production
make dump DUMP_SERVICES=all DUMP_MODE=maintenance
# Staging
make filter-personnel-dump \
BACKUP=backups/prod-full-backup-YYYYMMDD-HHMMSSZ \
OUTPUT_BACKUP=backups/prod-personnel-filtered-YYYYMMDD-HHMMSSZ
make restore \
BACKUP=backups/prod-personnel-filtered-YYYYMMDD-HHMMSSZ \
RESTORE_DATASET=personnel \
RESTORE_SERVICES=postgres \
CONFIRM_RESTORE=baron-sso
filter-personnel-dump는 full backup의 baron.dump, ory_kratos.dump, ory_keto.dump를 staging scratch DB에 일시 복원한 뒤 personnel JSONL dataset을 생성한다. Hydra dump와 RP metadata는 filtered backup에 복사하지 않는다.
추가 환경 변수:
| 변수 | 기본값 | 의미 |
|---|---|---|
DUMP_DATASET |
full |
full은 기존 동작, personnel은 인력정보 논리 데이터셋 |
RESTORE_DATASET |
manifest 기준 | 복구할 dataset profile |
FILTER_SERVICES |
postgres,ory-postgres |
full backup에서 personnel dataset으로 필터링할 서비스 범위 |
OUTPUT_BACKUP |
empty | filter-personnel-dump의 personnel dataset 출력 경로 |
PERSONNEL_TENANT_ROOT_SLUGS |
empty | 비어 있으면 전체 인력정보, 값이 있으면 지정 tenant root 하위만 |
PERSONNEL_INCLUDE_KRATOS_IDENTITIES |
true |
staging 로그인/subject 일치 검증이 필요할 때 Kratos identity subset 포함 |
PERSONNEL_RESET_CREDENTIALS |
true |
Kratos credential/session을 production 그대로 복구하지 않도록 강제 |
PERSONNEL_INCLUDE_WORKSMOBILE_MAPPING |
true |
WORKS externalKey 비교와 조직도 검증용 mapping 포함 |
PERSONNEL_INCLUDE_OUTBOX |
false |
queue state는 기본 제외, 장애 재현 시에만 별도 허용 |
DUMP_DATASET=personnel은 DUMP_SERVICES=all에서도 Hydra DB와 RP metadata를 포함하지 않도록 내부적으로 차단한다. 사용자가 DUMP_DATASET=personnel DUMP_SERVICES=ory-postgres를 지정해도 ory_hydra dump는 생성하지 않는다.
백업 산출물 구조
baron-sso-backup-YYYYMMDD-HHMMSSZ/
manifest.json
checksums.sha256
datasets/
personnel/
dataset-manifest.json
postgres/
users.jsonl
user_login_ids.jsonl
tenants.jsonl
tenant_domains.jsonl
user_groups.jsonl
worksmobile_resource_mappings.jsonl
ory_kratos/
identities.jsonl
identity_credentials.reset-plan.jsonl
ory_keto/
relation_tuples.jsonl
reports/
row-counts.json
exclusions.json
restore-plan.md
personnel dataset은 pg_dump -Fc만으로 만들지 않는다. 행 필터, 민감값 제거, RP/Hydra 제외를 안전하게 보장하려면 COPY (SELECT ...) TO STDOUT 또는 psql JSONL export를 사용한다. full backup은 기존 postgres/baron.dump, postgres/ory_*.dump 형식을 그대로 유지한다.
포함 범위
Baron Postgres 포함
| 테이블/데이터 | 포함 이유 | 처리 |
|---|---|---|
users |
인력 기본 정보, 상태, 조직 표시 read model | 포함. relying_party_id는 null 처리 또는 제외 검증 |
user_login_ids |
사번/로그인 ID 등 인력 식별자 | 포함 |
tenants |
회사/조직/사용자 그룹 계층 | COMPANY_GROUP, COMPANY, ORGANIZATION, USER_GROUP 중심 포함 |
tenant_domains |
회사 도메인 기반 소속 판단 | 포함 |
user_groups |
조직도/부서 계층 | 포함 |
worksmobile_resource_mappings |
WORKS externalKey 기반 비교/동기화 기준 | USER, ORGUNIT만 포함 |
Ory Kratos 포함
PERSONNEL_INCLUDE_KRATOS_IDENTITIES=true일 때만 포함한다.
identities: subject UUID와 traits 기반 식별을 위해 포함한다.- credential/session/recovery/verifiable address는 production 값을 그대로 복구하지 않는다.
- restore 단계에서 staging용 임시 credential 정책 또는 password reset-required 상태를 만든다.
- Kratos DB 직접 조작은 일반 write path가 아니므로 maintenance guard와 별도 확인값을 요구한다.
Ory Keto 포함
- 사용자, tenant, user group membership/ownership 관계 tuple만 포함한다.
- RP namespace 또는 RP object를 참조하는 tuple은 제외한다.
- restore 후 Keto relation tuple subject/object가 복구된 user/tenant/group만 참조하는지 검증한다.
제외 범위
| 제외 대상 | 이유 |
|---|---|
| Hydra DB 전체 | OAuth2 client, consent, token/session은 staging RP 상태를 오염시킬 수 있음 |
| Baron RP metadata | 사용자가 명시한 비대상이며 staging RP 설정은 별도 관리 대상 |
rp_user_metadata |
RP별 custom claim 데이터라 personnel 공통 데이터가 아님 |
client_consents |
Hydra/RP consent read model 성격 |
| API key/client secret류 | staging secret과 충돌 위험 |
| audit/clickhouse logs | 인력정보 환경 구축의 필수 원장이 아님 |
worksmobile_outbox |
큐 처리 상태라 반복 restore 시 중복 작업 위험 |
| Redis | 휘발성 cache/session |
Restore 전략
staging restore는 DB 전체 drop/restore가 아니라 scoped replace 방식으로 설계한다.
- restore 전
restore-plan을 생성해 포함/제외 테이블, row count, tenant scope, Hydra/RP exclusion을 표시한다. - backend worker, WORKS relay, Keto outbox relay를 중지한다.
- dataset을 staging scratch schema 또는 임시 DB에 적재한다.
- row count, foreign key, soft-delete, tenant hierarchy, user-login collision을 검증한다.
- staging의 Hydra/RP 관련 테이블과 설정은 건드리지 않는다.
- Baron personnel tables를 dependency order에 따라 replace/upsert한다.
- Kratos identity subset을 포함한 경우 production credential/session을 제거하고 staging credential policy를 적용한다.
- Keto personnel tuple만 replace/upsert하고 RP tuple은 보존한다.
restore-verify에서 다음 항목을 검증한다.
검증 항목:
users.id와 Kratosidentities.id일치 여부user_login_ids.user_id,tenant_id참조 무결성tenants.parent_id,user_groups.parent_id계층 무결성users.relying_party_id가 남아 있지 않은지rp_user_metadata, Hydra dump 파일, Hydra restore step이 생성되지 않았는지- Keto tuple이 복구 대상 user/tenant/group만 참조하는지
- WORKS mapping의 Baron resource 참조가 존재하는지
구현 위치
제안 파일:
scripts/backup/lib/dataset.sh: dataset profile validation과 공통 manifest helperscripts/backup/lib/personnel_dataset.sh: personnel export/import SQL, exclusion guardscripts/backup/dump.sh:DUMP_DATASET분기 추가scripts/backup/restore.sh:RESTORE_DATASET분기와 scoped restore 추가scripts/backup/restore-plan.sh: dataset restore plan 출력scripts/backup/lib/report.sh: dataset row-count/exclusion report 표시Makefile:DUMP_DATASET,RESTORE_DATASET,PERSONNEL_*변수 전달
테스트 계획
구현 전 RED 테스트를 먼저 추가한다.
-
test/personnel_dataset_backup_policy_test.shDUMP_DATASET=personneldry-run 또는 fixture run에서 Hydra dump가 계획되지 않는지 확인한다.rp_user_metadata,client_consents,relying_parties계열 데이터가 dataset manifest에 포함되지 않는지 확인한다.- unknown dataset profile을 거부하는지 확인한다.
-
test/personnel_dataset_restore_policy_test.shRESTORE_DATASET=personnel이CONFIRM_RESTORE=baron-sso없이 실패하는지 확인한다.- restore-plan에 포함/제외 테이블과 credential reset policy가 표시되는지 확인한다.
- non-empty target guard와 scoped restore guard가 동시에 동작하는지 확인한다.
-
scripts/backup/lib/personnel_dataset.sh단위 shell test- tenant root scope가 있을 때 users/tenants/user_groups 쿼리가 같은 scope로 제한되는지 확인한다.
PERSONNEL_INCLUDE_OUTBOX=false기본값에서 outbox가 제외되는지 확인한다.
-
통합 테스트
- fixture Postgres에 users/tenants/RP/Hydra 유사 데이터를 넣는다.
- personnel dataset dump를 실행한다.
- 빈 staging fixture DB에 restore한다.
- 인력정보는 들어오고 Hydra/RP/consent/custom claim 데이터는 남지 않는지 검증한다.
-
E2E 또는 smoke
- staging restore 후 AdminFront/User list와 OrgFront 조직도 조회가 정상인지 확인한다.
- 화면 변화가 있는 기능은 아니므로 스냅샷 업로드는 구현 범위에서 제외한다. 단, 복구 후 조직도 화면 검증이 필요하면 별도 E2E 이슈로 분리한다.
위험과 결정 필요 사항
-
Kratos identity 포함 여부
- 포함하면 staging에서 production과 같은 subject UUID로 검증할 수 있다.
- 대신 credential/session 민감값 제거가 필수이고, Kratos DB maintenance 예외 정책을 문서화해야 한다.
- 제외하면 인력/조직 화면은 검증 가능하지만 실제 로그인 subject 일치 검증은 제한된다.
-
restore 방식
- table replace는 단순하지만 staging 고유 사용자와 충돌할 수 있다.
- upsert는 staging 고유 데이터 보존에 유리하지만 삭제/퇴사 반영 정책이 복잡해진다.
- 기본안은
PERSONNEL_RESTORE_MODE=replace-scoped로 두고, staging 고유 tenant slug allowlist는 보호한다.
-
WORKS mapping 포함 여부
- externalKey 비교를 위해 포함하는 것이 좋다.
- outbox는 중복 실행 위험이 있어 기본 제외가 맞다.
구현 순서
- Gitea 이슈에 본 설계와 테스트 RED 계획을 등록한다.
- RED 테스트를 먼저 추가하고 실패를 확인한다.
- dataset profile validation과 manifest/exclusion guard를 구현한다.
- Baron Postgres personnel export/import를 구현한다.
- Kratos/Keto subset 처리는 guard와 reset policy를 먼저 구현한 뒤 활성화한다.
make restore-plan, report, verification을 보강한다.- 테스트 통과 후 문서와 Wiki 반영 필요 여부를 검토한다.