Developer ID로 직접 배포한다는 것
macOS 앱을 사용자에게 전달하는 길은 크게 두 가지입니다. 하나는 **Mac App Store(MAS)**를 통하는 것이고, 다른 하나는 개발자가 직접 만든 .dmg(또는 .app) 파일을 웹사이트나 GitHub 같은 곳에서 내려받게 하는 **직접 배포(direct distribution)**입니다.
직접 배포에는 분명한 장점이 있습니다. App Store 심사를 기다릴 필요가 없고, 결제 수수료도 없으며, 업데이트를 원하는 시점에 원하는 방식으로 내보낼 수 있습니다. 대신 App Store가 대신 처리해 주던 일들 — 코드 서명, 공증(notarization), 자동 업데이트 — 을 개발자가 직접 갖춰야 합니다.
이 일들을 갖추지 않으면 macOS의 보안 장치인 Gatekeeper가 앱 실행을 막습니다. 사용자가 처음 앱을 열 때 “확인되지 않은 개발자가 배포한 앱이므로 열 수 없습니다” 같은 경고를 보게 되고, 대부분의 사용자는 거기서 설치를 포기합니다. 정상적으로 배포된 앱처럼 더블 클릭만으로 열리게 하려면, 앱을 Developer ID 인증서로 서명하고 Apple로부터 공증을 받아야 합니다.
이 시리즈는 그 사전 설정 과정을 다룹니다. 한 가지 좋은 소식은, 여기서 다루는 설정은 대부분 한 번만 끝내면 모든 릴리스에서 재사용된다는 점입니다.
이 시리즈에서 만드는 것
3편에 걸쳐 다음을 갖추게 됩니다.
- (1편, 이 글) Developer ID Application 인증서 + 공증용 자격 증명
- (2편) Sparkle 자동 업데이트를 위한 EdDSA 서명 키
- (3편) 업데이트 피드를 호스팅할 공개 저장소 + 빌드 설정 마무리
시리즈를 마치면 손에 다음이 갖춰져 있어야 합니다. 지금은 항목만 훑어 두고, 각 편에서 하나씩 채워 나가면 됩니다.
- macOS 키체인(Keychain)에
Developer ID Application인증서 - 키체인에 저장된 공증용 자격 증명 프로필
- Sparkle 업데이트 서명용 EdDSA 키 한 쌍(공개 키 + 비공개 키)
- 비공개 키를 안전한 곳에 백업
- 업데이트 피드(appcast)를 올릴 공개 GitHub 저장소 + GitHub Pages
- 빌드 설정 파일(
ExportOptions.plist)과 앱 측 설정
예시 앱 — FocusTimer
이 시리즈는 가상의 macOS 앱 FocusTimer(집중 시간을 관리하는 간단한 타이머 앱)를 예로 듭니다. 명령어와 경로에 등장하는 FocusTimer, 번들 식별자 com.example.FocusTimer, 도메인 example.com, 인증서 이름, Team ID 등은 모두 예시 값입니다. 실제로 따라 할 때는 본인의 앱 이름과 계정 정보로 바꿔서 사용하세요.
이 글은 Xcode 26과 Sparkle 2.x(자동 업데이트 프레임워크, 2편에서 등장) 기준으로 작성했습니다. Apple은 화면 구성과 메뉴 위치를 종종 바꾸므로, 버튼 이름이 조금 다르더라도 흐름은 같다고 생각하면 됩니다.
사전 준비 — 명령줄 도구
먼저 빌드·릴리스 자동화에 필요한 명령줄 도구 두 개를 설치합니다. macOS 패키지 매니저 Homebrew가 설치돼 있다는 전제입니다.
brew install gh create-dmg
gh— GitHub 공식 CLI. 나중에 GitHub Release를 만들 때 사용합니다.create-dmg— 배포용.dmg디스크 이미지를 만드는 도구. 사용자가 앱을Applications폴더로 끌어다 놓도록 안내하는 화면도 함께 생성해 줍니다.
지금 당장 쓰지는 않지만, 릴리스 자동화 스크립트가 이 도구들의 존재를 먼저 확인하고 없으면 즉시 멈추도록 설계하는 경우가 많으므로 미리 깔아 둡니다.
1단계 — Apple Developer Program 확인
Developer ID 인증서를 발급하고 앱을 공증하려면 Apple Developer Program 멤버십이 필요합니다. 개인 계정 기준 연 $99의 유료 프로그램입니다.
이미 가입돼 있다면 활성 상태인지만 확인하면 됩니다.
- developer.apple.com/account 접속
- Membership details 섹션에서 상태가 Active인지 확인
- 같은 화면에서 본인의 Team ID(예시에서는
ABCDE12345)를 메모해 둡니다. 뒤 단계에서 계속 쓰입니다.
아직 가입 전이라면 멤버십이 승인될 때까지 보통 하루 안팎 걸립니다. 승인 전에는 인증서 발급이 불가능하므로 가장 먼저 처리해 두는 편이 좋습니다.
2단계 — Developer ID Application 인증서 발급
Developer ID Application 인증서는 배포할 .app과 .dmg에 서명할 때 사용하는 인증서입니다. macOS Gatekeeper는 이 인증서로 서명된 앱을 “알려진 개발자가 만든 앱"으로 인식합니다.
Apple에는
.pkg설치 패키지에 서명하는 Developer ID Installer 인증서도 따로 있습니다. 이 시리즈는.dmg로 배포하므로 Application 인증서만 다룹니다.
발급 절차
가장 간단한 방법은 Xcode를 통하는 것입니다.
- Xcode 실행 → 메뉴 Xcode → Settings… (
⌘,) - Accounts 탭 선택 → 왼쪽 목록에서 본인의 Apple ID 클릭
- 오른쪽 아래 Manage Certificates… 버튼 클릭
- 새로 열린 창의 왼쪽 아래
+버튼 클릭 - 메뉴에서 Developer ID Application 선택
- 1~2초 후 목록에 새 인증서가 추가되면 Done
이렇게 발급된 인증서는 자동으로 macOS **키체인(Keychain)**에 저장됩니다. 인증서와 그에 대응하는 비공개 키가 한 쌍으로 저장되며, 이 비공개 키가 있어야 서명이 가능합니다.
발급 확인
터미널에서 다음 명령으로 인증서가 제대로 들어왔는지 확인합니다.
security find-identity -v -p codesigning | grep "Developer ID Application"
다음과 같이 한 줄이 나오면 성공입니다.
1) A1B2C3D4E5F6... "Developer ID Application: Gildong Hong (ABCDE12345)"
따옴표 안의 문자열이 인증서의 정식 이름입니다. Gildong Hong은 Apple 계정에 등록된 이름, 괄호 안 ABCDE12345는 1단계에서 메모해 둔 Team ID입니다. 이 이름은 뒤에서 코드 서명을 자동화할 때 그대로 쓰이므로 한 번 더 확인해 두세요.
인증서 갱신
Developer ID 인증서의 유효 기간은 5년입니다. 만료가 가까워지면 Xcode의 Manage Certificates 목록에서 Expired로 표시됩니다. 그때 위와 똑같은 절차로 새 인증서를 발급하면 됩니다.
좋은 소식은, 기존 인증서로 이미 서명·배포된 앱이 만료 즉시 무효화되지는 않는다는 점입니다. 앞으로 새로 만드는 빌드만 새 인증서로 서명하면 됩니다. 그러니 만료를 지나치게 걱정할 필요는 없습니다.
3단계 — 공증을 위한 App 전용 암호 등록
공증(notarization)이란
공증은 배포 전 앱을 Apple 서버에 올려 악성코드 검사를 받는 절차입니다. 검사를 통과하면 Apple이 “공증 티켓"을 발급하고, 이 티켓이 앱에 붙어 있어야 Gatekeeper가 경고 없이 앱을 열어 줍니다. 서명이 “누가 만들었는지"를 증명한다면, 공증은 “Apple이 한 번 검사했다"를 증명하는 별도의 절차입니다.
공증 제출에는 Apple의 notarytool 명령을 사용하는데, 제출할 때마다 Apple ID 비밀번호를 묻습니다. 매번 입력하지 않으려면 **App 전용 암호(App-Specific Password)**를 만들어 키체인에 미리 저장해 둡니다.
3-1. App 전용 암호 발급
App 전용 암호는 Apple ID 본 비밀번호 대신 특정 용도에만 쓰는 16자리 암호입니다.
- appleid.apple.com 접속 → Apple Developer Program에 가입된 Apple ID로 로그인 (예시에서는
[email protected]) - 로그인 및 보안(Sign-In and Security) → 앱 암호(App-Specific Passwords) 선택
+버튼 → 암호 이름 입력 (예:focustimer-notarize)- 생성(Create) → Apple ID 비밀번호를 한 번 더 입력
abcd-efgh-ijkl-mnop형식의 16자리 암호가 화면에 표시됩니다.
이 화면을 닫으면 암호를 다시 볼 수 없습니다. 다음 단계로 넘어가기 전에 비밀번호 관리자 등에 잠시 복사해 두세요.
3-2. notarytool 프로필에 저장
발급받은 암호를 키체인 프로필로 저장합니다. 아래 명령에서 --password 값을 방금 받은 실제 암호로 바꿔서 실행하세요.
xcrun notarytool store-credentials "focustimer-notarize" \
--apple-id "[email protected]" \
--team-id "ABCDE12345" \
--password "abcd-efgh-ijkl-mnop"
- 첫 번째 인자
"focustimer-notarize"— 이 프로필에 붙일 이름. 앞으로 공증할 때 이 이름으로 자격 증명을 불러옵니다. --apple-id— Apple Developer Program 계정 이메일--team-id— 1단계의 Team ID--password— 3-1에서 발급받은 App 전용 암호
다음 출력이 나오면 성공입니다.
Credentials saved to Keychain.
이제 키체인에 자격 증명이 저장됐으므로, App 전용 암호 원본은 더 이상 필요 없습니다. (단, 다른 컴퓨터에서도 빌드할 계획이라면 비밀번호 관리자에 보관해 두는 편이 편합니다.)
3-3. 확인
저장한 프로필이 실제로 동작하는지 확인합니다.
xcrun notarytool history --keychain-profile "focustimer-notarize"
Successfully received submission history.라는 메시지가 나오면 정상입니다. 그 아래 제출 내역은 비어 있을 수도 있고(아직 공증한 적이 없으니 정상), 이전 기록이 있을 수도 있습니다.
핵심 함정 — Apple ID와 GitHub 계정은 다르다
직접 배포를 처음 설정하는 사람이 가장 자주 막히는 지점입니다.
- Apple Developer Program 계정 — 인증서 발급, 공증에 사용 (예시:
[email protected]) - GitHub 계정 — 3편에서 업데이트 파일을 호스팅할 때 사용 (예시:
[email protected])
이 둘이 서로 다른 이메일인 경우가 많습니다. 특히 notarytool store-credentials의 --apple-id에는 반드시 Apple Developer 계정 이메일을 넣어야 합니다. GitHub 계정 이메일을 넣으면 인증에 실패하는데, 오류 메시지가 친절하지 않아 원인을 찾기 어렵습니다.
두 계정의 이메일이 헷갈리기 쉽다면, 어느 쪽이 Apple용이고 어느 쪽이 GitHub용인지 메모해 두는 것을 권합니다. 이 구분은 시리즈 내내 반복해서 등장합니다.
1편 정리
여기까지 따라왔다면 이제 다음을 갖췄습니다.
- ✅ 릴리스 자동화용 명령줄 도구(
gh,create-dmg) - ✅ 활성 상태의 Apple Developer Program 멤버십
- ✅ 키체인에 저장된 Developer ID Application 인증서
- ✅ 키체인에 저장된 공증용 자격 증명 프로필(
focustimer-notarize)
이것으로 앱을 서명하고 공증할 준비가 끝났습니다. 하지만 사용자에게 한 번 전달하고 끝나는 앱은 거의 없습니다. 버그를 고치고 기능을 더한 새 버전을 계속 내보내야 하죠. App Store라면 자동 업데이트를 알아서 처리해 주지만, 직접 배포에서는 이 역시 직접 갖춰야 합니다.
다음 편에서는 macOS 앱의 사실상 표준 자동 업데이트 프레임워크인 Sparkle을 위한 EdDSA 서명 키를 만듭니다. 인증서와는 또 다른, 업데이트 파일 전용 검증 장치입니다.