Credential custody: where your signing keys actually live
This page is written to be forwarded. If someone has asked you where your app signing material is stored — a security review, an auditor, a client contract, or a colleague who thinks about this more than you do — the answer should be checkable rather than asserted, and it should fit on one page.
The five credentials a release needs
Every iOS and Android release runs on the same five artifacts. They are all bearer credentials: possession is authorisation. There is no password on top, no second factor, and no per-person audit trail. Whoever holds them can ship as you.
| Credential | What it proves | If it leaks |
|---|---|---|
iOS distribution certificatedist.p12 | Software signed with it came from your Apple team. | Severe. Someone can sign software as you. Revoking it kills every profile built on it. |
Provisioning profile.mobileprovision | That certificate may ship that specific app. | Minor alone — useless without the private key. |
App Store Connect API keyAuthKey_*.p8 | You may act on App Store Connect with a given role. | Severe. Upload builds, edit your listing. No expiry — lives until revoked. |
Android upload keystoreupload.keystore | This bundle came from you. | Recoverable — Play can reset an upload key. |
Play service account*.json | You may publish to these Play apps. | Severe. Delete the key in Google Cloud and revoke in Play Console. |
Who holds each one
A hosted build service signs on its own machines. That is not a criticism — it is what the product is — but it has an unavoidable consequence: the machine doing the signing must have the private key, so your certificate and your API key have to be uploaded and stored by the vendor.
| Where it rests | Hosted service | leas, local build | leas, cloud build |
|---|---|---|---|
| Certificate and keystore | Vendor storage | Your disk | Your repo secrets |
| API keys | Vendor storage | Your disk | Your repo secrets |
| Machine that signs | Vendor fleet | Your Mac | A runner you rent |
| Who can read them | Vendor systems and staff with access | You | You and your CI provider |
| Revocation if the vendor is breached | Rotate everything | Not applicable | Not applicable |
leas has no upload endpoint. Not “we delete them after the build”, not “they are encrypted at rest” — there is no route that accepts a certificate, because the signing happens where the files already are.
Verify it rather than trusting it
The engine is MIT licensed, so this is checkable in an afternoon, and a claim you can check is worth more than one you cannot. Four things a reviewer can do:
- List every host the engine can reach. One command, and it is the whole answer:
grep -rhoE "https://[a-z0-9.-]+" src/ | sort -uWhat comes back is Apple (
api.appstoreconnect.apple.com), Google (androidpublisher.googleapis.com,www.googleapis.comfor the OAuth token exchange), Google Fonts — which the local dashboard’s page loads in your browser, not during a build — and three placeholder URLs that only appear in help text and usage examples (cli.github.com,updates.example.com,your-site.vercel.app). There is no host belonging to us in that list, because there is nothing to send anywhere. - Note what is missing: GitHub. Cloud builds dispatch through your own
ghCLI, under your own login. leas never holds a GitHub token and never makes an authenticated request to GitHub on your behalf — it shells out to a tool you already installed and already trust.grep -rn "'gh'," src/cloud.js - Watch the traffic anyway. Run a build behind a proxy. There is no telemetry, no licence check, and no phone-home to find.
- Inspect what the optional dashboard sends. Point
LEAS_SITE_URLat a server you control and read the request body yourself. The field list is below.
What the hosted dashboard would receive
The dashboard is optional and not built yet. When it exists, what leas sync sends about credentials is metadata by construction — a name, a date, and a truncated public fingerprint:
{
"id": "ios-distribution-certificate",
"platform": "ios",
"kind": "Distribution certificate",
"identity": "Apple Distribution: Your Company",
"expires": "2027-09-25T00:00:00.000Z",
"daysLeft": 399,
"status": "ok",
"fingerprint": "7CEE3DB540F010D9"
}No key material, no passwords, no PEM or DER blocks, and only the first sixteen characters of a fingerprint that is public information anyway — it is derived from the certificate embedded in every build you have ever shipped. That is what makes an expiry watch something a web page may hold at all.
A page arguing about custody has to be straight about where custody still ends.
- Cloud builds put your secrets in your CI provider. If you run
leas build --cloudon GitHub Actions, GitHub holds encrypted secrets and runs the job. That is a third party — a different one, chosen by you, under your own contract, and probably one you already trust with your source code. But it is not nobody. If it must be nobody, build locally. - iOS requires Apple hardware. Apple’s macOS licence forbids running macOS elsewhere, so an iOS build happens on a Mac — yours, or a rented one.
- Bearer credentials stay bearer credentials. Keeping them on your own disk does not make them safer than your disk. Nothing here is a substitute for encrypted storage, least-privilege API keys, and rotation.
- Local builds mean local responsibility. No vendor is patching your toolchain or backing up your keystore. Lose the upload keystore and you are asking Google for a reset.
For a security questionnaire
Short answers, if you are the one filling in the form:
| Question | Answer |
|---|---|
| Does the vendor store our signing keys? | No. There is no endpoint that accepts them. |
| Does the vendor process our source code? | No. Builds run on your machines or your rented runners. |
| What data leaves our environment? | Nothing, unless you enable the optional dashboard — then credential metadata and build history, as above. |
| Where is the signing performed? | On hardware you control or rent under your own account. |
| Can we audit the implementation? | Yes. The engine is MIT licensed. |
| What happens if the vendor disappears? | Nothing. The licence is irrevocable for published code and it runs without us. |
| Sub-processors? | For the engine, none. Apple, Google, and your CI provider are your relationships, not ours. |
Working through this for a regulated team and finding a question this page does not answer? Tell us what is missing and we will answer it here rather than only to you.