Guides / Apple signing credentials
A certificate is not a signing identity: Apple keys in macOS CI
Updated 2026-11-02 · Official sources checked 2026-11-02
A certificate copied to a build machine does not always make a signing job ready. Apple code signing needs the certificate and the private key that matches it. The pair is a signing identity. Understanding that distinction helps explain why a downloaded .cer may not work on another Mac, and how to keep the identity out of repository files, unrelated jobs, and leftover runner state.
Certificate, private key, identity: three different things
| Item | What it contains | Role in signing |
|---|---|---|
| Certificate (often .cer) | Public certificate data, including a public key and issuer, subject, and validity information. | Associates a public key with an identity; the certificate alone cannot create a code signature. |
| Private key | The secret key that matches the certificate’s public key. It is commonly created with the CSR and kept in the originating Mac’s keychain. | The signing operation uses it. Downloading the certificate does not copy the private key from the original Mac. |
| Signing identity | The certificate and its matching private key. Apple tools commonly use a PKCS#12 file, usually .p12, to move an exported identity between systems. | The signing user must be able to access both parts for the relevant signing operation. |
Apple’s TN3161 says a certificate contains the public key, while code signing requires the matching private key as well. When Keychain Access creates a certificate signing request, the private key is created in the keychain; the certificate downloaded later does not include it. If the original Mac is unavailable, a .cer file alone cannot recreate that key. If a team needs to move the identity, an authorized member can export it from Keychain Access as a password-protected identity file and handle it through the team’s credential process.
Choose the signing model before exporting a .p12
With Xcode Cloud, Apple’s cloud-managed signing manages the certificate and private key; do not force a self-hosted .p12 import recipe onto that flow. With a self-hosted macOS runner, a team may need to make an identity created in Keychain Access available to a build job. That is when to evaluate a .p12 import.
Treat the exported .p12 and its password as credentials; the .p12 password and the temporary CI keychain password are separate credentials. Apple warns that someone with the exported identity and its password may sign software that appears to users and the operating system to come from your developer account. Keep them out of the repository, build artifacts, shared caches, machine images, and ordinary workspaces. Do not put either password in workflow YAML. If an identity is exposed, follow Apple’s revocation guidance for its certificate type and your account role; deleting a local copy alone does not revoke an exposed identity.
Limit which GitHub Actions job can see signing credentials
- Send secrets only to the signing job. A repository secret can be used by workflows in that repository. An environment secret is available only to jobs that reference that environment. For a release step, keep signing credentials in the narrowest appropriate environment and use approval and branch rules when they fit your release process.
- Do not treat log masking as a guarantee. GitHub redacts recognized secret values, but that does not ensure transformed values, error output, or tool diagnostics cannot expose sensitive data. Do not print the identity file, its password, or encoded secrets; review both successful and failed run logs.
- Protect the runner that performs signing. Secrets are normally withheld from workflows triggered by fork pull requests, with separate rules for `GITHUB_TOKEN`. A self-hosted runner is not an isolated container, however, and environment approvals do not make untrusted code safe. Do not run untrusted pull request code in the same self-hosted environment that holds signing credentials.
- Keep token permissions narrow. Set the default `GITHUB_TOKEN` permissions to the minimum needed, then grant additional permissions only to the job that needs them.
Use a job keychain and clean it up
A self-hosted runner needs the signing identity in a keychain accessible to the user running the build. macOS `security(1)` includes commands to create, import into, lock, and delete keychains; `codesign(1)` documents that the signing identity must be in a keychain the calling user can search. If a job reports that an identity is missing, run `security find-identity -v -p codesigning` as the job user to check whether the expected identity is visible; do not paste the full output into a public log. One approach is to import the identity into a keychain created for that job, limit the signing step to it, and delete the keychain and temporary files during cleanup.
Avoid copying scripts that put the keychain password directly in command-line arguments. The macOS `security(1)` manual marks the `create-keychain` `-p` password option as insecure, and GitHub warns that command-line arguments can be visible to other processes on the same machine. Use a supported method for the macOS version you run, and keep shell tracing and debug output away from credential values. If a keychain unlock fails, check which user and keychain the job actually uses; do not broadly allow every application to access the private key just to suppress a prompt.
If the identity is visible but `codesign` still cannot access its private key, check the key’s access control. The current `security(1)` manual says the partition list must include `apple:` for `/usr/bin/codesign` to use the key. Do not use `security import -A` to bypass an access prompt; Apple marks that option insecure. Options vary by macOS version, so check the local manual and make sure passwords do not appear in command history or logs.
Configure cleanup for normal completion and failure, but do not describe it as secure erasure or host isolation. If a runner is forcibly terminated, temporary files may remain. When hardware is reused, follow the team’s runner cleanup policy and check for residual state. For the broader runner boundary, see the iOS CI and runner guide.
Before and after signing
- As the job user, confirm the expected signing identity is visible (for example, with `security find-identity -v -p codesigning`); do not copy the full output to a public log.
- Expose signing credentials only to trusted release jobs; keep them unavailable to unrelated workflows.
- Manage the .p12, its password, and provisioning profiles as credentials; check repositories, artifacts, caches, and logs for accidental copies.
- Define cleanup for the temporary keychain and files on success, failure, and cancellation. This is not isolation from malicious jobs on the same host.
- If credentials are exposed, restrict or delete affected workflow logs and follow GitHub and Apple guidance to rotate secrets and revoke or replace the certificate.
Common questions
Can I sign with only the .cer Apple downloaded?
No. Apple says a certificate contains the public key; signing also needs the matching private key. Together they form the signing identity.
Does a GitHub Environment make a self-hosted runner safe?
No. An environment can limit which jobs receive secrets and can require approval. GitHub also states that self-hosted runners do not run in isolated containers just because a workflow uses an environment. Code trust and runner cleanliness still need separate controls.
Do I have to export a .p12 when using Xcode Cloud?
Not necessarily. Apple-managed signing in Xcode Cloud keeps the certificate and private key under Apple’s cloud signing infrastructure. Use that flow’s signing setup rather than assuming the private key can be exported to a self-hosted runner.
If you are still choosing between managed CI and a self-hosted Mac, see the iOS CI workflow guide. For people logging in to a Mac, read the SSH and Screen Sharing security guide; this article covers code-signing identities, not SSH login keys.
Sources
The following primary sources were checked on 2026-11-02. Apple and GitHub may update their docs; verify the current page and macOS version when applying a procedure.
- Apple Developer: TN3161 — Inside Code Signing: Certificates
- Apple Developer Help: Create a certificate signing request
- Apple Support: Import and export keychain items using Keychain Access on Mac
- Apple Developer: Synchronizing code-signing identities with your developer account
- Apple Developer Help: Revoke a certificate
- Apple Developer: Xcode Cloud
- GitHub Docs: Using secrets in GitHub Actions
- GitHub Docs: Secure use reference
- GitHub Docs: Deployments and environments
For command options, consult the `security(1)` and `codesign(1)` manuals shipped with the target Mac. This guide does not evaluate third-party credential-sync tools or claim how any hosting provider stores signing material.