|
1 | | -= wharf |
2 | | -Jonathan D.A. Jewell <jonathan.jewell@gmail.com> |
3 | | -:toc: macro |
| 1 | += Project Wharf |
| 2 | +:toc: left |
| 3 | +:toclevels: 3 |
4 | 4 | :icons: font |
5 | | -:source-highlighter: rouge |
6 | | -:experimental: |
7 | | -:url-github: https://github.com/hyperpolymath/wharf |
8 | | -:url-gitlab: https://gitlab.com/hyperpolymath/wharf |
9 | | -:url-bitbucket: https://bitbucket.org/hyperpolymath/wharf |
10 | | -:url-codeberg: https://codeberg.org/hyperpolymath/wharf |
| 5 | +:source-highlighter: highlight.js |
11 | 6 |
|
12 | | -Container deployment and harbor management |
| 7 | +== The Sovereign Web Hypervisor |
13 | 8 |
|
14 | | -image:https://img.shields.io/badge/RSR-Certified-gold[RSR Certified] |
15 | | -image:https://img.shields.io/badge/License-AGPL%20v3-blue[License] |
| 9 | +image::docs/wharf-architecture.png[Wharf Architecture,align="center"] |
16 | 10 |
|
17 | | -toc::[] |
| 11 | +*Wharf* is a revolutionary approach to Content Management System (CMS) security that separates administration from runtime. Instead of plugins with full system access running on your live site, Wharf uses an *offline controller* (the Wharf) and a *read-only runtime* (the Yacht) connected via a Zero Trust mesh network. |
18 | 12 |
|
19 | | -== Overview |
| 13 | +=== Core Philosophy |
20 | 14 |
|
21 | | -wharf is part of the link:https://rhodium.sh[Rhodium Standard] (RSR) ecosystem. |
| 15 | +[quote] |
| 16 | +The gun should not be in the safe. |
22 | 17 |
|
23 | | -Domain: *software-development* |
| 18 | +Traditional CMS security is like storing the vault's drill, dynamite, and blueprints *inside* the vault. If an attacker gets in, they use your own tools against you. |
24 | 19 |
|
25 | | -== Installation |
| 20 | +Wharf inverts this: |
| 21 | + |
| 22 | +* *The Yacht (Live Site)*: A neutered runtime. It serves content but cannot install plugins, edit code, or change configuration. |
| 23 | +* *The Wharf (Controller)*: Your offline workshop. It holds the keys, runs diagnostics, and makes all administrative decisions. |
| 24 | +* *The Mooring*: A cryptographically secured connection that temporarily allows the Wharf to sync state to the Yacht. |
| 25 | + |
| 26 | +== Architecture |
| 27 | + |
| 28 | +[source] |
| 29 | +---- |
| 30 | + THE WHARF (Offline Controller) THE YACHT (Online Runtime) |
| 31 | + +--------------------------------+ +------------------------------+ |
| 32 | + | [Physical/Local Hardware] | | [Cloud/Edge Server] | |
| 33 | + | | | | |
| 34 | + | 1. IDENTITY (The Keys) | | 4. THE SHIELD (Rust Agent) | |
| 35 | + | • Nitrokey / FIDO2 | | • eBPF Force Field | |
| 36 | + | • Argon2id + LUKS | | • Header Airlock | |
| 37 | + | | | • DB Proxy (AST Aware) | |
| 38 | + | 2. INTENT (The Brain) | | | |
| 39 | + | • Nickel Config Schema | | 5. THE PAYLOAD (Legacy) | |
| 40 | + | • Nebula CA (Offline) | | • WordPress / Drupal | |
| 41 | + | • Rust Compiler | | • Read-Only Filesystem | |
| 42 | + | | | • Ephemeral RAM Disk | |
| 43 | + +---------------+----------------+ +--------------+---------------+ |
| 44 | + | | |
| 45 | + | THE MOORING (Zero Trust) | |
| 46 | + | | |
| 47 | + +==========================================+ |
| 48 | + | • Hidden UDP Port (Nebula Mesh) | |
| 49 | + | • Mutual TLS (mTLS) | |
| 50 | + | • Invisible to Public Internet | |
| 51 | + +==========================================+ |
| 52 | +---- |
| 53 | + |
| 54 | +== Key Features |
| 55 | + |
| 56 | +=== Database "Virtual Sharding" |
| 57 | + |
| 58 | +The Yacht Agent acts as a SQL proxy, parsing queries using an *Abstract Syntax Tree* (not regex!) to enforce security policies: |
| 59 | + |
| 60 | +* *Mutable Tables* (Blue Zone): Content like comments and orders—allowed to write |
| 61 | +* *Immutable Tables* (Red Zone): Config like users and plugins—blocked unless from Wharf |
| 62 | +* *Hybrid Tables* (Grey Zone): Mixed content like `wp_options`—conditional rules |
| 63 | + |
| 64 | +[source,sql] |
| 65 | +---- |
| 66 | +-- ALLOWED: User comment |
| 67 | +INSERT INTO wp_comments (comment_content) VALUES ('Great post!') |
| 68 | +
|
| 69 | +-- BLOCKED: New admin user |
| 70 | +INSERT INTO wp_users (user_login, user_pass) VALUES ('hacker', 'password') |
| 71 | +-- Error: Policy violation: write to immutable table 'wp_users' |
| 72 | +---- |
| 73 | + |
| 74 | +=== Filesystem Immutability |
| 75 | + |
| 76 | +The Yacht filesystem is mounted read-only with specific writable "playgrounds": |
| 77 | + |
| 78 | +|=== |
| 79 | +| Path | Type | Purpose |
| 80 | + |
| 81 | +| `/wp-content/uploads` | Persistent, No PHP | User media files |
| 82 | +| `/wp-content/cache` | RAM Disk (tmpfs) | Temporary cache—wipes on restart |
| 83 | +| `/wp-content/plugins` | OverlayFS | "The Lie"—plugins think they write, but it's ephemeral |
| 84 | +|=== |
| 85 | + |
| 86 | +=== HTTP Header Airlock |
| 87 | + |
| 88 | +A Rust-based HTTP proxy strips dangerous headers and injects security headers: |
| 89 | + |
| 90 | +[source] |
| 91 | +---- |
| 92 | +# Stripped (Information Leakage) |
| 93 | +- Server: Apache/2.4.41 |
| 94 | +- X-Powered-By: PHP/8.1 |
| 95 | +
|
| 96 | +# Injected (Security Hardening) |
| 97 | ++ Cross-Origin-Opener-Policy: same-origin |
| 98 | ++ Cross-Origin-Embedder-Policy: require-corp |
| 99 | ++ Permissions-Policy: camera=(), microphone=() |
| 100 | +---- |
| 101 | + |
| 102 | +=== Zero Trust Networking (Nebula) |
| 103 | + |
| 104 | +Admin ports are *invisible* to the public internet. The Yacht's management API (port 9000) only responds to devices with valid Nebula certificates. |
| 105 | + |
| 106 | +== Quick Start |
| 107 | + |
| 108 | +=== Prerequisites |
| 109 | + |
| 110 | +* Rust (via rustup) |
| 111 | +* Podman (or Docker) |
| 112 | +* Just (command runner) |
| 113 | +* Optional: Nebula, named-checkzone (bind-utils) |
| 114 | + |
| 115 | +=== Installation |
26 | 116 |
|
27 | 117 | [source,bash] |
28 | 118 | ---- |
29 | | -# Clone from GitHub (primary) |
30 | | -git clone {url-github} |
| 119 | +# Clone the repository |
| 120 | +git clone https://gitlab.com/hyperpolymath/wharf.git |
| 121 | +cd wharf |
31 | 122 |
|
32 | | -# Or from mirrors |
33 | | -git clone {url-gitlab} |
34 | | -git clone {url-codeberg} |
| 123 | +# Initialize the workspace |
| 124 | +just init |
| 125 | +
|
| 126 | +# Build everything |
| 127 | +just build |
35 | 128 | ---- |
36 | 129 |
|
37 | | -== RSR Stack |
| 130 | +=== Basic Usage |
38 | 131 |
|
39 | | -This project follows RSR conventions: |
| 132 | +[source,bash] |
| 133 | +---- |
| 134 | +# Create zone file variables |
| 135 | +cat > vars/example.json << 'EOF' |
| 136 | +{ |
| 137 | + "domain": "example.com", |
| 138 | + "ip": "192.0.2.1", |
| 139 | + "ipv6": "2001:db8::1", |
| 140 | + "nameserver": "ns1.example.com", |
| 141 | + "nameserver2": "ns2.example.com", |
| 142 | + "rpemail": "hostmaster.example.com", |
| 143 | + "serial": "2025112601", |
| 144 | + "ttl": "3600", |
| 145 | + "nsttl": "86400" |
| 146 | +} |
| 147 | +EOF |
| 148 | +
|
| 149 | +# Build DNS zone files |
| 150 | +just build-zones |
40 | 151 |
|
41 | | -* ✅ ReScript for frontend/logic |
42 | | -* ✅ Deno for JS runtime |
43 | | -* ✅ WASM for performance-critical code |
44 | | -* ✅ Rust/OCaml/Haskell for systems/proofs |
45 | | -* ✅ Guile/Scheme for configuration |
46 | | -* ❌ No TypeScript |
47 | | -* ❌ No Go |
48 | | -* ❌ No npm |
| 152 | +# Audit the generated zone |
| 153 | +just audit-zone dist/example.db example.com |
| 154 | +
|
| 155 | +# Detect if dedicated or shared hosting |
| 156 | +just detect-env example.com 192.0.2.1 |
| 157 | +---- |
49 | 158 |
|
50 | | -== Mirrors |
| 159 | +== DNS Zone Templates |
| 160 | + |
| 161 | +Wharf includes four DNS templates for different environments: |
51 | 162 |
|
52 | | -[cols="1,2"] |
53 | 163 | |=== |
54 | | -| Platform | URL |
| 164 | +| Template | Use Case | Key Difference |
55 | 165 |
|
56 | | -| GitHub (primary) | {url-github} |
57 | | -| GitLab | {url-gitlab} |
58 | | -| Bitbucket | {url-bitbucket} |
59 | | -| Codeberg | {url-codeberg} |
| 166 | +| `simple.tpl` | Modern minimum viable | Basic records + email deliverability (SPF, DMARC, CAA) |
| 167 | +| `shared.tpl` | Shared/Virtual hosting | Uses CNAMEs, includes provider SPF, no SSHFP |
| 168 | +| `standard.tpl` | Dedicated IP | Explicit FTP A record, full control |
| 169 | +| `maximalist.tpl` | Enterprise/Security-focused | DANE, SSHFP, OPENPGPKEY, HTTPS/SVCB, LOC |
60 | 170 | |=== |
61 | 171 |
|
62 | | -== License |
| 172 | +== CMS Adapters |
| 173 | + |
| 174 | +Wharf includes adapters for popular CMS platforms: |
| 175 | + |
| 176 | +=== WordPress |
| 177 | + |
| 178 | +[source,bash] |
| 179 | +---- |
| 180 | +# Copy the DB proxy drop-in |
| 181 | +cp adapters/wordpress/db.php /var/www/html/wp-content/db.php |
| 182 | +
|
| 183 | +# The Yacht Agent must be running on 127.0.0.1:3307 |
| 184 | +---- |
| 185 | + |
| 186 | +=== Drupal |
| 187 | + |
| 188 | +[source,bash] |
| 189 | +---- |
| 190 | +# Include the settings override |
| 191 | +echo "include_once '/opt/wharf/adapters/drupal/settings.php';" >> sites/default/settings.php |
| 192 | +---- |
| 193 | + |
| 194 | +=== Others |
| 195 | + |
| 196 | +* Joomla (adapter included) |
| 197 | +* Moodle (adapter included) |
| 198 | +* Generic LAMP (customizable adapter) |
| 199 | + |
| 200 | +== Security Model |
| 201 | + |
| 202 | +=== Threat Model |
63 | 203 |
|
64 | | -Licensed under AGPL-3.0-or-later OR LicenseRef-Palimpsest-0.5. |
| 204 | +Wharf assumes: |
65 | 205 |
|
66 | | -See link:LICENSE[LICENSE] for details. |
| 206 | +* The live server (Yacht) is *hostile territory* |
| 207 | +* Attackers may have SQL injection or file upload vulnerabilities |
| 208 | +* Network is *untrusted* (even internal networks) |
| 209 | + |
| 210 | +=== Protections |
| 211 | + |
| 212 | +|=== |
| 213 | +| Attack Vector | Wharf Defense |
| 214 | + |
| 215 | +| SQL Injection → New Admin User | Database proxy blocks writes to `wp_users` |
| 216 | +| File Upload → PHP Shell | Uploads directory has `php_flag engine off` |
| 217 | +| Plugin Backdoor | Plugins directory is read-only (OverlayFS) |
| 218 | +| Config Tampering | `wp-config.php` changes trigger instant revert |
| 219 | +| Network Sniffing | Nebula mesh encrypts all admin traffic |
| 220 | +|=== |
| 221 | + |
| 222 | +== Configuration Reference |
| 223 | + |
| 224 | +Wharf uses https://nickel-lang.org/[Nickel] for declarative configuration: |
| 225 | + |
| 226 | +* `configs/fleet.ncl` - Define your Yachts |
| 227 | +* `configs/policies/database.ncl` - Database virtual sharding rules |
| 228 | +* `configs/policies/airlock.ncl` - HTTP header rules |
| 229 | +* `configs/policies/filesystem.ncl` - File immutability policies |
| 230 | +* `configs/policies/auth.ncl` - FIDO2 and session policies |
| 231 | +* `configs/policies/network.ncl` - Nebula mesh and firewall rules |
| 232 | + |
| 233 | +== Justfile Commands |
| 234 | + |
| 235 | +[source] |
| 236 | +---- |
| 237 | +just init # Initialize workspace |
| 238 | +just build # Compile everything |
| 239 | +just moor <target> # Connect to a Yacht |
| 240 | +just audit <target> # Security audit |
| 241 | +just gen-nebula-ca # Generate mesh CA |
| 242 | +just gen-yacht-cert # Generate Yacht certificate |
| 243 | +just gen-email-records # Generate SPF/DKIM/DMARC |
| 244 | +just deploy-yacht # Deploy agent to server |
| 245 | +---- |
67 | 246 |
|
68 | 247 | == Contributing |
69 | 248 |
|
70 | | -See link:CONTRIBUTING.adoc[CONTRIBUTING.adoc]. |
| 249 | +Contributions are welcome! Please ensure: |
| 250 | + |
| 251 | +1. Code passes `just lint` and `just fmt-check` |
| 252 | +2. Tests pass with `just test` |
| 253 | +3. Security-sensitive changes are documented |
| 254 | + |
| 255 | +== License |
| 256 | + |
| 257 | +MIT License. See LICENSE file for details. |
| 258 | + |
| 259 | +== Credits |
| 260 | + |
| 261 | +* Concept by Jonathan D. A. Jewell (@hyperpolymath) |
| 262 | +* Built with Rust, Nickel, Nebula, and Podman |
71 | 263 |
|
72 | | -== Metadata |
| 264 | +--- |
73 | 265 |
|
74 | | -* Domain: software-development |
75 | | -* Framework: RSR (Rhodium Standard Repository) |
76 | | -* Dublin Core: link:.well-known/dc.xml[.well-known/dc.xml] |
| 266 | +[quote, Project Wharf Manifesto] |
| 267 | +"The admin panel has no place on the production server." |
0 commit comments