feat: center DDS demo on sales knowledge authorization
This commit is contained in:
@@ -5,15 +5,15 @@
|
||||
- 기본 포트: `8083`
|
||||
- 기본 화면: `/` (공통 권한 여정), `/dds` (DDS 직접 조회 검증)
|
||||
- 권한 반영: `/dds-provision` (공통 권한을 DDS DATA GRANT로 미리보기·게시)
|
||||
- 기본 보호 객체: `ADMIN.V_DDS_CUSTOMERS_PG`, `ADMIN.V_DDS_CUSTOMERS_MY`
|
||||
- 지식 검색 보호 객체: `ADMIN.CB_DDS_VECTOR_SEARCH_DOCUMENTS`
|
||||
- DDS 직접 비교 사용자: `dds_demo_my`, `dds_demo_pg`, `dds_demo_both`, `dds_demo_none`
|
||||
- 주 보호 객체: `ADMIN.CB_DDS_VECTOR_SEARCH_DOCUMENTS` (지식 청크·분류값 검색)
|
||||
- 보조 직접 검증 객체: `ADMIN.V_DDS_CUSTOMERS_PG`, `ADMIN.V_DDS_CUSTOMERS_MY`
|
||||
- 보조 DDS 비교 사용자: `dds_demo_my`, `dds_demo_pg`, `dds_demo_both`, `dds_demo_none`
|
||||
- 토큰 경로 기술 사용자: `dds_demo_token` (고객별 DDS 계정이 아님)
|
||||
- 조회 방식: 직접 DDS END USER 비교 경로 + 단일 기술 사용자·Bearer 토큰 경로
|
||||
|
||||
## 두 데모의 관계
|
||||
|
||||
두 인스턴스는 프로세스·포트·실행 경계를 분리하지만, 화면에서 설명하는 관리 순서는 같습니다.
|
||||
두 인스턴스는 프로세스·포트·실행 경계를 분리하지만, 화면에서 설명하는 관리 순서는 같습니다. PG/MySQL 원본 매트릭스는 DDS의 저수준 행/객체 Grant 예제일 뿐이며, 제품형 주 시나리오는 벡터 지식자료입니다.
|
||||
|
||||
```text
|
||||
사용자·그룹·역할 → 데이터 권한 규칙 → DDS Grant 게시 → 보호 연결 → 실제 결과 확인
|
||||
@@ -58,13 +58,16 @@ ORDS Handler가 Bearer 값을 `cb_dds_hr` 같은 문자열로 바꾸는 것만
|
||||
sqlplus "$ADB_USER/$ADB_PASSWORD@$ADB_TNS" @sql/adb/31_dds_standalone_demo_setup.sql
|
||||
sqlplus "$ADB_USER/$ADB_PASSWORD@$ADB_TNS" @sql/adb/32_dds_vector_tag_setup.sql
|
||||
bash scripts/setup-dds-token-data-grant.sh
|
||||
sqlplus "$ADB_USER/$ADB_PASSWORD@$ADB_TNS" @sql/adb/36_dds_sales_knowledge_scenario.sql
|
||||
```
|
||||
|
||||
`32_dds_vector_tag_setup.sql`은 공통 청크·태그 저장소를 읽는 DDS 전용 VIEW를 만들고, 동일한 `CB_PERMISSION`/`CB_PERMISSION_RULE`에 역할별 TAG 규칙을 등록합니다. `SPRING_BOOT`, `ORDS`, `ORACLE_VPD`, `MCP`처럼 한 역할에 여러 TAG가 있으면 `/dds-provision`이 OR 조건으로 합쳐 DDS DATA GRANT를 다시 만듭니다. 벡터 검색에 필요한 `EMBEDDING`은 DDS 엔진이 거리 계산에 사용하므로 Grant에서 제외하지 않고, 검색 응답에서는 애플리케이션이 반환하지 않습니다. 그 외 민감 컬럼은 애플리케이션 권한의 원문 허용 목록에 없으면 `ALL COLUMNS EXCEPT`로 제외됩니다. 검색 화면에서는 같은 문서를 청킹·임베딩한 뒤 선택한 END USER로 직접 조회하므로, DDS Grant가 없는 주체는 보호 VIEW 자체를 볼 수 없습니다.
|
||||
|
||||
`34_dds_token_data_grant_common_auth.sql`은 `dds_demo_token` 하나와 `cb_dds_token_role` 하나를 만들고, `ADMIN.CB_DDS_VECTOR_SEARCH_DOCUMENTS`에 객체별 Data Grant를 연결합니다. Data Grant의 predicate 함수는 직접 역할과 활성 그룹 역할을 합친 뒤 `CB_PERMISSION`·`CB_PERMISSION_RULE`의 TAG 허용/거부 규칙을 요청 시 평가합니다. 토큰은 Data Grant 문법의 인자가 아니라 `CB_AGENT_CTX`를 초기화하는 입력입니다.
|
||||
|
||||
토큰 경로를 제거할 때는 사용 중인 애플리케이션이 없는지 확인한 뒤 `sql/adb/35_dds_token_data_grant_cleanup.sql`을 별도로 승인해 실행합니다.
|
||||
`36_dds_sales_knowledge_scenario.sql`은 `agent_sales`와 `SALES_KNOWLEDGE_ROLE`을 만들고 `TECH_TAG=SALES`인 세일즈 청크(28004)를 추가합니다. 짧은 데모 토큰 `dds_sales_demo_token`을 사용하면 결과는 28004만 남아야 합니다. 운영에서는 이 토큰 대신 Bearer 관리 화면에서 발급한 임시 토큰을 사용합니다.
|
||||
|
||||
토큰 경로를 제거할 때는 사용 중인 애플리케이션이 없는지 확인한 뒤 `sql/adb/37_dds_sales_knowledge_scenario_cleanup.sql`과 `sql/adb/35_dds_token_data_grant_cleanup.sql`을 별도로 승인해 실행합니다.
|
||||
|
||||
그 다음 DDS 인스턴스를 실행합니다.
|
||||
|
||||
|
||||
@@ -37,10 +37,10 @@
|
||||
</section>
|
||||
|
||||
<section class="content-band">
|
||||
<div class="section-heading"><div><h2>현재 DDS 검증 대상</h2><p class="section-subtitle">고객 데이터 원본과 벡터 지식자료를 각각 DDS 전용 객체로 확인합니다.</p></div></div>
|
||||
<div class="section-heading"><div><h2>현재 DDS 검증 대상</h2><p class="section-subtitle">주 시나리오는 업무 분류값이 붙은 벡터 지식자료 검색입니다. 원본 테이블은 보조 기술 검증으로만 제공합니다.</p></div></div>
|
||||
<div class="table-responsive"><table class="table table-sm align-middle"><thead><tr><th>대상</th><th>보호 방식</th><th>검증</th></tr></thead><tbody>
|
||||
<tr><td><code>ADMIN.V_DDS_CUSTOMERS_PG/MY</code></td><td>DATA ROLE/DATA GRANT</td><td><a href="/dds">원본별 직접 조회</a></td></tr>
|
||||
<tr><td><code th:text="${vectorObject}">ADMIN.CB_DDS_VECTOR_SEARCH_DOCUMENTS</code></td><td>객체별 TAG DATA GRANT + 토큰 Context + VECTOR_DISTANCE</td><td><a href="/vector-knowledge">지식 검색</a></td></tr>
|
||||
<tr><td><code th:text="${vectorObject}">ADMIN.CB_DDS_VECTOR_SEARCH_DOCUMENTS</code></td><td>객체별 분류값 DATA GRANT + 토큰 Context + VECTOR_DISTANCE</td><td><a href="/vector-knowledge">지식 검색</a></td></tr>
|
||||
<tr><td>PG/MY 원본 예제</td><td>보조 END USER 직접 Grant</td><td><a href="/dds">저수준 검증 열기</a></td></tr>
|
||||
</tbody></table></div>
|
||||
</section>
|
||||
</main>
|
||||
|
||||
@@ -7,12 +7,12 @@
|
||||
<main class="container py-4">
|
||||
<header class="hero">
|
||||
<span class="eyebrow">DEEP DATA SECURITY · INDEPENDENT DEMO</span>
|
||||
<h1>같은 접근 결과를 다른 보안 모델로 확인합니다.</h1>
|
||||
<p class="lead">이 화면은 VPD 데모와 별도로 실행되는 DDS 전용 데모입니다. 선택한 END USER로 직접 접속해 Oracle의 DATA ROLE과 DATA GRANT가 적용된 결과를 보여줍니다.</p>
|
||||
<h1>업무 사용자의 지식 접근 범위를 DDS로 확인합니다.</h1>
|
||||
<p class="lead">이 화면은 VPD 데모와 별도로 실행되는 DDS 보조 검증 화면입니다. 실제 시나리오는 세일즈 사용자의 토큰이 `TECH_TAG=SALES`인 지식 청크만 검색하도록 제한하는 것입니다.</p>
|
||||
<details class="explanation">
|
||||
<summary>이 화면의 보안 경계</summary>
|
||||
<p>이 인스턴스는 VPD 권한 테이블을 읽어 조건을 계산하지 않습니다. <code>END USER → DATA ROLE → DATA GRANT → 보호 VIEW</code>가 전부 Oracle DDS에 선언되어 있고, 조회 결과는 그 선언의 적용 결과입니다.</p>
|
||||
<p class="mb-0">두 데모는 같은 접근 매트릭스를 비교하지만 실행 모델은 다릅니다. VPD는 공통 계정·Bearer·동적 predicate를 사용하고, DDS는 직접 END USER와 선언형 DATA GRANT를 사용합니다. Bearer 키를 ORDS Handler에서 사용자 이름으로 바꾸는 것만으로는 DDS 보안 컨텍스트가 만들어지지 않습니다.</p>
|
||||
<p>문서를 청킹·임베딩할 때 각 청크의 <code>TECH_TAG</code>에 업무 분류값을 저장합니다. 권한 관리에서는 역할에 허용할 값을 등록하고, DDS Data Grant가 보호 VIEW의 해당 컬럼 값을 predicate로 평가합니다.</p>
|
||||
<p class="mb-0">예를 들어 세일즈 사용자의 토큰이 업무 사용자 <code>agent_sales</code>로 매핑되고 역할에 <code>ALLOW TAG SALES</code>가 있으면, 검색 결과에는 <code>TECH_TAG</code>에 SALES가 포함된 청크만 남습니다.</p>
|
||||
</details>
|
||||
</header>
|
||||
|
||||
@@ -21,15 +21,15 @@
|
||||
<section class="flow-grid" aria-label="DDS 접근 흐름">
|
||||
<article class="flow-card">
|
||||
<span class="flow-number">1</span>
|
||||
<div><span class="eyebrow">IDENTITY</span><h2>END USER</h2><p>실제 DDS 보안 사용자로 DB에 접속합니다.</p></div>
|
||||
<div><span class="eyebrow">IDENTITY</span><h2>업무 사용자 토큰</h2><p>Bearer 토큰을 세일즈 업무 사용자로 매핑합니다.</p></div>
|
||||
</article>
|
||||
<article class="flow-card">
|
||||
<span class="flow-number">2</span>
|
||||
<div><span class="eyebrow">POLICY</span><h2>DATA ROLE / GRANT</h2><p>원본별 허용 범위가 선언형으로 연결됩니다.</p></div>
|
||||
<div><span class="eyebrow">POLICY</span><h2>객체별 DATA GRANT</h2><p>보호 VIEW의 컬럼 값과 공통 권한 규칙을 연결합니다.</p></div>
|
||||
</article>
|
||||
<article class="flow-card">
|
||||
<span class="flow-number">3</span>
|
||||
<div><span class="flow-number result-number">3</span><span class="eyebrow">EVIDENCE</span><h2>조회 결과</h2><p>허용된 VIEW와 행만 반환됩니다.</p></div>
|
||||
<div><span class="flow-number result-number">3</span><span class="eyebrow">EVIDENCE</span><h2>허용된 지식</h2><p>SALES 값이 붙은 청크만 벡터 검색 결과로 반환됩니다.</p></div>
|
||||
</article>
|
||||
</section>
|
||||
|
||||
@@ -38,7 +38,7 @@
|
||||
<div>
|
||||
<span class="eyebrow">SAME MANAGEMENT FLOW</span>
|
||||
<h2>VPD 데모와 같은 권한 관리 흐름</h2>
|
||||
<p>사용자·그룹·역할·데이터 권한은 같은 순서로 설계하고, 보호 적용 단계만 DDS 선언형 객체로 연결합니다.</p>
|
||||
<p>사용자·그룹·역할·데이터 권한은 같은 순서로 설계하고, 문서 청크의 분류값과 보호 VIEW를 DDS Data Grant로 연결합니다.</p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="matrix-grid">
|
||||
@@ -50,15 +50,17 @@
|
||||
</section>
|
||||
|
||||
<div class="alert alert-warning" th:if="${configuredUserCount == 0}">
|
||||
DDS 사용자 비밀번호가 설정되지 않았습니다. VM에서는 <code>DDSUSER_*_PASSWORD</code> 또는 <code>DDS_BACKOFFICE_*_PASSWORD</code> 환경 변수를 설정해야 조회할 수 있습니다.
|
||||
DDS 직접 비교 사용자의 비밀번호가 설정되지 않았습니다. 주 시나리오인 토큰 검색은 <code>/vector-knowledge</code>에서 기술 사용자 설정을 별도로 확인합니다.
|
||||
</div>
|
||||
|
||||
<details class="explanation mb-4">
|
||||
<summary>저수준 PG/MY DDS 예제 열기</summary>
|
||||
<section class="panel">
|
||||
<div class="panel-heading">
|
||||
<div>
|
||||
<span class="eyebrow">1 · SECURITY SUBJECT</span>
|
||||
<h2>조회 주체와 데이터 원본 선택</h2>
|
||||
<p>선택한 DDS END USER의 권한으로 직접 연결합니다. 비밀번호는 화면에 표시하거나 저장하지 않습니다.</p>
|
||||
<h2>저수준 DDS 직접 검증</h2>
|
||||
<p>PG/MY는 제품 시나리오가 아니라 DDS의 객체별 직접 Grant 동작을 확인하기 위한 보조 예제입니다.</p>
|
||||
</div>
|
||||
</div>
|
||||
<form method="post" action="/dds/query" class="query-grid">
|
||||
@@ -96,8 +98,8 @@
|
||||
<div class="panel-heading">
|
||||
<div>
|
||||
<span class="eyebrow">2 · EXPECTED MATRIX</span>
|
||||
<h2>원본별 권한 매트릭스</h2>
|
||||
<p>VPD 데모와 같은 결과를 별도 데이터·권한 객체에서 DDS 선언형 모델로 비교합니다.</p>
|
||||
<h2>보조 원본 권한 매트릭스</h2>
|
||||
<p>아래 PG/MY 매트릭스는 지식 검색 시나리오와 분리된 DDS 저수준 테스트 데이터입니다.</p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="matrix-grid">
|
||||
@@ -107,6 +109,7 @@
|
||||
<div class="matrix-card muted"><strong>dds_demo_none</strong><span>접속만 허용</span><small>데이터 권한 없음 · default deny</small></div>
|
||||
</div>
|
||||
</section>
|
||||
</details>
|
||||
|
||||
<section class="panel" th:if="${queryResult != null}">
|
||||
<div class="panel-heading result-heading">
|
||||
|
||||
@@ -15,7 +15,7 @@
|
||||
</div>
|
||||
<div class="table-responsive mt-3" th:if="${searchResult.success() and searchResult.hasRows()}">
|
||||
<table class="table table-sm align-middle">
|
||||
<thead><tr><th>검색 단위</th><th>자료 ID</th><th>제목</th><th>기술 태그</th><th>관련도</th><th>본문</th></tr></thead>
|
||||
<thead><tr><th>검색 단위</th><th>자료 ID</th><th>제목</th><th>업무 분류값</th><th>관련도</th><th>본문</th></tr></thead>
|
||||
<tbody>
|
||||
<tr th:each="row : ${searchResult.rows()}">
|
||||
<td th:text="${row['CHUNK_ID']}">28001</td>
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
<p class="context-summary">문서 → 청크·임베딩 → 기술 태그 → 권한 규칙 → DDS DATA GRANT → 검색 결과</p>
|
||||
<details class="explanation-details">
|
||||
<summary>이 화면의 큰 흐름 보기</summary>
|
||||
<p>문서는 검색 가능한 청크로 나뉘고 각 청크에 기술 태그가 붙습니다. 권한 관리에서 역할별로 허용할 태그를 등록하면 DDS의 DATA GRANT가 해당 태그가 붙은 청크만 검색 대상으로 남깁니다.</p>
|
||||
<p>문서는 검색 가능한 청크로 나뉘고 각 청크에 업무 접근 분류값(<code>TECH_TAG</code>)이 붙습니다. 권한 관리에서 역할별로 허용할 값을 등록하면 DDS의 DATA GRANT가 해당 값이 붙은 청크만 검색 대상으로 남깁니다.</p>
|
||||
<p class="mb-0">VPD 화면과 같은 사용자·그룹·역할·권한 규칙을 사용합니다. 아래에는 DDS END USER를 직접 선택하는 비교 경로와, 하나의 DDS 기술 사용자에 Bearer 토큰을 전달해 공통 권한을 평가하는 제품형 경로를 함께 둡니다.</p>
|
||||
</details>
|
||||
</div>
|
||||
@@ -45,9 +45,9 @@
|
||||
<label>문서 ID<input class="form-control" name="documentId" placeholder="knowledge-security-001" required></label>
|
||||
<label>문서 제목<input class="form-control" name="title" placeholder="DDS 기술 태그 권한 설계" required></label>
|
||||
<label>원문 주소 (선택)<input class="form-control" name="sourceUri" placeholder="kb://security/dds-vector"></label>
|
||||
<label>기술 태그 (쉼표 또는 공백)
|
||||
<input class="form-control" name="techTags" placeholder="SPRING_BOOT ORACLE_DDS" required>
|
||||
<span class="form-hint">태그는 대문자로 정규화됩니다. 권한 규칙의 TAG 값과 일치해야 합니다.</span>
|
||||
<label>지식 접근 분류값 (쉼표 또는 공백)
|
||||
<input class="form-control" name="techTags" placeholder="SALES INTERNAL" required>
|
||||
<span class="form-hint">예: SALES. 값은 대문자로 정규화되고 권한 규칙의 TAG 값과 일치해야 합니다.</span>
|
||||
</label>
|
||||
<label>검색 단위 길이<input class="form-control" name="chunkSize" type="number" min="80" max="2000" value="600"></label>
|
||||
<label>임베딩 방식
|
||||
@@ -80,8 +80,8 @@
|
||||
</div>
|
||||
</div>
|
||||
<div class="macro-micro-grid">
|
||||
<div><h3>관리 관점</h3><p>역할에 <code>ALLOW TAG</code>를 여러 개 등록하면 태그 중 하나라도 맞는 청크를 허용합니다. <code>DENY TAG</code>는 허용 후보에서 제외합니다.</p></div>
|
||||
<div><h3>DDS 실행 관점</h3><p><code th:text="${ddsVectorObject}">ADMIN.CB_DDS_VECTOR_SEARCH_DOCUMENTS</code>에 연결된 DATA GRANT가 END USER의 DATA ROLE을 통해 이 규칙을 집행합니다.</p></div>
|
||||
<div><h3>관리 관점</h3><p>예를 들어 세일즈 역할에 <code>ALLOW TAG SALES</code>를 등록하면 SALES 값이 붙은 청크만 허용합니다. <code>DENY TAG</code>는 허용 후보에서 제외합니다.</p></div>
|
||||
<div><h3>DDS 실행 관점</h3><p><code th:text="${ddsVectorObject}">ADMIN.CB_DDS_VECTOR_SEARCH_DOCUMENTS</code>의 객체별 DATA GRANT predicate가 토큰으로 식별된 업무 사용자와 청크의 <code>TECH_TAG</code> 값을 비교해 이 규칙을 집행합니다.</p></div>
|
||||
</div>
|
||||
<details class="explanation-details mt-3">
|
||||
<summary>VPD와 DDS의 차이 보기</summary>
|
||||
@@ -106,7 +106,7 @@
|
||||
<li><code>CB_DDS_VECTOR_SEARCH_DOCUMENTS</code>의 객체별 DATA GRANT predicate가 <code>CB_APP_USER</code>, 역할·그룹, <code>CB_PERMISSION</code>, <code>CB_PERMISSION_RULE</code>을 조회합니다.</li>
|
||||
<li>ALLOW TAG는 OR로 합치고 DENY TAG는 최종 결과에서 제외합니다.</li>
|
||||
</ol>
|
||||
<p class="mb-0">토큰은 DATA GRANT 문법의 바인드 파라미터가 아닙니다. 토큰이 만든 신뢰된 Context를 Data Grant predicate가 참조하는 구조입니다. 토큰은 저장하거나 화면에 재표시하지 않습니다.</p>
|
||||
<p class="mb-0">세일즈 예제에서는 <code>agent_sales</code> 역할이 <code>ALLOW TAG SALES</code>를 가지고, 청크의 <code>TECH_TAG</code>에 SALES가 포함된 지식만 남습니다. 토큰은 DATA GRANT 문법의 바인드 파라미터가 아니라 Context를 만드는 입력이며 저장하지 않습니다.</p>
|
||||
</details>
|
||||
<form hx-post="/vector-knowledge/token-search" hx-target="#vector-token-search-result" hx-swap="innerHTML" class="form-grid mt-3">
|
||||
<input type="hidden" th:name="${_csrf.parameterName}" th:value="${_csrf.token}">
|
||||
@@ -122,7 +122,7 @@
|
||||
</select>
|
||||
</label>
|
||||
<label class="span-2">검색 질문
|
||||
<textarea class="form-control" name="query" rows="3" placeholder="예: ORACLE_VPD 태그가 있는 지식자료의 접근 조건" required></textarea>
|
||||
<textarea class="form-control" name="query" rows="3" placeholder="예: 세일즈 파이프라인 후속 조치 기준" required></textarea>
|
||||
</label>
|
||||
<button class="btn rw-btn-primary" type="submit">토큰 권한으로 검색</button>
|
||||
</form>
|
||||
|
||||
Reference in New Issue
Block a user