Figment.so
Mac hostingWebsite hostingGuidesHow to usePricing

Rotate Apple Certs in CI Without Build Downtime

An expired Apple distribution certificate stops App Store Connect uploads the moment it lapses. This page is the runbook: rotate during business hours, keep in-flight CI builds green, and hold an encrypted rollback asset in case the new certificate fails verification. Commands below come from the primary docs at Apple Developer certificates and Fastlane match.

Apple Certificate Rules That Shape The Rotation

Apple's certificates page is explicit about the constraints you have to design around:

  • Apple Distribution belongs to the team, not a user. Only one type of each distribution certificate is allowed per team at a time — Developer ID is the exception and can have several.
  • When an Apple Distribution certificate expires, apps already on the App Store keep working, but you cannot upload new builds signed with the expired cert.
  • Developer ID Application: previously signed apps continue to run; you cannot sign new versions until a new certificate is issued. A revoked (not merely expired) Developer ID cert blocks installs.
  • Only the Account Holder or Admin role can create distribution certificates.

Because only one Apple Distribution certificate is active per team, you cannot run two overlapping App Store distribution certs in parallel the way you might with Developer ID. The "overlap window" here is a time overlap — generate the replacement before the old one expires — not two simultaneously trusted certificates.

The 30-Day Advance Window

Put a calendar alert 30 days before expiry and use the time to:

  1. Pick a low-traffic rotation slot (Tuesday morning beats Friday afternoon).
  2. Confirm every CI runner can reach the Match repository.
  3. Freeze release-branch merges for the rotation window.
  4. Export an encrypted .p12 of the current certificate and private key for rollback.

Automate the alert with a weekly check that fails CI when the cert has 30 days or less left:

#!/usr/bin/env bash
# cert-expiry-check.sh — run weekly on a macOS runner
set -euo pipefail

: "${CERT_P12_PATH:?set CERT_P12_PATH}"
: "${CERT_P12_PASSWORD:?set CERT_P12_PASSWORD via CI secret}"

EXPIRY=$(openssl pkcs12 -in "$CERT_P12_PATH" -nokeys -passin "pass:${CERT_P12_PASSWORD}" \
  | openssl x509 -noout -enddate | cut -d= -f2)

EXPIRY_EPOCH=$(date -j -f "%b %e %T %Y %Z" "$EXPIRY" +%s)
DAYS_LEFT=$(( (EXPIRY_EPOCH - $(date +%s)) / 86400 ))

printf 'Distribution cert expires: %s (%d days)\n' "$EXPIRY" "$DAYS_LEFT"
[ "$DAYS_LEFT" -gt 30 ] || { echo "Rotate now: $DAYS_LEFT days left" >&2; exit 1; }

Read CERT_P12_PASSWORD from the CI secret manager — never hard-code it. This is an unexecuted example; run it against your own encrypted .p12 on a macOS runner and confirm the output before scheduling.

Rotating With Fastlane Match

Per the Fastlane match docs, match nuke "revokes your certificates and provisioning profiles" for the chosen environment, and readonly mode "only fetch[es] existing certificates and profiles, don't generate new ones" — Fastlane recommends readonly on CI. --force renews provisioning profiles every run; it does not by itself revoke a certificate.

The clean, repeatable rotation on a macOS workstation (not on CI):

# 1. Revoke the current distribution cert and its App Store profiles
fastlane match nuke distribution   # confirms interactively; review the list before approving

# 2. Regenerate a fresh distribution cert plus App Store profiles and commit to the Match repo
fastlane match appstore

# 3. Optional: refresh development material at the same time
fastlane match development

Match writes the regenerated assets to its Git repository in a single commit. CI runners pick up the new cert on their next match ... readonly fetch. match nuke distribution also invalidates existing App Store provisioning profiles tied to the revoked cert; match appstore regenerates them. Do not run nuke on an Enterprise (in-house) program casually — revoking that distribution cert blocks previously installed in-house apps from launching.

The Rotation Runbook

Run in order. Do not skip step 4.

#StepCommand or check
1Pre-flight: Match reachabilityfastlane match appstore --readonly from one of each runner type
2Pre-flight: freeze releasesHold merges to the release branch; announce the window
3Rollback assetExport current cert + private key as an encrypted .p12; store in the secret manager, not in Git
4Drain CIWait for all in-flight builds to finish; pause new jobs on release lanes
5Rotatefastlane match nuke distribution then fastlane match appstore on an admin macOS machine
6Verify buildTrigger a signed Release archive on a non-production branch
7Verify uploadfastlane pilot upload to a TestFlight internal group
8ResumeUnfreeze releases
9Reset alertUpdate the 30-day calendar entry and the weekly script baseline

Rollback path. The window is narrow: once match nuke revokes the old cert, previously signed in-flight builds that have not been uploaded may be marked Invalid Binary. If the new cert fails step 6 before you nuke, abort — nothing has changed on Apple's side. If it fails after step 5, re-import the encrypted .p12 from step 3 on an admin machine, upload the preserved public certificate back to the Apple Developer portal only if Apple still accepts it, then re-run fastlane match appstore pointed at the restored material. If Apple will not reinstate the revoked certificate, your fastest recovery is finishing the new-cert path: re-run match appstore, re-sign the pending build, and push.

Keep The Match Secret Out Of Shell History

Store the Match encryption password in a CI secret named MATCH_PASSWORD; Fastlane reads it from the environment. Use readonly on every CI job:

# Fastfile — CI-side lane; interactive rotation is a separate admin lane
lane :sync_signing do
  match(type: "appstore", readonly: is_ci)
end

Do not echo the password, do not write a plaintext dump of the full environment to disk, and keep the signing job restricted to trusted branches. If you need to move a secret between systems, transfer the name list and restore values through the secret manager.

Picking A Mac For The Rotation Work

The rotation itself needs a Mac with the Match repo cloned, Fastlane installed, and the right Xcode for your target. Figment's options:

  • Virtual Intel macOS, $29/month. This is a real macOS environment on virtualized Intel — Keychain, security, codesign and Xcode toolchains that still support Intel all work. It can host the weekly expiry check, run readonly match fetches, and sign supported Intel-compatible targets. ARM-only execution, GPU tasks and Xcode 27 are out of scope: Apple's porting guide says to use Xcode 26 or earlier on Intel. Access is via the browser console; inbound SSH is not available today.
  • i3 Mac, $49/month. Physical Intel for teams still shipping with Xcode 26 or earlier. Availability is request-based while supply is confirmed in the quote.
  • M-series Mac, from $95/month. Apple silicon for ARM execution, GPU, and Xcode 27. The $95 entry price is for an M-series machine; the exact chip, RAM and disk are confirmed in your quote, not promised here.
  • Managed Build Mac, $249/month. One M-series Mac with CI setup, backups, monitoring and 30 minutes of monthly support — the useful tier when you want someone else to wire the Match repo, secret manager and rotation alert into your pipeline. Managed Mac Team, $999/month adds a second M-series Mac, two CI runners, team setup and one hour of monthly support.

Worked example: rotation month cost

Assume one admin Mac for the rotation plus one CI runner. A straight read of the price list:

  • 1 × virtual Intel macOS admin + 1 × i3 CI runner = $29 + $49 = $78/month, both Intel, suitable while you remain on Xcode 26 or earlier.
  • 1 × M-series Mac for admin + CI, entry price = $95/month (specific chip/RAM in the quote), the pick when you need Xcode 27 or ARM.
  • 1 × Managed Build Mac = $249/month — includes the CI setup and monitoring work, so the first rotation is mostly someone else's checklist.

Physical Intel and M-series plans currently collect requests until supply is confirmed; agree an evaluation window in the quote if your rotation deadline is tight. See /mac-hosting and start a quote at /mac-hosting/start. Tax and any fees apply as stated on the actual quote.


Related guides:


Subscribe for Figma design and website publishing guides.


Figment.so

Contact

Twitter

Website pricing

Compute index

About

Privacy

Terms