Title: [llm-config] how to encrypt a per-user API key at rest, with no new infrastructure · Issue #438 · regybean/Trellis · GitHub
Open Graph Title: [llm-config] how to encrypt a per-user API key at rest, with no new infrastructure · Issue #438 · regybean/Trellis
X Title: [llm-config] how to encrypt a per-user API key at rest, with no new infrastructure · Issue #438 · regybean/Trellis
Description: Question How should a per-user API key be encrypted at rest, in this stack, with no new infrastructure? Settled: app-level envelope encryption, AES-256-GCM, master key supplied via env, ciphertext in Postgres. Not KMS, not pgcrypto. Noth...
Open Graph Description: Question How should a per-user API key be encrypted at rest, in this stack, with no new infrastructure? Settled: app-level envelope encryption, AES-256-GCM, master key supplied via env, ciphertext ...
X Description: Question How should a per-user API key be encrypted at rest, in this stack, with no new infrastructure? Settled: app-level envelope encryption, AES-256-GCM, master key supplied via env, ciphertext ...
Opengraph URL: https://github.com/regybean/Trellis/issues/438
X: @github
Domain: github.com
{"@context":"https://schema.org","@type":"DiscussionForumPosting","headline":"[llm-config] how to encrypt a per-user API key at rest, with no new infrastructure","articleBody":"## Question\n\nHow should a per-user API key be encrypted at rest, in this stack, with no new infrastructure?\n\nSettled: app-level envelope encryption, AES-256-GCM, master key supplied via env, ciphertext in Postgres. Not KMS, not `pgcrypto`. Nothing in this repo does crypto today — `tooling/secrets-sync` is dev-env plumbing, not a runtime primitive.\n\nFind:\n\n- **Node's built-in `crypto` versus a library.** Whether `node:crypto` covers AES-256-GCM envelope encryption cleanly enough to avoid a dependency, and what a maintained library buys. The repo prefers standard libraries over custom solutions, so the bar for hand-rolling is high — but so is the bar for taking a dependency on crypto code.\n- **Envelope structure.** Master key → data key → ciphertext, versus encrypting directly under a key derived from the master. What each costs at rotation time.\n- **The stored value.** One `bytea`/`text` column or several (ciphertext, IV, auth tag, key version). What a key-version field buys before rotation is specified.\n- **Master key handling.** Format and length, how it arrives through `@acme/env` as a secret with no profile value, and what happens on a run that has no key — the repo's `secretsOnly` pattern relaxes secrets on runs that cannot supply one, which must not silently disable encryption.\n- **Tests.** Backend suites self-provision containers and never mock env (ADR 0014). How a test gets a real master key without one being committed.\n- **Runtime portability.** Must work under Node on Next.js and under Nitro for the TanStack apps. Flag anything Web Crypto-only or Node-only that would break one of them.\n\nPrimary sources: Node docs, the library's own docs, OWASP guidance on key storage. Post the findings as a comment on this ticket and close it.\n","author":{"url":"https://github.com/regybean","@type":"Person","name":"regybean"},"datePublished":"2026-09-24T15:16:50Z","url":"https://github.com/regybean/Trellis/issues/438"}
| react-profiling | 0 |
| react-import-map | react,react-dom,react-dom/client,react-dom/profiling,react-is,react-reconciler,react/compiler-runtime,react/jsx-dev-runtime,react/jsx-runtime,scheduler@d5750093facf |
| route-pattern | /_view_fragments/issues/show/:user_id/:repository/:id/issue_layout(.:format) |
| route-controller | voltron_issues_fragments |
| route-action | issue_layout |
| fetch-nonce | v2:182c2a57-500c-5191-30ad-6660824e0667 |
| current-catalog-service-hash | 81bb79d38c15960b92d99bca9288a9108c7a47b18f2423d0f6438c5b7bcd2114 |
| request-id | C1BA:1C7D35:18884F8:20B6E42:6AED7960 |
| html-safe-nonce | fe660177db617336c945d0f2142bd92c46fe33100fe644e4d9deb7d9bd6f2b9a |
| visitor-payload | eyJyZWZlcnJlciI6IiIsInJlcXVlc3RfaWQiOiJDMUJBOjFDN0QzNToxODg4NEY4OjIwQjZFNDI6NkFFRDc5NjAiLCJ2aXNpdG9yX2lkIjoiNDg2MjgzODI0ODY0OTM1NzY2NCIsInJlZ2lvbl9lZGdlIjoiaWFkIiwicmVnaW9uX3JlbmRlciI6ImlhZCJ9 |
| visitor-hmac | e5abe0091e9124594998a3e8c10fc73030b844660075e80b3dc74794773cf31f |
| hovercard-subject-tag | issue:5570512309 |
| github-keyboard-shortcuts | repository,issues,copilot |
| google-site-verification | Apib7-x98H0j5cPqHWwSMm6dNU4GmODRoqxLiDzdx9I |
| octolytics-url | https://collector.github.com/github/collect |
| analytics-location | / |
| fb:app_id | 1401488693436528 |
| apple-itunes-app | app-id=1477376905, app-argument=https://github.com/_view_fragments/issues/show/regybean/Trellis/438/issue_layout |
| twitter:image | https://opengraph.githubassets.com/3ad70d7eb1b3de776ba45e75a49860865b36c3b1f1f76353707a1ead7e00f9de/regybean/Trellis/issues/438 |
| twitter:card | summary_large_image |
| og:image | https://opengraph.githubassets.com/3ad70d7eb1b3de776ba45e75a49860865b36c3b1f1f76353707a1ead7e00f9de/regybean/Trellis/issues/438 |
| og:image:alt | Question How should a per-user API key be encrypted at rest, in this stack, with no new infrastructure? Settled: app-level envelope encryption, AES-256-GCM, master key supplied via env, ciphertext ... |
| og:image:width | 1200 |
| og:image:height | 600 |
| og:site_name | GitHub |
| og:type | object |
| og:author:username | regybean |
| hostname | github.com |
| expected-hostname | github.com |
| None | 56fb42677ae87ed3e64410323d67980aa65d0485568a7858f874e7edfc6d1c11 |
| turbo-cache-control | no-preview |
| go-import | github.com/regybean/Trellis git https://github.com/regybean/Trellis.git |
| octolytics-dimension-user_id | 72984305 |
| octolytics-dimension-user_login | regybean |
| octolytics-dimension-repository_id | 1268736093 |
| octolytics-dimension-repository_nwo | regybean/Trellis |
| octolytics-dimension-repository_public | true |
| octolytics-dimension-repository_is_fork | false |
| octolytics-dimension-repository_network_root_id | 1268736093 |
| octolytics-dimension-repository_network_root_nwo | regybean/Trellis |
| turbo-body-classes | logged-out env-production page-responsive |
| disable-turbo | false |
| browser-stats-url | https://api.github.com/_private/browser/stats |
| browser-errors-url | https://api.github.com/_private/browser/errors |
| release | 9c9a37e2423ed382cf39f70b5aa4b4858b40a3b0 |
| ui-target | full |
| theme-color | #1e2327 |
| color-scheme | light dark |
| react-app-name | issues |
Links:
Viewport: width=device-width