콘텐츠로 이동

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

다중 사용자 모드로 바꾸는 배포에는 단일 사용자 시절에 저장된 키가 남아 있을 수 있다.

  1. 읽지 않는다. 다중 사용자 모드에서 resolver 는 저장소를 보지 않는다 — 저장된 키가 있어도 요청에 키가 없으면 키 없이 부른다. GET /providers/{p}/credential 은 "설정되지 않음" 이다.
  2. 사용자가 지운다. DELETE /providers/{p}/credential 은 모드와 무관하게 동작한다.
  3. 운영자가 한꺼번에 지운다. 저장소는 <output_root>/.service/provider-credentials.sqlite3 (publish 토큰도 같은 파일의 publish-* 슬롯) 이다. 다중 사용자로 전환한 뒤 이 파일을 지우고 KPUBDATA_BUILDER_CREDENTIAL_MASTER_KEY 를 폐기하면, 남은 백업에서도 키를 복호화할 수 없다.
  4. 되돌려 단일 사용자로 돌아가면 저장소가 다시 쓰인다 — 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 는 키를 요청마다 헤더로 보낸다.
  • 스케줄 빌드는 단일 사용자 배포의 기능으로 남는다.