Repository navigation
[Demo][Reliability] RLS 환경에서 Demo Seed tenant context·transaction 경계 호환 #204
Description
한 줄 목표
PostgreSQL RLS가 활성화된 제한 Runtime DB Role 환경에서도
DEMO_SEED_ENABLED=true를 유지한 채 Demo/Test Seed가 최초 기동과 동일
DB 재기동 모두 정상·멱등하게 수행되도록 Demo Seed의 tenant context와
transaction 경계를 정리합니다.
- 선행/연계: feat: PostgreSQL RLS 기반 사업장 2차 격리 활성화 #135
- 관련 배포: [Deploy] PostgreSQL·AI Runtime 기반 데모 배포 구성 #9
현재 배포 전제
이 이슈는 아직 배포되지 않은 신규 환경을 준비하는 작업이 아닙니다.
- Server·PostgreSQL DB·Infra는 이미 dev 환경에 배포되어 외부 URL로
서비스 중입니다. - Server는
SPRING_PROFILES_ACTIVE=dev로 실행 중입니다. - 배포 환경은
DEMO_SEED_ENABLED=true이며 애플리케이션 기동·재기동 시
Demo Seed가 실행됩니다. - 기존 PostgreSQL PVC에는 현재 Demo/Test fixture가 저장되어 있습니다.
- 이 변경은 기존 fixture를 삭제하거나 새 DB로 교체하지 않고, 기존
DB/PVC를 그대로 유지한 재기동에서도 호환성을 보장해야 합니다. - PR feat: PostgreSQL RLS 기반 사업장 2차 격리 활성화 #135 배포 전 실제 Runtime Role이 Migration Role과 분리되어 있고
RLS를 우회하지 않는지는 현재 dev 배포 DB의 live catalog 기준으로
별도 확인합니다.
왜 필요한가요?
PR #135는 PostgreSQL RLS를 활성화하여 애플리케이션의 company_id 범위
조건에 더해 DB가 다른 사업장의 행을 한 번 더 차단하도록 합니다.
현재 배포 환경은 DEMO_SEED_ENABLED=true이며 Demo/Test fixture를
startup seed로 유지하고 있습니다. 하지만 현재 Demo Seed runner는 RLS가
활성화된 제한 Runtime Role과 호환되지 않습니다.
PR #135에서 수행한 수동 검증에서는 RLS 활성화 후 Seed를 켠 상태로
재기동할 때 다음 흐름으로 실패했습니다.
- tenant context 없이 기존
company를 조회 - RLS에 의해 기존 Demo/Test company 행을 조회하지 못함
- Seed가 company가 없는 것으로 판단하고 신규 insert 시도
- RLS
WITH CHECK에 의해 SQLSTATE42501로 차단 - startup Seed 실패로 애플리케이션 기동 실패
특히 RLS Flyway migration은 Seed runner보다 먼저 commit되므로, 이
상태에서 Pod가 기동에 실패해도 DB에는 RLS가 활성화된 상태가 남습니다.
단순 image rollback만으로 migration을 되돌릴 수 없습니다.
현재의 임시 우회책은 #135 배포 전에 DEMO_SEED_ENABLED=false로 변경하는
것이지만, 이 경우 기존 데이터는 유지되더라도 재기동 시 Demo/Test
fixture의 자동 복구·보충 기능을 사용할 수 없습니다.
따라서 배포 환경에서 Demo Seed를 계속 활성화하려면 PR #135보다 먼저 Seed
자체를 RLS-aware하게 만드는 별도 호환 변경이 필요합니다.
현재 대상
현재 startup Demo Seed의 주요 단계는 다음 세 runner입니다.
DemoAuthSeedRunner- Demo/Test 회사·사용자 등 인증 fixture
DemoWorkerSeedRunner- Demo/Test 근로자 fixture
DemoOperationalSeedRunner- 업무·문서·승인 등 운영 fixture
현재 구조에서는 Demo/Test 두 회사에 대한 Seed가 각 runner의 큰
transaction 경계 안에서 함께 처리될 수 있어, RLS 활성 환경에서 회사별
tenant context를 안전하게 적용하기 어렵습니다.
작업 범위
1. Demo/Test 회사별 transaction 분리
- 각 runner의 Demo/Test Seed 처리를 회사별 transaction으로
분리합니다. - 한 회사의 transaction에서 다른 회사의 fixture를
조회·생성·수정하지 않습니다. - transaction 실패 시 해당 회사 Seed 단위로 rollback되도록 합니다.
- 앞선 회사 transaction이 성공한 뒤 다음 회사 transaction이
실패하면, 성공한 회사의 commit은 유지하고 실패한 회사만 rollback한
뒤 startup 전체를 실패 처리합니다. - 기존 runner 실행 순서와 fixture 의미는 유지합니다.
2. transaction-local tenant context 적용
- 각 회사 Seed transaction 시작 직후 해당
company_id를 DB tenant
context에 설정합니다. -
company존재 여부 조회·생성처럼 RLS 적용 대상에 접근하기
전에도 필요한 tenant context가 설정되어 있어야 합니다. - tenant context는 connection pool에 남지 않도록 transaction-local
방식으로 적용합니다. - 기존 애플리케이션의
app.company_idtransaction-local tenant DB
context 계약을 재사용합니다. - Seed 전용으로 RLS를 우회하는 별도 권한이나 전역 bypass 경로를
만들지 않습니다.
3. transaction 실행 구조 정리
- 같은 Bean 내부의
@Transactionalself-invocation에 의존하지
않습니다. - 회사별 transaction을 확실히 분리할 수 있도록 별도 transaction
Bean,TransactionTemplate또는 동등한 구조를 사용합니다. - transaction 시작 → tenant context 설정 → 해당 회사 Seed 실행
순서를 테스트로 보장합니다. - Seed 종료 후 tenant context가 다음 transaction/connection으로
누출되지 않음을 검증합니다.
4. 기존 Seed 멱등성 유지
- 빈 DB의 최초 Seed에서 Demo/Test fixture가 정상 생성됩니다.
- 동일 DB를 재기동해도 기존 fixture를 다시 찾을 수 있습니다.
- 재기동으로 company/user/worker/task/document 등 기존 Seed
데이터가 중복 생성되지 않습니다. - 일부 fixture가 이미 존재하는 DB에서도 기존 Seed의 보충 동작을
유지합니다. -
DEMO_SEED_ENABLED=false일 때 Seed가 실행되지 않는 기존 동작은
변경하지 않습니다.
구현 원칙
이번 작업은 RLS를 약화시키지 않고 Seed를 기존 tenant 계약에 맞추는
방향으로 구현합니다.
다음 방식으로 문제를 우회하지 않습니다.
- Runtime DB Role에
SUPERUSER또는BYPASSRLS부여 - Runtime Role을 tenant table owner로 변경하여 RLS 우회
- Seed 실행 중 임시로
DISABLE ROW LEVEL SECURITY - 모든 tenant를 볼 수 있는 Seed 전용 unrestricted Repository 추가
- connection session 전체에 tenant context를 남기는 방식
- #135의 RLS policy 범위를 축소하여 Seed를 통과시키는 방식
Seed도 실제 Runtime과 같은 tenant isolation 원칙을 따라야 합니다.
완료 조건
자동 테스트
- 기존 전체 테스트 통과
- PostgreSQL 16 기반 Demo Seed 통합 테스트 추가
- RLS 비활성 상태에서 기존 Demo Seed 회귀 없음
- RLS 활성 + 제한 Runtime Role +
DEMO_SEED_ENABLED=true최초
기동 성공 - 동일 조건에서 같은 DB 재기동 성공
- Demo/Test 두 회사의 Seed 데이터가 각 회사 context에서 정상
조회됨 - 다른 회사 context에서는 상대 회사 Seed 데이터가 노출되지 않음
- 재기동 후 Seed 대상 주요 엔티티 중복 0건
- transaction 종료 후 tenant context 누출 없음
- Seed 실패 시 실패한 회사 transaction의 부분 반영이 없고, 이미
성공한 다른 회사 transaction의 결과는 다음 재기동에서 멱등하게
재사용됨
PostgreSQL 제한 Role 검증
다음 검증은 table owner/superuser가 아닌 실제 제한 Runtime Role로
수행합니다.
- Flyway migration Role과 Runtime Role이 분리되어 있음
- Runtime Role은
rolsuper=false,rolbypassrls=false이고 tenant
table owner가 아님 - Runtime Role에는 애플리케이션에 필요한 최소
DML·sequence·bootstrap 함수 권한만 부여됨 - RLS 활성 상태에서 Demo company Seed 성공
- RLS 활성 상태에서 Test company Seed 성공
- context 없는 tenant table 접근이 기존 RLS 계약대로 차단/비가시
처리됨 - Seed가 RLS bypass 권한 없이 성공함
- SQLSTATE
42501로 startup이 실패하지 않음
재기동 Smoke Test
- RLS 활성 PostgreSQL에
DEMO_SEED_ENABLED=true로 서버를 기동합니다. - Demo/Test 로그인과 주요 화면 데이터를 확인합니다.
- 같은 DB/PVC를 유지한 채 서버 Pod를 재기동합니다.
- 두 번째 기동도 정상 완료되는지 확인합니다.
- Demo/Test 회사·사용자·근로자·주요 운영 fixture의 중복이 없는지
확인합니다. - Demo/Test tenant 간 데이터 격리가 유지되는지 확인합니다.
권장 검증·배포 순서
이 이슈의 호환 변경과 #135를 한 번에 배포하지 않습니다.
- 이 이슈 구현 PR merge
- RLS가 아직 활성화되지 않은 현재 환경에 먼저 배포
DEMO_SEED_ENABLED=true상태의 최초/재기동 회귀 확인- #135를 최신
main에 갱신하고 RLS 활성화 migration을 포함한 임시
통합 branch 또는 동일 commit 조합을 준비 - 운영 DB가 아닌 격리된 새 PostgreSQL DB에서 다음 리허설 완료
- Flyway 전체 migration 적용 및 validate
- 제한 Runtime Role 사용
DEMO_SEED_ENABLED=true최초 기동- 동일 DB 재기동
- Demo/Test 로그인·fixture 멱등성·tenant 격리 확인
- 위 리허설이 통과한 경우에만 feat: PostgreSQL RLS 기반 사업장 2차 격리 활성화 #135 merge 및 RLS migration 배포
- 배포 직후
DEMO_SEED_ENABLED=true + 제한 Runtime Role + RLS enabled
상태에서 재기동 Smoke Test - 이상이 없으면 Seed 활성 상태를 유지
PR #135가 먼저 배포되어야 하는 긴급 상황에서는
DEMO_SEED_ENABLED=false를 임시 운영 우회책으로 사용할 수 있지만, 이
이슈가 배포·검증되기 전에는 Seed를 다시 true로 전환하지 않습니다.
이번 이슈에서 하지 않는 것
- #135의 RLS policy 자체 변경
- 새로운 tenant isolation 모델 도입
- Runtime DB Role 권한 완화
- Flyway RLS 활성화 migration 추가/변경
- Demo fixture 내용의 대규모 개편
- Demo/Test 데이터 초기화 또는 재생성 정책 변경
- 기존 PostgreSQL PVC 데이터 삭제
- production profile에서 Demo Seed 활성화
- Infra Secret 원문 또는 DB credential 변경
연계
- feat: PostgreSQL RLS 기반 사업장 2차 격리 활성화 #135 --- PostgreSQL RLS 기반 사업장 2차 격리 활성화
- 이 이슈가
DEMO_SEED_ENABLED=true유지 조건에서의 선행 배포
게이트
- 이 이슈가
- [Deploy] PostgreSQL·AI Runtime 기반 데모 배포 구성 #9 --- PostgreSQL·AI Runtime 기반 데모 배포 구성
Activity