feat: publish application permissions to DDS grants
This commit is contained in:
@@ -61,24 +61,35 @@ dds:
|
||||
pg-object: ${DDS_BACKOFFICE_PG_OBJECT:ADMIN.V_DDS_CUSTOMERS_PG}
|
||||
my-object: ${DDS_BACKOFFICE_MY_OBJECT:ADMIN.V_DDS_CUSTOMERS_MY}
|
||||
vector-object: ${DDS_BACKOFFICE_VECTOR_OBJECT:ADMIN.CB_DDS_VECTOR_SEARCH_DOCUMENTS}
|
||||
object-mappings:
|
||||
CB_VECTOR_SEARCH_DOCUMENTS: ${DDS_BACKOFFICE_VECTOR_OBJECT:ADMIN.CB_DDS_VECTOR_SEARCH_DOCUMENTS}
|
||||
CB_V_SEARCH_DOCUMENTS: ${DDS_BACKOFFICE_DOCUMENT_OBJECT:ADMIN.CB_DDS_V_SEARCH_DOCUMENTS}
|
||||
users:
|
||||
my:
|
||||
label: MY 전용 사용자
|
||||
description: MySQL 원본만 허용하는 DATA ROLE
|
||||
username: ${DDS_BACKOFFICE_MY_USERNAME:dds_demo_my}
|
||||
password: ${DDS_BACKOFFICE_MY_PASSWORD:${DDSUSER_MY_PASSWORD:}}
|
||||
application-user-id: ${DDS_BACKOFFICE_MY_APPLICATION_USER_ID:101}
|
||||
data-role: ${DDS_BACKOFFICE_MY_DATA_ROLE:dds_demo_my_role}
|
||||
pg:
|
||||
label: PG 전용 사용자
|
||||
description: PostgreSQL 원본만 허용하는 DATA ROLE
|
||||
username: ${DDS_BACKOFFICE_PG_USERNAME:dds_demo_pg}
|
||||
password: ${DDS_BACKOFFICE_PG_PASSWORD:${DDSUSER_PG_PASSWORD:}}
|
||||
application-user-id: ${DDS_BACKOFFICE_PG_APPLICATION_USER_ID:102}
|
||||
data-role: ${DDS_BACKOFFICE_PG_DATA_ROLE:dds_demo_pg_role}
|
||||
both:
|
||||
label: 통합 사용자
|
||||
description: 두 원본을 모두 허용하는 DATA ROLE
|
||||
username: ${DDS_BACKOFFICE_BOTH_USERNAME:dds_demo_both}
|
||||
password: ${DDS_BACKOFFICE_BOTH_PASSWORD:${DDSUSER_BOTH_PASSWORD:}}
|
||||
application-user-id: ${DDS_BACKOFFICE_BOTH_APPLICATION_USER_ID:103}
|
||||
data-role: ${DDS_BACKOFFICE_BOTH_DATA_ROLE:dds_demo_both_role}
|
||||
none:
|
||||
label: 차단 사용자
|
||||
description: 접속만 가능하고 DATA GRANT가 없는 사용자
|
||||
username: ${DDS_BACKOFFICE_NONE_USERNAME:dds_demo_none}
|
||||
password: ${DDS_BACKOFFICE_NONE_PASSWORD:${DDSUSER_NONE_PASSWORD:}}
|
||||
application-user-id: ${DDS_BACKOFFICE_NONE_APPLICATION_USER_ID:0}
|
||||
data-role: ${DDS_BACKOFFICE_NONE_DATA_ROLE:dds_demo_none_role}
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
<header class="page-title guided-hero">
|
||||
<span class="architecture-kicker">DEEP DATA SECURITY · INDEPENDENT TRACK</span>
|
||||
<h1>같은 권한 기준을 DDS 방식으로 적용하고 확인합니다.</h1>
|
||||
<p class="context-summary">권한 설계 → DDS 보호 연결 → END USER 검증 → 지식 검색 결과 확인</p>
|
||||
<p class="context-summary">권한 설계 → DDS 보호 연결 → 권한 반영 → END USER 검증 → 지식 검색 결과 확인</p>
|
||||
<details class="explanation-details">
|
||||
<summary>이 인스턴스의 역할 보기</summary>
|
||||
<p>8083 DDS 인스턴스는 8082 VPD 인스턴스와 별도로 실행됩니다. 두 화면은 사용자·그룹·역할·권한 규칙을 같은 관리 흐름으로 보여주지만, DDS는 END USER·DATA ROLE·DATA GRANT를 통해 데이터를 보호합니다.</p>
|
||||
@@ -20,8 +20,9 @@
|
||||
<section class="journey-grid" aria-label="DDS 권한 적용 네 단계">
|
||||
<a class="journey-card" href="/permissions"><span class="journey-number">1</span><div><h2>1. 권한 설계</h2><p>사용자·그룹·역할에 객체와 TAG 규칙을 연결합니다.</p><strong>권한 규칙 만들기 →</strong></div></a>
|
||||
<a class="journey-card" href="/vpd-policies"><span class="journey-number">2</span><div><h2>2. DDS 보호 연결</h2><p>공통 규칙을 DDS 전용 VIEW와 DATA GRANT에 연결합니다.</p><strong>DDS 보호 객체 확인 →</strong></div></a>
|
||||
<a class="journey-card" href="/dds"><span class="journey-number">3</span><div><h2>3. END USER 검증</h2><p>실제 DDS END USER로 접속해 허용·차단 결과를 확인합니다.</p><strong>직접 조회 실행 →</strong></div></a>
|
||||
<a class="journey-card" href="/vector-knowledge"><span class="journey-number">4</span><div><h2>4. 지식 검색</h2><p>청크·임베딩·태그와 DDS 권한을 결합한 검색 시나리오를 확인합니다.</p><strong>권한 기반 검색 →</strong></div></a>
|
||||
<a class="journey-card" href="/dds-provision"><span class="journey-number">3</span><div><h2>3. DDS 권한 반영</h2><p>그룹 상속을 포함한 유효 권한을 DDS Grant로 게시합니다.</p><strong>Grant 미리보기·게시 →</strong></div></a>
|
||||
<a class="journey-card" href="/dds"><span class="journey-number">4</span><div><h2>4. END USER 검증</h2><p>실제 DDS END USER로 접속해 허용·차단 결과를 확인합니다.</p><strong>직접 조회 실행 →</strong></div></a>
|
||||
<a class="journey-card" href="/vector-knowledge"><span class="journey-number">5</span><div><h2>5. 지식 검색</h2><p>청크·임베딩·태그와 DDS 권한을 결합한 검색 시나리오를 확인합니다.</p><strong>권한 기반 검색 →</strong></div></a>
|
||||
</section>
|
||||
|
||||
<section class="content-band macro-micro-grid">
|
||||
|
||||
@@ -0,0 +1,99 @@
|
||||
<!doctype html>
|
||||
<html lang="ko" xmlns:th="http://www.thymeleaf.org">
|
||||
<head th:replace="~{fragments/layout :: head('DDS 권한 반영')}"></head>
|
||||
<body>
|
||||
<nav th:replace="~{fragments/layout :: nav}"></nav>
|
||||
<main class="container py-4">
|
||||
<div class="page-title">
|
||||
<span class="architecture-kicker">DDS · PUBLISH</span>
|
||||
<h1>애플리케이션 권한을 DDS에 반영</h1>
|
||||
<p class="context-summary">사용자·그룹·역할·테이블 권한을 계산한 뒤 DDS DATA GRANT로 게시합니다.</p>
|
||||
<details class="explanation-details">
|
||||
<summary>VPD와 DDS의 반영 차이 보기</summary>
|
||||
<p>VPD는 요청 때마다 권한 테이블을 읽습니다. DDS는 같은 권한체계를 배포 시점에 DATA GRANT로 컴파일합니다. 그래서 권한 저장 후 이 화면에서 변경 내용을 미리 확인하고 게시해야 합니다.</p>
|
||||
<p class="mb-0">그룹 자체를 DDS 그룹으로 복사하지는 않습니다. 애플리케이션 그룹의 역할 상속을 계산해 매핑된 DDS DATA ROLE에 하나의 최종 predicate로 합칩니다.</p>
|
||||
</details>
|
||||
</div>
|
||||
|
||||
<section th:replace="~{fragments/layout :: architectureStrip('vpd')}"></section>
|
||||
|
||||
<section class="content-band">
|
||||
<details class="explanation-details">
|
||||
<summary>VPD 권한과 DDS 객체의 매핑 기준</summary>
|
||||
<div class="table-responsive mt-3">
|
||||
<table class="table table-sm align-middle mb-0">
|
||||
<thead><tr><th>공통 권한 관리</th><th>DDS에서의 표현</th><th>반영 시점</th></tr></thead>
|
||||
<tbody>
|
||||
<tr><td>애플리케이션 사용자</td><td>매핑된 DDS END USER + DATA ROLE</td><td>게시할 때 매핑 확인</td></tr>
|
||||
<tr><td>그룹과 그룹에 연결된 역할</td><td>그룹을 복사하지 않고 최종 predicate로 합산</td><td>미리보기·게시 때 계산</td></tr>
|
||||
<tr><td>테이블·VIEW SELECT 권한</td><td>보호 객체별 <code>DATA GRANT ... WHERE ...</code></td><td>권한 변경 후 게시</td></tr>
|
||||
<tr><td>원문 표시 허용 컬럼</td><td><code>AS SELECT</code> 또는 <code>ALL COLUMNS EXCEPT</code></td><td>권한 변경 후 게시</td></tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
<p class="text-muted mt-3 mb-0">VPD는 요청마다 권한 테이블을 평가하지만, DDS는 게시된 Grant가 바뀔 때까지 이전 선언을 계속 사용합니다. 이 화면의 게시 버튼이 두 모델을 동기화하는 경계입니다.</p>
|
||||
</details>
|
||||
</section>
|
||||
|
||||
<div class="alert alert-success" th:if="${successMessage}" th:text="${successMessage}"></div>
|
||||
<div class="alert alert-warning" th:if="${warningMessage}" th:text="${warningMessage}"></div>
|
||||
<div class="alert alert-danger" th:if="${errorMessage}" th:text="${errorMessage}"></div>
|
||||
|
||||
<section class="content-band">
|
||||
<div class="section-heading">
|
||||
<div>
|
||||
<span class="architecture-kicker">1 · COMPILE</span>
|
||||
<h2>현재 유효 권한 미리보기</h2>
|
||||
<p class="section-subtitle">직접 부여된 역할과 활성 그룹에서 상속된 역할을 합쳐 DDS Grant를 만듭니다.</p>
|
||||
</div>
|
||||
<span class="badge text-bg-secondary" th:text="${plan.mappedUserCount() + '명 매핑'}">0명 매핑</span>
|
||||
</div>
|
||||
<div class="alert alert-info" th:if="${plan.publishableCount() == 0}">
|
||||
게시할 수 있는 ALLOW 권한이 없습니다. 보호 객체 매핑과 권한 규칙을 먼저 확인하세요.
|
||||
</div>
|
||||
<form method="post" action="/dds-provision/publish" class="mb-3" th:if="${plan.publishableCount() > 0}">
|
||||
<input type="hidden" th:name="${_csrf.parameterName}" th:value="${_csrf.token}">
|
||||
<button class="btn rw-btn-primary" type="submit"
|
||||
onclick="return confirm('현재 미리보기대로 DDS DATA GRANT를 교체하고 권한 없는 Grant를 회수할까요?')">미리보기대로 DDS에 게시</button>
|
||||
</form>
|
||||
<div class="table-responsive">
|
||||
<table class="table table-sm align-middle">
|
||||
<thead><tr><th>애플리케이션 주체</th><th>애플리케이션 객체</th><th>DDS 주체/객체</th><th>판정</th><th>predicate</th><th>컬럼 제외</th></tr></thead>
|
||||
<tbody>
|
||||
<tr th:each="grant : ${plan.grants()}">
|
||||
<td><strong th:text="${grant.userLabel()}">사용자</strong><small class="d-block text-muted" th:text="${'userId=' + grant.applicationUserId() + ' · ' + grant.dataRole()}">mapping</small></td>
|
||||
<td><code th:text="${grant.applicationObject()}">CB_VECTOR_SEARCH_DOCUMENTS</code></td>
|
||||
<td><code th:text="${grant.ddsObject()}">ADMIN.CB_DDS_VECTOR_SEARCH_DOCUMENTS</code><small class="d-block text-muted" th:text="${grant.grantName()}">GRANT</small></td>
|
||||
<td>
|
||||
<span class="badge text-bg-success" th:if="${grant.publishable()}">게시 가능</span>
|
||||
<span class="badge text-bg-warning" th:unless="${grant.publishable()}">검토 필요</span>
|
||||
<small class="d-block text-muted" th:text="${grant.note()}">메모</small>
|
||||
</td>
|
||||
<td><code th:text="${grant.predicate() ?: '-'}">predicate</code></td>
|
||||
<td th:text="${grant.excludedColumns() ?: '없음'}">없음</td>
|
||||
</tr>
|
||||
<tr th:if="${#lists.isEmpty(plan.grants())}"><td colspan="6" class="text-muted">매핑된 유효 권한에서 DDS Grant 대상을 찾지 못했습니다.</td></tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<section class="content-band" th:if="${plan.hasWarnings()}">
|
||||
<div class="section-heading"><div><h2>반영 전 확인할 항목</h2><p class="section-subtitle">지원되지 않는 객체나 매핑 누락은 게시하지 않고 경고로 남깁니다. DDS 객체 매핑이 없는 기존 Grant도 이 화면에서는 건드리지 않습니다.</p></div></div>
|
||||
<ul>
|
||||
<li th:each="warning : ${plan.warnings()}" th:text="${warning}">경고</li>
|
||||
</ul>
|
||||
</section>
|
||||
|
||||
<section class="content-band" th:if="${plan.publishableCount() > 0}">
|
||||
<details class="explanation-details">
|
||||
<summary>게시되는 SQL 보기</summary>
|
||||
<div th:each="grant : ${plan.grants()}" th:if="${grant.publishable()}" class="mt-3">
|
||||
<strong th:text="${grant.grantName()}">GRANT</strong>
|
||||
<pre class="code-block" th:text="${grant.sql()}">CREATE OR REPLACE DATA GRANT ...</pre>
|
||||
</div>
|
||||
</details>
|
||||
</section>
|
||||
</main>
|
||||
</body>
|
||||
</html>
|
||||
@@ -33,6 +33,7 @@
|
||||
<div class="rw-menu-panel">
|
||||
<a class="nav-link" href="/vpd-policies"
|
||||
th:text="${backofficeTrack == 'DDS' ? 'DDS 보호 연결' : 'DB 보호 연결'}">DB 보호 연결</a>
|
||||
<a class="nav-link" href="/dds-provision" th:if="${backofficeTrack == 'DDS'}">DDS 권한 반영</a>
|
||||
<a class="nav-link" href="/tokens" th:if="${backofficeTrack != 'DDS'}">검증 세션 발급</a>
|
||||
<a class="nav-link" href="/probe" th:if="${backofficeTrack != 'DDS'}">권한 결과 확인</a>
|
||||
<a class="nav-link" href="/dds">DDS 직접 조회</a>
|
||||
|
||||
@@ -74,7 +74,10 @@
|
||||
<h2>권한 규칙은 한 곳에서 관리합니다.</h2>
|
||||
<p class="section-subtitle">사용자·그룹·역할·TAG 규칙은 VPD와 같은 권한 관리 화면에서 작성합니다.</p>
|
||||
</div>
|
||||
<a class="btn btn-sm rw-btn-primary" href="/permissions">권한 관리 열기</a>
|
||||
<div class="d-flex gap-2">
|
||||
<a class="btn btn-sm rw-btn-secondary" href="/permissions">권한 관리 열기</a>
|
||||
<a class="btn btn-sm rw-btn-primary" href="/dds-provision">DDS 권한 반영</a>
|
||||
</div>
|
||||
</div>
|
||||
<div class="macro-micro-grid">
|
||||
<div><h3>관리 관점</h3><p>역할에 <code>ALLOW TAG</code>를 여러 개 등록하면 태그 중 하나라도 맞는 청크를 허용합니다. <code>DENY TAG</code>는 허용 후보에서 제외합니다.</p></div>
|
||||
|
||||
@@ -27,7 +27,10 @@
|
||||
<h2>VPD와 동일한 권한 관리 대상을 사용합니다.</h2>
|
||||
<p class="section-subtitle">사용자·그룹·역할·행 규칙·TAG 규칙은 한 권한 화면에서 관리합니다.</p>
|
||||
</div>
|
||||
<a class="btn btn-sm rw-btn-primary" href="/permissions">권한 규칙 열기</a>
|
||||
<div class="d-flex gap-2">
|
||||
<a class="btn btn-sm rw-btn-secondary" href="/permissions">권한 규칙 열기</a>
|
||||
<a class="btn btn-sm rw-btn-primary" href="/dds-provision">DDS 권한 반영</a>
|
||||
</div>
|
||||
</div>
|
||||
<div class="policy-apply-flow" aria-label="DDS 적용 계층">
|
||||
<span>사용자·그룹·역할</span><strong>→</strong>
|
||||
|
||||
Reference in New Issue
Block a user