Files
vpd-permission-poc/sql/adb/03_seed.sql
devmrko 68d53dc5a9 Initial commit — VPD Permission POC (clone-and-go)
ADB-centered row-level access control across heterogeneous DB sources
(AWS RDS Postgres + MySQL) using Oracle VPD + Data Redaction +
Secure Application Context, packaged as a one-click demo.

Mechanism:
- LOGON trigger calls ctx_pkg.init once per session to load the user's
  allowed regions from the permission mapping tables into a Secure App
  Context (VPD_CTX, USING ctx_pkg).
- VPD policy function vpd_region_filter reads SYS_CONTEXT and returns
  an IN-list predicate (or '1=0' for fail-closed, NULL for '*'),
  which Oracle injects into every SELECT on the protected views.
- Data Redaction reuses the same context to mask PII (email, full_name)
  when the allowed-regions value is not '*'.
- 5 documented bypass attempts (direct DB link SELECT, SET_CONTEXT
  spoof, DBMS_RLS drop, mapping table SELECT) all blocked by GRANT
  scoping + DEFINER rights on ctx_pkg.

One-click entrypoint:
- ./run.sh {prereq|source|adb|tests|audit|all|teardown}
- Source DDL (Postgres + MySQL customers + 12-row seed each) is
  applied via local psql/mysql; ADB-side setup via sqlplus with .env
  values injected as SQL*Plus DEFINE substitutions.

Verified E2E on ADB 26ai + AWS RDS PG + RDS MySQL (mysql_community
gateway) on 2026-05-26: VPDUSER_A sees only APAC rows (PG 2 / MySQL 6,
PII masked), VPDUSER_B sees all (PG 12 / MySQL 17, PII unmasked).

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-05-26 14:03:32 +09:00

47 lines
1.9 KiB
SQL

-- ============================================================
-- 02_seed.sql
-- Seed two end-users with different permissions to demonstrate VPD.
--
-- VPDUSER_A -> group KR_ANALYSTS -> allowed_regions = 'APAC'
-- VPDUSER_B -> group GLOBAL_ADMINS -> allowed_regions = '*' (all rows)
--
-- Run as ADMIN.
-- ============================================================
SET ECHO OFF
SET FEEDBACK ON
PROMPT === Seeding permission data ===
INSERT INTO app_customer (customer_id, customer_name) VALUES (1, 'Acme Corp');
INSERT INTO app_user (user_id, db_username, customer_id) VALUES (1, 'VPDUSER_A', 1);
INSERT INTO app_user (user_id, db_username, customer_id) VALUES (2, 'VPDUSER_B', 1);
INSERT INTO app_group (group_id, customer_id, group_name) VALUES (10, 1, 'KR_ANALYSTS');
INSERT INTO app_group (group_id, customer_id, group_name) VALUES (20, 1, 'GLOBAL_ADMINS');
-- A -> KR_ANALYSTS
INSERT INTO user_group (user_id, group_id) VALUES (1, 10);
-- B -> GLOBAL_ADMINS
INSERT INTO user_group (user_id, group_id) VALUES (2, 20);
INSERT INTO db_source (source_id, source_name, source_type, dblink_name)
VALUES (100, 'RDS_POSTGRES', 'DBLINK_PG', 'RDS_POSTGRES_LINK');
INSERT INTO db_source (source_id, source_name, source_type, dblink_name)
VALUES (200, 'RDS_MYSQL', 'DBLINK_MY', 'RDS_LINK');
-- Permissions: KR analysts see APAC only; Global admins see everything.
INSERT INTO permission (perm_id, group_id, source_id, object_name, allowed_regions)
VALUES (1, 10, 100, 'V_CUSTOMERS_PG', 'APAC');
INSERT INTO permission (perm_id, group_id, source_id, object_name, allowed_regions)
VALUES (2, 10, 200, 'V_CUSTOMERS_MY', 'APAC');
INSERT INTO permission (perm_id, group_id, source_id, object_name, allowed_regions)
VALUES (3, 20, 100, 'V_CUSTOMERS_PG', '*');
INSERT INTO permission (perm_id, group_id, source_id, object_name, allowed_regions)
VALUES (4, 20, 200, 'V_CUSTOMERS_MY', '*');
COMMIT;
PROMPT === Seed complete ===
EXIT;