본문으로 건너뛰기

보안

로그인, 세션, API 키, 결제, 잡 실행 환경에서 XenoCI가 비밀과 격리를 다루는 방식을 설명합니다

XenoCI는 비밀번호를 쓰지 않고, 키와 토큰은 해시로만 저장하며, 잡마다 새 VM을 씁니다

로그인과 세션

항목방식
로그인Google 계정 또는 이메일 링크(6자리 코드 포함), 비밀번호 없음
이메일 링크15분 동안 한 번만, 토큰은 URL 조각(#token=)에 실려 서버 로그와 Referer에 남지 않음, 코드는 5번 틀리면 무효
Google인가 코드 + PKCE(S256), 상태 값은 해시로 저장하고 10분 뒤 만료, 확인된 이메일만 기존 계정에 연결
세션14일, 쿠키 xci_console은 HttpOnly; Secure; SameSite=Lax, 서버에는 세션 ID의 SHA-256만 저장
요청 제한로그인 메일은 이메일당 15분에 5번, IP당 20번
같은 출처 검사쿠키로 하는 모든 쓰기 요청(POST, PUT, PATCH, DELETE)은 Origin 또는 Referer가 같은 출처여야 합니다, 아니면 403 insufficient_permission

API 키

  • 형식 xci_live_<43자>_<6자>, 뒤 6자는 CRC32 체크섬이라 데이터베이스를 읽기 전에 걸러냅니다
  • 서버는 SHA-256 해시만 저장하고 발급 응답에서 한 번만 보여 줍니다
  • 키는 워크스페이스 하나에 묶이고 run 또는 read 권한만 가집니다, 결제와 관리 기능은 어떤 키로도 불가(console_only)
  • 서버 오류 메시지와 로그, CLI와 MCP 출력에서 xci_live_ 문자열을 가립니다
  • 공개 유출 자동 폐기와 사용량 급증 알림은 키 유출 대응에 있습니다
  • Authorization 헤더가 있으면 쿠키가 있어도 키 요청으로 처리하고, 잘못된 키는 401입니다

잡 실행 환경

항목방식
격리잡마다 봉인된 베이스 이미지를 복제한 새 VM, 끝나면 파기하고 삭제를 확인
비밀값잡 env는 VM에 표준 입력으로 전달, 명령줄과 로그에 남지 않음
소스업로드는 잡 전용 1회용 토큰으로 맥 호스트가 받아 가고 잡이 끝나면 지움, git 소스는 VM 안에서 공개 저장소를 받음
결과물잡 전용 토큰으로 올리고 15분짜리 서명 링크로 내려받음, 링크에 API 키가 들어가지 않음
요청 ID모든 응답에 X-Request-Id, 오류 봉투에 request_id
캐시모든 응답이 Cache-Control: private, no-store

결제

  • 결제는 PortOne 경유 원화 카드 결제이고 서버는 카드 정보를 받지 않습니다
  • 결제 확인 때 서버가 PortOne에서 결제를 다시 읽어 금액, 통화, 상점을 주문과 대조합니다, 다르면 payment_amount_mismatch로 적립하지 않습니다
  • 결제 웹훅은 Standard-Webhooks 서명을 검증하고, 같은 결제 ID는 한 주문에만 묶입니다(payment_reference_reused)
  • 매일 전날 결제 목록을 PortOne과 대사합니다

감사 기록

조직 만들기, 역할 변경, 멤버 내보내기, 워크스페이스 보관, API 키 발급과 폐기, 유출 자동 폐기가 감사 이벤트로 남습니다, 지금은 콘솔이나 API로 조회하는 화면이 없고 문의하면 지원팀이 확인해 드립니다

책임 공유

  • 키와 토큰을 저장소나 공개 채널에 두지 마세요
  • 포크 PR 워크플로에 시크릿을 넘기지 마세요
  • 서명 인증서와 App Store Connect 키는 API 제출의 env 필드로 넘기고 스크립트에서 파일로 풀어 쓰세요, 서버에 보관하는 금고 기능은 아직 없고 CLI와 MCP에는 env 옵션이 없습니다
  • 빌드 스크립트가 받는 외부 호스트를 최소로 두세요

다음 단계