ReviewOS

stacks/ts-cloud

Consolidating apps onto one server grants every app's CI full write over the whole provider project

#169
Closed glennmichael123 opened this 24 days ago · 0 comments
24 days ago

Summary

Attaching an app to a server owned by another project (#167, operation 1) requires that app's CI to hold a provider credential that can see, and therefore modify and delete, every server in the project. On Hetzner there is no narrower option: Cloud API tokens are project-scoped with Read or Read & Write and no per-resource scoping. Consolidation is presented as a cost and tidiness win; it is also a credential-blast-radius change, and nothing in the model says so.

Why it is forced, not incidental

attachToComputeInfrastructure(ownerSlug, config, environment) resolves the host with this.client.listServers() and label matching. The listing comes from the attached app's own token, so the owner's box has to be visible to it, which means same project. HetznerDriver takes a single apiToken and there is no second, narrower credential anywhere in the path.

So for the consolidation in #167:

BeforeAfter
loghq CI token can touch loghq's boxloghq CI token can touch statushq, bughq, stacks, localtunnels
bughq CI token can touch bughq's boxbughq CI token can touch all of the above

Three pipelines that previously had blast radius over one box each now each have it over the entire fleet. A compromised CI run, a bad cloud:destroy (stacksjs/stacks#2342), or a name collision now reaches production systems that have nothing to do with the app being deployed.

The reverse is equally true and worth stating in the docs: an app in its own provider project cannot be attached at all. Isolation and co-hosting are mutually exclusive under this design, and that tradeoff should be a stated, deliberate choice rather than something discovered afterwards.

What is missing

Not necessarily code. The minimum is that the model is honest about it:

  • Document the tradeoff on attachTo and on the consolidation flow: attaching requires shared project scope, and therefore shared credential reach.
  • Surface it in the plan. attach --dry-run should state which other servers the credential in use can reach, so the operator sees the radius before approving.
  • Scope down where the provider allows it. Hetzner does not today, but AWS and others do, so the driver interface should not assume "one all-powerful token" is the only shape.
  • Consider a host-side attach path that does not need the attached app's token to enumerate the owner's project at all, for example the owner registering the site and the attached app deploying to a known target. That would restore isolation without giving up consolidation.

Acceptance criteria

  • attachTo documents that it requires the same provider project and what that grants
  • The attach plan reports the other resources the credential can reach
  • The driver interface allows a narrower credential where a provider supports one
  • The docs state plainly that per-project isolation and attaching are mutually exclusive

Found while deciding whether to attach loghq to the statushq box or give it its own project, against ts-cloud 0.7.114.

Sign in to comment on this issue.