sitescope a small health monitor and status page for a few hosts

Use

Vault and secrets

API tokens live in an age-encrypted file and are only ever decrypted into locked memory, by an operator, after the hub starts.

What goes where

secret where why
agent token environmentFile agents need it unattended, and it only reads host facts
heartbeat URL environmentFile the hub needs it from startup
Linode token vault reads billing and account details
Cloudflare token vault reads DNS records and token expiry
Cert Spotter key vault, optional raises Cert Spotter’s rate limit
admin password hash vault protects the detail view

The file

/var/lib/sitescope/vault.age is encrypted with age in passphrase mode. scrypt uses work factor 2^15, which needs 32 MiB during unlock; age’s default of 2^18 would need 256 MiB, four times the hub’s memory limit. Writes go to a temporary file with mode 0600, are synced, and then renamed over the old one. The plaintext never touches the disk. The vault holds at most 64 KiB.

Back it up. Without it you re-enter the tokens; history is optional.

Unlocking

The hub always starts locked, and says so by email. Until it is unlocked, checks that need a secret report locked (which doesn’t count against any light), and the detail view answers 503. Everything else runs. If it is still locked after hub.lockedAfter (15 minutes), hub.vault warns.

sitescope unlock      # passphrase from the terminal, over the control socket
sitescope lock

The control socket is mode 0660, owned by the admin group, and the hub logs each caller’s uid and pid. There is no way to unlock from the web.

After vault set, the running hub keeps the old contents until the next sitescope unlock.

In memory

Two copies are unavoidable: a token sits on the Go heap for the moment it is put in an Authorization header, and age decrypts through its own heap buffer. Both are short-lived, but not zeroed.

Token scopes

Give each token the least it needs.

name minimum scope
linode_token Personal access token with Account: Read Only, Events: Read Only, Linodes: Read Only; everything else No Access
cloudflare_token Zone → DNS → Read, for the one zone. Add Zone → Zone → Read only if cloudflare.zoneId is not set. To watch other tokens add User → API Tokens → Read (Account → Account API Tokens → Read for account-owned tokens); it shows names and expiry, never token values
certspotter_token optional: a Cert Spotter API key. Without it the CT checks run unauthenticated, 10 requests an hour

The secret names can be changed with linode.tokenSecret, cloudflare.tokenSecret and ct.tokenSecret.