Pivot scenario from region-based 2 users to source-based 4 users

Replaces the original APAC-vs-all 2-user demo (vpduser_a/b on
KR_ANALYSTS/GLOBAL_ADMINS groups) with a 2x2 source-access matrix:

  vpduser_my    -> MY_ONLY      group  -> MySQL view only
  vpduser_pg    -> PG_ONLY      group  -> Postgres view only
  vpduser_both  -> BOTH_SOURCES group  -> both views
  vpduser_none  -> (no group)          -> nothing (default deny)

Why: source-level segmentation is the more common production
permission story than region-level filtering. Region filtering
remains available as an opt-in variant via commented UPDATE in
sql/adb/03_seed.sql.

Key changes:
- 03_seed.sql, 07_end_users.sql, 00_cleanup.sql, .env.example,
  run.sh updated for the new 4-user model. All 4 users get
  identical view GRANTs; the only differentiator is the
  permission table (proves the model is "data-driven, not
  GRANT-driven").
- 08-11 split into one file per user: my (+ 5 bypass attempts),
  pg, both, none (default-deny verification).
- 12_tests_admin_audit.sql uses LEFT JOIN so vpduser_none shows
  up as NULL permissions, and filters by object_owner=USER to
  exclude cross-schema policies.
- Removed inline "-- comment" after ";" lines in 03_seed.sql:
  SQL*Plus silently skipped the inserts (documented gotcha).
- README.md + docs/01,02 updated for the 4-user matrix. docs/03
  detailed guide keeps the region-filter example but now has a
  preface explaining it's a variant of the default 4-user model.
- docs/04: db_type='mysql_community' note added (RDS MySQL).

E2E verified: PG=0/MY=17, PG=12/MY=0, PG=12/MY=17, PG=0/MY=0
plus all 5 bypass attempts blocked.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
devmrko
2026-05-26 14:42:11 +09:00
parent 68d53dc5a9
commit ed91306ee3
17 changed files with 424 additions and 191 deletions

27
run.sh
View File

@@ -7,7 +7,7 @@
# ./run.sh prereq # 도구 존재 / .env 변수만 검증
# ./run.sh source # 원격 PG + MySQL 에 customers 테이블/seed 생성
# ./run.sh adb # ADB 측 cleanup → dblinks → perm/ctx/view/policy → end_users
# ./run.sh tests # vpduser_a / vpduser_b 로 접속해서 행 필터 검증
# ./run.sh tests # 4-user (my/pg/both/none) 로 접속해서 행 필터 검증
# ./run.sh audit # admin 으로 정책/뷰/유저 상태 점검
# ./run.sh all # source → adb → tests → audit
# ./run.sh teardown # ADB 측 객체 + 원격 link/cred 만 정리 (원격 PG/MySQL 데이터는 보존)
@@ -61,14 +61,16 @@ DEFINE MY_PORT = ${MY_PORT}
DEFINE MY_DB = "${MY_DB}"
DEFINE MY_USER = "${MY_USER}"
DEFINE MY_PASSWORD = "${MY_PASSWORD}"
DEFINE VPDUSER_A_PASSWORD = "${VPDUSER_A_PASSWORD}"
DEFINE VPDUSER_B_PASSWORD = "${VPDUSER_B_PASSWORD}"
DEFINE VPDUSER_MY_PASSWORD = "${VPDUSER_MY_PASSWORD}"
DEFINE VPDUSER_PG_PASSWORD = "${VPDUSER_PG_PASSWORD}"
DEFINE VPDUSER_BOTH_PASSWORD = "${VPDUSER_BOTH_PASSWORD}"
DEFINE VPDUSER_NONE_PASSWORD = "${VPDUSER_NONE_PASSWORD}"
@${sql_file}
SQLEOF
}
# ============================================================
# 헬퍼: 엔드유저 (vpduser_a / vpduser_b) 로 sqlplus 호출
# 헬퍼: 엔드유저 (vpduser_my / pg / both / none) 로 sqlplus 호출
# 인자: $1 = USER, $2 = PASSWORD, $3 = SQL 파일
# ============================================================
run_sqlplus_as() {
@@ -93,7 +95,8 @@ do_prereq() {
require_env \
TNS_ADMIN ADB_TNS ADB_USER \
VPDUSER_A_PASSWORD VPDUSER_B_PASSWORD \
VPDUSER_MY_PASSWORD VPDUSER_PG_PASSWORD \
VPDUSER_BOTH_PASSWORD VPDUSER_NONE_PASSWORD \
PG_HOST PG_PORT PG_DB PG_USER \
MY_HOST MY_PORT MY_DB MY_USER \
DBLINK_PG_NAME DBLINK_MY_NAME
@@ -140,15 +143,17 @@ do_adb() {
}
do_tests() {
log "=== tests: 엔드유저 권한/필터 검증 ==="
run_sqlplus_as vpduser_a "$VPDUSER_A_PASSWORD" "$ROOT/sql/adb/08_tests_user_a.sql"
run_sqlplus_as vpduser_b "$VPDUSER_B_PASSWORD" "$ROOT/sql/adb/09_tests_user_b.sql"
ok "user_a / user_b 테스트 실행 완료 (위 출력에서 행 수 / 거부 결과 확인)"
log "=== tests: 4-user access matrix 검증 ==="
run_sqlplus_as vpduser_my "$VPDUSER_MY_PASSWORD" "$ROOT/sql/adb/08_tests_user_my.sql"
run_sqlplus_as vpduser_pg "$VPDUSER_PG_PASSWORD" "$ROOT/sql/adb/09_tests_user_pg.sql"
run_sqlplus_as vpduser_both "$VPDUSER_BOTH_PASSWORD" "$ROOT/sql/adb/10_tests_user_both.sql"
run_sqlplus_as vpduser_none "$VPDUSER_NONE_PASSWORD" "$ROOT/sql/adb/11_tests_user_none.sql"
ok "4명 (MY / PG / BOTH / NONE) 테스트 실행 완료"
}
do_audit() {
log "=== audit: admin 으로 정책 / 뷰 / 유저 상태 점검 ==="
run_sqlplus_file "$ROOT/sql/adb/10_tests_admin_audit.sql"
log "=== audit: admin 으로 정책 / 뷰 / 매트릭스 점검 ==="
run_sqlplus_file "$ROOT/sql/adb/12_tests_admin_audit.sql"
ok "audit 완료"
}