ADR 0020 — 배포 형태에 따른 자격 증명의 수명¶
- 상태: 승인됨 — 2026-10-01 소유자가 D1 에서 따라 나온 항목을 확인했다 (아래 "확인" 절)
- 이력: 제안됨 (2026-09-30) — 2026-09-30 소유자 결정 D1 을 문장으로 옮긴 것. 결정에서 따라 나오는 항목은 소유자 확인을 받는다(#682)
- 관련 이슈: #682, #683, #635, #679, #685, #785, #796, #802
- 관련 문서: ADR 0012 — provider credential 경계 (그 문서의 2026-09-30 개정 절), POLICY 1.2
맥락¶
ADR 0012 는 principal 별 credential 을 암호화해 저장한다. POLICY 1.2 는 키를 요청·작업 동안만 메모리에 두고 영속 저장하지 않는다고 적는다. 두 문서가 모두 현행이었고 정면으로 어긋났다. 어느 쪽이 제품의 약속인지가 비어 있었다(#682).
결정 (소유자, 2026-09-30, D1)¶
배포 형태로 나눈다. 판단 기준은 multi_user_mode()(#760) — OIDC 가 설정됐거나
ENFORCE_OWNERSHIP 이 켜진 배포다.
| 실행 형태 | 키의 출처 | 규칙 |
|---|---|---|
| kpubdata 라이브러리 / CLI (사용자 자신의 프로세스) | 사용자의 환경변수·인자 | 유지. 그 자체로 BYOK 다 |
| Builder 단일 사용자 self-hosted | 운영자가 곧 사용자 | 현행 유지 — 환경변수·저장 credential 모두 허용 (ADR 0012 본문) |
| Builder 다중 사용자 (self-hosted OIDC, hosted) | 사용자가 요청마다 보낸다 | 영속 저장 금지, 요청·작업 수명만 |
ADR 0012 는 대체되지 않는다. 단일 사용자 배포의 규칙으로 그대로 남고, 다중 사용자 규칙은 ADR 0012 의 개정 절과 이 ADR 이 덧붙인다.
#682 의 아홉 항목에 대한 답¶
| # | 항목 | 답 | 근거 |
|---|---|---|---|
| 1 | 다중 사용자에서 provider 키 영속 저장 금지 | 금지. 저장 요청은 403 credential_storage_disabled, 이미 저장된 키는 읽지 않는다 |
D1 (직접) |
| 2 | HF 토큰에도 같은 규칙인가 | 같다. publish 토큰도 "키" 다 — 다중 사용자에서 저장·서버 환경변수 폴백 없이 요청·작업 수명만 | D1 에서 따라 나옴 — 확인 필요 |
| 3 | 서버 환경변수 폴백 제거 (라이브러리·CLI 제외) | 다중 사용자에서 제거. 어떤 client 도 환경의 키를 싣지 않는다 | D1 에서 따라 나옴 |
| 4 | 운영자 키 폴백 제거 | 다중 사용자에서 제거 — 3 과 같은 것이다. 요청자 키가 없으면 키 없이 부른다 | D1 에서 따라 나옴 |
| 5 | 공유 credential 금지 | 금지. 다중 사용자에서 키는 요청자 한 사람의 요청·작업에만 묶인다. 조직 공유 credential 은 두지 않는다(ADR 0012 의 범위 밖 그대로) | D1 에서 따라 나옴 — 확인 필요 |
| 6 | hosted / self-hosted 구분 | 배포 형태가 아니라 모드로 나눈다. self-hosted 라도 OIDC 로 여러 사람이 쓰면 다중 사용자 규칙이다 | D1 (직접) |
| 7 | 스케줄 빌드 정책 | 단일 사용자 전용. 다중 사용자에는 작업 밖에 살아 있는 키가 없으므로 스케줄 빌드가 성립하지 않는다 | D1 에서 따라 나옴 — 확인 필요 |
| 8 | 재시작 의미 | 진행 중이던 작업의 키는 메모리에만 있었으므로 사라진다. 그 작업은 credentials_required 로 실패하고, 사용자가 키와 함께 다시 제출한다 |
D1 에서 따라 나옴 (#683) |
| 9 | 기존 저장소 이관·삭제 | 아래 "기존 저장 credential" | D1 에서 따라 나옴 — 확인 필요 |
기존 저장 credential¶
다중 사용자 모드로 바꾸는 배포에는 단일 사용자 시절에 저장된 키가 남아 있을 수 있다.
- 읽지 않는다. 다중 사용자 모드에서 resolver 는 저장소를 보지 않는다 — 저장된 키가 있어도
요청에 키가 없으면 키 없이 부른다.
GET /providers/{p}/credential은 "설정되지 않음" 이다. - 사용자가 지운다.
DELETE /providers/{p}/credential은 모드와 무관하게 동작한다. - 운영자가 한꺼번에 지운다. 저장소는
<output_root>/.service/provider-credentials.sqlite3(publish 토큰도 같은 파일의publish-*슬롯) 이다. 다중 사용자로 전환한 뒤 이 파일을 지우고KPUBDATA_BUILDER_CREDENTIAL_MASTER_KEY를 폐기하면, 남은 백업에서도 키를 복호화할 수 없다. - 되돌려 단일 사용자로 돌아가면 저장소가 다시 쓰인다 — 3 을 했다면 사용자가 다시 저장해야 한다.
구현 현황¶
| 규칙 | 상태 |
|---|---|
요청·작업 수명 provider 키, X-Provider-Key 헤더, 저장 거부, 환경변수 폴백 제거, 재시작 → credentials_required |
#683 (PR #857) |
ENFORCE_OWNERSHIP 강제, allowlist 필수 |
#635 (PR #852) |
| 가입 승인 원장 (선택지 B) | #785 (PR #855) |
| 관리자는 메타데이터만 (선택지 a) | #679 (PR #854) |
| 남의 run 은 404 | #796 (PR #851) |
bare url source 금지 |
#685 (PR #853) |
publish 토큰(HF·Kaggle)의 요청 수명, X-Publish-Credential 헤더, 저장된 publish-* 슬롯 미사용, 서버 HF_TOKEN·KAGGLE_* 폴백 제거(reconcile probe 포함) |
#925. publish 는 요청 안에서 끝나는 동기 경로라 작업 수명 보관(JobCredentials)은 필요 없다 |
| 스케줄 빌드를 다중 사용자에서 막는 장치 | 해당 없음 — Builder 에 스케줄러가 없다. 스케줄 게시는 저장소의 GitHub Actions 레거시 경로(ADR 0018)이고 단일 운영자 환경이다 |
확인 (소유자, 2026-10-01)¶
2026-10-01: the owner confirmed the items above marked "D1 에서 따라 나옴". 위 표의 답이 그대로 규칙이 된다. 다중 사용자 모드에서:
- 항목 2 — HF 토큰(publish 토큰)도 provider 키와 같은 규칙이다. 저장·서버 환경변수 폴백 없이 요청·작업 수명만
- 항목 3·4 — 서버 환경변수·운영자 키 폴백은 없다
- 항목 5 — 공유 credential 은 두지 않는다
- 항목 7 — 스케줄 빌드는 단일 사용자 전용이다
- 항목 8 — 재시작으로 키를 잃은 작업은
credentials_required로 실패한다 - 항목 9 — 이미 저장된 credential 은 읽지 않고, 위 "기존 저장 credential" 의 절차로 지운다
위 "구현 현황" 표의 publish 토큰 행은 이 확인으로 후속 이슈 #925 로 옮겼다.
결과¶
- 단일 사용자 배포는 아무것도 바뀌지 않는다. 설치 방법·환경변수·저장 credential 이 그대로다.
- 다중 사용자 배포에서 "Builder 에 키를 맡긴다" 는 선택지는 없다. Studio 는 키를 요청마다 헤더로 보낸다.
- 스케줄 빌드는 단일 사용자 배포의 기능으로 남는다.