You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Copy file name to clipboardExpand all lines: apps/loopover-ui/content/docs/self-hosting-security.mdx
+60-1Lines changed: 60 additions & 1 deletion
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -20,7 +20,7 @@ description: The self-host stack holds maintainer credentials and policy. Keep t
20
20
{
21
21
title: "Rotate deliberately",
22
22
description:
23
-
"Rotate GitHub webhook secrets, API tokens, REES secrets, and provider keys with a restart window and validation PR.",
23
+
"Cadence, per-secret procedure, and the categories that can't be rotated safely yet -- see \"Secret rotation policy\" below.",
24
24
},
25
25
]}
26
26
/>
@@ -34,6 +34,65 @@ cp /path/to/your-downloaded-key.pem secrets/github_app_private_key.pem # the o
34
34
docker compose up -d --no-deps loopover`}
35
35
/>
36
36
37
+
## Secret rotation policy (#4925)
38
+
39
+
**Cadence:** rotate every secret at least once a year. **Rotate immediately**, regardless of
40
+
cadence, on suspected compromise, a secret appearing in a log/commit/screenshot/PR even briefly,
41
+
or the departure of anyone who held it.
42
+
43
+
Not every secret rotates the same way — some are a same-day config change, others require an
44
+
external console, and one category currently has **no safe rotation path at all**. Check which
45
+
category a secret falls into before rotating it.
46
+
47
+
<FeatureRow
48
+
items={[
49
+
{
50
+
title: "Freely rotatable",
51
+
description:
52
+
"GITHUB_WEBHOOK_SECRET, LOOPOVER_API_TOKEN, LOOPOVER_MCP_TOKEN, INTERNAL_JOB_TOKEN, SELFHOST_SETUP_TOKEN, REES_SHARED_SECRET. Static bearer comparisons -- nothing is encrypted with them. Generate a new value, restart both sides. Only cost: updating callers holding the old value.",
53
+
},
54
+
{
55
+
title: "Externally issued",
56
+
description:
57
+
"GITHUB_APP_PRIVATE_KEY, GITHUB_OAUTH_CLIENT_SECRET, PAGERDUTY_ROUTING_KEY, CLAUDE_CODE_OAUTH_TOKEN, and AI-provider API keys. Rotate at the source (GitHub App/OAuth settings, PagerDuty, `claude setup-token`, the provider's own console), then update the stored value.",
58
+
},
59
+
{
60
+
title: "Encryption master keys -- do not rotate routinely",
61
+
description:
62
+
"TOKEN_ENCRYPTION_SECRET, DRAFT_TOKEN_ENCRYPTION_SECRET. Swapping either makes every row already encrypted under the old value permanently undecryptable -- there is no re-encryption tooling today. Only rotate on suspected compromise; see below.",
rm secrets/loopover_api_token.txt && ./scripts/selfhost-init-secrets.sh # generates a fresh value
71
+
docker compose up -d --no-deps loopover
72
+
73
+
# Freely rotatable secret -- hosted Worker path
74
+
wrangler secret put LOOPOVER_API_TOKEN
75
+
# then redeploy`}
76
+
/>
77
+
78
+
<Calloutvariant="warn"title="Encryption master keys have no safe rotation path yet">
79
+
`TOKEN_ENCRYPTION_SECRET` (maintainer BYOK AI-provider keys at rest) and
80
+
`DRAFT_TOKEN_ENCRYPTION_SECRET` (in-flight contributor draft OAuth tokens) are AES-256-GCM keys
81
+
every already-encrypted row was written against. The decrypt path always derives the AES key
82
+
from whatever value is currently set, with no fallback to a prior value -- there is no
83
+
re-encryption tooling in this codebase today. Rotating `TOKEN_ENCRYPTION_SECRET` means every
84
+
maintainer who saved a BYOK provider key has to re-enter it; rotating
85
+
`DRAFT_TOKEN_ENCRYPTION_SECRET` fails any draft submission mid-flight. Only rotate these two on
86
+
suspected compromise, and treat the resulting key/token loss as an accepted, unavoidable cost
87
+
until a re-encrypt-in-place migration exists (tracked as separate follow-up work).
88
+
</Callout>
89
+
90
+
`ORB_ENROLLMENT_SECRET` has the same gap from the other direction: `orb_enrollments.revoked_at` is
91
+
checked on every brokered-token/relay request, but nothing in this codebase currently sets it —
92
+
there is no revoke or re-enrollment endpoint yet. Treat a brokered self-host's enrollment secret as
93
+
not currently rotatable in place; escalate a suspected-compromised enrollment to the Orb operator
94
+
directly instead of expecting self-service rotation.
95
+
37
96
## Optional: Infisical secrets management
38
97
39
98
The hardened default above — `.env` plus Docker Compose `secrets:` — has no rotation, audit trail, or RBAC. If you want secrets-manager-grade rotation, audit logging, and access control on top of that default, you can opt into [Infisical](https://infisical.com) — an open-source, self-hostable secrets manager. This is **strictly optional and additive**: skip this section entirely and the hardened `.env`/Docker secrets default keeps working unchanged.
0 commit comments