Skip to content

Consider decrypting vaults on the CI runner instead of server-side #116

Description

@ineedjet

Context

#111/#114 (implemented in #115) explicitly decided decryption stays
server-side: the CI runner only resolves/downloads refs and pushes
still-encrypted .sops.env files; the target host runs sops decrypt
itself, so the age private key never leaves it. That's a deliberate
trust-boundary choice, not an oversight — this issue is about revisiting
it, not a bug report.

What's prompting a second look

Bootstrapping sops on a fresh host turns out to be more annoying than
expected: it isn't packaged in Ubuntu or Debian at all (checked through
Ubuntu 26.04 and Debian sid/trixie/forky) — the only install path is a
pinned binary/.deb from GitHub Releases, same as encrypt-env/action.yml
already does in CI. Every target host needs that bootstrap step repeated,
plus its own age private key provisioned and kept in sync with
keys/<target>.pub.

If decryption moved to the runner instead:

  • Target hosts would need neither sops nor a local age key at all — one
    less package to bootstrap, one less secret to provision and rotate per
    host.
  • The age private key would need to live as a GitHub Secret instead of a
    file on each server.

The tradeoff (why this isn't a clear win)

Moving the private key into GitHub Secrets changes the blast radius of a
GitHub Secrets compromise: today, decrypting a target's vaults requires
both GitHub Secrets access (to get the ciphertext/refs) and physical
access to that specific host's local key file. Centralizing decryption in
CI collapses that to GitHub Secrets access alone being sufficient to
decrypt everything, for every target, from one place.

With a single target (hawkeye) today, the bootstrap-friction case is real
but small; the security downside is permanent and scales with however many
targets/hosts this ever grows to.

Proposal

Not a decided migration — write up both models properly (what changes in
deploy/deploy.py, deploy-shared.yml's secrets, and each target's
prerequisites) and weigh them once there's more than one real target to
judge the bootstrap-cost side against, rather than deciding on a single
data point.

Related

#111 (decided server-side decryption as part of the push-based redesign
this would reopen), #114 (the per-app vault delivery this decryption model
carries), #106 (hawkeye's prerequisites list, which currently includes
sops + age key setup on the host).

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions