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:
83
sql/adb/12_tests_admin_audit.sql
Normal file
83
sql/adb/12_tests_admin_audit.sql
Normal file
@@ -0,0 +1,83 @@
|
||||
-- ============================================================
|
||||
-- 12_tests_admin_audit.sql
|
||||
-- Run as ADMIN to audit / verify policy attachment and the
|
||||
-- 4-user access matrix.
|
||||
-- ============================================================
|
||||
SET FEEDBACK ON
|
||||
SET LINESIZE 220
|
||||
SET PAGESIZE 100
|
||||
COL object_name FORMAT a20
|
||||
COL policy FORMAT a25
|
||||
COL pf_owner FORMAT a15
|
||||
COL package FORMAT a15
|
||||
COL function FORMAT a25
|
||||
COL sel FORMAT a3
|
||||
COL enable FORMAT a6
|
||||
|
||||
PROMPT
|
||||
PROMPT === Attached VPD policies (expect rows for V_CUSTOMERS_PG and V_CUSTOMERS_MY) ===
|
||||
SELECT object_name,
|
||||
policy_name AS policy,
|
||||
pf_owner,
|
||||
package,
|
||||
function,
|
||||
sel,
|
||||
enable
|
||||
FROM dba_policies
|
||||
WHERE object_owner = USER
|
||||
AND object_name IN ('V_CUSTOMERS_PG','V_CUSTOMERS_MY')
|
||||
ORDER BY object_name, policy_name;
|
||||
|
||||
PROMPT
|
||||
PROMPT === Attached Data Redaction policies ===
|
||||
COL object_name FORMAT a20
|
||||
COL policy_name FORMAT a20
|
||||
COL expression FORMAT a80 WORD_WRAPPED
|
||||
SELECT object_name,
|
||||
policy_name,
|
||||
expression
|
||||
FROM redaction_policies
|
||||
WHERE object_owner = USER
|
||||
ORDER BY object_name, policy_name;
|
||||
|
||||
PROMPT
|
||||
PROMPT === Redacted columns ===
|
||||
COL object_name FORMAT a20
|
||||
COL column_name FORMAT a15
|
||||
COL function_type FORMAT a15
|
||||
COL regexp_pattern FORMAT a25
|
||||
COL regexp_replace_string FORMAT a15
|
||||
SELECT object_name,
|
||||
column_name,
|
||||
function_type,
|
||||
regexp_pattern,
|
||||
regexp_replace_string
|
||||
FROM redaction_columns
|
||||
WHERE object_owner = USER
|
||||
ORDER BY object_name, column_name;
|
||||
|
||||
PROMPT
|
||||
PROMPT === 4-user access matrix (from permission table) ===
|
||||
PROMPT === Expected: ===
|
||||
PROMPT === VPDUSER_MY -> V_CUSTOMERS_MY '*' ===
|
||||
PROMPT === VPDUSER_PG -> V_CUSTOMERS_PG '*' ===
|
||||
PROMPT === VPDUSER_BOTH -> V_CUSTOMERS_PG '*' + V_CUSTOMERS_MY '*' ===
|
||||
PROMPT === VPDUSER_NONE -> (no rows — fail-closed by absence) ===
|
||||
COL db_username FORMAT a14
|
||||
COL group_name FORMAT a14
|
||||
COL source_name FORMAT a14
|
||||
COL object_name FORMAT a16
|
||||
COL allowed_regions FORMAT a16
|
||||
SELECT u.db_username,
|
||||
g.group_name,
|
||||
s.source_name,
|
||||
p.object_name,
|
||||
p.allowed_regions
|
||||
FROM app_user u
|
||||
LEFT JOIN user_group ug ON ug.user_id = u.user_id
|
||||
LEFT JOIN app_group g ON g.group_id = ug.group_id
|
||||
LEFT JOIN permission p ON p.group_id = g.group_id
|
||||
LEFT JOIN db_source s ON s.source_id = p.source_id
|
||||
ORDER BY u.db_username, p.object_name NULLS LAST;
|
||||
|
||||
EXIT;
|
||||
Reference in New Issue
Block a user