feat(vault-agent): session resume across restart via kernel keyring (opt-in)#15
Merged
Conversation
…opt-in) Opt-in `agent.session_keyring` (Linux): on unlock, mirror the user key into the kernel session keyring (kernel memory — never on disk, never swapped, possessor-gated, evicted on logout) so a restarted agent resumes unlocked without the master password, bounded by the idle-lock TTL. - session.rs: SessionBlob + store/load/clear over linux-keyutils (target.linux dep, MIT/Apache-2.0); no-op stub on non-Linux. - state.rs: session_keyring flag, persist_session (deadline = idle TTL), throttled re-arm on touch(); split lock() (in-memory, used by Quit/SIGTERM -> resumable) from lock_and_clear_session() (vault lock / idle-lock -> clears keyring, durably locked). - main.rs: --session-keyring flag; try_resume() at startup via unlock::load_cache + vault_from_user_key; SIGTERM keeps lock() (resumable). - vault-config: agent.session_keyring key (parse_bool) -> --session-keyring on auto-spawn. - Sole, default-off carve-out to PRD §7.3/G4; documented in PRD/README. Tests: SessionBlob serde round-trip (xplat) + keyring store/load/clear (skips where no keyring); vault-config get/set/unset + agent_args flag. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
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.
What
Opt-in session resume across agent restarts on Linux. The agent starts cold
and locked today, so every restart (crash,
stop-agent+ auto-spawn, logout)forces a full master-password unlock. With
agent.session_keyringenabled, anunlock mirrors the user key into the Linux kernel session keyring so a
restarted agent resumes unlocked without the master password — bounded by
the idle-lock TTL.
Why the kernel keyring
To usefully resume, a cold agent needs the user key back (it's what
decrypts items), not just the server token — which means the key must persist
outside the agent's memory. That's in tension with PRD §7.3 / G4 ("master key
never resident outside the agent process … never swapped"). The kernel session
keyring is the most PRD-aligned option: kernel memory, never on disk, never
swapped, possessor-gated, evicted on logout. It's the sole, default-off
carve-out to G4, now documented in PRD §7.3. Off, the key never leaves the
process; the feature is a no-op on non-Linux.
How
session.rs—SessionBlob(user key + account + deadline) andstore/load/clearover the pure-Rustlinux-keyutilscrate(
[target.'cfg(target_os = "linux")'], MIT/Apache-2.0; no C dep → avoids thering/
-fltolink breakage). No-op stub elsewhere.state.rs—persist_session(deadline =idle_lock_secs, kernelset_timeoutso a dead agent's session self-expires; re-armed on activity,throttled). The
lock()funnel is split:lock()(in-memory wipe) forQuit/SIGTERM→ resumable;lock_and_clear_session()forvault lock/idle-lock → clears the keyring (durably locked).
main.rs—--session-keyringflag;try_resume()at startup rebuildsthe vault via the existing
unlock::load_cache+vault_from_user_keypath,honoring the deadline. SIGTERM keeps
lock()(resumable).vault-config—agent.session_keyringkey →--session-keyringonauto-spawn (same path as
idle_lock_secs).Resume model
vault lock/ idle-lockstop-agent(Quit) /SIGTERM/ crashTests
SessionBlobserde round-trip (cross-platform) + a keyring store/load/clearround-trip that skips gracefully where no keyring exists (passes on this host).
vault-config:agent.session_keyringget/set/unset +agent_argsflagemission (only when
true).lock()split leaves current lock behaviorintact.
Local CI-exact gates all green:
fmt, fresh isolatedclippy -D warnings,cargo test --workspace --all-targetsunderRUSTFLAGS=-D warnings,cargo deny check(the newlinux-keyutilsdep — licenses ok), bothheadless builds.
🤖 Generated with Claude Code