Files
portfolio-hub/docs/srs/Interface/req-052_user-owned-credential-management-api.md
T

9.4 KiB

REQ-052: 사용자 소유 스코프 인증정보 관리 HTTP API

  • Status: Implemented
  • Type: Interface
  • Priority: High
  • Owner: Justin Ko

Intent

  • 현재 BrokerCredential 관리는 CLI(pfhub credential)와 service-token read 경로(REQ-051/REQ-049)만 존재하며, HTTP user-token 기반 관리 표면이 없다.
  • trex-web dcy-009 사용자 self-service UI가 소비하는 백엔드 경로를 신설한다: 사용자가 자기 소유 데몬의 KIS 인증정보를 HTTP API로 등록·회전·삭제하고, 메타데이터(secret 미포함)를 조회할 수 있도록 한다.
  • dcy-010 자산(BrokerCredential 모델, Fernet 암호화, CREDENTIAL_ENCRYPTION_KEY, PK (daemon_id, broker))을 재사용하여 CLI와 동일 repository·암호화 경로를 공유한다.

Requirement

  • 시스템은 user-token으로 인증된 사용자가 자기 소유 데몬의 broker 인증정보를 등록·회전·삭제할 수 있는 write 엔드포인트를 제공해야 한다.
    • 등록/회전: app_key + app_secret + account_ref 입력을 Fernet 암호화하여 BrokerCredential에 upsert. 회전 시 credential_version 증가, last_rotated_at 갱신.
    • 삭제: 해당 (daemon_id, broker) 행 제거.
  • 시스템은 사용자가 자기 소유 데몬의 인증정보 메타데이터를 조회할 수 있는 read 엔드포인트를 제공해야 한다. 응답에는 broker, account_ref, credential_version, last_rotated_at, 보유 여부(has_credential)만 포함하며 복호화된 app_key/app_secret은 절대 포함하지 않는다.
  • 소유 스코프 인가를 모든 관리 경로에 강제해야 한다: 요청자 user_id가 대상 데몬의 owner_user_id와 일치하지 않으면 HTTP 403 Forbidden을 반환한다. 인증 토큰이 없는 요청은 HTTP 401을 반환한다.
  • 인증정보 write 요청이 성공하면 응답에는 메타데이터(broker, account_ref, credential_version, last_rotated_at)만 반환하고 app_key/app_secret은 포함하지 않는다.
  • 엔드포인트 경로·HTTP 메서드의 구체 형태는 draft-batch-design에서 v1 컨벤션(/v1/daemons/{daemon_id}/credential 방향 권고, dcy-011 OQ-1 Deferred)에 맞춰 확정한다.
  • 기존 CLI(pfhub credential)와 동일한 BrokerCredentialRepository 메서드 및 app/core/encryption.py Fernet 자산을 재사용해야 한다.

Acceptance Criteria

  1. Given user-token(소유자 A)으로 자기 소유 daemon D에 app_key/app_secret/account_ref 를 등록, When write 엔드포인트를 호출, Then HTTP 200/201 + 메타데이터 응답(broker, account_ref, credential_version, last_rotated_at)이 반환되고 응답 JSON에 app_key/app_secret 필드가 존재하지 않는다.
  2. Given 같은 소유자 A가 동일 daemon D 인증정보를 재등록(회전), When write 엔드포인트를 호출, Then 응답의 credential_version이 이전보다 1 증가하고 last_rotated_at이 갱신된다.
  3. Given 소유자 A가 daemon D 인증정보를 등록한 뒤, When service-token /v1/user_info(REQ-049)로 해당 daemon D의 인증정보를 fetch하면, Then broker.account_ref가 방금 등록한 값과 일치한다(CLI·API·service-token 경로 정합).
  4. Given user-token(소유자 A)으로 자기 소유 daemon D 인증정보 메타데이터를 GET, When 조회 엔드포인트를 호출, Then HTTP 200 + broker, account_ref, credential_version, last_rotated_at, has_credential 반환되고 app_key/app_secret 필드는 응답에 없다.
  5. Given user-token(소유자 A)으로 자기 소유 daemon D 인증정보를 삭제, When delete 엔드포인트를 호출, Then HTTP 200/204 반환 후 해당 daemon D 메타데이터 조회 시 has_credential: false(또는 인증정보 없음 응답).
  6. Given user-token(사용자 B)으로 사용자 A 소유 daemon D의 인증정보에 대한 write/read/delete 요청, When 엔드포인트를 호출, Then HTTP 403 Forbidden 반환(소유 스코프 위반).
  7. Given 인증 토큰 없는 요청으로 인증정보 관리 엔드포인트 호출, When 호출, Then HTTP 401 반환.
  8. Given 존재하지 않는 daemon_id를 대상으로 인증정보 관리 요청, When 호출, Then HTTP 404 반환.
  9. Given admin 토큰으로 자기 소유 데몬이 아닌 daemon D의 인증정보 write 엔드포인트 호출, When 호출, Then HTTP 403 반환(관리 API는 소유 스코프 전용 — admin role로 타인 인증정보 조작 불가).
  10. Given service-token으로 인증정보 관리 엔드포인트 호출, When 호출, Then HTTP 403 반환(service-token은 read 전용 /v1/user_info 경로만 허용).

Impacted Area

  • Docs:
    • docs/interface-contract.md — 인증정보 관리 엔드포인트 경로·권한·응답 스키마(secret 미포함 정책) 신규 섹션 추가.
  • Modules:
    • 신규 라우터 파일(경로·파일명은 design 확정) — 인증정보 관리 write/read/delete 엔드포인트.
    • app/schemas/ — CredentialSetRequest(app_key/app_secret/account_ref), CredentialMetaResponse(메타데이터 only, secret 미포함) 스키마 신규 정의.
    • app/services/ — 소유 스코프 인가 검사 + Fernet 암호화/upsert/삭제 서비스 메서드 신규 또는 확장.
    • app/repositories/broker_credential_repository.py — 메타데이터 조회·write 메서드 확장(CLI와 공유).
    • app/core/encryption.py — 재사용 (변경 없음).
    • app/main.py 또는 라우터 등록 — 신규 라우터 include.
  • Tests:
    • AC-1~10 커버 pytest 케이스. 특히 AC-6(소유 스코프 음성), AC-9(admin 소유 스코프 음성), AC-10(service-token 음성), AC-3(CLI·API·service-token 정합) 강제 검증.

Notes

  • OQ-1(엔드포인트 경로): draft-batch-design 위임(dcy-011 Deferred). 팀장 권고 = daemon-scoped(/v1/daemons/{daemon_id}/credential). v1 컨벤션·dcy-009 UI 흐름 정합 설계 단계 확정.
  • 복호화 secret 미반환 불변: 이 REQ의 어떤 응답도 app_secret/app_key 평문을 포함하지 않는다. 유일 decrypt-return 경로는 service-token GET /v1/user_info(REQ-051/REQ-049) — 본 REQ로 변경하지 않는다.
  • AC-9(admin 소유 스코프): admin은 데몬 CRUD(REQ-053)를 담당하며, admin role로 타인 인증정보 write/read를 허용하지 않는다. 인증정보는 사용자 본인 소유 스코프만. 이 경계가 REQ-052(user-token, 소유 스코프)와 REQ-053(admin, 데몬 CRUD)의 책임 분리이다.
  • NFR-1(보안 — secret 미반환·로그 미노출)은 REQ-054에서 독립 Non-Functional REQ로 추적한다. 이 REQ AC는 응답 schema 단의 secret 부재 확인을 포함하며, REQ-054가 전체 보안 격리를 측정한다.
  • NFR-3(일관성 — CLI·API 정합): AC-3이 흡수한다. 구현 시 동일 repository 메서드 재사용 강제.
  • Source: dcy-011 FR-1, FR-2, FR-3, NFR-2, NFR-3.

Change Log

CHG-20260628-01

  • Date: 2026-06-28
  • Author: Justin Ko

Change Summary

  • 신규 생성 (Proposed) — dcy-011 FR-1/FR-2/FR-3 산출물.

Intent

  • dcy-011 confirmed Discovery의 FR-1(인증정보 등록·회전·삭제), FR-2(메타데이터 조회, secret 미반환), FR-3(소유 스코프 인가 강제)를 단일 Interface REQ로 정규화한다. 세 FR이 동일 관리 표면(user-token + 소유 스코프 인증정보 관리)에 속하므로 하나의 REQ로 묶는다.

Acceptance Criteria Delta

  • Added:
    • AC-1 ~ AC-10 전체 (신규 초안)
  • Updated: 없음
  • Removed: 없음

Impacted Area Delta

  • Docs:
    • docs/srs/Interface/req-052_user-owned-credential-management-api.md 신규 생성
    • docs/interface-contract.md 갱신 예고
  • Modules:
    • 인증정보 관리 라우터(신규), 스키마(신규), 서비스·repository 확장
  • Tests:
    • 소유 스코프 음성(AC-6/9/10), 메타데이터 secret 부재(AC-1/4), CLI 정합(AC-3) 케이스 신규

Delivery Trace Delta

  • Batches: 미정 (suggest-batch-reqs 대기)
  • Releases: 미정

Revalidation Impact

  • Reverification Needed: no
  • Existing Implementation Invalidated: no
  • Status Recommendation: keep-current
  • Follow-up Action: confirm-req 후 suggest-batch-reqs. REQ-053/REQ-054와 동일 batch 묶기 권고. OQ-1(경로)은 design 단계 해소.

Validation Plan

  • pytest로 AC-1~10 각 케이스 확인. AC-6(타 사용자 소유 스코프 음성), AC-9(admin 소유 스코프 음성), AC-10(service-token 음성)은 음성 테스트로 강제 검증.

CHG-20260628-02

  • Date: 2026-06-28
  • Author: 팀장(Claude)
  • confirm-req: Proposed → Approved. dcy-011 FR-1/2/3 추적. 소유 스코프 음성(AC-6/9/10)·메타데이터 secret 부재(AC-1/4)·CLI·API·service-token 정합(AC-3) 적절. AC-9(admin도 타인 인증정보 write→403) = 사장님 "self-service 전용·admin 감독 없음" 결정과 정합 확인(admin은 데몬 CRUD만, 인증정보는 본인 소유 스코프). 경로(OQ-1) design 위임. blocker 없음.

CHG-20260628-03

  • Date: 2026-06-28
  • Author: 팀장(Claude)
  • confirm-req-implemented: Approved → Implemented. 근거: BAT-022 PR #19 mergeCommit 1b78c18, QC PASS-WITH-NOTES(opus, blocker 0). AC-1~10 전건 테스트 통과(565 passed). 음성 케이스(AC-6 소유 스코프·AC-9 admin 소유 스코프·AC-10 service-token) 및 secret 미반환(AC-1/4) 검증 PASS. Major 보안 #3(owner 재할당 credential leak) 원자화 수정 83e6dde — 단일 트랜잭션+선삭제+leak 방지 테스트 3종 포함하여 전체 통과. 잔여 리스크 없음.