feat: center DDS demo on sales knowledge authorization

This commit is contained in:
devmrko
2026-06-30 14:21:39 +09:00
parent 188b398dcb
commit 04cca64f10
9 changed files with 270 additions and 55 deletions

View File

@@ -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>

View File

@@ -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">

View File

@@ -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>

View File

@@ -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>