Skip to content

Cert Mirror — 무엇이고 왜 있나

ainote 계정에 fastlane match 의 cert + provisioning profile 묶음을 암호화 백업으로 저장할 수 있는 dev-facing API. iOS/macOS 빌드 자동화를 운영하는 사람이 GitHub 외에 두 번째 안전망을 원할 때 씁니다.

한 줄 요약

fastlane match 가 git push 한 디렉터리를 통째로 tarball 로 묶어서 ainote 에 HMAC 검증 업로드 → 나중에 GitHub repo 가 사라져도 ainote 에서 다시 받을 수 있게.

누구를 위한 기능인가

ainote 계정만 있으면 누구나 — 특히 다음 사용자들이 효용을 봅니다:

  • Claude Code / Cursor / Windsurf 같은 AI agent — TestFlight 자동화 워크플로우를 운영하면서 자기가 만든 IPA 의 signing artefact 까지 안전하게 책임지고 싶을 때
  • fastlane match 사용자 — GitHub repo 1개에 의존하기 불안할 때 두 번째 안전망으로
  • 모든 ainote 사용자 — cert tarball 외에도 "암호화된 작은 바이너리 백업" 이 필요한 모든 케이스에 일반적으로 활용 가능 (현재 1차 use case 는 cert mirror)

ainote 의 노트 / 메모리 / 동기화 같은 end-user 기능과는 별도 layer 의 dev API 입니다. 계정만 있으면 동일 인증 체계 (McpKey 토큰) 안에서 추가 발급으로 바로 쓸 수 있습니다.

왜 만들었나

fastlane match 의 표준 저장 위치는 GitHub private repo. 이 자체가 git 이라 안전하지만:

  1. 단일 의존성 — GitHub 가 다운되거나 organization 이 정지되면 빌드 자동화 전체가 멈춤
  2. 계정 이전 — 회사·개인 GitHub 계정 옮길 때 cert repo migration 이 손이 많이 감
  3. AI agent 가 자기 빌드를 추적하기 어려움 — git 은 LLM 이 직접 들춰보기 까다로움. HTTP endpoint + JSON 응답이 훨씬 다루기 쉬움

ainote 의 cert_mirror 는 GitHub 를 대체하는 게 아니라 보조합니다. fastlane match 는 그대로 git 에 push 하고, push 가 성공하면 그 직후 동일 commit 의 tarball 을 ainote 에도 업로드. 둘 다 살아있어야 정상 — 한쪽이 사라지면 다른 쪽으로 복구.

무엇이 다른가

측면GitHub (fastlane match 기본)ainote cert_mirror
저장 형태git refs, 파일별단일 tarball (commit 단위)
인증SSH key / PATAuthorization: McpKey <token>
무결성git shaHMAC-SHA256 (별도 secret)
권한 모델repo 전체 collaborator사용자별 UserMirrorCredential 1개
사이즈 한도100MB/file, 5GB/repo50MB/blob, 5GB/user (예정)
다운로드git cloneHTTP GET (JSON metadata + 바이너리)

어떻게 동작하나 (한 사이클)

┌────────────────────────────────────────────────────────────────┐
│  fastlane sync_signing                                          │
│  1. ASC API 로 cert / profile 발급                              │
│  2. seunghan91/apple-certs git push (1차 저장)                  │
│  3. mirror_to_ainote 호출 ─┐                                    │
│                              │                                  │
│                              ▼                                  │
│           ┌─────────────────────────────────────┐               │
│           │  git archive --format=tar.gz HEAD   │               │
│           │  → streaming HMAC-SHA256 (8KB chunk)│               │
│           │  → POST /api/cert_mirror            │               │
│           │     Authorization: McpKey <token>   │               │
│           │     X-Mirror-Signature: sha256=...  │               │
│           │     X-Commit-Sha: <40 hex>          │               │
│           │     Content-Type: application/octet-stream │        │
│           └────────────────┬────────────────────┘               │
│                            │                                    │
└────────────────────────────┼────────────────────────────────────┘


            ┌────────────────────────────────────┐
            │  ainote_server                     │
            │  ┌──────────────────────────────┐  │
            │  │ Api::CertMirrorController    │  │
            │  │  - McpKey 인증               │  │
            │  │  - HMAC 재계산 후 비교       │  │
            │  │  - 50MB 초과 시 inline 413   │  │
            │  │  - tempfile → storage_path   │  │
            │  └──────────────┬───────────────┘  │
            │                 │                  │
            │                 ▼                  │
            │   CertMirrorBlob (PostgreSQL)      │
            │   - commit_sha, byte_size, sha256  │
            │   - uploaded_at, uploaded_by       │
            │   - storage_path → 디스크 또는 S3   │
            └────────────────────────────────────┘

신뢰 모델

  • 수신자(ainote) 는 token 으로 사용자 인증, HMAC 으로 무결성 검증. body 자체는 fastlane match 가 이미 MATCH_PASSWORD 로 암호화한 상태라 ainote 가 평문 cert 를 만지지 않습니다.
  • 발신자(클라이언트)MATCH_PASSWORD 만 분실 안 하면 안전 — repo 도 mirror 도 둘 다 털려도 평문 cert 추출 불가.
  • 자기 자신(ainote 운영자) 에게도 cert 평문은 안 보임. UserMirrorCredential hmac_secret 은 non-deterministic 암호화, token 은 deterministic (검색용).

AI agent 통합 시 추천 패턴

  1. 첫 실행 — 사용자에게 ainote-cert-mirror issue (또는 api 페이지 의 curl) 안내. CLI 가 Keychain 저장까지 자동
  2. fastlane 워크플로우의 마지막에 mirror_to_ainote 패턴 호출
  3. 주기적으로 ainote-cert-mirror verify 호출 (heartbeat — endpoint 200 + Keychain present + blob count)
  4. 새 dev 환경 셋업 시 setup-guide "다른 mac 에서 같은 계정 사용" 섹션 따라가면 끝
  5. 회전 (issue --rotate) 후에는 반드시 fastlane sync_signing 재실행 — 기존 blob 무효화됨

다음

알려진 제약

  • UserMirrorCredential 은 계정당 1개. 회전은 기존 entry 삭제 + 재생성 (자세한 절차는 api 인증 섹션)
  • blob 영구 보관 — soft delete 지원 안 함 (이력 보존 정책상)
  • 한 계정당 5GB 정도까지를 권장 (강제 quota 는 미구현)
  • Render edge WAF 가 default Ruby/curl User-Agent 를 차단. 클라이언트는 custom User-Agent 명시 필수 (ainote-fastlane-mirror/1.0 등)