- .env.example: REDMINE_URL/API_KEY and GITEA_URL/USER/PASSWORD/TOKEN placeholders so a fresh clone surfaces the optional tracker/mirror hookups without exposing real credentials. - docs/notes/2026-06-08-dds-qa-session.md: personal session reference covering DDS role model, scenario walkthrough, group/DB Link/Data Catalog patterns, and the mapping-table vs declarative-DDL decision. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
13 KiB
2026-06-08 — DDS 깊이 이해 Q&A 세션 기록
이 문서는 vpd-permission-poc 작업 중 DDS (Oracle 26ai Deep Data Security) 의 운영 모델·시나리오·확장 가능성을 짚어본 Q&A 세션의 기록이다. 정식 docs 가 아니라 개인 참조용 노트.
TL;DR — 핵심 7 가지
- DDS 의 권한 모델 = 3 객체:
END USER(개인) →DATA ROLE(그룹) →DATA GRANT(정책). - DATA GRANT 한 줄에 행 필터(WHERE) + 컬럼 마스킹(
ALL COLUMNS EXCEPT) + 작업 단위(SELECT/INSERT/UPDATE) 가 다 들어간다. - END USER ≠ 그룹. 그룹은
DATA ROLE. 같은 권한 받을 사람들을 묶고, DATA GRANT 는 항상 DATA ROLE 대상. - 테이블 DDL 은 안 건드린다. 정책은 별도 DDL 객체(
CREATE DATA GRANT ...) 로 외부에서 붙는다. 변경/회수는 객체 단위 (CREATE OR REPLACE,DROP). - DB Link / Data Catalog 등 외부 데이터도 통제 가능. 패턴은 동일:
원격객체 → 로컬 VIEW → DATA GRANT. 원격 객체에 직접은 못 붙임. - 권한 없는 유저 →
ORA-00942(객체 자체 미노출). VPD 의 "0 rows" 보다 강한 enumeration 방어. - 권한 매핑 테이블 모델은 VPD 가 맞음. DDS 는 권한을 "데이터 행" 이 아니라 "DDL 객체" 로 두는 모델.
이번 세션에서 README 에 반영된 변경
| 커밋 | 내용 |
|---|---|
3045271 |
README 에 ## 무엇을 통제하는가 섹션 추가 — 행/컬럼/구현 비교 (드라이 톤) |
b80d119 |
README 에 ## DDS 설정 핵심 추가 — 사전조건·4스텝 DDL·함정 4종·변주 |
두 섹션 모두 비유 없이 표·코드 위주.
1. DDS 기본 모델
등장 인물 3 종
| 역할 | 한 줄 | |
|---|---|---|
| END USER | 데이터 조회자 (개인) | 스키마 없음 → 객체 못 만듦 |
| DATA ROLE | 권한 묶음 (그룹) | END USER 는 이걸 통해서만 권한 받음 |
| DATA GRANT | "누가 뭘 본다" 선언 | DDL 한 줄에 행·컬럼·작업 다 들어감 |
흐름: END USER → DATA ROLE → DATA GRANT → 테이블/뷰
DATA GRANT 한 줄 예시
CREATE DATA GRANT admin.sales_apac
AS SELECT (ALL COLUMNS EXCEPT ssn, email) -- 컬럼 마스킹
ON admin.customers -- 어느 객체
WHERE region = 'APAC' -- 행 필터
AND owner_id = ORA_END_USER_CONTEXT.username -- 세션 정체성
TO sales_role; -- 누구에게 (그룹)
VPD 와 비교 한 표
| VPD | DDS | |
|---|---|---|
| 정책 표현 | PL/SQL 함수 (절차형) | SQL DDL (선언형) |
| 컬럼 마스킹 | 별도 DBMS_REDACT |
그랜트에 내장 |
| 미권한 동작 | 0 rows | 객체 숨김 (ORA-00942) |
| 신원 | DB 유저 + LOGON 트리거 | END USER ± OAuth2 매핑 |
| 운영 코드 | 정책 함수 + 컨텍스트 패키지 + 트리거 | 그랜트 DDL 만 |
| 감사 | 함수 본문 까야 함 | 카탈로그 뷰 |
2. 시나리오 — HR employees 테이블 9-STEP
3 종 사용자:
hr_lead— 전체 행, 모든 컬럼mgr_eng— Engineering 부서만, SSN 마스킹auditor_ext— 전체 행, salary/ssn/email 마스킹
두 가지 핵심 질문 직답
| Q | A |
|---|---|
| 유저는 어느 객체에 추가? | 어디에도 안 추가. CREATE END USER 로 카탈로그(dba_end_users)에 생기는 독립 객체 |
| 일반 CREATE TABLE 에 같이 쓰나? | 아니오. 테이블 DDL 은 평범하게. 정책은 별도 CREATE DATA GRANT |
| 테이블 정의를 바꿔야 하나? | 거의 안 바꿈. 예외는 MAC 모드 켤 때 ALTER TABLE ... SET USE DATA GRANTS ONLY ENABLED 한 줄 |
9 스텝 요약
STEP 0 ADMIN 으로 접속
STEP 1 CREATE TABLE employees (...) -- 평범한 DDL
STEP 2 CREATE END USER "hr_lead" / "mgr_eng" / "auditor_ext"
STEP 3 CREATE ROLE dds_db_role + GRANT CREATE SESSION
CREATE DATA ROLE hr_lead_role / eng_mgr_role / auditor_role
GRANT dds_db_role TO <each data role>
STEP 4 GRANT DATA ROLE <role> TO "<user>"
STEP 5 CREATE DATA GRANT (행+컬럼+대상) × 3
STEP 6 각 유저로 접속해 결과 확인
STEP 7 CREATE OR REPLACE DATA GRANT 로 정책 라이브 변경
DROP DATA GRANT 로 회수 (= 즉시 ORA-00942)
STEP 8 (선택) ALTER TABLE ... SET USE DATA GRANTS ONLY ENABLED -- MAC 모드
STEP 9 감사 (dba_data_grants 등) + 역순 정리
전체 스크립트는 세션 본문 참조. 이 POC 의 sql/adb/13_dds_variant.sql + 15_dds_cleanup.sql 가 동일 패턴.
3. 그룹 적용
END USER 는 그룹이 아니다 — 그룹은 DATA ROLE
마케팅팀 N 명에게 같은 권한:
-- 1) 그룹 1 개
CREATE DATA ROLE marketing_role;
GRANT dds_db_role TO marketing_role;
-- 2) 정책 1 줄 — 그룹에 부여
CREATE DATA GRANT admin.dg_marketing_view
AS SELECT (ALL COLUMNS EXCEPT ssn, salary)
ON admin.employees
WHERE department = 'Marketing'
TO marketing_role;
-- 3) 멤버 N 명 추가 (반복)
GRANT DATA ROLE marketing_role TO "carol";
GRANT DATA ROLE marketing_role TO "david";
-- 멤버 제거
REVOKE DATA ROLE marketing_role FROM "frank";
정책은 한 번, 멤버 변경은 GRANT/REVOKE.
DATA ROLE 중첩 (그룹 안에 그룹)
GRANT all_employees_role TO marketing_role; -- 마케팅이 전사 권한 흡수
GRANT marketing_role TO marketing_lead_role; -- 리드가 마케팅 권한 흡수
Federated Identity (외부 IdP 그룹 그대로)
CREATE DATA ROLE marketing_role MAPPED TO 'AZURE_ROLE=Marketing';
CREATE DATA ROLE finance_role MAPPED TO 'OKTA_GROUP=Finance-Read';
→ DB 에 END USER 안 만들고, Azure/Okta 그룹 멤버십이 진실. SaaS / agentic AI 에 가장 큰 차별점.
4. DB Link (heterogeneous) 데이터 통제
패턴
[원격 PG/MySQL]
│ DB Link
▼
[ADB: CREATE VIEW v_dds_customers_pg AS SELECT ... FROM ...@RDS_POSTGRES_LINK]
│ CREATE DATA GRANT ON v_dds_customers_pg
▼
[DATA ROLE] ──GRANT──▶ [END USER]
핵심 4 가지 주의점
| 주의 | 내용 |
|---|---|
| 1. 원격 객체에 직접 ❌ | DATA GRANT 는 로컬 객체에만. 무조건 VIEW 한 겹 |
| 2. VPD 와 같은 뷰 공유 ❌ | VPD 1=0 가 DDS 보다 먼저 적용 → silent 0 rows. DDS 전용 뷰 따로 만들 것 |
| 3. WHERE 푸시다운 보장 X | 옵티마이저 판단. 큰 테이블이면 EXPLAIN PLAN 으로 REMOTE 노드 확인 |
| 4. MV 는 다른 얘기 | MV 만들면 데이터 캐시됨 → fresh 정책 트레이드오프 |
이 POC 의 v_customers_* (VPD용) ↔ v_dds_customers_* (DDS용) 분리가 정확히 #2 회피 때문.
5. OCI Data Catalog 객체 통제
모델 — 2 층 권한
| 층 | 무엇 | 누가 관리 |
|---|---|---|
| ① OCI IAM | Object Storage 버킷 + Data Catalog 자산 자체 | OCI 콘솔 (IAM Policy) |
| ② DDS | ADB 안에 동기화된 External Table/View | ADB ADMIN |
DDS 는 ②만. ①에서 ADB credential 이 가진 권한이 천장.
흐름
[Object Storage / RDB]
│ (등록)
▼
[OCI Data Catalog]
│ DBMS_DCAT.RUN_SYNC
▼
[ADB: External Table DCAT$XYZ] ← 평범한 ADB 객체
│
▼
[ADB: VIEW v_sales] ◀── CREATE DATA GRANT ON v_sales TO ...
스크립트 골격
-- 1) Catalog 연결 (최초 1회)
BEGIN
DBMS_DCAT.SET_DATA_CATALOG_CONN(
region => 'ap-seoul-1',
catalog_id => 'ocid1.datacatalog.oc1...',
catalog_tenancy => 'ocid1.tenancy.oc1...');
END;
/
-- 2) 동기화 — External Table 생성됨
BEGIN
DBMS_DCAT.RUN_SYNC(
synced_objects => '{"asset_list":[...]}',
sync_mode => 'AUTO',
target_schema => 'DCAT_LANDING',
sync_response => :resp);
END;
/
-- 3) sync-안전 VIEW 한 겹 (★)
CREATE OR REPLACE VIEW admin.v_customers AS
SELECT customer_id, full_name, email, region, signup_date
FROM dcat_landing."DCAT$CUSTOMERS";
-- 4) DDS 정책
CREATE DATA GRANT admin.dg_sales_apac_customers
AS SELECT (ALL COLUMNS EXCEPT email)
ON admin.v_customers
WHERE region = 'APAC'
TO sales_apac_role;
-- 5) (선택) MAC
ALTER TABLE admin.v_customers SET USE DATA GRANTS ONLY ENABLED;
왜 VIEW 한 겹이 중요한가
DBMS_DCAT.RUN_SYNC 가 자산 변경 시 External Table 을 DROP/CREATE 할 수 있다.
External Table 에 직접 DATA GRANT 붙이면 sync 한 번에 정책이 사라진다.
VIEW 를 사이에 끼우면 DATA GRANT 는 VIEW 에 붙으니 sync 와 무관하게 살아남는다.
(DB Link 패턴과 동일한 이유)
6. "row 형태로 권한 적용" 이라는 표현
80% 맞지만 부족
| 통제 | 표현 |
|---|---|
| 행 | WHERE region = 'APAC' |
| 컬럼 | (ALL COLUMNS EXCEPT email, ssn) |
| 작업 | AS SELECT/INSERT/UPDATE/DELETE |
| 객체 노출 | 그랜트 없으면 ORA-00942 |
정확한 한 줄: "행 + 컬럼 + 작업 단위 권한을, 그룹(DATA ROLE) 대상으로 선언형 DDL 한 줄에 표현."
흔한 오해 — 권한 저장 매체가 다름
| VPD | DDS | |
|---|---|---|
| 권한 어디 저장? | permission 테이블의 행 |
DB 카탈로그의 DATA GRANT 객체 |
| 권한 추가 | INSERT INTO permission ... |
CREATE DATA GRANT ... |
| 권한 회수 | DELETE FROM permission ... |
DROP DATA GRANT ... |
| 권한 변경 | UPDATE permission SET ... |
CREATE OR REPLACE DATA GRANT ... |
DDS = "권한을 데이터처럼 다루는" 게 아니라 "권한을 SQL 객체로 다룬다" (GRANT 처럼).
7. 권한 매핑 테이블 모델 — VPD vs DDS
결론: 매핑 테이블 패턴은 VPD 가 맞다.
VPD 정책 함수는 PL/SQL → 그 안에서 임의의 SELECT 가능 → 매핑 테이블 lookup 자연스러움. DDS 의 DATA GRANT 는 선언형 DDL → 동적 lookup 불가능.
운영 패턴 비교
| 운영 | VPD | DDS |
|---|---|---|
| 권한 추가 | INSERT INTO permission ... |
CREATE DATA GRANT ... 또는 GRANT DATA ROLE |
| 누가 변경? | 매핑 테이블에 INSERT 권한자 (앱/사람, DBA 아님) | DDL 권한자 (ADMIN) |
| 셀프서비스 (앱이 권한 위임) | 자연스러움 | 부자연 (앱이 DDL 실행은 부담) |
| 수만 명 운영 | 매핑 행 N → 함수가 동적 처리 (확장 잘 됨) | DATA GRANT/DATA ROLE 폭증 시 부담 |
DDS 우회 (권장 X)
DATA GRANT 대상 객체를 매핑 테이블과 JOIN 한 뷰 로 만들 수 있다.
CREATE OR REPLACE VIEW admin.v_customers_scoped AS
SELECT c.*
FROM admin.customers c
JOIN admin.permission p ...
JOIN admin.user_group ug ...
WHERE ug.user_name = ORA_END_USER_CONTEXT.username
AND INSTR(',' || p.allowed_regions || ',', ',' || c.region || ',') > 0;
CREATE DATA GRANT admin.dg_scoped
AS SELECT ON admin.v_customers_scoped TO some_role;
→ 동작은 한다. 그러나:
- 선언형 DDS 의 장점 상실 (로직이 뷰 SQL 로 옮겨갔을 뿐)
- 매핑 테이블 별도 보호 필요
- 디버깅이 두 곳 (뷰 + 그랜트) 으로 나뉨
- 이럴 거면 그냥 VPD 가 깔끔
선택 가이드
| 상황 | 권장 |
|---|---|
| 권한이 데이터 자체 (테넌트·고객·부서 매핑 자주 변경, 앱이 관리) | VPD |
| 권한이 운영 정책 (소수 역할, DBA/SRE 가 DDL 관리, IdP 연동) | DDS |
| 수만 행 × 동적 lookup (멀티테넌트 SaaS) | VPD |
| 선언형 단일 평면 + 카탈로그 감사 우선 | DDS |
| OAuth2 / Azure AD 그룹 그대로 사용 | DDS (MAPPED TO) |
이 POC 에서 보면
sql/adb/06_policy.sql+permission테이블 = "앱/운영자가 행으로 권한 관리" → VPD 답안sql/adb/13_dds_variant.sql= "DBA 가 DDL 로 4 종 역할 정의" → DDS 답안- 같은 결과를 두 다른 모델로 표현한 비교 데모
권한 매핑 테이블 중심으로 가겠다면 VPD 그대로 두는 게 정답.
DDS 로 옮기려면 매핑 자체를 DATA ROLE 멤버십 으로 재구성해야 한다 (매핑 테이블 사라지고 GRANT DATA ROLE 이 그 자리 차지).
부록 — DDS 운영 시 자주 보는 쿼리
-- 누가 뭘 볼 수 있는지
SELECT * FROM dba_data_grants;
-- 데이터 역할 (그룹)
SELECT * FROM dba_data_roles;
-- 데이터 사용자
SELECT * FROM dba_end_users;
-- 일반 ROLE ↔ DATA ROLE 매핑 관계
SELECT grantee, granted_role
FROM dba_role_privs
WHERE grantee LIKE '%role';
-- MAC 모드 켜진 객체
SELECT owner, table_name
FROM dba_tables
WHERE use_data_grants_only = 'YES'; -- 정확한 컬럼명은 카탈로그 확인
다음 세션 재개 시 확인할 것
- 이 POC 의 DDS 변형은 이미 E2E 검증 완료 (Task #28).
./run.sh dds한 번이면 재현됨. - README 의
## 무엇을 통제하는가+## DDS 설정 핵심섹션은 이번에 추가됨. - 매핑 테이블 패턴 = VPD, 선언형 패턴 = DDS — POC 가 두 길 다 보여줌.
- 확장 검토 후보:
- DDS 변형에
MAPPED TO(federated identity) 데모 추가 - DB Link 외에 OCI Data Catalog 싱크 자산을 같은 DDS 매트릭스로 보호하는 변형
SET USE DATA GRANTS ONLY활성화 후 우회 시도 5종 재검증
- DDS 변형에