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>
47 lines
1.9 KiB
SQL
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;
|