> ## Documentation Index
> Fetch the complete documentation index at: https://docs.sifi.life/llms.txt
> Use this file to discover all available pages before exploring further.

# OBO로 앱 사용자 추적하기

> **질문**: "외부 포털에서 SP 1개로 Databricks를 호출하는데, 실제 사용자를 식별할 수 없습니다. SP 1개를 유지하면서 호출한 사용자를 특정할 수 있나요?"

***

## 문제 상황

외부 포털이 **단일 Service Principal**로 Databricks를 호출하면, 감사 로그에 SP만 기록됩니다.

```
[현재] 외부 포털 → SP 토큰 → Databricks
       감사 로그: "service_principal_app_12345가 쿼리 실행" (누가 요청했는지 알 수 없음)
```

***

## 해결 방법 1: On-Behalf-Of (OBO) 인증 (권장)

**사용자의 OAuth 토큰**으로 Databricks API를 호출하면, 감사 로그에 실제 사용자가 기록됩니다.

```
[OBO] 외부 포털 → 사용자 SSO 로그인 → OBO 토큰 → Databricks
      감사 로그: "hong.gildong@company.com이 쿼리 실행"
```

### 구현 (FastAPI 예제)

```python theme={null}
import os
from databricks.sdk import WorkspaceClient
from fastapi import FastAPI, Request

app = FastAPI()

@app.get("/query")
def run_query(request: Request, sql: str):
    # 사용자의 OAuth 토큰을 헤더에서 추출
    user_token = request.headers.get("x-forwarded-access-token")
    
    # 사용자 토큰으로 Databricks 클라이언트 생성
    w = WorkspaceClient(
        host=os.getenv("DATABRICKS_HOST"),
        token=user_token  # SP 토큰이 아닌 사용자 토큰!
    )
    
    # 이 쿼리는 사용자 ID로 감사 로그에 기록됨
    result = w.statement_execution.execute_statement(
        warehouse_id=os.getenv("WAREHOUSE_ID"),
        statement=sql
    )
    return result
```

### app.yaml 설정

```yaml theme={null}
command: ['uvicorn', 'app:app', '--host', '0.0.0.0', '--port', '${DATABRICKS_APP_PORT}']
env:
  - name: DATABRICKS_HOST
    valueFrom: host
  - name: WAREHOUSE_ID
    valueFrom: sql_warehouse
# 사용자 인증 활성화 — OBO 토큰이 자동 전달됨
auth:
  type: user  # SP가 아닌 사용자 토큰 사용
```

### OBO가 적합한 경우

| 요구사항                    | OBO 적합                  |
| ----------------------- | ----------------------- |
| 사용자별 UC 권한 적용           | 적합 — 사용자의 GRANT가 그대로 적용 |
| 감사 로그에 사용자 기록           | 적합 — 실제 사용자 ID 기록       |
| 외부 포털에서 Databricks 호출   | 포털이 SSO 연동 가능해야 함       |
| Databricks 계정 없는 외부 사용자 | **부적합** — 워크스페이스 계정 필요  |

***

## 해결 방법 2: 쿼리 태그 (OBO 불가 시)

외부 시스템이 Databricks SSO와 연동할 수 없는 경우, **쿼리 태그**로 사용자 정보를 전달합니다.

```sql theme={null}
-- 외부 포털 서버에서 Databricks SQL API 호출 시
SET spark.databricks.queryTag = '{"user": "hong.gildong@company.com", "source": "외부 포털", "department": "marketing"}';

SELECT * FROM gold.customer_360 WHERE region = 'APAC';
```

### 감사 로그에서 추적

```sql theme={null}
-- 누가 어떤 쿼리를 실행했는지 추적
SELECT
  event_time,
  get_json_object(request_params.queryTag, '$.user') AS actual_user,
  get_json_object(request_params.queryTag, '$.source') AS source_app,
  request_params.commandText AS sql_query
FROM system.access.audit
WHERE action_name = 'commandSubmit'
  AND service_name = 'databrickssql'
ORDER BY event_time DESC;
```

### 두 방법 비교

| 항목             | OBO                    | 쿼리 태그          |
| -------------- | ---------------------- | -------------- |
| **사용자 식별 정확도** | 높음 (토큰 기반)             | 중간 (앱이 정직해야 함) |
| **UC 권한 적용**   | 사용자별 자동 적용             | SP 권한만 적용      |
| **감사 로그**      | 사용자 ID 자동 기록           | 태그에서 수동 추출     |
| **구현 난이도**     | SSO 연동 필요              | SQL SET 한 줄    |
| **사전 조건**      | 사용자에게 Databricks 계정 필요 | 없음             |

***

## 관련 문서

* [Databricks Apps 인증](/blog/guides/apps/authentication) — SP vs 사용자 인증 상세
* [감사 로그](/training/12-security-and-governance/audit-logs) — system.access.audit 활용
* [차세대 ID 보안](/translations/2025-05-21-identity-security) — Token Federation, OBO 배경
