Jenkins errSecInternalComponent 出現時,不要先反覆重裝憑證;應先在圖形登入 Terminal、SSH 與 Jenkins Job 使用同一 macOS 帳號、同一簽名身份和同一測試檔案,完成最小 codesign 測試,再按數位身份、Keychain、ACL 與 Agent 安全上下文定位。正式發布則應採用非 root 專用簽名帳號、隔離節點,並把重啟後的無人值守恢復列入准入驗收。
本指南適合三類人員:維護 Jenkins Mac Agent、需要恢復 iOS 或 macOS 發布流水線的平台工程負責人;管理憑證私鑰、Keychain 權限與發布稽核的企業安全負責人;以及評估遠端 Mac 能否支援無人值守簽名和故障恢復的 IT 採購決策者。
最後更新於 2026 年 9 月 5 日;日期與排障邊界核對自 Apple Developer 程式碼簽名討論區、Apple TN3161 憑證技術說明,以及 Jenkins Agent 官方文件。
[ SECTION_01 ] 先建立三處相同的簽名基線
最有辨識力的故障資料是:「圖形 Terminal 簽名成功,但同一帳號的 Jenkins Job 回傳 errSecInternalComponent。」這代表憑證檔案未必損壞,優先懷疑執行時的 Keychain 狀態、私鑰存取控制或 Agent 的安全上下文。Apple 已將這類錯誤與 SSH、CI 等非標準簽名環境的差異列為排查邊界;不能只看憑證是否出現在 Keychain。
先使用非生產測試檔案與隔離測試帳號,記錄三處測試的完整輸出:
security find-identity -v -p codesigning
codesign --force --sign "測試簽名身份" --timestamp=none ./Test.app
codesign --verify --verbose=4 ./Test.app
測試時三個條件必須一致:
- macOS 使用者帳號與
HOME。 - 憑證、私鑰及其對應的簽名身份。
- 測試 App、Keychain 搜尋範圍與
codesign參數。
若圖形 Terminal 和 SSH 都成功,只有 Jenkins 失敗,故障範圍通常集中在 Agent 啟動方式或 Job 執行環境。若三處均失敗,才把數位身份、信任鏈或私鑰狀態列為第一層問題。這個分層比直接匯入同一張憑證更有效,因為「憑證可見」不等於「完整身份可簽名」。
[ SECTION_02 ] 數位身份完整性要分開驗證
為甚麼 Jenkins 能編譯,到了 codesign 階段卻失敗?
編譯只證明原始碼、工具鏈與依賴可用;codesign 還需要可用的憑證、對應私鑰、受信任的鏈,以及目前執行者能無互動存取私鑰。兩者使用的安全資源不同,所以「能編譯」不能推導出「能簽名」。
Apple 的 TN3161 憑證內部結構說明可用來核對憑證用途、鏈結與身份組成。排查時不要只截取 security find-certificate 的結果,應建立以下證據:
| 指標 | 核查方式 | 判讀重點 | 決策評分 |
|---|---|---|---|
| 憑證 | security find-identity -v -p codesigning |
是否列出可用簽名身份 | 高 |
| 私鑰 | 在同一 Keychain 檢查對應私鑰 | 憑證與私鑰是否成對存在 | 高 |
| 信任狀態 | 核對憑證鏈與用途 | 過期、用途不符或鏈不完整 | 高 |
| 實際簽名 | 使用非生產 App 執行 codesign |
是否可在無彈窗條件下完成 | 最高 |
證書在 Keychain 中看得到,但 Jenkins 仍不能簽名,常見原因是只匯入了公開憑證,沒有匯入對應私鑰;或者 Jenkins 使用的 Keychain 搜尋範圍與圖形登入不同。重複匯入公開憑證不會補回缺失私鑰,也不會修復 ACL。
Apple DTS 最近一次明確修訂相關排障帖的日期為 2026 年 7 月 6 日。這裡的日期只代表官方排障資料的修訂狀態,不代表每一個社群個案都有相同根因。企業紀錄應保留失敗輸出、身份清單與憑證信任結果,避免把推測寫成修復結論。
[ SECTION_03 ] Keychain 可存取性是獨立的准入指標
圖形登入可能已自動解鎖登入 Keychain;SSH 登入通常不會因為 Unix 帳號相同,就自動建立相同的圖形安全會話。這正是「圖形 Terminal 成功、SSH 或 Jenkins 失敗」的重要分界。
SSH 登入遠端 Mac 後,如何處理 errSecInternalComponent?
先不要把 sudo 或 root 當作修復方法。應先確認 SSH 會話實際使用的 Keychain、鎖定狀態、搜尋列表與私鑰存取規則,再在隔離測試身份上執行最小簽名。目標是讓 codesign 在無彈窗條件下獲得明確、可稽核的私鑰授權。
可按以下順序核查:
- 確認目前帳號、
HOME和進程所有者。 - 列出實際使用的 Keychain,確認不是誤用另一個帳號的登入 Keychain。
- 檢查 Keychain 是否鎖定,以及 Agent 啟動後狀態是否一致。
- 檢查私鑰的 ACL 或 partition list,只授權必要的簽名工具。
- 在無圖形彈窗、無人工點擊的狀態下重跑最小簽名。
| Keychain 情況 | 圖形 Terminal | SSH / Jenkins | 主要結論 |
|---|---|---|---|
| Keychain 已解鎖,私鑰可用 | 成功 | 可能失敗 | 多半是會話或 Agent 上下文差異 |
| 只有公開憑證 | 可查看憑證 | 失敗 | 不是匯入更多憑證,而是補齊完整身份 |
| 私鑰存在但被鎖定 | 失敗或跳出提示 | 失敗 | 需設計可稽核的解鎖流程 |
| 私鑰 ACL 不允許簽名工具 | 可能提示授權 | 常見失敗 | 應限定工具授權,不應放寬到所有程式 |
注意:密碼、私鑰內容和解鎖材料不得寫入 Jenkinsfile、一般環境變數範例或建置紀錄。環境變數可被子進程、除錯輸出或失敗報告讀取,不能取代正式的秘密管理與權限設計。
Apple 對 程式碼簽名主題的 SSH、CI 與 Keychain 邊界已有排障討論。企業實作仍應在隔離測試帳號和非生產憑證上驗證,完成後再將同一規則移植到發布節點。
[ SECTION_04 ] Jenkins Agent 安全上下文不能只看 Unix 使用者
Jenkins Agent 的執行者、啟動方式、HOME、父進程和登入狀態,會共同決定 Job 能否看到預期的 Keychain。Jenkins 官方文件說明了 節點與執行器的管理邊界;Agent 使用文件則可用來核對 Agent 的連線與執行關係。
如何判斷問題來自私鑰、ACL,還是使用者上下文?
採用「一次只改一項」的判斷法:三處使用同一身份時,若所有環境都失敗,先查私鑰和信任鏈;若圖形 Terminal 成功、SSH 失敗,查 Keychain 解鎖與 ACL;若 SSH 測試成功、Jenkins 失敗,查 Agent 的 HOME、啟動方式、父進程和 Job 實際執行者。
| 比對項目 | 交互測試者 | Jenkins Job | 不一致時的風險 |
|---|---|---|---|
| macOS 帳號 | 簽名者身份 | Agent 進程所有者 | 看似同名,實際權限不同 |
HOME |
登入帳號目錄 | Agent 啟動環境 | 找到不同 Keychain |
| 啟動方式 | 圖形或 SSH | Launch、服務或連線 Agent | 缺少登入安全上下文 |
| Controller 憑據 | Jenkins 連線認證 | 不等於本地簽名身份 | 兩種身份被錯誤混用 |
| 執行紀錄 | 手動輸出 | Job console log | 證據不完整或暴露秘密 |
禁止以 root 或 sudo 作為通用修復。這可能暫時改變檔案、Keychain 或進程可見性,卻沒有解決正式發布帳號的授權邊界。生產簽名應使用非 root 專用帳號;Jenkins Controller 的憑據只負責流水線需要的認證,不應被當成 macOS 本地簽名身份。
[ SECTION_05 ] 簽名隔離決定故障半徑
普通 PR 建置、歸檔任務與正式發布不應共用同一個可取得生產私鑰的節點。隔離不是把所有工作都搬到另一台 Mac,而是讓每個工作負載只取得完成任務所需的最小權限。
| 方案 | 適用工作 | 私鑰暴露面 | 維運複雜度 | 本文評分 |
|---|---|---|---|---|
| 登入 Keychain | 低風險測試、短期驗證 | 依登入環境而定 | 低 | 測試可用 |
| 專用臨時 Keychain | 隔離歸檔、輪換演練 | 可限制在單一任務 | 中 | 較佳 |
| 專用發布節點 | 正式簽名與發布 | 節點、帳號、任務可分層 | 高 | 最佳 |
| 所有 Job 共用發布節點 | PR、歸檔、正式發布混跑 | 高 | 表面較低 | 不建議 |
節點標籤至少要能證明三件事:哪些 Job 可以排程到該節點、哪些帳號可以讀取簽名材料、哪些操作會留下稽核紀錄。工作區、匯入的憑證材料和暫存檔案在任務完成後也要可驗證清理。
對需要短期驗證的團隊,可先在 NOVAKVM 的遠端 Mac 方案建立獨立測試節點;若團隊所在區域與連線路徑已確定,再比較香港 M4 遠端 Mac等可用方案。這些節點仍須通過本身的帳號、Keychain、重啟和簽名驗收,不能因為能遠端連線就直接視為生產發布機。
[ SECTION_06 ] 重啟恢復必須通過無人值守驗收
Jenkins Agent 重啟後若不能自動恢復簽名,問題就不只是一次性的 errSecInternalComponent。企業發布應在三種狀態重複最小簽名與真實歸檔測試:
- 主機重新啟動後。
- Agent 斷線並重新連線後。
- 沒有人工圖形登入、沒有點擊 Keychain 彈窗時。
Jenkins Agent 重啟後,怎樣確認程式碼簽名能自動恢復?
先記錄重啟前的 Agent 使用者、Keychain 狀態和簽名身份,再重啟主機或模擬 Agent 重連。服務恢復後,先執行最小 codesign,再執行一次真實歸檔。兩者均成功,且紀錄中沒有人工授權動作,才可進入下一階段。
驗收表應至少包含:
- 失敗 Job 的原始輸出與發生時間。
- 修復動作及變更前後的 ACL、Keychain 狀態。
- 無互動最小簽名結果。
- 重啟後 Agent 重連與真實歸檔結果。
- 憑證材料、工作區和暫存檔案的清理證據。
若節點只能依靠人工點擊 Keychain 彈窗恢復,便不應列為無人值守生產發布節點。這個條件比「現在手動跑一次成功」更接近企業真正需要的恢復能力。
提醒:Jenkins 的成功狀態只代表該次 Job 完成,不等於主機重啟、Agent 重連和無圖形登入後仍具備相同簽名上下文。准入文件要保存這三種條件下的獨立結果。
[ SECTION_07 ] 企業 CI 修復的最小落地流程
為避免把排障改寫成無限重試,可依以下五個階段執行:
- 封存證據:保留圖形 Terminal、SSH 和 Jenkins Job 的輸出,不先刪除失敗工作區。
- 固定身份:在隔離測試帳號和非生產憑證上,固定
HOME、Keychain、測試 App 和簽名身份。 - 確認完整身份:分別證明憑證、私鑰、信任鏈和
codesign實際可用,區分「可見」與「可簽名」。 - 縮小上下文差異:比較 Agent 進程所有者、啟動方式、Keychain 搜尋範圍和無互動授權結果。
- 完成准入測試:執行隔離任務、清理驗證、主機重啟、Agent 重連和真實歸檔,最後才恢復正式發布流量。
這套流程不要求立即更換所有節點。它要求每一次修復都有可重現的證據,並且不把臨時 sudo、人工點擊或公開憑證重複匯入當成長期方案。
[ SECTION_08 ] 現有設備與遠端 Mac 的取捨
如果現有 Mac 已經能穩定處理編譯,但發布節點缺少隔離帳號、遠端恢復或重啟後的 Keychain 驗證,直接改動生產機會放大回滾風險。實體設備還可能受限於辦公室電力、遠端存取方式、硬體維護窗口,以及故障時必須到場處理。
對短期故障恢復、簽名隔離試點或發布窗口前的獨立驗證,租用 NOVAKVM 的遠端 Mac 可把測試節點與現有生產設備分開,並透過圖形連線、SSH 和控制台驗證同一套准入證據。不過,若團隊需要長期固定高負載、實體 USB 裝置或完全自主管理硬體,仍應評估自購 Mac;遠端租用更適合臨時算力、隔離測試和快速建立獨立簽名環境。
完成最小簽名、隔離驗證與重啟復測後,最穩妥的做法是用同一份證據表驗收新的 Mac 節點,而不是直接把生產憑證搬過去。若現有設備無法在發布窗口前完成隔離試點,可先申請一台具備專用帳號、SSH、圖形存取和遠端恢復能力的 NOVAKVM 遠端 Mac,讓 errSecInternalComponent 的修復結論建立在可重現測試上。