readme: add e2ee section
Kim committed
Mar 25, 2026 at 16:45 UTC
1661436f70d1e72f4abd202ad541c9c1fb35c421
6 files changed
+14
-195
README.md
+14
-1
@@ -18,11 +18,24 @@ Unlike other tunneling services, Portal is self-hosted and permissionless. You c
18
19
- **NAT-friendly connectivity**: Works behind NAT or firewalls without opening inbound ports
20
- **Automatic subdomain routing**: Gives each app its own subdomain (`your-app.<base-domain>`)
21
-- **End-to-end encryption**: Supports TLS passthrough with relay keyless certificates
21
+- **End-to-end tenant TLS**: Relay routes by SNI, while tenant TLS terminates on your side with relay-backed keyless signing
22
- **Permissionless Hosting**: Anyone can run their own Portal — no approval needed
23
- **One-Command Setup**: Expose any local app with a single command
24
- **UDP Relay (Experimental)**: Supports raw UDP relay use cases, but the transport model and operational behavior may still change
25
26
+## How Portal Provides End-to-End Encryption
27
+
28
+Portal is designed so that tenant TLS terminates on your side rather than at the relay. In the normal data path, the relay forwards encrypted traffic without access to tenant TLS plaintext.
29
+
30
+1. The relay accepts the public connection and reads only the TLS ClientHello required for SNI-based routing.
31
+2. It forwards the tenant connection as raw encrypted bytes over the reverse session without terminating tenant TLS.
32
+3. The Portal client on your side acts as the TLS server and completes the tenant handshake locally.
33
+4. For relay-hosted domains, the Portal client obtains certificate signatures via `/v1/sign`, using the relay only as a keyless signing oracle.
34
+5. Session keys are derived entirely on your side. The relay provides certificate signatures only and does not receive tenant traffic secrets.
35
+6. After the handshake, the relay continues forwarding ciphertext without needing tenant TLS plaintext to keep routing traffic.
36
+
37
+Portal also checks that the relay is preserving TLS passthrough. The Portal client connects to its own public endpoint and compares TLS exporter values observed on both client-controlled ends. If they differ, Portal treats the relay as a suspected TLS terminator, closes the listener, and bans that relay for the current exposure.
38
+
39
## Components
40
41
- **Relay**: A server that routes public requests to the right connected app.
docs/adr/0001-raw-tcp-reverse-connect-and-autocert-tls.md
deleted
-42
@@ -1,42 +0,0 @@
1
-# ADR 0001: Raw TCP Reverse Connect and ACME TLS for Portal Root
2
-
3
-- Status: `Accepted`
4
-- Date: `2026-03-03`
5
-- Owners: `Portal maintainers`
6
-
7
-## Context
8
-
9
-Portal must support NAT-friendly inbound connectivity for tenant traffic while keeping root-domain behavior predictable. The legacy approach mixed websocket assumptions into reverse-connect flow and derived TLS hosts inconsistently for non-apex portal domains.
10
-
11
-## Decision
12
-
13
-- Use raw TCP reverse-connect as the canonical transport between relay and tunnel clients.
14
-- Keep SNI routing as the ingress split for tenant subdomains.
15
-- Keep root-domain fallback forwarding from SNI router to the admin/API listener.
16
-- Derive relay `BaseHost` and TLS domain construction from the full portal root host (for example `portal.example.com`), not apex extraction (`example.com`).
17
-- Serve admin/API exclusively over TLS using ACME/local certificate material; no HTTP fallback path.
18
-
19
-## Consequences
20
-
21
-### Benefits
22
-
23
-- Reverse-connect transport stays NAT-friendly and removes proxy protocol ambiguity.
24
-- Root-domain behavior remains explicit: SNI fallback forwards to admin/API listener.
25
-- SNI route registration, public URL derivation, and SDK TLS domain construction align on the same host derivation.
26
-
27
-### Trade-offs
28
-
29
-- Startup availability depends on certificate material being present and loadable.
30
-- Non-apex portal host deployments require wildcard coverage on the full portal root host (for example `*.portal.example.com`).
31
-
32
-### Risks and Mitigations
33
-
34
-- Risk: certificate files unavailable or invalid at startup.
35
- Mitigation: fail fast during startup and surface explicit operator diagnostics; do not downgrade to HTTP.
36
-- Risk: non-apex portal host deployments route to wrong TLS host if derivation drifts.
37
- Mitigation: enforce portal-root-host derivation consistently in relay and SDK.
38
-
39
-## Alternatives Considered
40
-
41
-- Keep websocket reverse-connect transport for compatibility: rejected due to complexity and policy drift.
42
-- Derive SNI routes from apex/base domain only: rejected due to `portal.example.com` mismatch failures.
docs/adr/0002-remove-websocket-and-legacy-compatibility.md
deleted
-40
@@ -1,40 +0,0 @@
1
-# ADR 0002: Remove WebSocket and Legacy Compatibility Paths
2
-
3
-- Status: `Accepted`
4
-- Date: `2026-03-03`
5
-- Owners: `Portal maintainers`
6
-
7
-## Context
8
-
9
-Portal transport and registration flows previously carried compatibility behavior for websocket-era clients. This increased code-path count, made failure handling inconsistent, and obscured the canonical tunnel behavior.
10
-
11
-## Decision
12
-
13
-- Treat raw TCP reverse-connect as the only supported data-plane transport.
14
-- Remove websocket compatibility expectations from architecture guidance and operational assumptions.
15
-- Keep SDK registration APIs aligned with current raw transport behavior only.
16
-
17
-## Consequences
18
-
19
-### Benefits
20
-
21
-- Fewer protocol paths to secure, test, and debug.
22
-- Clearer invariants for lease registration, route updates, and reverse-hub acquisition.
23
-- Lower maintenance cost by removing compatibility-only logic from design decisions.
24
-
25
-### Trade-offs
26
-
27
-- Older websocket-based clients are intentionally unsupported.
28
-- Migration burden moves to client operators that still depend on websocket semantics.
29
-
30
-### Risks and Mitigations
31
-
32
-- Risk: clients attempt deprecated websocket workflows and fail unexpectedly.
33
- Mitigation: keep docs explicit that raw TCP is the single supported transport and reject unsupported paths clearly.
34
-- Risk: hidden compatibility assumptions in future changes.
35
- Mitigation: use this ADR as a gate in design/review to avoid reintroducing websocket dependencies.
36
-
37
-## Alternatives Considered
38
-
39
-- Keep dual-stack (raw TCP + websocket): rejected due to complexity and security surface growth.
40
-- Keep websocket as fallback only: rejected because fallback behavior still multiplies test and incident scenarios.
docs/adr/0003-security-and-anti-abuse-hardening.md
deleted
-55
@@ -1,55 +0,0 @@
1
-# ADR 0003: Security and Anti-Abuse Hardening
2
-
3
-- Status: `Deprecated`
4
-- Date: `2026-03-03`
5
-- Owners: `Portal maintainers`
6
-
7
-## Context
8
-
9
-Portal accepts unauthenticated internet traffic on relay/admin edges while managing long-lived reverse tunnel sessions. Abuse controls and security boundaries must be first-class or operational risk rises quickly.
10
-
11
-This ADR captured a broader policy/bans/admin-settings model than the current runtime now implements.
12
-Keep it as historical context only. Current descriptive docs and `AGENTS.md` are the source for the simplified runtime behavior until a replacement ADR is written.
13
-
14
-## Decision
15
-
16
-- Treat admin-authenticated controls (approval, settings, bans) as authoritative for runtime policy.
17
-- Wire IP ban checks into SDK registration and reverse-connection acceptance paths.
18
-- Enforce lease-token validation before bridging reverse connections.
19
-- Keep root-domain and tenant-subdomain traffic split through SNI routing rules to prevent accidental cross-path handling.
20
-- Standardize SDK endpoint handling: `/sdk/register` (and related SDK APIs) and `/sdk/connect` validation failures return JSON envelopes (`{ ok, error }`) with explicit error codes prior to connection hijack, and `/sdk/connect` remains subject to `ReverseHub` authorization before pooling.
21
-- Use token-only admission on `/sdk/register`, `/sdk/connect`, `/sdk/renew`, and `/sdk/unregister` with deterministic order `IP -> Lease -> Token`.
22
-- Do not request or validate client certificates for `/sdk/*` runtime admission; authorization is enforced by lease token and policy checks.
23
-- Enforce installer binary integrity with mandatory SHA256 sidecar verification (`${BIN_URL}.sha256`) and fail-closed behavior on verification errors.
24
-
25
-Operator setup remains unchanged: no new relay flags/env vars are introduced for anti-abuse behavior.
26
-
27
-## Consequences
28
-
29
-### Benefits
30
-
31
-- Faster blocking response to abusive sources with centralized IP policy.
32
-- Stronger boundary between control-plane actions and data-plane forwarding.
33
-- Reduced chance of unauthorized reverse-connection use.
34
-
35
-### Trade-offs
36
-
37
-- Extra checks in critical paths may increase operational complexity during debugging.
38
-- Incorrect ban-list management can block legitimate clients if policy operations are misused.
39
-- SDK clients must classify `/sdk/connect` rejection codes and statuses into fatal vs retryable outcomes for stable reverse-worker behavior.
40
-
41
-### Risks and Mitigations
42
-
43
-- Risk: policy drift between admin state and runtime enforcement.
44
- Mitigation: initialize runtime components from admin-managed settings and keep a single IP manager source.
45
-- Risk: abuse pressure shifts from one endpoint to another.
46
- Mitigation: enforce checks at multiple ingress points (SDK registration and reverse-hub admission).
47
-- Risk: policy behavior drift from operator confusion.
48
- Mitigation: keep policy source single-owner (`admin` settings + IP manager) and document that operator bootstrap/setup remains stable.
49
-- Risk: accidental weakening during refactors.
50
- Mitigation: require explicit ADR-aware review for security-sensitive path changes.
51
-
52
-## Alternatives Considered
53
-
54
-- Endpoint-local ad hoc checks only: rejected because policy diverges and creates inconsistent enforcement.
55
-- Rely solely on external perimeter controls: rejected because application-level lease/auth context is required for accurate decisions.
docs/adr/README.md
deleted
-23
@@ -1,23 +0,0 @@
1
-# Architecture Decision Records (ADR)
2
-
3
-This directory is the source of truth for major Portal architecture decisions.
4
-
5
-## Status Values
6
-
7
-- `Accepted`: active and expected in current code paths
8
-- `Superseded`: replaced by a newer ADR
9
-- `Deprecated`: still present but planned for removal
10
-- `Proposed`: under review, not yet implemented
11
-
12
-## ADR Index
13
-
14
-- [0001 - Raw TCP Reverse Connect and ACME TLS for Portal Root](./0001-raw-tcp-reverse-connect-and-autocert-tls.md) (`Accepted`)
15
-- [0002 - Remove WebSocket and Legacy Compatibility Paths](./0002-remove-websocket-and-legacy-compatibility.md) (`Accepted`)
16
-- [0003 - Security and Anti-Abuse Hardening](./0003-security-and-anti-abuse-hardening.md) (`Deprecated`)
17
-- [0004 - QUIC-Based UDP Transport](./0004-quic-udp-transport.md) (`Accepted`)
18
-
19
-## Authoring Notes
20
-
21
-- Use [template.md](./template.md) for new ADRs.
22
-- Keep each ADR focused on one decision and its consequences.
23
-- Update this index whenever adding, superseding, or deprecating an ADR.
docs/adr/template.md
deleted
-34
@@ -1,34 +0,0 @@
1
-# ADR XXXX: <Title>
2
-
3
-- Status: `Proposed|Accepted|Superseded|Deprecated`
4
-- Date: `YYYY-MM-DD`
5
-- Owners: `<team or maintainer>`
6
-
7
-## Context
8
-
9
-Describe the problem, constraints, and why a decision is required.
10
-
11
-## Decision
12
-
13
-State the final decision in concrete terms.
14
-
15
-## Consequences
16
-
17
-### Benefits
18
-
19
-- <benefit 1>
20
-- <benefit 2>
21
-
22
-### Trade-offs
23
-
24
-- <trade-off 1>
25
-- <trade-off 2>
26
-
27
-### Risks and Mitigations
28
-
29
-- Risk: <risk>
30
- Mitigation: <mitigation>
31
-
32
-## Alternatives Considered
33
-
34
-- `<alternative>`: reason rejected