fastlane match リモートMac署名:2026 CI設定ガイド
ローカルでは署名できるのに、リモートMacのCIだけが「Signing certificate not found」やプロファイル不一致で停止します。
最短の解決策は、CIではfastlane matchを読み取り専用で実行し、専用または一時的な鍵チェーンを使い、Targetごとのプロファイルを明示し、ジョブ終了後に署名資産を消去する構成です。ビルド成功だけでなく、再起動、連続実行、並列実行、証明書更新後の復旧まで確認して初めて、fastlane match リモートMac署名は運用可能になります。
本記事は、iOSまたはmacOSの自動署名、アーカイブ、TestFlight公開を担当するDevOpsエンジニア向けです。複数のAppやExtensionを同じMac Runnerで扱うチーム、ローカルのfastlaneを長期稼働するリモートMacへ移行する開発者にも適しています。
ローカル成功とリモート失敗を分ける4つの境界
ローカルのXcode環境には、署名に必要な情報がすでに蓄積されています。リモートMacへソースコードだけを移しても、次の資産は自動では同じ状態になりません。
| 境界 | 主な資産 | CIで確認する内容 |
|---|---|---|
| 証明書 | Apple Development、Apple Distributionなど | 証明書と秘密鍵が同じ鍵チェーンにあるか |
| プロファイル | App ID、Entitlements、Team、証明書の対応情報 | Bundle IDごとに期待するファイルか |
| Xcode設定 | CODE_SIGN_IDENTITY、DEVELOPMENT_TEAM、PROVISIONING_PROFILE_SPECIFIER |
Targetと構成ごとの値が明示されているか |
| セッション | ログイン状態、鍵チェーンのロック、アクセス制御 | バックグラウンドRunnerでも秘密鍵を読めるか |
AppleのBuild Settings公式リファレンスでは、署名ID、Team ID、プロビジョニングプロファイルが別々の設定として扱われています。したがって、証明書だけをインポートしても、プロファイルやTarget設定が一致しなければ署名は成立しません。
特に長期稼働ノードでは、対話的なSSHセッションで成功した結果を、そのままCIサービスのバックグラウンド実行へ移せない点が問題になります。ログインユーザー、デフォルト鍵チェーン、ロック解除状態、秘密鍵へのアクセス許可が異なるためです。
最初に選ぶべき構成は「同期」と「ビルド」の分離です
fastlane matchは証明書とプロビジョニングプロファイルを、Gitリポジトリなどの保管先から同期できます。CIでは新しい証明書やプロファイルを作らず、既存資産だけを取得するreadonlyが基本です。詳細はfastlane match公式ドキュメントで、実際に使用するfastlaneのバージョンと合わせて確認してください。
| 運用方式 | 証明書の作成 | CI向きか | 適した場面 |
|---|---|---|---|
readonly: true |
しない | 高い | 通常のプルリクエスト、リリースCI |
readonly: false |
条件により実行 | 低い | 管理者が行う資産更新 |
| 自動署名のみ | Xcodeが管理 | 条件付き | 小規模な開発用ビルド |
| 明示的な署名 | MatchfileとBuild Settingsで指定 | 高い | 配布、複数Target、監査が必要なCI |
Xcodeの自動署名は、開発初期や単一アプリのローカル作業では便利です。一方、公開用CIでは、どの証明書とプロファイルを使ったかをログと設定から追跡できる明示的な構成の方が再現性を保ちやすくなります。
第一段階:単一Appの最小構成を固定する
まずは主Appだけで署名経路を確立します。証明書保管リポジトリへの読み取り権限、MATCH_PASSWORD、必要なApple認証情報をCIの秘密情報として登録します。パスワード、APIキー、セッション情報、リポジトリトークンはログへ出力しません。
Fastfileの最小例は次の形です。
platform :ios do
lane :release do
setup_ci if ENV["CI"]
match(
type: "appstore",
readonly: true,
app_identifier: "com.example.app"
)
build_app(
scheme: "Example",
export_method: "app-store"
)
end
end
setup_ciはCI用の一時鍵チェーンを作成し、matchとgymが使える状態を準備します。CIでの一時鍵チェーンについては、fastlane公式のCIガイドを参照してください。実際のオプション名や挙動は、導入時点の公式ドキュメントで再確認します。
実行後は、laneの終了コードだけで判断しません。
security find-identity -v -p codesigning
xcodebuild \
-workspace Example.xcworkspace \
-scheme Example \
-configuration Release \
-showBuildSettings | \
grep -E 'CODE_SIGN_IDENTITY|DEVELOPMENT_TEAM|PROVISIONING_PROFILE_SPECIFIER'
xcrun codesign -dvvv "build/Example.app"
確認すべき証拠は、署名IDの存在、Team IDの一致、期待するプロファイル名またはUUID、アーカイブ内の署名情報です。署名対象のパスはプロジェクト構成によって変わるため、固定値として扱わず、実際のアーカイブ内容を確認します。
fastlane matchを複数Targetへ広げる場合は暗黙選択を捨てる
Widget、Notification Service Extension、Share Extensionを追加すると、主Appと同じ証明書でもプロファイルは別になることがあります。Bundle ID、Entitlements、配布方式が異なるためです。macOSアプリでも、Extensionごとに対応するプロファイルを組み込む必要があります。配布用署名の考え方は、AppleのMac向け署名資料で確認できます。
| Target | Bundle ID例 | Match指定 | Xcode側の確認 |
|---|---|---|---|
| 主App | com.example.app |
App Store用 | Releaseのプロファイル |
| Widget | com.example.app.widget |
App Store用 | Widget専用プロファイル |
| 通知Extension | com.example.app.notification |
App Store用 | Entitlementsとの一致 |
| macOS補助Target | com.example.app.helper |
配布方式に応じて指定 | 埋め込み署名の確認 |
Matchfileには共有可能な基本設定を置き、FastfileにはCIで実行する型とBundle IDの組み合わせを置きます。Xcodeプロジェクトや.xcconfigには、TargetごとのPROVISIONING_PROFILE_SPECIFIERなど、最終的なビルド設定を保持します。
match(
type: "appstore",
readonly: true,
app_identifier: [
"com.example.app",
"com.example.app.widget",
"com.example.app.notification"
]
)
アーカイブ後は、単に.ipaが生成されたかではなく、内部の各Bundleを調べます。
unzip -q Example.ipa -d ipa_check
find ipa_check/Payload -name "*.app" -o -name "*.appex"
codesign -dvvv ipa_check/Payload/Example.app
codesign -dvvv ipa_check/Payload/Example.app/PlugIns/ExampleWidget.appex
XcodeのSchemeは、ビルド対象Targetと構成を決めます。複数TargetではScheme、Build Configuration、署名設定の組み合わせを固定しないと、ローカルとCIで異なる成果物になり得ます。
複数Teamを同じMacで扱う場合は資格情報の境界を分ける
複数のApple Teamや複数アプリを一台のRunnerで処理する場合、古い証明書やプロファイルの再利用が起きやすくなります。Matchリポジトリ、暗号化パスワード、CI変数、鍵チェーンを、少なくともTeamまたは公開環境単位で分離します。
| 分離単位 | 分ける対象 | 失敗時の確認 |
|---|---|---|
| Team | Team ID、Apple認証、署名保管先 | DEVELOPMENT_TEAM |
| App | Bundle ID、プロファイル | app_identifier |
| 環境 | Development、Ad Hoc、App Store | typeとExport設定 |
| Runner | 鍵チェーン、作業ディレクトリ | 前回ジョブの残留資産 |
開発者全員にDeveloper Portalの変更権限を与える必要はありません。CIでは署名保管先と暗号化パスフレーズへのアクセスを分け、通常のビルド担当者が誤って証明書を失効させる範囲を抑えます。
自動署名は、単一Teamでの開発用ビルドや、Xcode上で頻繁に端末を追加する流れに適しています。反対に、公開用CI、複数Team、複数Extensionでは、明示的な設定と変更履歴を残す構成が安全です。
長期Runnerでは一時鍵チェーンと常設鍵チェーンを使い分ける
一回限りの実行環境なら、setup_ciで作成された一時鍵チェーンをジョブ終了時に破棄する方式が適しています。長期オンラインのリモートMacでは、再起動後も同じユーザー環境で処理されるため、鍵チェーンとプロファイルの残留が別のジョブへ影響しない設計が必要です。
実行前後に、次の項目を記録します。
security list-keychains
security default-keychain
security find-identity -v -p codesigning
find "$HOME/Library/MobileDevice/Provisioning Profiles" \
-type f -maxdepth 1 -print
確認は3段階に分けます。
- Macを再起動し、最初のCIジョブだけを実行します。
- 同じ設定で連続ジョブを実行し、前回の鍵やプロファイルに依存しないことを確認します。
- 失敗するジョブを意図的に作り、終了処理後に署名資産や作業ディレクトリが残らないか確認します。
並列実行を許可する場合、同一の鍵チェーン名、同一の一時フォルダー、同一のDerived Dataを共有しないことが重要です。長期Runnerで並列数を増やすより、まずジョブ単位の作業領域と鍵チェーンを分ける方が原因追跡は容易になります。
証明書の期限切れ・失効・ノード再構築は順番を固定する
証明書やプロファイルに問題が出たとき、いきなり破壊的なリセットを実行するのは危険です。Apple Developer側で資産の状態を確認し、現在のMatchリポジトリ履歴と利用中のApp IDを保全してから更新します。プロファイルの再生成や削除手順は、Appleのプロビジョニングプロファイル管理資料を基準にしてください。
復旧順序は次の通りです。
- Apple Developer側で証明書、App ID、プロファイルの状態を確認します。
- 失効前のMatchリポジトリ履歴と、現在のCI変数を保全します。
- 管理者権限のある環境で必要な資産だけを更新します。
- リモートMacでは
readonlyで新しい資産を同期します。 - アーカイブ、署名、エクスポート、配布先での受理まで確認します。
- ノード再構築時に旧鍵チェーンと旧プロファイルが使われていないことを確認します。
破壊的なmatch nukeなどは、既存の配布経路、他のRunner、チームメンバーのローカル環境へ影響します。実行前に保管リポジトリのバックアップ、現在の証明書一覧、利用中のApp ID、ロールバック方法を記録してください。
構成を決めるための最終判定表
| 条件 | 推奨構成 | 合格とする証拠 |
|---|---|---|
| 単一App、単一Runner | setup_ci+readonly |
アーカイブと署名検証 |
| Extensionがある | Bundle IDを配列で指定 | 各.appexの署名確認 |
| 複数Teamを共有 | リポジトリと変数を分離 | Team IDとプロファイルの一致 |
| 長期オンライン | ジョブ単位の鍵チェーンまたは隔離Runner | 再起動後の初回ジョブ |
| 証明書更新が多い | 更新担当とCI担当を分離 | 更新履歴と再現ビルド |
| 並列ビルド | 作業領域と鍵チェーンを分離 | 同時実行後の資産汚染なし |
この表で一つでも証拠を提出できない項目があれば、本番公開用のmacOS CIとしては未完成です。特に「laneが成功した」という結果だけでは、意図した証明書が使われたことや、次回の再起動後も動くことまでは証明できません。
ローカルMacからリモートMacへ移行する場合、現在の構成にも弱点があります。ローカル機はスリープ、OS更新、個人のログイン状態に左右されます。Linuxサーバーや仮想環境では、XcodeとApple署名資産を同じ条件で再現しにくく、長期Runnerとして保守負担が残ります。
短期の移行検証や段階的なリリース運用なら、Macレンタルの料金と利用期間を確認し、root権限付きのリモートMacで再起動とノード再構築まで先に試す方法が現実的です。物理ポートへの常時アクセスが必要な開発や、長期間まったく同じ機材を占有する高負荷運用では、自社保有のMac miniが適する場合もあります。
購入とレンタルの違いは、Mac miniの導入方法と比較してください。署名資産の隔離、保守担当、利用期間を基準に判断すると、fastlane matchの移行や証明書更新を一時的に検証したいケースでは、SFTPMACのリモートMacが選択肢になります。