Skip to content

Security: nick-kilian/quicklysign-code

Security

docs/security.md

Security

Network exposure

Surface Exposure Rationale
Coder dashboard/API 443 (Caddy/Let's Encrypt), 80 (ACME only) Coder handles authn; TLS everywhere
Control plane SSH IAP tunnel only (gcloud compute ssh --tunnel-through-iap) no public 22
Workspace VMs no inbound rules at all agent connects outbound; access via Coder relay (coder ssh/config-ssh)
Cloud SQL private IP only, VPC peering never on the public internet

There is deliberately no public SSH anywhere. Workspace access rides Coder's authenticated WebSocket/WireGuard path.

Identity & least privilege

Principal Roles Why
coder-control-plane SA compute.instanceAdmin.v1, iam.serviceAccountUser (on the workspace SA only), logging.logWriter, monitoring.metricWriter, secretAccessor (db-url secret only) runs the Terraform provisioner that creates/deletes workspace VMs
coder-workspace SA logging.logWriter, monitoring.metricWriter workspaces need nothing else; instance-identity agent auth needs an attached SA but no roles
Terraform (you) your user ADC no long-lived bootstrap SA keys exist

The previous iteration had these inverted (workspaces had compute.admin, the control plane couldn't create VMs) — fixed.

Secrets

  • DB connection URL: Secret Manager only; fetched by the control plane VM at boot via its SA. Never in Terraform-rendered metadata. (Terraform state does contain the generated DB password — state is local and gitignored; treat terraform.tfstate as sensitive.)
  • Coder agent auth: Google instance identity — no token in VM metadata.
  • Watchdog token: owner session token, regenerated by Coder on every workspace start, written to ~/.config/agent-watchdog/env mode 0600 on the workspace's own disk.
  • Nothing in git: .gitignore blocks .env, tfvars, tfstate. CI secret scanning is moot — there are no committed credentials.

Rotation

Secret Rotate by
DB password terraform taint random_password.db_password && terraform apply, then reboot the control plane VM (it re-reads the secret at boot)
Coder session tokens revoke in Coder UI (/settings/tokens); workspace watchdog tokens rotate themselves every workspace start
GitHub / Claude / Codex credentials gh auth logout/login, claude /logout + re-login, codex logout/login inside the workspace

GitHub access (decision: per-workspace gh auth login)

Workspaces authenticate with gh auth login (HTTPS + gh credential helper via gh auth setup-git). Credentials are stored once per workspace on its persistent disk, scoped to your GitHub user. No deploy keys or shared machine credentials exist. If/when this should be automatic for new workspaces, switch to Coder's GitHub external-auth (OAuth app) — documented as a TODO in the README.

Claude / Codex credentials (decision: subscription logins)

Interactive logins (claude browser-code flow, codex login --device-auth) stored by the CLIs in $HOME on the workspace disk. No API keys exist in GCP or this repo. The disk is the trust boundary: deleting the workspace deletes the credentials.

Trade-offs accepted

  • Cloud SQL connection uses sslmode=disable — traffic stays on the private VPC peering; enabling TLS adds cert management for little gain here.
  • Workspace VMs have ephemeral public IPs for egress (package installs, GitHub, agent APIs) instead of Cloud NAT (~$32/mo+). With zero inbound rules, exposure is limited to outbound-initiated traffic.
  • Coder dashboard is on the public internet (it must be, for agents and for you). Single admin account; enable OIDC SSO later if desired.

There aren't any published security advisories