feat(security): systemd-creds fallback for token + audit seed#15
Merged
Conversation
Adds an optional at-rest-encryption mode for the bot token and
audit seed. The current env-file mode stays the default; flipping
to credentials mode is a single helper-script invocation.
Background: with the env-file approach, `/etc/shellboto/env` is
plaintext root-0600 on disk. Backup / snapshot / disk-image theft
exposes the token verbatim — the attacker doesn't need runtime
access to the VPS. systemd-creds (systemd 250+) encrypts the
secrets at rest, keying to the TPM2 if present or to the system
credential-secret otherwise. Decrypted values live only in a
per-invocation memfd, never on disk.
What this doesn't fix: runtime root on the VPS can still
`cat /proc/<pid>/environ` (but env var isn't set here) or read
`$CREDENTIALS_DIRECTORY/<name>`. Memory dump of the running VM
captures the decrypted secret. Those are fundamentally runtime-
trust issues; `systemd-creds` targets the at-rest threat.
Changes:
- `internal/config/secret.go` (new)
- `ResolveSecret(envVar, credName) (string, error)` — env-var
first, then `$CREDENTIALS_DIRECTORY/<credName>` file, else
empty. A missing cred file is not an error; the caller's
"was this required?" logic decides.
- `ResolveSecretWithSource(...)` — same, plus a `SecretSource`
tag (env / systemd-creds / unset) so doctor + startup log
can report which mode is active without echoing the value.
- `internal/config/config.go` — token loading routes through
the new helper. Superadmin ID stays env-only (it's a public
identifier, not a secret).
- `cmd/shellboto/main.go:resolveAuditSeed` — same helper; logs
the source on success.
- `cmd/shellboto/cmd_doctor.go` — reports
`SHELLBOTO_TOKEN set source=env|systemd-creds` and
`SHELLBOTO_AUDIT_SEED valid 32 bytes, source=env|systemd-creds`.
- `deploy/enable-credentials.sh` (new) — one-shot migration:
reads plaintext secrets from /etc/shellboto/env, encrypts
via systemd-creds, drops a
/etc/systemd/system/shellboto.service.d/credentials.conf
override with LoadCredentialEncrypted= lines, strips the
plaintext secrets from env file (keeps SUPERADMIN_ID),
daemon-reload + restart, runs doctor. Reversible with
`--revert`. Non-interactive with `-y`.
- Tests in `internal/config/secret_test.go` covering every
source combination (env only, creds only, both set, neither,
file unreadable, whitespace trimming).
- Docs:
- New `docs/security/secrets-at-rest.md` — full treatment of
both modes + threat-model table + rotation + migration-to-
new-host guidance.
- `docs/security/README.md` indexes it.
- `docs/configuration/environment.md` + `docs/reference/env-vars.md`
document the `$CREDENTIALS_DIRECTORY` fallback for both
sensitive variables.
- `docs/security/audit-seed.md` — seed-storage section expanded
to cover both modes.
- `docs/deployment/production-checklist.md` — optional-hardening
step pointing at `enable-credentials.sh`.
amiwrpremium
added a commit
that referenced
this pull request
Apr 22, 2026
🤖 I have created a release *beep* *boop* --- ## [0.1.2](v0.1.1...v0.1.2) (2026-04-22) ### Features * **security:** systemd-creds fallback for token + audit seed ([#15](#15)) ([a5a27dc](a5a27dc)) --- This PR was generated with [Release Please](https://github.com/googleapis/release-please). See [documentation](https://github.com/googleapis/release-please#release-please).
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Optional at-rest-encryption mode for SHELLBOTO_TOKEN and SHELLBOTO_AUDIT_SEED.
ResolveSecret(envVar, credName)helper: env-var first, then$CREDENTIALS_DIRECTORY/<name>.deploy/enable-credentials.shone-shot migration (reversible with --revert).docs/security/secrets-at-rest.mdexplains the threat model + trade-offs.Env-file mode stays the default. Nothing breaks for existing installs.