skip to content

Which storage backends can match use for a team's encrypted Apple signing assets?

level: middleimportance: nice to knowfreq 42%

answer

  1. four backends, not two
  2. storage_mode chooses the transport
  3. OpenSSL encrypts before anything is stored
  4. git, google_cloud, s3, gitlab_secure_files
  5. each backend has its own option family

basics

~10 s

sync_code_signing supports exactly four storage backends, chosen with storage_mode: git, google_cloud, s3 and gitlab_secure_files. match encrypts the Apple certificates and profiles with OpenSSL before writing, so whichever backend you pick only ever holds ciphertext.

solid answer

~40 s

`storage_mode` picks one of **four** backends — `git`, `google_cloud`, `s3` and `gitlab_secure_files` — and each has its own option family: `git_url`, `git_branch`, `git_private_key`, `shallow_clone` for Git, and the `s3_*`, `google_cloud_*` and `gitlab_*` families (plus `job_token` or `private_token`) for the rest. The choice is about *where the ciphertext lives and who can reach it*, not about the confidentiality of the contents: match encrypts client-side with **OpenSSL** first, so a bucket or repository only ever holds unreadable blobs. Git is where most teams start and is the easiest to audit — every change to the falconry weight-log app's Apple identities is a commit. Object storage suits teams who would rather express access as bucket policy, and `gitlab_secure_files` keeps the assets inside a GitLab project.

code

ruby · 10 lines
ruby
lane :sync_signing_from_s3 do
  sync_code_signing(
    type: "adhoc",
    app_identifier: "com.mews.falconry-weight-log",
    storage_mode: "s3",
    s3_bucket: "falconry-signing",
    s3_region: "eu-west-1",
    readonly: true
  )
end

go deeper

for a junior

Know that the encrypted Apple signing assets live in a backend you choose with storage_mode, and that Git is the one you will most often see configured.

for a middle

Name all four backends and the option family each one reads, and be able to say that match itself encrypts with OpenSSL before anything is stored.

for a senior

Argue the choice on access control and auditability — commit history versus bucket policy — and explain why the passphrase, not the repository permissions, is the secret that matters.

for a principal

Decide where signing material belongs across many teams: one vault or several, which access model gets reviewed, and what regeneration would cost if the passphrase were lost.

## storage_mode is a closed list of four The most common half-memory about `match` — canonically `sync_code_signing` — is that it 'uses a Git repo, or S3'. The supported set is **four** backends, selected by `storage_mode`: | storage_mode | where the encrypted assets live | option family | |---|---|---| | `git` | a repository you control | `git_url`, `git_branch`, `git_private_key`, `git_basic_authorization`, `git_bearer_authorization`, `shallow_clone`, `clone_branch_directly` | | `s3` | an S3 bucket | the `s3_*` family | | `google_cloud` | Google Cloud Storage | the `google_cloud_*` family | | `gitlab_secure_files` | files attached to a GitLab project | the `gitlab_*` family, with `job_token` or `private_token` | All four are built in; none requires a plugin. Naming all four, and knowing which option family each reads, is the difference between having configured match once and understanding it. ## Encryption happens in match, not in the backend This is the fact that reframes the whole choice. match encrypts the Apple certificates and provisioning profiles **client-side, with OpenSSL**, before anything leaves the machine, and decrypts them on the way back down. `force_legacy_encryption` exists because that scheme has changed over time and an older repository may still be in the old format. The consequences are worth stating explicitly: - The backend is **transport and durability**, not confidentiality. A private Git repository and a public one would both hold the same unreadable blobs; you keep the repository private as a second layer, not as the only one. - **The passphrase is the secret that matters.** Anyone with the ciphertext and the passphrase can sign as your team. Anyone with the ciphertext alone has bytes. - Server-side encryption offered by an object store protects data at rest against a different threat — a stolen disk, not a colleague with read access to the bucket. - Losing the passphrase, rather than losing the repository, is what forces a team to regenerate identities from scratch. ## Choosing a backend There is no security ranking between the four; the differences are operational. 1. **`git`** — the assets are commits, so you get history for free: who changed the falconry weight-log app's signing material, when, and what came in with it. The cost is another repository to lock down, and a clone on every run (mitigated by `shallow_clone` and `clone_branch_directly`). 2. **`s3`** and **`google_cloud`** — no repository to manage, and access is expressed with the same bucket policy and identity tooling as the rest of your cloud estate. You give up the commit log; whatever object versioning or audit logging the bucket provides is what you have instead. 3. **`gitlab_secure_files`** — the assets ride along with the GitLab project, authenticated by `job_token` or `private_token`, so pipeline access and project access are the same grant. Attractive when the whole delivery story already lives in one GitLab project, and one fewer thing to provision. A useful tiebreaker: pick the backend whose access model your team already reviews. Whichever you choose, the read side belongs to the CI runner and the write side belongs to a developer machine, because the runner should be running with `readonly`. ## Git-backend specifics worth knowing The `git` mode carries the largest option family because it is the most configurable. `git_branch` lets several products share one repository by branch. `git_private_key` supplies a deploy key rather than relying on the runner's ambient SSH configuration, and `git_basic_authorization` and `git_bearer_authorization` cover token-based hosts. `shallow_clone` and `clone_branch_directly` cut the clone cost on a repository that has accumulated years of identity changes — a real saving when every CI job pays it. ## What the backend does not change Switching `storage_mode` changes where bytes live and who can read them. It changes nothing about the rest of the model: - Assets are still keyed by `app_identifier` and `type`. - The material is still Apple-only: certificates and provisioning profiles. There is no backend that makes match sync an Android keystore, which is configured in the Gradle build instead. - CI still runs `readonly`, and creation still happens on a machine with write access. - The passphrase and the backend credentials still have to reach the job somehow, which is a CI secrets question rather than a match option. If you are asked this in an interview, name all four modes, then immediately say that match encrypts before it stores. The second half is what shows you understand the threat model rather than the configuration.

  • Does putting the signing repository in a private Git repo remove the need for the passphrase?
    No. match encrypts with OpenSSL regardless, and the passphrase is what makes a stolen clone useless. Repository permissions are one layer; client-side encryption is the layer that survives an over-broad grant, a mirrored backup or a leaked read token. Losing the passphrase, not losing the repository, is what forces you to regenerate identities.
  • What is different about gitlab_secure_files compared with the git backend?
    The encrypted assets are attached to a GitLab project and reached with `job_token` or `private_token`, rather than living as commits in a repository you manage and clone. The Git backend gives you a commit history of every identity change; the GitLab mode gives you one fewer thing to provision, with project access as the single grant.

saying these in an interview costs you the question

  • Says match supports only Git and S3
  • Thinks a private repository makes encryption unnecessary
  • Assumes the backend, not match, performs the encryption
  • Treats the signing repository as an ordinary code repo
  • Cannot name the option that selects the backend