Files
vpd-permission-poc/docs/design/559-independent-vpd-dds-demos/README.md

8.1 KiB

독립 VPD·DDS 데모 구성

상태: VPD·DDS 병행 검증 완료, 토큰 기반 객체별 Data Grant 적용 완료 추적성: Redmine #565, #566 · DDS 구현 커밋 1e48864, a5e70bc 기준 구현: sql/adb/32_dds_vector_tag_setup.sql, sql/adb/34_dds_token_data_grant_common_auth.sql, dds-backoffice/src/main/java/com/cloudhandson/ddsbackoffice/service/DdsGrantPublisher.java, dds-backoffice/src/main/java/com/cloudhandson/ddsbackoffice/service/DdsVectorKnowledgeService.java

목적

VPD와 Oracle Deep Data Security(DDS)를 별도 인스턴스로 운영하면서도, 고객의 업무 권한을 정의하는 공통 테이블을 기준으로 같은 검색 시나리오를 비교한다. 고객마다 DDS 계정을 만드는 것이 목표가 아니다. 현재 기본 데모는 하나의 DDS 기술 사용자 세션에서 Bearer 토큰으로 Context를 만들고, 객체별 Data Grant predicate가 공통 권한 테이블을 읽어 결과를 제한한다.

인스턴스 경계

구분 VPD Demo DDS Demo
실행 디렉터리 /home/opc/apps/vpd-backoffice /home/opc/apps/dds-backoffice
기본 포트 8082 8083
사용자 식별 공통 DB 계정 + Bearer/세션 컨텍스트 단일 DDS 기술 사용자 + 토큰 Context(기본 경로)
권한 기준 업무 권한 테이블 + VPD 함수 같은 업무 권한 테이블 + 객체별 DDS DATA GRANT predicate
보호 객체 V_CUSTOMERS_* / VPD 전용 객체 V_DDS_CUSTOMERS_* / DDS 전용 객체
운영 프로세스 VPD start/stop/status DDS start/stop/status

두 인스턴스는 화면, JAR, PID, 로그, 설정 파일을 공유하지 않는다. 다만 권한의 업무 원천(source of truth)은 CB_APP_USER, 그룹·역할, CB_PERMISSION, CB_PERMISSION_RULE 같은 공통 테이블로 유지하고, 각 보안 엔진이 자기 방식으로 그 결과를 집행한다. DDS 벡터 설치 스크립트는 같은 TAG 권한을 DDS 검색 뷰와 연결한다.

동일하게 비교할 수 있는 것

  • 사용자별 원본 접근 범위
  • 행 단위 허용/차단
  • 권한 없는 사용자의 default deny
  • 보호 VIEW 우회 시도 차단

DDS 기본 시나리오: 한 기술 사용자, 토큰 Context, 객체별 DATA GRANT

일반 사용자가 이해하는 흐름

Bearer 토큰
  → 토큰 해시로 CB_AGENT_BEARER_KEY 조회
  → CB_APP_USER와 연결
  → 직접 역할 + 활성 그룹 역할 계산
  → CB_PERMISSION_RULE의 TAG 허용/거부 규칙 계산
  → CB_DDS_VECTOR_SEARCH_DOCUMENTS의 DATA GRANT predicate가 행을 평가
  → 허용된 청크만 반환

dds_demo_token 하나의 DDS 기술 사용자 세션에서 토큰 함수가 CB_AGENT_CTX를 설정하고, 객체별 Data Grant ADMIN.DDS_DEMO_TOKEN_VECTOR_GRANT의 predicate 함수가 공통 권한을 다시 평가하는 흐름을 검증했다. 고객마다 DDS 계정을 만들지 않고 토큰으로 업무 사용자를 식별한다. 같은 ALLOW 권한의 태그는 OR로 합치고, DENY 태그는 NOT EXISTS 의미로 제외한다.

여기서 CB_AGENT_CTX_PKG는 Bearer 해시·만료·회수·업무 사용자 매핑을 담당하는 공통 인증 어댑터다. DDS 경로는 VPD 정책 함수 CB_AGENT_DOC_VPD_FILTER를 호출하지 않고, Data Grant predicate가 별도로 권한을 집행한다.

호출 계약은 의도적으로 단순하다.

BEGIN
  ADMIN.CB_AGENT_CTX_PKG.SET_USER_BY_BEARER(:bearer_token);
END;
/

SELECT chunk_id, tech_tag
FROM   ADMIN.CB_DDS_VECTOR_SEARCH_DOCUMENTS
ORDER  BY chunk_id;

실제 Data Grant predicate 내부의 조회 조건은 다음 의미를 가진다.

WHERE EXISTS (허용된 TAG  하나가 청크 TAG와 일치)
  AND NOT EXISTS (거부된 TAG  하나가 청크 TAG와 일치)

즉, 토큰은 Context 초기화 입력이고 권한 결정은 객체별 DDS Data Grant가 기존 CB_* 테이블을 조회해 담당한다. 토큰별로 DDS 계정을 바꾸거나 고객 사용자마다 DDS DB 계정을 만드는 단계는 없다. DDS End User Security Context를 드라이버가 직접 전달하는 순수 DDS 경로는 이 데모와 별도다.

검증 결과

토큰으로 식별된 업무 사용자 TAG 권한 결과 반환 청크
agent_hr SPRING_BOOT OR ORACLE_VPD 28001, 28002 (2건)
agent_fin_self ORACLE_VPD 28002 (1건)
agent_all 전체 허용 역할 28001, 28002, 28003 (3건)

토큰 행, 임시 함수, 임시 권한은 검증 직후 삭제했다. 이 결과는 “DDS 사용자 수 = 고객 사용자 수”가 아니라 “DDS 기술 사용자 1개 + 고객 권한 테이블” 모델이 동작함을 보여 준다.

DDS 집행 경계

구분 토큰 기반 기본 데모 순수 DDS Context 확장
토큰 전달 토큰 함수가 신뢰된 CB_AGENT_CTX 설정 지원 드라이버/ORDS가 EndUserSecurityContext로 전달
권한 계산 객체별 DATA GRANT predicate가 공통 CB_* 테이블 조회 DATA GRANT predicate가 DDS 런타임 컨텍스트 참조
사용자 객체 DDS 기술 사용자 1개 + DDS Data Role 1개 DDS End User identity와 Data Role 매핑
현재 상태 벡터 VIEW에서 검증 완료 드라이버·ORDS 전달 경로를 별도 검증해야 함

중요한 경계는 DATA GRANT 자체가 호출 시점의 임의 함수 인자를 받는 구조가 아니라는 점이다. 그렇다고 Data Grant를 생략하는 것은 아니다. ON 절로 보호 VIEW/TABLE을 지정하고, WHERE predicate가 Context와 공통 권한 테이블을 사용해 행을 결정한다. 토큰 함수는 그 predicate가 참조할 Context를 만든다. 향후 순수 DDS Context를 사용하려면 토큰을 SQL 실행 전에 드라이버가 붙이고, 그때 ORA_END_USER_CONTEXT 기반 Data Grant를 적용한다. ORDS Handler가 Bearer 값을 DDS 사용자명 문자열로 바꾸는 것만으로는 DDS Context가 자동 생성되지 않는다.

객체별 Grant와 공통 권한체계 매핑

보호 대상이 늘어나면 대상별로 Data Grant를 추가한다. 하나의 Data Grant는 하나의 ON 테이블·뷰·Materialized View를 대상으로 하며, 해당 객체의 SELECT/DML·컬럼 범위와 행 predicate를 선언한다.

공통 권한체계 DDS 집행 위치
CB_PERMISSION.target_name 보호 객체와 논리 대상 매핑
CB_PERMISSION.action_name Data Grant의 SELECT/UPDATE
CB_PERMISSION_RULE Data Grant predicate의 WHERE 조건
직접 역할·활성 그룹 역할 predicate 함수의 effective role 집합
Bearer 키 CB_AGENT_CTX의 업무 사용자 식별

같은 대상의 여러 Data Grant는 기본적으로 합집합으로 적용된다. 따라서 ALLOW TAG를 여러 개 허용하는 것은 OR로 표현할 수 있지만, DENY는 별도 Grant로 만들면 전체를 차단하지 못할 수 있다. 이 데모는 하나의 객체별 predicate 안에서 (ALLOW A OR ALLOW B) AND NOT (DENY C) 의미를 만든다.

실행 확인

/home/opc/apps/vpd-backoffice/status.sh
/home/opc/apps/dds-backoffice/status.sh

외부 공개 포트는 애플리케이션 분리와 별개의 운영 변경이다. DDS 기본 바인딩은 127.0.0.1:8083이며, 직접 공개하려면 HTTPS, NSG, VM firewalld 정책을 별도로 승인한다.

변경·확장 가이드

  • 업무 사용자·역할·태그 권한은 기존 CB_* 테이블에서 관리한다. DDS 전용 고객 계정을 추가해 권한을 복제하지 않는다.
  • 토큰 조회 함수는 해시된 Bearer 키만 사용하고 원문 토큰을 저장하거나 로그에 남기지 않는다.
  • 새로운 TAG를 추가할 때는 태그 사전, CB_PERMISSION_RULE, 샘플 청크, 허용·거부 테스트를 함께 갱신한다.
  • 함수 경계를 벗어나 직접 DDS 객체를 노출하는 Handler를 만들지 않는다. 벡터 검색은 임베딩을 반환하지 않는 전용 뷰/Handler를 사용한다.
  • 운영에서 드라이버 기반 DDS Context로 전환할 때는 별도 설계·검증 이슈를 만들고, 현재의 토큰 WHERE 결과와 동일한 회귀 테스트를 통과시킨다.