[Developer] #619 focus POC on KB VPD permissions

This commit is contained in:
devmrko
2026-07-07 16:02:22 +09:00
parent ef944a6758
commit 2ef04e6ab2
18 changed files with 1238 additions and 167 deletions

View File

@@ -13,40 +13,40 @@
- `CB_AGENT_BEARER_KEY.STAKEHOLDER_USER_ID``KB_STAKEHOLDERS.USER_ID`를 가리킨다. 기존 숫자형 `USER_ID`는 기존 기능 호환용 application-user bridge로 유지한다.
- 이해당사자마다 `CB_APP_USER.STAKEHOLDER_USER_ID` bridge를 하나 만들고, `KB_STAKEHOLDERS.ROLE``지점장`이면 `KB_BRANCH_MANAGER_ROLE`, `설계사`이면 `KB_DESIGNER_ROLE`을 부여한다. 다른 역할은 토큰은 발급되지만 별도 권한을 추가하기 전까지 fail-closed다.
- VPD package는 토큰에서 `STAKEHOLDER_USER_ID`, `STAKEHOLDER_ROLE`, 정규화된 `STAKEHOLDER_CHANNEL`을 application context에 설정한다. `설계사채널 → 설계사`, `GA채널 → GA`를 정규화한다.
- `지점장` 여부는 package의 하드코딩 분기가 아니라 `KB_BRANCH_MANAGER_ROLE`의 rule value(`지점장`)와 `KB_STAKEHOLDERS.ROLE` 일치로 결정한다. 설계사 분기는 같은 방식으로 `설계사`를 확인한다.
- `RLS_FILTER`의 문자열은 실행하지 않는다. 권한 테이블에 저장된 allowlist rule type만 predicate로 변환한다.
- 토큰의 업무 역할은 `KB_STAKEHOLDERS`에서 한 번 해석해 context에 넣고, 그 역할에 매핑된 `CB_PERMISSION`이 어떤 조건 코드를 사용할지 결정한다. filter predicate에 업무 역할명은 직접 저장하지 않는다.
- 행 규칙은 두 가지다. allowlist condition code는 secure context 값으로 치환하고, `STATIC_SQL`은 현재 보호 객체 컬럼만 사용하는 검증된 정적 WHERE 조건식을 그대로 추가한다.
## 3. 예제 권한
| 역할 | 보호 객체 | 행 규칙 | 결과 |
|---|---|---|---|
| KB_DESIGNER_ROLE | KB_CONTRACTS | `FC_ID / STAKEHOLDER_SELF` | 본인 담당 계약 |
| KB_BRANCH_MANAGER_ROLE | KB_CONTRACTS | `FC_CHANNEL / STAKEHOLDER_CHANNEL` | 같은 채널 계약 |
| KB_DESIGNER_ROLE | 고객·담보·청구·외부보유 | `CUST_ID / STAKEHOLDER_SELF` | 본인 담당 고객 기준 |
| KB_BRANCH_MANAGER_ROLE | 고객·담보·청구·외부보유 | `CUST_ID / STAKEHOLDER_CHANNEL` | 같은 채널 고객 기준 |
| 두 역할 | KB_STAKEHOLDERS | `USER_ID / STAKEHOLDER_SELF` | 토큰 주체 자신의 매핑 행 |
| KB_DESIGNER_ROLE | KB_CONTRACTS | `FC_ID / OWN_CONTRACT` | 본인 담당 계약 |
| KB_BRANCH_MANAGER_ROLE | KB_CONTRACTS | `FC_CHANNEL / CHANNEL_CONTRACT` | 같은 채널 계약 |
| KB_DESIGNER_ROLE | 고객·담보·청구·외부보유 | `CUST_ID / OWN_CUSTOMER` | 본인 담당 고객 기준 |
| KB_BRANCH_MANAGER_ROLE | 고객·담보·청구·외부보유 | `CUST_ID / CHANNEL_CUSTOMER` | 같은 채널 고객 기준 |
| KB_STAKEHOLDER_IDENTITY_ROLE | KB_STAKEHOLDERS | `USER_ID / TOKEN_SUBJECT` | 토큰 주체 자신의 매핑 행 |
`STAKEHOLDER_SELF` `STAKEHOLDER_CHANNEL`은 접근 규칙 화면에서 선택 가능한 행 규칙이다. 두 규칙에는 대상 컬럼과 업무 역할값을 함께 저장한다. Bearer Token을 해석할 때 `KB_STAKEHOLDERS`를 한 번만 조회해 `STAKEHOLDER_USER_ID`, `STAKEHOLDER_ROLE`, `STAKEHOLDER_CHANNEL` secure context를 만들고, 이후 `FC_ID`/`FC_CHANNEL``CUST_ID`/`CONTRACT_NO` 조건은 계약원장과 그 context만 사용한다. 허용된 역할별 분기는 **OR**로 합쳐진다.
`OWN_CONTRACT`, `CHANNEL_CONTRACT`, `OWN_CUSTOMER`, `CHANNEL_CUSTOMER`, `TOKEN_SUBJECT`는 접근 규칙 화면에서 선택하는 filter 조건 코드다. Bearer Token을 해석할 때 `KB_STAKEHOLDERS`를 한 번만 조회해 `STAKEHOLDER_USER_ID`, `STAKEHOLDER_ROLE`, `STAKEHOLDER_CHANNEL` secure context를 만들고, VPD filter가 condition code를 대상 object의 WHERE 조각으로 확장한다.
각 접근 규칙 안에서는 치환된 condition code와 `STATIC_SQL`**AND**로 합친다. 예를 들어 `본인 담당 고객 / CUST_ID`에 `CONTRACT_STATUS = '정상'` 정적 조건을 더하면, 담당 고객이면서 상태가 정상인 행만 허용된다. 서로 다른 ALLOW 권한(역할/권한 세트)은 **OR**, DENY 권한은 최종 허용 결과에서 제외한다. `STATIC_SQL`은 세미콜론·주석·서브쿼리·다른 테이블 참조를 차단하고 현재 보호 객체의 컬럼과 allowlist SQL 연산자만 허용한다.
```sql
-- 고객·청구·외부보유의 CUST_ID 예시: 역할별 허용 분기
-- 고객·청구·외부보유의 CUST_ID 예시: permission condition code 확장 결과
EXISTS (
SELECT 1
FROM POC_2.KB_CONTRACTS c
WHERE c.CUST_ID = <>.CUST_ID
AND SYS_CONTEXT('CB_AGENT_CTX', 'STAKEHOLDER_ROLE') = '설계사'
AND c.FC_ID = SYS_CONTEXT('CB_AGENT_CTX', 'STAKEHOLDER_USER_ID')
)
OR EXISTS (
SELECT 1
FROM POC_2.KB_CONTRACTS c
WHERE c.CUST_ID = <>.CUST_ID
AND SYS_CONTEXT('CB_AGENT_CTX', 'STAKEHOLDER_ROLE') = '지점장'
AND c.FC_CHANNEL = SYS_CONTEXT('CB_AGENT_CTX', 'STAKEHOLDER_CHANNEL')
)
```
위의 `'설계사'`/`'지점장'`은 함수 하드코딩이 아니라 각 permission rule의 `rule_value`에서 온다. 토큰 원문은 predicate에 노출하지 않으며, `CB_AGENT_BEARER_KEY → KB_STAKEHOLDERS`에서 한 번 검증·해석한 subject context만 사용한다.
어느 분기를 사용할지는 token context에 매핑된 effective role의 permission이 결정한다. 토큰 원문은 predicate에 노출하지 않으며, `CB_AGENT_BEARER_KEY → KB_STAKEHOLDERS`에서 한 번 검증·해석한 subject context만 사용한다.
## 4. CLS / NULL 처리
@@ -85,6 +85,7 @@ Bearer Token → CB_AGENT_CTX_PKG → application context
- [x] 설계사 역할은 `FC_ID = stakeholder user_id`와 담당 고객 범위 규칙으로 등록된다.
- [x] 지정 7개 민감 컬럼은 원문 표시 예외가 없으면 NULL 처리하는 VPD column policy가 등록된다.
- [x] 토큰 없음·역할 없음·지원하지 않는 rule mapping은 VPD filter에서 `1 = 0`으로 fail-closed 된다.
- [x] 조건 코드와 정적 SQL 조건은 같은 접근 규칙 안에서 AND로 결합되며, 정적 SQL은 단일 안전 조건식만 저장할 수 있다.
## 7. 검증 계획
@@ -103,5 +104,5 @@ Bearer Token → CB_AGENT_CTX_PKG → application context
## 8. 리스크와 제한
- `CB_APP_USER`는 업무 원장이 아니라 permission engine용 bridge다. 업무 identity의 원천은 반드시 `KB_STAKEHOLDERS`다.
- `RLS_FILTER`는 사람이 읽는 설명으로만 보존한다. 저장된 SQL을 실행하면 rule injection 위험이 있으므로 사용하지 않는다.
- 정적 SQL은 백오피스 검증과 VPD 함수의 이중 검증을 통과한 단일 조건식만 사용한다. 임의 SQL, 주석, 바인드, 서브쿼리, 다른 테이블 참조는 허용하지 않는다.
- 지점장의 “집계만” 요구는 원시 행 조회를 완전히 차단하는 별도 집계 View/ORDS endpoint가 필요하다. 이번 예제는 채널 행 범위와 민감 컬럼 NULL 처리까지 구현하며, 집계 전용 endpoint는 후속 범위다.