Skip to content

Commit c7073f7

Browse files
Jonathan D.A. Jewellclaude
andcommitted
feat: production hardening — persistent keypairs, metrics, integrity verification
Persist Ed448+ML-DSA-87 hybrid keypairs to disk for both CLI (~/.wharf/keys/) and yacht-agent (/etc/wharf/keys/) with 0600 permissions, replacing ephemeral generation. Wire Prometheus metrics and stats endpoints to real counters. Connect mooring verify to BLAKE3 manifest verification. Add HTTP client timeouts and connection pooling. Update all documentation and create TOPOLOGY.md. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
1 parent 7915999 commit c7073f7

10 files changed

Lines changed: 738 additions & 69 deletions

File tree

.machine_readable/META.scm

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,4 +21,12 @@
2121
(adr "ast-aware-sql-proxy"
2222
(status accepted)
2323
(description "Database proxy parses SQL AST to enforce table allowlists and block dangerous operations.")
24-
(rationale "Prevents SQL injection at the wire protocol level, not just application level."))))
24+
(rationale "Prevents SQL injection at the wire protocol level, not just application level."))
25+
(adr "persistent-hybrid-keypairs"
26+
(status accepted)
27+
(description "CLI and agent persist Ed448+ML-DSA-87 keypairs to disk with restrictive file permissions.")
28+
(rationale "Stable identity is required for trust establishment. Ephemeral keys prevent the yacht from recognizing returning controllers."))
29+
(adr "ebpf-xdp-firewall"
30+
(status accepted)
31+
(description "Kernel-level packet filtering via eBPF XDP with nftables fallback.")
32+
(rationale "XDP processes packets before the kernel network stack for lowest latency. Cascade to nftables ensures protection without CAP_BPF."))))

.machine_readable/STATE.scm

Lines changed: 11 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3,20 +3,27 @@
33
(project-context
44
(name "project-wharf")
55
(purpose "Sovereign Web Hypervisor — immutable CMS infrastructure with offline admin (Wharf) and online runtime (Yacht)")
6-
(completion-percentage 75))
6+
(completion-percentage 90))
77
(route-to-mvp
88
(milestone "crypto-overhaul" (status complete) (description "Ed448 + ML-DSA-87 hybrid signatures, SHAKE3-512, XChaCha20-Poly1305, HKDF, Argon2id"))
99
(milestone "http-mooring-client" (status complete) (description "MooringClient HTTP API: init → verify → rsync → commit"))
1010
(milestone "identity-file" (status complete) (description "SSH identity resolution: yacht → fleet → ~/.ssh/id_ed448 → agent"))
1111
(milestone "container-compliance" (status complete) (description "Chainguard bases, Containerfile naming, selur-compose orchestration"))
1212
(milestone "demo-script" (status complete) (description "End-to-end mooring + SQL injection blocking + file tampering detection"))
13-
(milestone "production-hardening" (status pending) (description "Persist keypairs, eBPF loader, real database proxy, certificate management")))
13+
(milestone "production-hardening" (status in-progress) (description "Production hardening milestone")
14+
(sub-milestone "keypair-persistence" (status complete) (description "Persistent hybrid keypairs for CLI and yacht-agent with file permissions"))
15+
(sub-milestone "ebpf-loader" (status complete) (description "Full XDP kernel program + userspace loader in crates/wharf-ebpf/"))
16+
(sub-milestone "database-proxy" (status complete) (description "Full AST parser via sqlparser 0.39 in db_policy.rs"))
17+
(sub-milestone "certificate-management" (status complete) (description "1024-line Nebula module in nebula.rs with CA, cert signing, IP allocation, revocation"))
18+
(sub-milestone "metrics" (status complete) (description "Prometheus metrics and stats endpoints wired to real counters"))
19+
(sub-milestone "http-resilience" (status complete) (description "Timeouts, connection pooling on mooring HTTP client"))
20+
(sub-milestone "integrity-verification" (status complete) (description "Yacht agent mooring verify wired to BLAKE3 manifest verification"))
21+
(sub-milestone "ed448-audit" (status pending) (description "ed448-goldilocks v0.14.0-pre.10 needs third-party audit before production"))))
1422
(components
1523
(component "wharf-core" (path "crates/wharf-core") (role "shared library: crypto, fleet, integrity, mooring, sync"))
1624
(component "wharf-cli" (path "bin/wharf-cli") (role "offline admin CLI: moor, integrity, fleet management"))
1725
(component "yacht-agent" (path "bin/yacht-agent") (role "online runtime: HTTP API, DB proxy, firewall, integrity enforcement"))
1826
(component "wharf-ebpf" (path "crates/wharf-ebpf") (role "eBPF programs for XDP firewall (optional, excluded from default build)"))
1927
(component "xtask" (path "xtask") (role "build tasks: eBPF compilation")))
2028
(blockers-and-issues
21-
(blocker "ed448-goldilocks-pre-release" (severity medium) (description "v0.14.0-pre.10 is unaudited; needs audit before production"))
22-
(blocker "keypair-persistence" (severity medium) (description "CLI generates ephemeral keypairs; need disk persistence with file permissions"))))
29+
(blocker "ed448-goldilocks-pre-release" (severity medium) (description "v0.14.0-pre.10 is unaudited; needs third-party audit before production deployment"))))

CHANGELOG.adoc

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,19 +13,33 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
1313
- Rust workspace with wharf-core, wharf-cli, and yacht-agent crates
1414
- DNS zone templates (simple, shared, standard, maximalist)
1515
- Nickel configuration schemas for security policies
16-
- Database policy engine with AST-based SQL filtering
16+
- Database policy engine with AST-based SQL filtering (sqlparser 0.39)
1717
- CMS adapters for WordPress, Drupal, Joomla, Moodle
1818
- Shell scripts for zone rendering, auditing, and deployment
1919
- Comprehensive Justfile with 50+ recipes
2020
- RSR (Rhodium Standard Repository) compliance documentation
2121

22+
=== Production Hardening (2026-02-14)
23+
- *Persistent hybrid keypairs*: Wharf CLI (`~/.wharf/keys/wharf.key`) and Yacht Agent (`/etc/wharf/keys/yacht.key`) now persist Ed448 + ML-DSA-87 keypairs across restarts with proper file permissions (0600 private, 0644 public)
24+
- *Keypair serialization*: Custom binary format with `WHRF` magic, versioning, and optional password encryption via HKDF-SHAKE512 + XChaCha20-Poly1305
25+
- *eBPF XDP firewall*: Full kernel-level packet filtering with XDP programs and userspace loader (`crates/wharf-ebpf/`)
26+
- *Certificate management*: Complete Nebula certificate lifecycle — CA creation, cert signing, IP allocation, and revocation (`nebula.rs`)
27+
- *Prometheus metrics*: Real-time counters for queries (allowed/blocked/audited), mooring sessions, integrity checks, and moored status at `GET /metrics`
28+
- *Statistics endpoint*: `GET /stats` now returns actual counters instead of placeholder zeros
29+
- *File integrity verification*: Yacht Agent mooring verify phase now checks BLAKE3 manifests against on-disk files when `site_root` is configured
30+
- *HTTP client resilience*: Mooring client configured with 30s timeout, 10s connect timeout, and connection pooling (2 idle per host)
31+
- *Configuration*: Added `key_store_dir` (CLI + agent) and `site_root` (agent) config options
32+
2233
=== Security
2334
- Implemented AST-based SQL query analysis (not regex)
2435
- Added HTTP header airlock configuration
2536
- Defined filesystem immutability policies
2637
- Configured Nebula mesh network policies
2738
- Added FIDO2/WebAuthn authentication framework
2839

40+
=== Known Issues
41+
- `ed448-goldilocks` v0.14.0-pre.10 is unaudited — needs third-party audit before production deployment
42+
2943
== [0.1.0] - 2025-11-26
3044

3145
=== Added
@@ -47,6 +61,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
4761

4862
| Version | Date | Highlights |
4963
|---------|------|------------|
64+
| Unreleased | 2026-02-14 | Production hardening: persistent keypairs, eBPF, metrics, integrity verification |
5065
| 0.1.0 | 2025-11-26 | Initial release |
5166

5267
== Upgrade Guide

README.adoc

Lines changed: 46 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -60,7 +60,7 @@ Wharf inverts this:
6060

6161
=== Database "Virtual Sharding"
6262

63-
The Yacht Agent acts as a SQL proxy, parsing queries using an *Abstract Syntax Tree* (not regex!) to enforce security policies:
63+
The Yacht Agent acts as a SQL proxy, parsing queries using an *Abstract Syntax Tree* (via `sqlparser` 0.39, not regex!) to enforce security policies:
6464

6565
* *Mutable Tables* (Blue Zone): Content like comments and orders—allowed to write
6666
* *Immutable Tables* (Red Zone): Config like users and plugins—blocked unless from Wharf
@@ -76,6 +76,23 @@ INSERT INTO wp_users (user_login, user_pass) VALUES ('hacker', 'password')
7676
-- Error: Policy violation: write to immutable table 'wp_users'
7777
----
7878

79+
=== Persistent Hybrid Keypairs
80+
81+
Both the Wharf CLI and Yacht Agent persist their Ed448 + ML-DSA-87 hybrid keypairs to disk, establishing stable identities across restarts.
82+
83+
|===
84+
| Component | Key Location | Permissions
85+
86+
| Wharf CLI | `~/.wharf/keys/wharf.key` | `0600` (private), `0644` (public)
87+
| Yacht Agent | `/etc/wharf/keys/yacht.key` | `0600`
88+
|===
89+
90+
Keys use a custom binary format (`WHRF` magic + version + length-prefixed key material). Password-encrypted serialization is available via HKDF-SHAKE512 + XChaCha20-Poly1305 for offline storage.
91+
92+
=== eBPF XDP Firewall
93+
94+
The Yacht Agent supports kernel-level packet filtering via eBPF XDP programs for high-performance network enforcement. Falls back to nftables when CAP_BPF is unavailable.
95+
7996
=== Filesystem Immutability
8097

8198
The Yacht filesystem is mounted read-only with specific writable "playgrounds":
@@ -88,6 +105,21 @@ The Yacht filesystem is mounted read-only with specific writable "playgrounds":
88105
| `/wp-content/plugins` | OverlayFS | "The Lie"—plugins think they write, but it's ephemeral
89106
|===
90107

108+
=== File Integrity Verification
109+
110+
The Yacht Agent verifies incoming BLAKE3 file manifests against on-disk state during the mooring verify phase. Mismatched, missing, and unexpected files are reported back to the Wharf CLI before any rsync transfer.
111+
112+
=== Prometheus Metrics
113+
114+
The Yacht Agent exposes real-time operational counters at `GET /metrics` (Prometheus format):
115+
116+
* `yacht_queries_total{status="allowed|blocked|audited"}` — database proxy traffic
117+
* `yacht_mooring_sessions_total` — mooring session count
118+
* `yacht_integrity_checks_total` — integrity verification runs
119+
* `yacht_moored` — whether the agent is currently moored
120+
121+
Statistics are also available as JSON via `GET /stats`.
122+
91123
=== HTTP Header Airlock
92124

93125
A Rust-based HTTP proxy strips dangerous headers and injects security headers:
@@ -106,7 +138,7 @@ A Rust-based HTTP proxy strips dangerous headers and injects security headers:
106138

107139
=== Zero Trust Networking (Nebula)
108140

109-
Admin ports are *invisible* to the public internet. The Yacht's management API (port 9000) only responds to devices with valid Nebula certificates.
141+
Admin ports are *invisible* to the public internet. The Yacht's management API (port 9001) only responds to devices with valid Nebula certificates. Full certificate lifecycle management (CA, signing, IP allocation, revocation) is built into `nebula.rs`.
110142

111143
== Quick Start
112144

@@ -236,6 +268,8 @@ The Wharf controller syncs state to the Yacht via a four-phase HTTP protocol:
236268

237269
All init and commit requests carry hybrid signatures. The Yacht verifies both Ed448 and ML-DSA-87 components before accepting.
238270

271+
The mooring HTTP client uses a 30-second request timeout, 10-second connect timeout, and connection pooling (2 idle connections per host) for resilient communication.
272+
239273
=== Threat Model
240274

241275
Wharf assumes:
@@ -287,7 +321,9 @@ just sign-images
287321

288322
== Configuration Reference
289323

290-
Wharf uses https://nickel-lang.org/[Nickel] for declarative configuration:
324+
Wharf uses https://nickel-lang.org/[Nickel] for declarative configuration and TOML for runtime settings:
325+
326+
=== Policy Files (Nickel)
291327

292328
* `configs/fleet.ncl` - Define your Yachts
293329
* `configs/policies/database.ncl` - Database virtual sharding rules
@@ -296,6 +332,13 @@ Wharf uses https://nickel-lang.org/[Nickel] for declarative configuration:
296332
* `configs/policies/auth.ncl` - FIDO2 and session policies
297333
* `configs/policies/network.ncl` - Nebula mesh and firewall rules
298334

335+
=== Runtime Configuration (TOML)
336+
337+
Configuration is loaded with the following precedence (highest first): CLI args > environment variables > project-local (`.wharf/config.toml`) > user config (`~/.config/wharf/`) > system config (`/etc/wharf/`) > defaults.
338+
339+
* `yacht-agent.toml` — Yacht Agent runtime settings (db proxy, firewall, API, site root, key store)
340+
* `wharf-cli.toml` — CLI settings (paths, build, mooring, state, key store)
341+
299342
== Justfile Commands
300343

301344
[source]

TOPOLOGY.md

Lines changed: 95 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,95 @@
1+
<!-- SPDX-License-Identifier: PMPL-1.0-or-later -->
2+
# TOPOLOGY.md - Project Wharf
3+
4+
## System Architecture
5+
6+
```
7+
THE WHARF (Offline Controller)
8+
+---------------------------------+
9+
| wharf-cli |
10+
| +-----------+ +-----------+ |
11+
| | moor.rs | | fleet.rs | |
12+
| | (keypair | | (yacht | |
13+
| | persist) | | config) | |
14+
| +-----+-----+ +-----+-----+ |
15+
| | | |
16+
| +-----v--------------v-----+ |
17+
| | wharf-core | |
18+
| | crypto | integrity | sync | |
19+
| | mooring_client | config | |
20+
| | db_policy | fleet | |
21+
| +-------------+-------------+ |
22+
+-----------------|--+--------------+
23+
| |
24+
Mooring Protocol (HTTP) | | rsync (SSH)
25+
Ed448+ML-DSA-87 signed | |
26+
| |
27+
+-----------------|--+--------------+
28+
| THE YACHT (Online Runtime) |
29+
| yacht-agent |
30+
| +-----------+ +-------------+ |
31+
| | Mooring | | DB Proxy | |
32+
| | API | | (sqlparser | |
33+
| | (init/ | | AST filter)| |
34+
| | verify/ | +------+------+ |
35+
| | commit) | | |
36+
| +-----+-----+ +------v------+ |
37+
| | | Shadow DB | |
38+
| +-----v-----+ +-------------+ |
39+
| | Integrity | |
40+
| | (BLAKE3) | +-------------+ |
41+
| +-----------+ | Firewall | |
42+
| | eBPF/nftab | |
43+
| +-----------+ +-------------+ |
44+
| | Metrics | |
45+
| | /metrics | +-------------+ |
46+
| | /stats | | Nebula Mesh | |
47+
| +-----------+ +-------------+ |
48+
+----------------------------------+
49+
50+
+-----------------------------------------------------------+
51+
| wharf-ebpf (optional, excluded from default build) |
52+
| XDP kernel program + userspace loader (aya 0.12) |
53+
+-----------------------------------------------------------+
54+
```
55+
56+
## Completion Dashboard
57+
58+
| Component | Progress | Status |
59+
|------------------------|------------------------------|--------|
60+
| **wharf-core** | `[██████████]` 100% | Complete |
61+
| - crypto (Ed448+ML-DSA)| `[██████████]` 100% | Hybrid sigs, HKDF, XChaCha20, Argon2id, keypair serialization |
62+
| - db_policy (AST) | `[██████████]` 100% | sqlparser 0.39, policy engine |
63+
| - integrity (BLAKE3) | `[██████████]` 100% | Manifest gen/verify, remote SSH verify |
64+
| - mooring protocol | `[██████████]` 100% | Init/verify/commit/abort, canonical signing |
65+
| - mooring_client | `[██████████]` 100% | HTTP client with timeouts + pooling |
66+
| - fleet/sync/config | `[██████████]` 100% | Fleet TOML, rsync, config hierarchy |
67+
| **wharf-cli** | `[█████████░]` 90% | Near-complete |
68+
| - moor operations | `[██████████]` 100% | Full mooring flow, persistent keypairs |
69+
| - fleet management | `[██████████]` 100% | Add/remove/list yachts |
70+
| - integrity audit | `[████████░░]` 80% | Local + remote SSH, API mode pending |
71+
| **yacht-agent** | `[█████████░]` 90% | Near-complete |
72+
| - DB proxy | `[██████████]` 100% | MySQL + PostgreSQL wire protocol |
73+
| - mooring API | `[██████████]` 100% | Init/verify/commit with sig verification |
74+
| - integrity verify | `[██████████]` 100% | BLAKE3 manifest verification wired |
75+
| - firewall (nftables) | `[██████████]` 100% | Rule generation, validation, runtime updates |
76+
| - metrics/stats | `[██████████]` 100% | Prometheus + JSON with real counters |
77+
| - keypair persistence | `[██████████]` 100% | /etc/wharf/keys/yacht.key |
78+
| **wharf-ebpf** | `[████████░░]` 80% | XDP program + loader, needs production testing |
79+
| **nebula.rs** | `[██████████]` 100% | CA, cert signing, IP allocation, revocation |
80+
| **Overall** | `[█████████░]` 90% | ed448 audit pending |
81+
82+
## Key Dependencies
83+
84+
| Dependency | Version | Purpose |
85+
|------------|---------|---------|
86+
| ed448-goldilocks | 0.14.0-pre.10 | Classical hybrid signature component (UNAUDITED) |
87+
| pqcrypto-mldsa | 0.1 | Post-quantum ML-DSA-87 signatures |
88+
| sqlparser | 0.39 | AST-based SQL query analysis |
89+
| axum | 0.7 | Yacht agent HTTP API |
90+
| reqwest | 0.12 | Mooring HTTP client |
91+
| blake3 | 1.5 | File integrity hashing |
92+
| chacha20poly1305 | 0.10 | Symmetric encryption |
93+
| aya | 0.12 | eBPF userspace loader |
94+
| tokio | 1.x | Async runtime |
95+
| clap | 4.4 | CLI argument parsing |

0 commit comments

Comments
 (0)