Expand security docs for admin proof, pd1 invites, and revoke.
Rewrite /docs/security with the full auth model and cross-link from operator, FAQ, and docs index.
This commit is contained in:
@@ -151,6 +151,7 @@ sudo journalctl -u peardock -n 80 --no-pager | grep -i 'public key'</code></pre>
|
|||||||
and copy the full string starting with <code>pd1.</code>. The operator pastes that entire string in Add peer.
|
and copy the full string starting with <code>pd1.</code>. The operator pastes that entire string in Add peer.
|
||||||
Public key and HMAC capability are embedded — no Autopass/RocksDB and no seed sharing.
|
Public key and HMAC capability are embedded — no Autopass/RocksDB and no seed sharing.
|
||||||
Invites can be persistent (default) or limited by TTL / max uses. Revoke peers from Access when devices are lost.
|
Invites can be persistent (default) or limited by TTL / max uses. Revoke peers from Access when devices are lost.
|
||||||
|
Deep dive: <a href="/docs/security">Security model</a>.
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
<h2>Container list empty / “permission denied” on Docker</h2>
|
<h2>Container list empty / “permission denied” on Docker</h2>
|
||||||
|
|||||||
+2
-2
@@ -132,8 +132,8 @@
|
|||||||
</a>
|
</a>
|
||||||
<a class="docs-card" href="/docs/security">
|
<a class="docs-card" href="/docs/security">
|
||||||
<span class="card-tag">Hardening</span>
|
<span class="card-tag">Hardening</span>
|
||||||
<h3>Security & threat model</h3>
|
<h3>Security model</h3>
|
||||||
<p>Assets, trust boundaries, ACL, residual risks, operator checklist.</p>
|
<p>Admin seed proof, pd1 invites, roles, revoke, threat model, checklist.</p>
|
||||||
</a>
|
</a>
|
||||||
<a class="docs-card" href="/docs/api">
|
<a class="docs-card" href="/docs/api">
|
||||||
<span class="card-tag">Reference</span>
|
<span class="card-tag">Reference</span>
|
||||||
|
|||||||
@@ -237,6 +237,10 @@ PEARDOCK_AUDIT=1</code></pre>
|
|||||||
</tbody>
|
</tbody>
|
||||||
</table>
|
</table>
|
||||||
</div>
|
</div>
|
||||||
|
<p>
|
||||||
|
Full model (handshake elevation, capability format, redeem vs reconnect, revoke):
|
||||||
|
<a href="/docs/security">Security model</a>.
|
||||||
|
</p>
|
||||||
|
|
||||||
<h2>Registry vault</h2>
|
<h2>Registry vault</h2>
|
||||||
<p>Credentials encrypted at rest (AES-GCM derived from <code>SERVER_SEED</code>):</p>
|
<p>Credentials encrypted at rest (AES-GCM derived from <code>SERVER_SEED</code>):</p>
|
||||||
|
|||||||
+272
-53
@@ -4,8 +4,8 @@
|
|||||||
<meta charset="UTF-8" />
|
<meta charset="UTF-8" />
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1, viewport-fit=cover" />
|
<meta name="viewport" content="width=device-width, initial-scale=1, viewport-fit=cover" />
|
||||||
<title>Security · PearDock Docs</title>
|
<title>Security · PearDock Docs</title>
|
||||||
<meta name="description" content="PearDock threat model, trust boundaries, controls, residual risks, hardening checklist." />
|
<meta name="description" content="PearDock security model: admin seed proof, viewer default, pd1 invites, roles, revoke, threat model, and hardening." />
|
||||||
<meta name="keywords" content="PearDock security, threat model, ACL, hardening" />
|
<meta name="keywords" content="PearDock security, admin proof, pd1 invite, roles, threat model, ACL, hardening" />
|
||||||
<meta name="author" content="HoneyPeer, LLC" />
|
<meta name="author" content="HoneyPeer, LLC" />
|
||||||
<meta name="robots" content="index, follow, max-image-preview:large, max-snippet:-1, max-video-preview:-1" />
|
<meta name="robots" content="index, follow, max-image-preview:large, max-snippet:-1, max-video-preview:-1" />
|
||||||
<meta name="googlebot" content="index, follow, max-image-preview:large, max-snippet:-1, max-video-preview:-1" />
|
<meta name="googlebot" content="index, follow, max-image-preview:large, max-snippet:-1, max-video-preview:-1" />
|
||||||
@@ -28,7 +28,7 @@
|
|||||||
<meta property="og:locale" content="en_US" />
|
<meta property="og:locale" content="en_US" />
|
||||||
<meta property="og:url" content="https://peardock.boats/docs/security" />
|
<meta property="og:url" content="https://peardock.boats/docs/security" />
|
||||||
<meta property="og:title" content="Security · PearDock Docs" />
|
<meta property="og:title" content="Security · PearDock Docs" />
|
||||||
<meta property="og:description" content="PearDock threat model, trust boundaries, controls, residual risks, hardening checklist." />
|
<meta property="og:description" content="PearDock security model: admin seed proof, viewer default, pd1 invites, roles, revoke, threat model, and hardening." />
|
||||||
<meta property="og:image" content="https://peardock.boats/assets/brand/og-image.png" />
|
<meta property="og:image" content="https://peardock.boats/assets/brand/og-image.png" />
|
||||||
<meta property="og:image:secure_url" content="https://peardock.boats/assets/brand/og-image.png" />
|
<meta property="og:image:secure_url" content="https://peardock.boats/assets/brand/og-image.png" />
|
||||||
<meta property="og:image:type" content="image/png" />
|
<meta property="og:image:type" content="image/png" />
|
||||||
@@ -39,7 +39,7 @@
|
|||||||
<!-- Twitter / X -->
|
<!-- Twitter / X -->
|
||||||
<meta name="twitter:card" content="summary_large_image" />
|
<meta name="twitter:card" content="summary_large_image" />
|
||||||
<meta name="twitter:title" content="Security · PearDock Docs" />
|
<meta name="twitter:title" content="Security · PearDock Docs" />
|
||||||
<meta name="twitter:description" content="PearDock threat model, trust boundaries, controls, residual risks, hardening checklist." />
|
<meta name="twitter:description" content="PearDock security model: admin seed proof, viewer default, pd1 invites, roles, revoke, threat model, and hardening." />
|
||||||
<meta name="twitter:image" content="https://peardock.boats/assets/brand/twitter-card.png" />
|
<meta name="twitter:image" content="https://peardock.boats/assets/brand/twitter-card.png" />
|
||||||
<meta name="twitter:image:alt" content="PearDock: decentralized Docker management" />
|
<meta name="twitter:image:alt" content="PearDock: decentralized Docker management" />
|
||||||
|
|
||||||
@@ -65,7 +65,7 @@
|
|||||||
"TechArticle"
|
"TechArticle"
|
||||||
],
|
],
|
||||||
"name": "Security \u00b7 PearDock Docs",
|
"name": "Security \u00b7 PearDock Docs",
|
||||||
"description": "PearDock threat model, trust boundaries, controls, residual risks, hardening checklist.",
|
"description": "PearDock security model: admin seed proof, viewer default, pd1 invites, roles, revoke, threat model, and hardening.",
|
||||||
"url": "https://peardock.boats/docs/security",
|
"url": "https://peardock.boats/docs/security",
|
||||||
"isPartOf": {
|
"isPartOf": {
|
||||||
"@type": "WebSite",
|
"@type": "WebSite",
|
||||||
@@ -103,13 +103,243 @@
|
|||||||
<button type="button" class="docs-sidebar-toggle" aria-label="Docs menu">☰</button>
|
<button type="button" class="docs-sidebar-toggle" aria-label="Docs menu">☰</button>
|
||||||
|
|
||||||
<article class="docs-main">
|
<article class="docs-main">
|
||||||
<h1>Security & threat model</h1>
|
<h1>Security model</h1>
|
||||||
<p class="docs-lead">
|
<p class="docs-lead">
|
||||||
Audience: operators deploying PearDock in multi-operator or semi-trusted environments.
|
How PearDock authenticates peers: keys in <code>.env</code>, default <strong>viewer</strong>,
|
||||||
Scope: HyperDHT P2P control plane + local Docker Engine socket.
|
admin seed proof, <code>pd1.</code> invites, roles on every RPC method, and revoke.
|
||||||
|
Also: threat model summary and hardening checklist.
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
<h2>1. Assets</h2>
|
<nav class="toc">
|
||||||
|
<strong>On this page</strong>
|
||||||
|
<ol>
|
||||||
|
<li><a href="#overview">Overview</a></li>
|
||||||
|
<li><a href="#keys">Keys in <code>.env</code></a></li>
|
||||||
|
<li><a href="#roles">Roles</a></li>
|
||||||
|
<li><a href="#handshake">Handshake elevation</a></li>
|
||||||
|
<li><a href="#admin">Admin seed proof</a></li>
|
||||||
|
<li><a href="#invites">pd1 invites & capabilities</a></li>
|
||||||
|
<li><a href="#revoke">Registration, reconnect, revoke</a></li>
|
||||||
|
<li><a href="#workflows">Workflows</a></li>
|
||||||
|
<li><a href="#threat">Threat model</a></li>
|
||||||
|
<li><a href="#checklist">Hardening checklist</a></li>
|
||||||
|
</ol>
|
||||||
|
</nav>
|
||||||
|
|
||||||
|
<h2 id="overview">1. Overview</h2>
|
||||||
|
<p>
|
||||||
|
PearDock is a <strong>self-hosted P2P Docker control plane</strong>. There is no central login.
|
||||||
|
Anyone who knows the <strong>server public key</strong> can attempt a HyperDHT dial.
|
||||||
|
That alone must not mean full Docker control — so the default role is <strong>viewer</strong> (read-only).
|
||||||
|
</p>
|
||||||
|
<pre><code>[Desktop client] --Noise/HyperDHT--> [peardock-server] --unix socket--> [dockerd]
|
||||||
|
|
|
||||||
|
+-- /opt/peardock/.env
|
||||||
|
+-- peardock-peers.json
|
||||||
|
+-- peardock-vault.json
|
||||||
|
+-- peardock-audit.log</code></pre>
|
||||||
|
<p>Three legitimate ways in:</p>
|
||||||
|
<div class="table-wrap">
|
||||||
|
<table>
|
||||||
|
<thead>
|
||||||
|
<tr><th>Paste in Add peer</th><th>Access</th></tr>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
<tr><td>Public key only (<code>SERVER_PUBLIC_KEY</code>)</td><td><strong>Viewer</strong> (read-only)</td></tr>
|
||||||
|
<tr><td>Public key + <code>SERVER_SEED</code></td><td><strong>Admin</strong> (seed never sent on the wire)</td></tr>
|
||||||
|
<tr><td>Full <code>pd1.…</code> invite</td><td>Role in the invite — <strong>no seed sharing</strong></td></tr>
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
<p>
|
||||||
|
Canonical long-form doc in the source tree:
|
||||||
|
<a href="https://git.ssh.surf/snxraven/peardock/src/branch/main/docs/SECURITY_AUTH.md" target="_blank" rel="noopener"><code>docs/SECURITY_AUTH.md</code></a>.
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<h2 id="keys">2. Keys live in <code>.env</code></h2>
|
||||||
|
<p>
|
||||||
|
After the first successful start, identity is written to
|
||||||
|
<code>/opt/peardock/.env</code> (mode 600). <strong>Check that file</strong>:
|
||||||
|
</p>
|
||||||
|
<pre><code>sudo grep -E '^(SERVER_PUBLIC_KEY|SERVER_SEED)=' /opt/peardock/.env
|
||||||
|
# or: sudo cat /opt/peardock/.env</code></pre>
|
||||||
|
<div class="table-wrap">
|
||||||
|
<table>
|
||||||
|
<thead>
|
||||||
|
<tr><th>Variable</th><th>Who</th><th>Notes</th></tr>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
<tr>
|
||||||
|
<td><code>SERVER_PUBLIC_KEY</code></td>
|
||||||
|
<td>Safe to share for read-only</td>
|
||||||
|
<td>How clients dial the server over HyperDHT</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td><code>SERVER_SEED</code></td>
|
||||||
|
<td><strong>Admins only</strong></td>
|
||||||
|
<td>Server identity + HMAC MAC key + vault material. Never give to operators.</td>
|
||||||
|
</tr>
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
<p>
|
||||||
|
From the seed, PearDock derives a MAC key (HKDF). That key signs admin proofs and capability grants.
|
||||||
|
The seed itself is <strong>never</strong> transmitted on the wire.
|
||||||
|
Rotating the seed changes the public key; all clients must re-add the peer.
|
||||||
|
</p>
|
||||||
|
<p>
|
||||||
|
Each desktop client also keeps a <strong>stable DHT keypair</strong> (peer id).
|
||||||
|
The server uses that peer id for registration, reconnect, allowlist, and revoke.
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<h2 id="roles">3. Roles</h2>
|
||||||
|
<p>Order: <code>viewer</code> < <code>operator</code> < <code>admin</code>.</p>
|
||||||
|
<p>
|
||||||
|
Every RPC method has a minimum role (<code>MethodRoles</code>). Unknown methods default to
|
||||||
|
<strong>admin</strong> (fail closed). The UI may hide buttons; the <strong>server is authoritative</strong>.
|
||||||
|
</p>
|
||||||
|
<div class="table-wrap">
|
||||||
|
<table>
|
||||||
|
<thead>
|
||||||
|
<tr><th>Role</th><th>Typical powers</th></tr>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
<tr>
|
||||||
|
<td><code>viewer</code></td>
|
||||||
|
<td>List/inspect, logs, stats. No mutate. Cannot manage invites or ACL.</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td><code>operator</code></td>
|
||||||
|
<td>Day-to-day Docker mutate (start/stop, pull, stacks, many Swarm ops, terminals). Still cannot mint invites.</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td><code>admin</code></td>
|
||||||
|
<td>Everything + invite/revoke, vault, destructive prune paths, unrestricted CLI if enabled.</td>
|
||||||
|
</tr>
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
<p>
|
||||||
|
Invite management is <strong>admin-only</strong>:
|
||||||
|
<code>invitePeer</code>, <code>listInvites</code>, <code>deleteInvite</code>,
|
||||||
|
<code>revokePeer</code>, <code>unrevokePeer</code>, <code>clearRevokedPeers</code>.
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<h2 id="handshake">4. Handshake elevation</h2>
|
||||||
|
<p>Baseline role (usually viewer) is resolved from env / admin keys / peer policy. Then handshake may elevate:</p>
|
||||||
|
<ol>
|
||||||
|
<li><strong>adminProof</strong> — seed ownership → admin</li>
|
||||||
|
<li><strong>capability</strong> — HMAC grant from a <code>pd1.</code> invite (or direct token)</li>
|
||||||
|
<li>Otherwise stay at baseline</li>
|
||||||
|
</ol>
|
||||||
|
<div class="callout warn">
|
||||||
|
<div class="callout-icon">!</div>
|
||||||
|
<div class="callout-body">
|
||||||
|
<strong>Fail closed.</strong> If the client presents a capability that is invalid, spent, or expired,
|
||||||
|
and the peer is <em>not</em> already registered as elevated, the handshake <strong>fails</strong>.
|
||||||
|
It does not silently succeed as viewer.
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<p>
|
||||||
|
If a capability fails but this client identity is already registered as operator/admin,
|
||||||
|
reconnect can use the <strong>registered</strong> role so restarts keep working.
|
||||||
|
</p>
|
||||||
|
<p>
|
||||||
|
Optional: <code>PEARDOCK_ADMIN_KEYS</code> (fixed admin peer ids),
|
||||||
|
<code>PEARDOCK_DEFAULT_ROLE</code>, <code>PEARDOCK_PEER_ALLOWLIST=1</code>,
|
||||||
|
<code>PEARDOCK_INSECURE_OPEN_ADMIN=1</code> (dev only — everyone is admin).
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<h2 id="admin">5. Admin seed proof</h2>
|
||||||
|
<p>Goal: prove “I know <code>SERVER_SEED</code>” without sending the seed over the network.</p>
|
||||||
|
<ol>
|
||||||
|
<li>In Add peer, paste public key + <code>SERVER_SEED</code> (from <code>.env</code>).</li>
|
||||||
|
<li>Client derives the same MAC key and builds an HMAC over
|
||||||
|
<code>peardock-admin-v1 || nonce || peerId || serverPublicKey</code>.</li>
|
||||||
|
<li>Server verifies with its seed-derived key (constant-time compare).</li>
|
||||||
|
<li>Success → role <strong>admin</strong>. Failure → <code>ADMIN_PROOF_FAILED</code>.</li>
|
||||||
|
</ol>
|
||||||
|
<p>
|
||||||
|
<strong>Best practice:</strong> only true admins hold the seed.
|
||||||
|
Onboard everyone else with invites. Prefer <code>PEARDOCK_ADMIN_KEYS</code> for fixed admin machines
|
||||||
|
if you do not want to paste the seed on every client.
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<h2 id="invites">6. pd1 invites & capabilities</h2>
|
||||||
|
<p>
|
||||||
|
Invites do <strong>not</strong> use Autopass or RocksDB. They are pure HMAC capability grants
|
||||||
|
packaged as a self-contained share string.
|
||||||
|
</p>
|
||||||
|
<h3>Capability token</h3>
|
||||||
|
<pre><code>base64url(JSON payload) + "." + base64url(HMAC-SHA256(macKey, payload))</code></pre>
|
||||||
|
<p>Payload includes <code>role</code>, <code>jti</code> (unique grant id), <code>exp</code> (or null = never), optional peer bind, and issued-at.</p>
|
||||||
|
<h3>pd1 package</h3>
|
||||||
|
<pre><code>pd1.<base64url JSON { publicKeyHex, capability, role, jti, ... }></code></pre>
|
||||||
|
<p>
|
||||||
|
Operators paste the <strong>full</strong> string in Add peer (never truncate).
|
||||||
|
The client decodes public key + capability and dials with the grant at handshake.
|
||||||
|
</p>
|
||||||
|
<h3>Mint (admin)</h3>
|
||||||
|
<ol>
|
||||||
|
<li>Connect as admin (key + seed).</li>
|
||||||
|
<li><strong>Access → Create invite</strong> (role usually operator).</li>
|
||||||
|
<li>Default: never expires, unlimited uses (persistent). Optionally set TTL / max uses.</li>
|
||||||
|
<li>Copy the full <code>pd1.</code> string and share it (not the seed).</li>
|
||||||
|
</ol>
|
||||||
|
<h3>Redeem (operator)</h3>
|
||||||
|
<ol>
|
||||||
|
<li>Paste full <code>pd1.…</code> in Add peer.</li>
|
||||||
|
<li>Client dials embedded public key and presents the capability.</li>
|
||||||
|
<li>Server verifies HMAC, then <strong>registers</strong> the client peer id with the grant role.</li>
|
||||||
|
</ol>
|
||||||
|
<div class="callout info">
|
||||||
|
<div class="callout-icon">i</div>
|
||||||
|
<div class="callout-body">
|
||||||
|
<strong>Delete invite vs kick a person.</strong>
|
||||||
|
Deleting an invite stops <em>new</em> redemptions of that grant id.
|
||||||
|
An already-registered operator keeps reconnecting until you
|
||||||
|
<strong>revoke their peer id</strong>.
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<h2 id="revoke">7. Registration, reconnect, revoke</h2>
|
||||||
|
<p>State lives in <code>peardock-peers.json</code> (override with <code>PEARDOCK_PEER_POLICY</code>):</p>
|
||||||
|
<ul>
|
||||||
|
<li><code>peers</code> — registered elevated client identities for reconnect</li>
|
||||||
|
<li><code>capabilities</code> — active grants (by jti)</li>
|
||||||
|
<li><code>spentJtis</code> — deleted or exhausted grants</li>
|
||||||
|
<li><code>revoked</code> — hard ban list of peer ids</li>
|
||||||
|
</ul>
|
||||||
|
<p>
|
||||||
|
After a successful elevate, reconnect can use the registered role even if that invite jti is later deleted.
|
||||||
|
To remove access for a lost laptop: <strong>Access → revoke</strong> that peer.
|
||||||
|
Unrevoke / clear revoked are admin recovery tools.
|
||||||
|
</p>
|
||||||
|
<p>
|
||||||
|
Common error codes: <code>CAPABILITY_INVALID</code>, <code>CAPABILITY_EXPIRED</code>,
|
||||||
|
<code>CAPABILITY_SPENT</code>, <code>ADMIN_PROOF_FAILED</code>, <code>PERMISSION_DENIED</code>.
|
||||||
|
If a saved peer still holds a stale spent capability, paste a <strong>new full pd1 invite</strong>
|
||||||
|
or clear the cached grant.
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<h2 id="workflows">8. Workflows</h2>
|
||||||
|
<h3>Single admin</h3>
|
||||||
|
<ol>
|
||||||
|
<li>Install server; read keys from <code>/opt/peardock/.env</code>.</li>
|
||||||
|
<li>Add peer with public key + <code>SERVER_SEED</code> → admin.</li>
|
||||||
|
</ol>
|
||||||
|
<h3>Multi-operator (recommended)</h3>
|
||||||
|
<ol>
|
||||||
|
<li>Admin connects with seed proof.</li>
|
||||||
|
<li>Access → Create invite → share full <code>pd1.</code> string only.</li>
|
||||||
|
<li>Operator pastes invite → operator role; peer registered.</li>
|
||||||
|
<li>Lost device → revoke peer id. Leaked unused invite → delete invite, mint new one.</li>
|
||||||
|
</ol>
|
||||||
|
<h3>Viewer guest</h3>
|
||||||
|
<p>Share only <code>SERVER_PUBLIC_KEY</code>. Observe-only.</p>
|
||||||
|
|
||||||
|
<h2 id="threat">9. Threat model (summary)</h2>
|
||||||
|
<h3>Assets</h3>
|
||||||
<div class="table-wrap">
|
<div class="table-wrap">
|
||||||
<table>
|
<table>
|
||||||
<thead>
|
<thead>
|
||||||
@@ -119,37 +349,21 @@
|
|||||||
<tr><td><code>SERVER_SEED</code></td><td>Critical: identity and vault key derivation</td></tr>
|
<tr><td><code>SERVER_SEED</code></td><td>Critical: identity and vault key derivation</td></tr>
|
||||||
<tr><td>Docker socket access</td><td>Critical: full host container control</td></tr>
|
<tr><td>Docker socket access</td><td>Critical: full host container control</td></tr>
|
||||||
<tr><td>Registry passwords (vault)</td><td>High: encrypted at rest</td></tr>
|
<tr><td>Registry passwords (vault)</td><td>High: encrypted at rest</td></tr>
|
||||||
<tr><td>HMAC capability grants / <code>pd1.</code> invites</td><td>Medium: elevated access without seed (TTL / max uses optional)</td></tr>
|
<tr><td>HMAC capability grants / <code>pd1.</code> invites</td><td>Medium: elevated access without seed</td></tr>
|
||||||
<tr><td>Audit log</td><td>Medium: forensic integrity</td></tr>
|
<tr><td>Audit log</td><td>Medium: forensic integrity</td></tr>
|
||||||
<tr><td>Container data / env secrets</td><td>High: via inspect, logs, exec</td></tr>
|
<tr><td>Container data / env secrets</td><td>High: via inspect, logs, exec</td></tr>
|
||||||
</tbody>
|
</tbody>
|
||||||
</table>
|
</table>
|
||||||
</div>
|
</div>
|
||||||
|
<h3>Adversaries</h3>
|
||||||
<h2>2. Trust boundaries</h2>
|
|
||||||
<pre><code>[Client] --Noise/HyperDHT--> [peardock server] --unix socket--> [dockerd]
|
|
||||||
|
|
|
||||||
+-- peardock-vault.json (AES-GCM)
|
|
||||||
+-- peardock-peers.json
|
|
||||||
+-- peardock-audit.log</code></pre>
|
|
||||||
<ul>
|
|
||||||
<li><strong>Anyone with the server public key</strong> can attempt a DHT connection.</li>
|
|
||||||
<li><strong>Default role is viewer (read-only)</strong> unless elevated via admin seed proof, HMAC capability (<code>pd1.</code> invite), <code>PEARDOCK_ADMIN_KEYS</code>, peer policy, or <code>PEARDOCK_INSECURE_OPEN_ADMIN=1</code>.</li>
|
|
||||||
<li>Swarm is on by default (<code>ENABLE_SWARM=0</code> to disable). Plugins are off unless <code>ENABLE_PLUGINS=1</code>.</li>
|
|
||||||
<li>Holesail tunnels are on by default. Each <code>hs://</code> URL is a port capability.</li>
|
|
||||||
<li>Host FS browse is default-deny unless browse roots / open mode are set.</li>
|
|
||||||
</ul>
|
|
||||||
|
|
||||||
<h2>3. Adversaries</h2>
|
|
||||||
<ol>
|
<ol>
|
||||||
<li><strong>Remote peer with public key only:</strong> gets <strong>viewer</strong> only (read-only lists/inspect/logs).</li>
|
<li><strong>Public key only:</strong> viewer (read-only).</li>
|
||||||
<li><strong>Stolen <code>pd1.</code> invite / capability:</strong> limited by TTL / max uses + HMAC; revoke peer after redeem.</li>
|
<li><strong>Stolen pd1 invite:</strong> can elevate until delete/spend/expire; revoke peer after redeem.</li>
|
||||||
<li><strong>Compromised client:</strong> can use any role the peer holds until revoke.</li>
|
<li><strong>Compromised client:</strong> holds that role until revoke.</li>
|
||||||
<li><strong>Local host attacker with filesystem:</strong> can steal seed and vault if file perms are wrong — keep <code>/opt/peardock/.env</code> mode 600.</li>
|
<li><strong>Local filesystem on server:</strong> can steal seed if <code>.env</code> perms are wrong.</li>
|
||||||
<li><strong>Malicious container:</strong> out of scope for PearDock. Engine isolation applies.</li>
|
<li><strong>Malicious container:</strong> out of scope for PearDock; Engine isolation applies.</li>
|
||||||
</ol>
|
</ol>
|
||||||
|
<h3>Controls</h3>
|
||||||
<h2>4. Controls (implemented)</h2>
|
|
||||||
<div class="table-wrap">
|
<div class="table-wrap">
|
||||||
<table>
|
<table>
|
||||||
<thead>
|
<thead>
|
||||||
@@ -158,42 +372,47 @@
|
|||||||
<tbody>
|
<tbody>
|
||||||
<tr><td>Transport E2E</td><td>HyperDHT Noise</td></tr>
|
<tr><td>Transport E2E</td><td>HyperDHT Noise</td></tr>
|
||||||
<tr><td>Capability ACL</td><td>viewer / operator / admin + MethodRoles</td></tr>
|
<tr><td>Capability ACL</td><td>viewer / operator / admin + MethodRoles</td></tr>
|
||||||
<tr><td>Default role</td><td><strong>viewer</strong>; elevate via seed HMAC or <code>pd1.</code> invite</td></tr>
|
<tr><td>Default role</td><td><strong>viewer</strong>; elevate via seed HMAC or pd1 invite</td></tr>
|
||||||
<tr><td>Admin proof</td><td>HMAC-SHA256 from <code>SERVER_SEED</code> (seed never on the wire)</td></tr>
|
<tr><td>Admin proof</td><td>HMAC-SHA256 from <code>SERVER_SEED</code> (seed never on the wire)</td></tr>
|
||||||
<tr><td><code>pd1.</code> invites</td><td>Self-contained public key + capability share string (no vault DB)</td></tr>
|
<tr><td>pd1 invites</td><td>Self-contained public key + capability (no vault DB)</td></tr>
|
||||||
<tr><td>Peer policy</td><td>Register, revoke, capability jti spend, optional allowlist</td></tr>
|
<tr><td>Peer policy</td><td>Register, revoke, jti spend, optional allowlist</td></tr>
|
||||||
<tr><td>Audit</td><td>Append-only log for privileged methods</td></tr>
|
<tr><td>Audit / rate limit</td><td>Privileged method log; per-peer limiter</td></tr>
|
||||||
<tr><td>Rate limit</td><td>Per-peer limiter on RPC</td></tr>
|
<tr><td>Registry vault</td><td>AES-256-GCM</td></tr>
|
||||||
<tr><td>Registry secrets</td><td>AES-256-GCM vault</td></tr>
|
<tr><td>Browse FS / tunnels</td><td>Default-deny browse; loopback / allowlisted tunnel targets</td></tr>
|
||||||
<tr><td>Browse FS</td><td>Root allowlist / default deny</td></tr>
|
|
||||||
<tr><td>Tunnel targets</td><td>Loopback / allowlisted hosts only</td></tr>
|
|
||||||
</tbody>
|
</tbody>
|
||||||
</table>
|
</table>
|
||||||
</div>
|
</div>
|
||||||
|
<h3>Residual risks</h3>
|
||||||
<h2>5. Residual risks</h2>
|
|
||||||
<ul>
|
<ul>
|
||||||
<li><strong>Default viewer</strong> is intentional for production. Use <code>PEARDOCK_INSECURE_OPEN_ADMIN=1</code> only for single-operator dev.</li>
|
<li><strong>Default viewer</strong> is intentional. Use <code>PEARDOCK_INSECURE_OPEN_ADMIN=1</code> only for single-operator dev.</li>
|
||||||
<li>Binary image/export streams are size-capped but still large; DoS via memory if many concurrent transfers.</li>
|
<li>Persistent invites are powerful; tighten maxUses/TTL when sharing widely.</li>
|
||||||
<li>JSON-over-RPC relies on handler validation (not full hyperschema end-to-end).</li>
|
<li>Large binary transfers can stress memory under many concurrent jobs.</li>
|
||||||
<li>Swarm secrets/configs once enabled are highly privileged.</li>
|
<li>Swarm secrets/configs, once enabled, are highly privileged.</li>
|
||||||
</ul>
|
</ul>
|
||||||
|
|
||||||
<h2>6. Operator hardening checklist</h2>
|
<h2 id="checklist">10. Operator hardening checklist</h2>
|
||||||
<ul>
|
<ul>
|
||||||
<li>After install, confirm keys in <code>/opt/peardock/.env</code> (<code>SERVER_PUBLIC_KEY</code>, <code>SERVER_SEED</code>); back up seed offline; never commit <code>.env</code></li>
|
<li>After install, confirm keys in <code>/opt/peardock/.env</code>; back up seed offline; never commit <code>.env</code></li>
|
||||||
<li>Connect as admin with public key + <code>SERVER_SEED</code> in the client (seed is session-only)</li>
|
<li>Connect as admin with public key + <code>SERVER_SEED</code> (seed is session-local)</li>
|
||||||
<li>Share operators via Access → <code>pd1.</code> invite (never share <code>SERVER_SEED</code>)</li>
|
<li>Share operators via Access → full <code>pd1.</code> invite (never share <code>SERVER_SEED</code>)</li>
|
||||||
<li>Confirm public-key-only peers are viewer (read-only)</li>
|
<li>Confirm public-key-only peers are viewer</li>
|
||||||
<li>Set <code>PEARDOCK_ADMIN_KEYS=<your client public key hex></code> for fixed admin machines (optional)</li>
|
<li>Optional: <code>PEARDOCK_ADMIN_KEYS</code> for fixed admin machines</li>
|
||||||
<li>Enable <code>PEARDOCK_PEER_ALLOWLIST=1</code> after registering operators</li>
|
<li>Enable <code>PEARDOCK_PEER_ALLOWLIST=1</code> after registering operators</li>
|
||||||
<li>Do <strong>not</strong> set <code>PEARDOCK_INSECURE_OPEN_ADMIN</code> in production</li>
|
<li>Do <strong>not</strong> set <code>PEARDOCK_INSECURE_OPEN_ADMIN</code> in production</li>
|
||||||
<li>Set <code>PEARDOCK_BROWSE_ROOTS</code> only if host path pickers are needed</li>
|
<li>Set <code>PEARDOCK_BROWSE_ROOTS</code> only if host path pickers are needed</li>
|
||||||
<li>Enable <code>PEARDOCK_AUDIT=1</code></li>
|
<li>Enable <code>PEARDOCK_AUDIT=1</code></li>
|
||||||
<li>Treat <code>hs://</code> tunnel URLs as secrets; set <code>ENABLE_HOLESAIL=0</code> if unused</li>
|
<li>Treat <code>hs://</code> tunnel URLs as secrets; set <code>ENABLE_HOLESAIL=0</code> if unused</li>
|
||||||
<li>File mode <code>600</code> on vault, peer policy, tunnels, audit, <code>.env</code>, identity</li>
|
<li>File mode <code>600</code> on vault, peer policy, tunnels, audit, <code>.env</code>, identity</li>
|
||||||
|
<li>Revoke lost client peer ids immediately</li>
|
||||||
</ul>
|
</ul>
|
||||||
|
|
||||||
|
<p>
|
||||||
|
Install and multi-op steps:
|
||||||
|
<a href="/docs/operator">Operator guide</a> ·
|
||||||
|
<a href="/docs/quickstart">Quick start</a> ·
|
||||||
|
<a href="/docs/api">RPC & API</a>
|
||||||
|
</p>
|
||||||
|
|
||||||
<div class="docs-pager">
|
<div class="docs-pager">
|
||||||
<a href="/docs/holesail"><span>Previous</span><strong>← Holesail</strong></a>
|
<a href="/docs/holesail"><span>Previous</span><strong>← Holesail</strong></a>
|
||||||
<a class="next" href="/docs/api"><span>Next</span><strong>RPC & API →</strong></a>
|
<a class="next" href="/docs/api"><span>Next</span><strong>RPC & API →</strong></a>
|
||||||
|
|||||||
Reference in New Issue
Block a user