맥락 앱이 테이블 소유자 계정으로 접속하면, SQL 주입이나 자격 증명 유출 한 번으로 스키마 삭제·감사 로그 조작까지 가능하다.
결정
FLYWAY_USER=buildrisk), 앱 커넥션 풀은 buildrisk_app(DML 전용).afterMigrate 콜백이 매 기동 때 맞춘다: 없으면 만들고, 스키마 5개(ref·dart·mkt·risk·ops)의 모든 테이블에
SELECT·INSERT·UPDATE·DELETE, 시퀀스 USAGE. 새 테이블이 생겨도 다음 기동에 자동 반영. 비밀번호는 .env(DB_APP_PASSWORD) → placeholder.ops.audit_log 의 UPDATE·DELETE·TRUNCATE 회수. 마이그레이션 이력(flyway_schema_history) 접근 불가.검증 LeastPrivilegeIT — 앱 계정으로 읽기·쓰기·시퀀스·PostGIS 함수는 되고, CREATE TABLE(스키마·public) · DROP · ALTER · TRUNCATE ·
감사 로그 UPDATE/DELETE · 마이그레이션 이력 조회 · CREATE ROLE 은 모두 거부. 실제 스택에서도 커넥션이 buildrisk_app 으로만 열리는 것을 pg_stat_activity 로 확인.
덧붙임 (2026-10-09, VERIFICATION 108) 소유자 계정 비밀번호는 마이그레이션을 하는 api 와 단독 실행 batch 컨테이너에만 전달한다. 외부 API 를 부르는 worker 는 api 가 마이그레이션을 끝낸 뒤(depends_on healthy) 뜨므로 Flyway 를 끄고 소유자 계정을 받지 않는다 — 외부 입력을 가장 많이 다루는 프로세스가 스키마를 바꿀 수 있는 자격 증명을 들고 있지 않게.
덧붙임 (2026-10-11, VERIFICATION 178 · 188) — 비밀번호를 SQL 에 평문으로 넣지 않음 · 콜백 줄 세우기
AppRolePasswordCustomizer). DO 블록이 실패하면 PostgreSQL 이 문장 전체를
서버 로그에 남기는데(RDS 로그는 세 프로젝트 공용), 검증값은 그대로 저장되고 앱은 평문으로 로그인한다. ASCII 밖의 문자는 SASLprep 정규화를 같게 보장할 수 없어
평문으로 두고 경고한다(생성한 비밀번호는 16진수).