Skip to content

Commit b9ca5af

Browse files
committed
Docs: Record TLS bridge protocol/port coverage + non-goals
Add an explicit 'Protocol & port coverage' section to the design spec: the bridge is HTTPS-inspection (TLS + configured port + trusted CA), not general egress inspection. Tabulates the no-visibility categories (non-TLS TCP like SSH/DBs, TLS on non-standard ports, STARTTLS, non-TCP/QUIC, un-MITM-able pinned/mTLS/ECH), documents why the port gate is load-bearing (ServeConn assumes HTTP; bridging non-HTTP TLS like LDAPS/SMTPS would break the conn), and names connection-level egress policy as the backstop. Records envoy-sidecar bridging and non-HTTP protocols as non-goals. Signed-off-by: Hai Huang <huang195@gmail.com>
1 parent 26b3f57 commit b9ca5af

1 file changed

Lines changed: 40 additions & 0 deletions

File tree

authbridge/docs/superpowers/specs/2026-06-12-authbridge-tlsbridge-design.md

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,46 @@ impersonate the remote origin so the agent's TLS terminates at AuthBridge. That
5050
> first cut may exist transiently during implementation, but h2 is a prerequisite for enabling MITM by
5151
> default — it is not a fast-follow.)
5252
53+
## Protocol & port coverage (scope — what the bridge does NOT see)
54+
55+
The TLS bridge is an **HTTPS-inspection** mechanism, not a general egress-inspection guarantee. It yields
56+
decrypted, pipeline-visible traffic only when **all** of these hold: the connection is **TCP**, on a
57+
**configured bridge port** (default `{443, 8443}`), the first bytes are a **TLS ClientHello** record, and the
58+
agent **trusts the forged CA**. Everything outside that envelope is either tunneled opaquely (still egresses;
59+
the pipeline sees only `host:port` via the per-connection egress gate) or dropped. The categories with **no
60+
content visibility**:
61+
62+
| Category | Examples | Why blind | Outcome |
63+
|---|---|---|---|
64+
| **Non-TLS TCP** | SSH (22); plaintext DB (Postgres 5432, MySQL 3306, Redis 6379, Mongo 27017); SMTP/IMAP/FTP/LDAP; raw/custom TCP; h2c | first bytes ≠ TLS ClientHello → `non-tls`; usually non-bridge port → `port` | tunneled |
65+
| **TLS on non-standard ports** | LDAPS 636, SMTPS 465, IMAPS 993, AMQPS 5671, MQTTS 8883, DB-over-TLS, custom HTTPS on `:9443` etc. | port not in the bridge set → `port` (configurable) | tunneled |
66+
| **STARTTLS** | SMTP/IMAP/POP3/LDAP/XMPP/Postgres plaintext→TLS upgrade | connection opens plaintext; the 5-byte peek isn't a ClientHello → `non-tls` | tunneled |
67+
| **Non-TCP** | QUIC / HTTP-3 (UDP 443), DTLS, WireGuard/IPsec/VPN | `enforce-redirect` DROPs external non-TCP | **dropped** (forces TCP fallback for QUIC; a no-fallback client fails) |
68+
| **Un-MITM-able TLS** | cert-pinned clients; client-cert/mTLS to the origin; ECH / encrypted-SNI | leaf rejected / upstream-verify fails / SNI unreadable → fail open | tunneled (auto-skip) |
69+
70+
**Why the port gate is load-bearing (not just perf).** The downstream serving layer (`ServeConn`) parses the
71+
decrypted bytes as **HTTP/1.1 or h2**. TLS on `443`/`8443` is ~always HTTP(S); TLS on `636`/`465`/`5671`/DB
72+
ports is **not** HTTP. Bridging those would terminate the connection and then fail to serve non-HTTP wire bytes
73+
as HTTP → a **broken** agent connection (the upstream-verify `HEAD` probe usually rejects a non-HTTP origin and
74+
makes us fall open, but that is a fragile net that also sprays `HEAD /` at non-HTTP services). The port gate
75+
keeps interception **HTTP-only by operator intent**. To inspect HTTPS on an extra port, **widen the configured
76+
port set** (`Decision.Ports` is arbitrary; expose a `ports:` config key) — do **not** bridge all ports.
77+
78+
**Non-goals (coverage):**
79+
- **Non-HTTP protocols** (SSH, databases, SMTP/LDAP/AMQP/MQTT, raw TCP) — out of scope; inspecting/controlling
80+
them needs a protocol-aware proxy/bastion or, for *control without decryption*, connection-level egress
81+
policy.
82+
- **STARTTLS upgrade detection** — out of scope (the first-byte heuristic intentionally does not track
83+
mid-connection upgrades).
84+
- **envoy-sidecar bridging** — out of scope; it would need a separate Envoy-data-plane mechanism (dynamic
85+
per-SNI leaf issuance via SDS/filter + terminate/originate config), not this Go-proxy bridge. The operator
86+
rejects `tlsBridgeMode=enabled` with `envoy-sidecar` at admission. A future "Phase 3" if a real need arises.
87+
88+
**The backstop is connection-level egress policy.** Allow/deny by `host:port` *without* decryption, enforced at
89+
the per-connection egress gate that already runs on every captured connection (it sees the destination even
90+
when it cannot read the payload). That layer covers SSH, databases, STARTTLS, odd-port TLS, and pinned/mTLS
91+
traffic, and composes with the bridge: the bridge decrypts what it can (HTTPS), policy gates the rest.
92+
5393
## Design decisions
5494

5595
| Topic | Decision |

0 commit comments

Comments
 (0)