HarperFast / HarperFast/harper

Consider envelope-encrypting TLS certificate private keys at rest (design/decision)

Open
#1,793 0 comments 0 reactions 0 assignees View on GitHub
Dominant language
JavaScript
Stars
89
Forks
10
Avg merge
2d 6h
Merged PRs (30d)
200

Description

## Current state

TLS private keys live as plaintext PEM files under `/keys/` (e.g. `privateKey.pem`); `hdb_certificate` rows reference keys by `private_key_name` — key material is never in a table, but is unprotected against disk theft, backup exposure, and filesystem-read primitives.

## Why this is not a straightforward retrofit

**Boot ordering is the crux.** TLS contexts are built at server start (`security/keys.ts` loads keys from disk into the worker-local map); secrets **custody** registers only when the Pro secrets component loads. Encrypting TLS keys with the cluster secrets key creates a chicken-and-egg: the node cannot terminate TLS until custody is up, and under the two-key custody model a rebooted node may not be able to decrypt *at all* until a remote/operator share arrives — turning a security win into an availability coupling on every restart (incl. rolling restarts).

## Proposed shape (if we proceed)

- **Opt-in, per key file**: the keys loader detects an `enc:v1:` PEM (same `isEncryptedEnvValue` marker as env secrets) and decrypts via the registered decryptor (`resources/secretDecryptor.ts` hook already exists; the deferral precedent is `deferEncryptedEnvValue`). Plaintext keys keep working unchanged.
- Fail loudly (or defer that listener's TLS start) when an encrypted key is present without custody — never serve without the intended cert silently.
- Certificate ops and the ACME renewal path must seal on write, or renewal reintroduces plaintext.
- File-watch reload (`handlePrivateKeyReload`) must decrypt on reload too.

## Decision needed

Whether the at-rest gain justifies the boot/availability coupling, and whether custody init can be ordered ahead of TLS listener start (or scoped: encrypt only non-default/uploaded certs, not the bootstrap self-signed pair).

Refs: #1550/#1554/#1582 (secrets store + envelope format), two-key custody design (Confluence SD).

— filed by KrAIs (Claude, Fable 5) for Kris

Contributor guide

Open the contributing guide

Research direction

Start by reading security/keys.ts and resources/secretDecryptor.ts, then review the precedents in #1550, #1554, and #1582. Trace boot ordering, certificate operations, ACME renewal, and handlePrivateKeyReload. Done means documenting a decision on the availability tradeoff and an agreed encryption scope and startup behavior.

Written by the indexing model from the issue text.

Assessment

Tech stack
nodejs, typescript
Domain
security
Issue type
Feature
Difficulty
5/5
Estimated time
Over a week
Activity status
Quiet
Clarity
Needs clarification
Newbie friendliness
25/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.