Security model
What runs where
Section titled “What runs where”Everything backmesh runs is in your own accounts:
- anycloud’s API, on a management VM in the first cloud you install, with a checkpoint bucket for its backups.
- The listener, which scales runners, alone on the small unprivileged
bm-controlVM. It long-polls GitHub, so nothing needs an inbound port or a webhook. - The runners, on one spot pool per cloud.
No vendor account has access to your clouds, your runners or your code. Install connects each cloud with a role from your own cloud CLI session, so no cloud keys are stored. The listener’s anycloud identity is a short-lived token bound to its own container, not a stored token.
The API’s DNS name, <cluster-id>.anycloud.sh, is outside your accounts:
install publishes it with your anycloud GitHub sign-in.
The GitHub App
Section titled “The GitHub App”Install creates a private GitHub App in your org, with its webhook off and only these permissions:
| Permission | Why backmesh needs it |
|---|---|
| Self-hosted runners: write (org) | Scale sets, runner registration, the runner group, removing idle runners |
| Actions: write | Read a run’s commit for reclaim notes and jobs’ runner names; rerun jobs, once shipped |
| Checks: write | Post a check run when spot reclaims fail jobs you have to rerun |
| Metadata: read | Required by GitHub |
It has no Contents, Secrets, Members or Administration permission. Only the listener’s container holds the App’s private key.
What a stolen App key can do
Section titled “What a stolen App key can do”- Self-hosted runners: write: register a runner in backmesh’s runner group and take its jobs, with their secrets.
- Actions: write: read workflow runs and logs; rerun, cancel or delete runs; delete logs, artifacts and caches; approve fork pull requests’ runs; dispatch, enable or disable workflows; and change the repository’s OIDC subject claim, which cloud trust policies match on. Together with the runner permission, it can dispatch or rerun a job on a backmesh label and take it with its own runner, reaching that job’s secrets.
- Checks: write: write misleading check runs.
- Metadata: read: list the installation’s repositories.
It can’t read code or Secrets or change Administration settings. Rotate the key
with backmesh upgrade --app-key;
backmesh status warns when it’s 90 days old.
An App created by an older backmesh has Actions: read. backmesh status warns
until an org owner sets Actions to “Read and write” in the App’s settings and
accepts the request on the installation.
Which jobs run
Section titled “Which jobs run”The runner group doesn’t allow public repositories, so only private repositories can use the runners. backmesh adds no fork or actor policy of its own; GitHub’s fork pull request settings decide whether a fork’s workflow runs, and after whose approval.
One trust level
Section titled “One trust level”Every job that reaches the runner group is trusted the same way. Jobs from every repository in the org share each pool’s VMs, up to 8 per VM, in privileged containers. A compromised job is root on its VM and can read the environment and secrets of the other jobs on it. Use backmesh for code you trust as you trust your org’s members.
The listener never shares a VM with a runner, so a runner that escapes its container can’t read the App key. Per-repository runner groups and dedicated pools are planned.