feat: TCP transport, token auth, lease-aware proxy, and VM agent#5
Merged
feat: TCP transport, token auth, lease-aware proxy, and VM agent#5
Conversation
Add PeerIdentity::Tcp variant with peer address and token hash (SHA-256, never the raw token). Add TcpListener (localhost-only) and TcpConnector transports. Extend ClientHello with optional token field for TCP auth. UDS/vsock clients omit it (backward compatible via serde defaults). Add ClientHello::with_token() constructor. Add hash_token() helper and TokenHash type alias.
Add token parameter to Authenticator::authenticate() trait method. Existing impls (AllowAllAdmin) ignore it. Add TokenAuthenticator: reference implementation that maps pre-registered tokens (stored as SHA-256 hashes) to ConnectionIdentity values. Supports register() and revoke(). Server: extract token from ClientHello, hash into PeerIdentity::Tcp, pass raw token to authenticator for validation. Client: add connect_with_token() and connect_with_hello() for TCP transports that need to present a bearer token in the handshake.
Test the full handshake: TCP client with token → server parses ClientHello → enriches PeerIdentity with token hash → authenticator validates → ServerHello accept/reject. Tests both the happy path (registered token → Agent identity) and the rejection path (wrong token → handshake rejected).
README: document workspace structure, all three storage backends, three transport options, updated build/test commands, remove stale feature flag table and standalone server references. CLAUDE.md: reflect current workspace layout, transport/auth separation, storage/audit decoupling, code quality principles.
Describes the production layout: Claw orchestrator managing QEMU VM stacks with zerolease providing credential leasing via TCP + token auth. Includes ASCII diagram, Mermaid sequence chart, security properties, and component mapping.
New crate that acquires credentials from a zerolease vault via TCP + token auth, injects them as environment variables, and execs a command (typically claude). Designed for managed QEMU VMs where the prompt-run token is injected at boot. Usage: zerolease-cli --token $TOKEN -- claude code Reads a credential manifest (JSON) describing which secrets to acquire and which env vars to set. Default vault address is 10.0.2.2:9100 (QEMU user-mode networking gateway). Phase 1: env injection at startup. Phase 2 (future): git credential helper subcommand for per-request domain-validated credential injection.
The CLI is now the sole credential source inside a VM we control. Three injection mechanisms, each serving a different tool ecosystem: - env: set environment variables (GH_TOKEN, NPM_TOKEN, etc.) - file: write config files with template expansion and mode 0600 (.npmrc, pip.conf, etc.) - git_credential: git credential helper protocol with per-request domain validation — the vault's core security property exercised on every git operation Subcommands: - exec: acquire credentials, inject via all mechanisms, exec command - credential-fill: git credential helper called by git at auth time The manifest format now supports multiple injection mechanisms per credential. The exec subcommand sets GIT_CONFIG_* env vars to configure itself as the credential helper, and passes ZEROLEASE_TOKEN and ZEROLEASE_VAULT_ADDR through so credential-fill can reach the vault.
Covers git HTTPS (credential helper), git SSH (HTTPS rewrite or key file), gh CLI, Fastly, AWS OIDC, npm, pip, cargo, Docker, and database connection strings. Each with a manifest example. Explains the security model and when to prefer each injection mechanism.
…on/proxy/credential-fill The agent is now three subcommands: - provision: acquires credentials, writes env file + config files + lease state for proxy, exits. Vault token dies with this process. - proxy: lease-aware HTTPS CONNECT proxy (stub, implementation next). - credential-fill: git credential helper, unchanged. Key changes from the old exec-wrapper model: - No exec wrapping. Provisioner runs and exits. - Env file is sourceable (/etc/zerolease/env), not inherited. - Vault token (ZEROLEASE_TOKEN) never enters the agent's env. - credential-fill uses a separate ZEROLEASE_CREDENTIAL_TOKEN. - HTTPS_PROXY and git credential helper configured in env file. - Lease state file written for proxy consumption. New lease_state module with atomic write/read and expiry checking.
The proxy is the load-bearing security component — it makes lease revocation mean "network access cut off." Explicit proxy (CONNECT mode): - Parses HTTP CONNECT request to extract target host:port - Checks lease state: active lease → 200 + bidirectional tunnel, expired/unknown → 403 Forbidden - Integration tested: allowed domain tunnels data, denied gets 403, expired lease gets 403 Transparent proxy (SNI mode, defense-in-depth): - Peeks at TLS ClientHello to extract SNI hostname - Denies when SNI is absent (covers ECH, non-TLS, malformed) - Same lease check as CONNECT mode - SNI parser tested with synthetic ClientHello construction Shared infrastructure: - SharedLeaseState (Arc<RwLock<LeaseState>>) for concurrent access - Background refresh loop reloads lease file periodically - Both proxy modes use the same lease checking logic
Fixes from security audit: Critical: - Validate CONNECT target: restrict to ports 443/8443, validate hostname characters, resolve DNS and block private/link-local IPs (prevents SSRF to 169.254.169.254 and internal networks) High: - Bound request line reads (8 KiB max) and header count (64 max) to prevent OOM via unbounded allocation Medium: - Generic 502 responses (no internal error details leaked) - Case-normalize domains to lowercase in both CONNECT and SNI paths - Increase SNI peek buffer to 16 KiB (max TLS record size) - Prune expired leases from cache even when file read fails - Tunnel timeout derived from lease expiry (max 1 hour) Tests: - Private IP detection (127.0.0.1, 10.x, 169.254.x, etc.) - Hostname validation (path traversal, spaces, etc.) - Port restriction (SSH port 22 blocked with valid domain lease) - CONNECT to localhost gets 502 (IP validation)
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.
Summary
Adds TCP transport with token-based authentication, a lease-aware network proxy, and a VM-side agent binary — the complete infrastructure for deploying zerolease in QEMU VM environments where AI coding agents need credential access.
TCP Transport + Token Authentication
PeerIdentity::Tcpwith peer address + SHA-256 token hash (never raw token)ClientHello.tokenfield (backward-compatible — UDS/vsock omit it)TcpListener(localhost-only) +TcpConnectorTokenAuthenticator: reference impl mapping pre-registered tokens to identitiesVaultClient::connect_with_token()Lease-Aware Proxy (security-audited)
An HTTPS CONNECT proxy that makes lease revocation mean "network access cut off":
HTTPS_PROXYSecurity hardening from adversarial audit:
VM Agent Binary (
zerolease-agent)Three subcommands in a single binary:
Credential injection via manifest with three mechanisms:
env: Environment variables (GITHUB_TOKEN, NPM_TOKEN, etc.)file: Config files from templates with${SECRET}expansion (mode 0600)git_credential: Git credential helper mapping (per-request domain validation)Documentation
Test plan