N개 iOS 앱 출시 운영: 서명 자산과 Fastlane 자동화

  • iOS 출시 운영 구분은 팀 공통 자산, 앱별 등록 정보, 출시별 산출물, 배포 자동화의 책임 분리 체계
  • 여러 앱이 같은 Apple Developer Team에 속할 때 인증서와 API 키를 공유하고, Bundle ID와 provisioning profile을 앱별로 분리하는 다중 앱 운영 모델
  • Fastlane이 반복적인 서명·빌드·업로드를 실행하되 Apple 권한·Capability·심사 판단을 대신하지 않는 자동화 경계

이 구조가 필요한 이유

  • 인증서, API 키, Bundle ID, profile을 모두 같은 종류의 설정으로 취급하면 앱이 늘어날수록 소유자와 변경 시점이 불명확해진다.
  • API 키나 Distribution Certificate처럼 팀에 귀속된 자산은 공유하고, Bundle ID나 스토어 정보처럼 앱에 귀속된 자산은 분리해야 한다.
  • Associated Domains처럼 Capability가 바뀐 경우에는 코드·Developer Portal·provisioning profile이 모두 같은 상태여야 배포 서명이 성공한다.

AS-IS

flowchart LR
    A[개발자] --> B[인증서, Bundle ID, Profile을 매번 수동 확인]
    B --> C{누락 또는 만료?}
    C -->|예| D[빌드/업로드 실패]
    C -->|아니오| E[수동 빌드 및 업로드]

TO-BE

flowchart LR
    A[개발자: 앱 등록·Capability·출시 판단] --> B[Fastlane: 서명 동기화]
    B --> C[Fastlane: IPA 빌드]
    C --> D[Fastlane: TestFlight 또는 ASC 업로드]
    D --> E[개발자: 심사 제출·출시]

큰 그림: 개발자 준비 → 서명 자산 → Fastlane 실행

flowchart TB
    subgraph Manual[1. 개발자가 직접 준비하는 작업]
        TeamOnce[팀 최초 1회<br/>Developer Team·권한·계약<br/>API Key·Match 저장소 생성]
        AppOnce[앱별 최초 1회<br/>App ID / Bundle ID 등록<br/>Capability·entitlements·ASC 앱 레코드 설정]
        ReleaseInput[출시마다<br/>코드·버전·빌드 번호·테스트<br/>메타데이터·심사 정보 준비]
        TeamOnce --> AppOnce --> ReleaseInput
    end

    subgraph Assets[2. 설정·서명 자산 · Git·JSON·Apple 서버에 보관]
        SharedAssets[팀 최초 1회 후 N개 앱 재사용<br/>API Key JSON/CI Secret · Match Git<br/>Distribution Certificate]
        AppProfiles[앱별로 생성·보관<br/>각 Bundle ID의 App Store Profile<br/>암호화된 Match Git에 동기화]
        SharedAssets --> AppProfiles
    end

    subgraph Fastlane[3. Fastlane 자동화]
        Sync[sync_signing<br/>인증서·Profile 생성 및 동기화]
        Refresh[refresh_signing<br/>Capability 변경 후 Profile 재생성]
        Build[IPA 빌드·서명]
        Beta[TestFlight 업로드]
        Release[App Store Connect 빌드 업로드]
    end

    TeamOnce -->|팀 공통 자산 생성| SharedAssets
    AppOnce -->|앱별 profile의 전제 조건| AppProfiles
    ReleaseInput -->|빌드 입력| Build
    SharedAssets -->|인증| Sync
    AppProfiles -->|서명| Build
    Sync -->|동기화 완료| Build
    AppOnce -. Capability 변경 .-> Refresh
    Refresh --> Sync
    Build --> Beta
    Build --> Release

    classDef teamOnce fill:#EDE9FE,stroke:#7C3AED,color:#4C1D95;
    classDef appOnce fill:#FFE4E6,stroke:#E11D48,color:#881337;
    classDef releaseInput fill:#FEF3C7,stroke:#D97706,color:#78350F;
    classDef asset fill:#DBEAFE,stroke:#2563EB,color:#1E3A8A;
    classDef automated fill:#DCFCE7,stroke:#16A34A,color:#14532D;
    class TeamOnce teamOnce;
    class AppOnce appOnce;
    class ReleaseInput releaseInput;
    class SharedAssets,AppProfiles asset;
    class Sync,Refresh,Build,Beta,Release automated;
  • 보라색: 팀에서 최초 한 번 설정하고 다음 앱에도 재사용하는 개발자 직접 작업
  • 분홍색: 새 앱마다 최초 한 번 추가하는 개발자 직접 작업
  • 노란색: 출시마다 개발자가 준비·판단하는 작업
  • 초록색: Fastlane이 반복 실행을 자동화하는 작업
  • 파란색: 팀 또는 앱별로 보관·생성되는 자산
  • 팀 최초 1회: 같은 Apple Developer Team의 다음 앱에서도 재사용하는 작업
  • 앱별 최초 1회: 새 앱을 등록하거나 Capability를 처음 추가할 때 필요한 작업
  • 출시마다: Fastlane이 업로드한 뒤에도 개발자가 매 버전 결정해야 하는 작업

이 문서의 세 구분

여기서 “구분”은 코드 아키텍처의 계층이 아니라, 누가 소유하고 언제 관리하는가를 기준으로 묶은 운영 단위다.

1. 개발자가 직접 준비하는 작업

Apple Developer Portal과 App Store Connect에서 사람의 권한과 판단이 필요한 작업이다. 팀 설정은 한 번 해두면 N개 앱에서 재사용하고, App ID·Capability·앱 레코드는 새 앱마다 추가한다. 코드·버전·테스트·심사 판단은 출시마다 직접 준비한다.

2. 설정·서명 자산

1번 작업의 결과로 생기는 인증 정보와 서명 재료다. Fastlane이 이 자산을 저장하는 것은 아니다. Fastlane은 각 자산을 읽어 인증서와 profile을 동기화하고 빌드를 서명한다.

자산은 한 곳에만 두지 않는다. 용도에 따라 일반 프로젝트 Git, 암호화된 Match Git, Git에 커밋하지 않는 JSON/CI secret, Apple 서버로 나뉜다.

자산관리 형태실제 보관 위치공유 범위
Fastlane 설정Fastfile, Appfile, Matchfile, 배포 스크립트 등의 일반 텍스트 파일각 앱의 프로젝트 Git앱별, 소스 코드와 함께 관리
App Store Connect API KeyAppStoreConnectKey.json 또는 CI secret/환경변수로컬 비밀 저장소 또는 CI secret. 일반 Git에는 커밋하지 않음같은 App Store Connect 조직에서 재사용 가능
Distribution Certificate와 private keyMatch가 암호화한 인증서 파일Apple Developer Portal 및 암호화된 Match Git 저장소같은 Apple Developer Team에서 재사용
App Store Provisioning ProfileMatch가 암호화한 profile 파일Apple Developer Portal 및 암호화된 Match Git 저장소Bundle ID별로 분리
App Store Connect 앱 레코드·메타데이터Apple 서비스의 관리 데이터App Store Connect 서버앱별로 분리

즉, 프로젝트 Git에는 Fastlane 설정과 실행 스크립트를 넣고, Match Git에는 암호화된 서명 재료를 넣는다. AppStoreConnectKey.json처럼 private key를 담은 JSON은 Git에 넣지 않고 로컬 비밀 저장소나 CI secret으로 주입한다. App ID, Capability, 앱 레코드처럼 Apple이 소유하는 설정은 Apple 서버에 남는다.

3. Fastlane 자동화

준비된 2번 자산을 사용해 반복적인 배포 절차를 재현한다. Match로 인증서와 profile을 동기화하고, IPA를 빌드·서명한 뒤 TestFlight 또는 App Store Connect에 업로드한다. App ID 등록, Capability 활성화, 심사 제출 여부와 공개 출시는 개발자 판단으로 남는다.

개발자가 실제로 따르는 iOS 출시 흐름

공식 절차와 대조하면 App ID·Capability가 먼저여야 한다. 그 다음 App Store Connect 앱 레코드와 App Store profile은 서로 선후 의존하지 않지만, 둘 다 빌드 업로드 전에 준비되어야 한다. 앱 레코드는 이미 등록된 Bundle ID를 선택하며, Capability를 바꾸면 그 App ID를 담은 기존 profile은 무효가 된다. Apple: 신규 앱 레코드, Apple: Capability 변경

아래의 autonumber는 권장 운영 순서를 나타낸다. 보라색 블록은 팀 최초 한 번, 분홍색 블록은 새 앱마다 한 번, 노란색 블록은 매 출시마다 반복한다.

sequenceDiagram
    autonumber
    actor Developer as 개발자
    participant Portal as Apple Developer Portal
    participant ASC as App Store Connect
    participant Project as 앱 프로젝트 Git
    participant Match as 암호화된 Match Git
    participant Fastlane as Fastlane

    rect rgb(237, 233, 254)
        Note over Developer,Match: 팀 최초 1회 · 다음 앱에도 재사용
        Developer->>ASC: API 접근 권한 요청·Team API Key 생성
        Developer->>Match: private 저장소·접근 권한·암호 설정
    end

    rect rgb(255, 228, 230)
        Note over Developer,Fastlane: 새 앱마다 최초 1회
        Developer->>Portal: Explicit App ID 등록·Capability 활성화
        Note over Portal,Fastlane: 앱 레코드와 최초 signing은 순서 무관 · 업로드 전 둘 다 필요
        Developer->>ASC: 등록된 Bundle ID로 앱 레코드 생성
        Developer->>Project: Fastlane 설정·배포 스크립트 커밋
        Developer->>Fastlane: 최초 signing 동기화 실행
        Fastlane->>Portal: 인증서·App Store profile 생성 또는 갱신
        Fastlane->>Match: 서명 재료를 암호화해 저장
    end

    rect rgb(254, 243, 199)
        Note over Developer,ASC: 출시마다 반복
        Developer->>Project: 코드·버전·테스트·메타데이터 준비
        Developer->>Fastlane: beta 또는 release 실행
        Fastlane->>Match: 인증서·profile 동기화
        Fastlane->>Fastlane: IPA 빌드·서명
        Fastlane->>ASC: 빌드 업로드
        Developer->>ASC: TestFlight 검증·심사 제출·공개 결정
    end
  • 팀 최초 1회: Match Git에는 암호화된 certificate·private key·profile을 두고, API private key는 AppStoreConnectKey.json 또는 CI secret으로 보관한다. Team API Key는 같은 App Store Connect 조직의 모든 앱에 적용된다. JSON 파일과 Match 암호는 일반 프로젝트 Git에 커밋하지 않는다. Apple: Team API Key, Fastlane Match
  • 새 앱 최초 1회: App ID를 먼저 등록하고 Capability를 활성화한다. 이후 앱 레코드 생성과 최초 signing은 어느 쪽을 먼저 해도 되지만, 업로드 전에 모두 완료해야 한다. 앱 프로젝트에 Fastfile, Appfile, Matchfile, 배포 스크립트를 추가하고 최초 signing 동기화를 실행하면 Match가 필요한 인증서·profile을 생성하고 저장소에 보관할 수 있다.
  • 매 출시: Fastlane은 Match의 서명 재료를 동기화한 후 빌드·서명·업로드한다. 심사 제출·출시 방식 결정은 App Store Connect에서 사람이 수행한다. Capability를 새로 추가하거나 변경했다면, 이 반복 단계 전에 profile을 재생성해야 한다.

팀 공통 설정·서명 자산

같은 Apple Developer Team에 속한 N개 앱이 함께 사용하는 자산이다. 앱별로 복제하지 않으며, 접근 권한과 보안 정책을 팀 단위로 관리한다.

컴포넌트공유 범위관리 주기역할개발자가 직접 관리할 일
Apple Developer Team같은 개발 조직팀 최초 1회Certificates, Identifiers & Profiles와 코드 서명의 소유 주체프로그램 가입, 계약 동의, 구성원 권한 관리
App Store Connect 조직같은 판매자 조직팀 최초 1회앱 레코드, TestFlight, 심사, 판매 정보의 소유 주체사용자 역할, 세금·계약, 앱 접근 권한 관리
App Store Connect API Key같은 App Store Connect 조직팀 최초 1회 후 재사용Fastlane이 Apple 서버에 인증하여 빌드·메타데이터 작업을 수행하는 비밀 키생성, 최소 권한 선택, 안전한 보관, 유출 시 폐기
Match 인증서 Git 저장소같은 Apple Developer Team팀 최초 1회 후 재사용인증서 private key와 Bundle ID별 profile을 암호화해 팀이 공유하는 저장소최초 저장소 생성, 접근 권한, 암호 관리
Apple Distribution Certificate같은 Apple Developer Team팀 공통, 만료 시 갱신App Store/TestFlight용 IPA가 팀 소유임을 증명하는 서명 신원만료·폐기 정책 확인, Match 접근 권한 유지

App Store Connect API Key의 의미

AppStoreConnectKey.json은 보통 다음 세 가지를 파일로 묶은 표현이다.

{
  "key_id": "KEY_ID",
  "issuer_id": "ISSUER_ID",
  "key": "-----BEGIN PRIVATE KEY----- ..."
}

프로젝트는 같은 정보를 환경변수로 주입하거나, Git에 넣지 않는 로컬 AppStoreConnectKey.json 파일로 참조할 수 있다. 두 방식의 역할은 같고, 차이는 비밀 키를 로컬 JSON 파일로 둘지 실행 환경의 secret으로 둘지다.

  • Team API Key는 같은 App Store Connect 조직의 모든 앱에 적용되는 팀 공통 키다.
  • Individual API Key는 해당 사용자에게 부여된 앱 접근 권한과 역할을 따른다.
  • p8 private key는 한 번만 내려받을 수 있으므로 소스 저장소에 커밋하지 않는다.

앱별 등록·서명 자산

각 앱의 정체성과 Apple 기능 사용 여부를 정의한다. 같은 팀 안에서도 다른 앱과 공유하면 안 되는 영역이다.

컴포넌트앱별 분리 이유관리 주기역할개발자가 직접 관리할 일
App ID / Bundle ID설치·푸시·서명·스토어 대상을 구분하는 고유 식별자앱 최초 1회예: com.example.product가 하나의 앱을 식별Apple Developer Portal에서 Explicit App ID 등록
Capability앱이 사용할 Apple 서비스의 허가 목록앱 최초 또는 기능 추가 시Associated Domains, Push Notifications, Sign in with Apple 등의 entitlement 근거Portal에서 활성화하고 Xcode entitlements와 앱 코드를 함께 변경
App Store Connect 앱 레코드고객에게 보이는 하나의 상품 단위앱 최초 1회이름, SKU, 기본 언어, 카테고리, 가격, 심사 이력의 기준App Store Connect에서 신규 앱 생성 및 상품 정보 설정
App Store Provisioning Profile특정 Bundle ID·Capability·Distribution Certificate 조합의 서명 허가서앱별 자동 동기화, Capability·인증서 변경 시 갱신IPA가 해당 앱의 허용된 entitlement를 포함하도록 제한일반적으로 Match가 생성·동기화, 수동 생성은 자동화가 없을 때만 사용
Store Metadata앱 상세 페이지의 판매 정보앱 최초 후 출시마다 갱신 가능이름, 설명, 키워드, 스크린샷, 지원 URL, 심사 정보App Store Connect에서 관리하거나 별도 Fastlane metadata 설정으로 자동화

Capability 변경 규칙

Capability는 단순히 코드에 entitlement를 추가하는 것으로 끝나지 않는다.

  1. Developer Portal의 App ID에서 Capability를 활성화한다.
  2. Xcode entitlements와 앱 코드를 변경한다.
  3. 기존 App Store profile을 새 Capability 기준으로 재생성한다.
  4. 새 profile로 IPA를 다시 서명한다.

예를 들어 Associated Domains를 추가하면 applinks: 도메인 변경은 코드/entitlements 변경 대상이고, Capability를 처음 켠 시점에는 profile 재생성이 필요하다. 이후 도메인 값만 바꾸는 경우에도 entitlements가 바뀌므로 새 서명 결과를 TestFlight에서 검증해야 한다.

출시별 산출물과 개발자 판단

한 번의 버전 출시마다 새로 준비하거나 확인해야 하는 항목이다. Fastlane이 파일 생성과 업로드를 수행해도, 제품 품질과 판매·심사 판단은 개발자 책임이다.

컴포넌트역할개발자가 직접 관리할 일
코드·테스트실제 배포할 앱 동작기능·회귀·개인정보·정책 검증
버전·빌드 번호App Store Connect가 빌드를 구분하는 버전 식별자pubspec.yaml 버전 갱신, 같은 빌드 번호 재업로드 금지 확인
IPA배포 가능한 서명 산출물빌드 결과와 대상 Bundle ID 확인
TestFlight 빌드내부/외부 테스터에게 배포하는 검증 대상테스터 그룹, 테스트 범위, 피드백 확인
App Store 버전고객에게 제출할 출시 후보메타데이터, 스크린샷, 연령 등급, 심사 메모, 빌드 선택
심사·출시 결정공개 배포의 최종 판단심사 제출, 거절 대응, 수동/자동 출시 선택

Fastlane: 반복 작업을 실행하는 자동화 도구

Fastlane은 Apple 계정을 대신 만드는 도구가 아니다. 이미 준비된 권한과 설정을 사용해 반복되는 배포 작업을 명령으로 재현하는 도구다.

일반적인 iOS Fastlane 구성은 다음을 자동화한다.

  • sync_signing: Match 저장소에서 인증서와 각 Bundle ID의 App Store profile을 동기화
  • refresh_signing: Associated Domains 같은 Capability 변경 후 profile을 강제 재생성
  • beta: Flutter IPA를 빌드하고 TestFlight에 업로드
  • release: Flutter IPA를 빌드하고 App Store Connect에 업로드

release는 빌드를 App Store Connect에 올리는 명령이다. 메타데이터·스크린샷 업로드, 심사 제출, 공개 출시는 프로젝트 Fastlane 설정에 따라 별도로 자동화하거나 수동으로 수행한다.

신규 앱 최초 설정 체크리스트

  1. App Store Connect에서 신규 앱 레코드를 생성한다.
  2. Developer Portal에서 Explicit App ID와 필요한 Capability를 등록한다.
  3. 팀 공통 Match Git 저장소에 접근 가능한지 확인하고 MATCH_GIT_URL을 설정한다.
  4. 같은 App Store Connect 조직에서 API Key를 만들거나, 해당 앱에 접근 가능한 기존 키를 사용한다.
  5. 로컬 또는 CI secret에 ASC_KEY_ID, ASC_ISSUER_ID, ASC_KEY_CONTENT_BASE64, MATCH_GIT_URL을 설정한다.
  6. sync_signing으로 앱별 profile을 만든 뒤, 프로젝트의 beta lane으로 TestFlight 업로드 및 실기기 검증을 수행한다.

매 출시 실행 체크리스트

  1. 코드·테스트·버전·빌드 번호를 확정한다.
  2. 새 Capability가 있으면 Portal, entitlements, profile이 모두 같은 상태인지 확인한다.
  3. 스토어 메타데이터와 심사 정보를 App Store Connect에서 갱신한다.
  4. 프로젝트의 beta lane으로 TestFlight 검증을 수행한다.
  5. 프로젝트의 release lane으로 App Store Connect에 빌드를 올린다.
  6. App Store Connect에서 빌드를 선택하고 심사 제출 및 출시 방식을 결정한다.

참고 문서