feat: compress connection keys (rtun2) for easier copy/paste
This commit is contained in:
@@ -39,7 +39,7 @@ Creates: `ca.pem`, `ca.key`, `server.crt`, `server.key`, `client.crt`, `client.k
|
||||
|
||||
### `keygen`
|
||||
|
||||
Generate a single reusable connection key string. This bundles all certificate material, the auth token, and the target address into a base64-encoded JSON blob prefixed with `rtun1.`.
|
||||
Generate a single reusable connection key string. This bundles all certificate material, the auth token, and the target address into a base64url-encoded, DEFLATE-compressed JSON blob prefixed with `rtun2.`.
|
||||
|
||||
### `version`
|
||||
|
||||
|
||||
@@ -8,11 +8,19 @@ Simplify distribution of tunnel credentials between machines. Instead of transfe
|
||||
|
||||
## Format
|
||||
|
||||
Connection keys start with the prefix `rtun1.` followed by base64url-encoded (no padding) JSON:
|
||||
Connection keys start with the prefix `rtun2.` followed by base64url-encoded (no
|
||||
padding) **DEFLATE-compressed** JSON:
|
||||
|
||||
```
|
||||
rtun2.<base64url(deflate(json))>
|
||||
```
|
||||
|
||||
The JSON payload is compressed with DEFLATE (`miniz_oxide`) before base64url-encoding
|
||||
to keep the key short enough to copy and paste comfortably. Example payload:
|
||||
|
||||
```json
|
||||
{
|
||||
"version": 1,
|
||||
"version": 2,
|
||||
"target": "198.51.100.10:4180",
|
||||
"ca_cert_pem": "-----BEGIN CERTIFICATE-----...",
|
||||
"server_cert_pem": "-----BEGIN CERTIFICATE-----...",
|
||||
@@ -28,20 +36,23 @@ Connection keys start with the prefix `rtun1.` followed by base64url-encoded (no
|
||||
| Type | File | Description |
|
||||
| ---- | ---- | ----------- |
|
||||
| `ConnectionKey` | `src/connkey.rs` | Struct with all fields, version check, validation |
|
||||
| `ConnectionKey::encode` | `src/connkey.rs` | Serialize to JSON, base64url-encode, prepend prefix |
|
||||
| `ConnectionKey::decode` | `src/connkey.rs` | Strip prefix, base64url-decode, deserialize, validate |
|
||||
| `looks_like_connection_key` | `src/connkey.rs` | Quick check if a string starts with `rtun1.` |
|
||||
| `ConnectionKey::encode` | `src/connkey.rs` | Serialize to JSON, DEFLATE-compress, base64url-encode, prepend prefix |
|
||||
| `ConnectionKey::decode` | `src/connkey.rs` | Strip prefix, base64url-decode, DEFLATE-decompress, deserialize, validate |
|
||||
| `looks_like_connection_key` | `src/connkey.rs` | Quick check if a string starts with `rtun2.` |
|
||||
|
||||
## Validation
|
||||
|
||||
`decode` validates:
|
||||
|
||||
- Prefix must be `rtun1.`
|
||||
- Prefix must be `rtun2.`
|
||||
- Base64 decoding must succeed
|
||||
- DEFLATE decompression must succeed
|
||||
- JSON deserialization must succeed
|
||||
- Version must be exactly `1`
|
||||
- Version must be exactly `2`
|
||||
- All string fields must be non-empty after trimming
|
||||
|
||||
Legacy `rtun1.` keys are **not** accepted.
|
||||
|
||||
## Integration
|
||||
|
||||
`src/main.rs` uses `ConnectionKey::decode` when the `--connection-key` flag or positional argument is provided. The decoded material is passed to `ServerTlsMaterial::Pem` or `ClientTlsMaterial::Pem` variants, which bypass file loading and use the embedded PEM strings directly.
|
||||
@@ -49,7 +60,7 @@ Connection keys start with the prefix `rtun1.` followed by base64url-encoded (no
|
||||
## Entry points for modification
|
||||
|
||||
- To change the key format or add versioning: modify `src/connkey.rs`.
|
||||
- To add compression or encryption: consider extending the encode/decode pipeline in `ConnectionKey`.
|
||||
- To add encryption: consider extending the encode/decode pipeline in `ConnectionKey`.
|
||||
|
||||
## Key source files
|
||||
|
||||
|
||||
@@ -13,7 +13,7 @@ The project uses a layered error strategy:
|
||||
- The `Redacted` wrapper in `src/redact.rs` must be used before logging any secret.
|
||||
- `Redacted::inner()` and `into_inner()` are marked `#[allow(dead_code)]` to discourage use, but available for file writes.
|
||||
- `is_sensitive()` detects PEM private key blocks. `is_auth_token()` detects long alphanumeric strings.
|
||||
- `is_connection_key()` detects strings starting with `rtun1.`.
|
||||
- `is_connection_key()` detects strings starting with `rtun2.`.
|
||||
|
||||
## Async patterns
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
# Glossary
|
||||
|
||||
**Connection key** — a base64-encoded JSON blob (prefix `rtun1.`) that bundles the CA certificate, server certificate, server key, client certificate, client key, target address, auth token, and version. Generated by `rustunnel keygen` and consumed by `rustunnel listen` and `rustunnel connect`.
|
||||
**Connection key** — a base64url-encoded, DEFLATE-compressed JSON blob (prefix `rtun2.`) that bundles the CA certificate, server certificate, server key, client certificate, client key, target address, auth token, and version. Generated by `rustunnel keygen` and consumed by `rustunnel listen` and `rustunnel connect`.
|
||||
|
||||
**Connector** — the `rustunnel connect` side. Establishes an outbound HTTPS+mTLS connection to the listener, authenticates, then exposes a local SOCKS5 proxy for local applications.
|
||||
|
||||
|
||||
@@ -9,7 +9,7 @@ The tool is designed for local labs, development environments, and controlled te
|
||||
- **Listener** (`rustunnel listen`) — binds an HTTPS server that accepts mTLS connections from connectors, validates an auth token, then upgrades the connection to a persistent binary-framed tunnel.
|
||||
- **Connector** (`rustunnel connect`) — connects to the listener over HTTPS with mTLS, authenticates, then exposes a local SOCKS5 proxy that forwards traffic through the tunnel.
|
||||
- **Credential generation** (`rustunnel generate`) — creates a self-signed CA, server certificate, client certificate, and auth token for a local session.
|
||||
- **Connection keys** (`rustunnel keygen`) — bundles all credential material into a single base64-encoded string that can be copy-pasted between machines.
|
||||
- **Connection keys** (`rustunnel keygen`) — bundles all credential material into a single compressed base64url string that can be copy-pasted between machines.
|
||||
|
||||
## Quick links
|
||||
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
|
||||
```rust
|
||||
pub struct ConnectionKey {
|
||||
pub version: u8, // must be 1
|
||||
pub version: u8, // must be 2
|
||||
pub target: String, // listener address
|
||||
pub ca_cert_pem: String,
|
||||
pub server_cert_pem: String,
|
||||
@@ -15,7 +15,7 @@ pub struct ConnectionKey {
|
||||
}
|
||||
```
|
||||
|
||||
Encoded as: `rtun1.` + base64url(JSON) — no padding.
|
||||
Encoded as: `rtun2.` + base64url(deflate(JSON)) — no padding.
|
||||
|
||||
## Config
|
||||
|
||||
|
||||
@@ -27,6 +27,7 @@
|
||||
| `http-body-util` | 0.1 | HTTP body utilities |
|
||||
| `tower-service` | 0.3 | Service trait (Hyper ecosystem) |
|
||||
| `base64` | 0.22 | Connection key encoding |
|
||||
| `miniz_oxide` | 0.8 | DEFLATE compression for connection keys |
|
||||
| `sha2` | 0.10 | Certificate fingerprinting |
|
||||
| `bytes` | 1 | Byte buffers for framing |
|
||||
| `futures` | 0.3 | Future utilities |
|
||||
|
||||
@@ -33,7 +33,7 @@ The E2E test `auth_required_in_addition_to_mtls` verifies that valid mTLS alone
|
||||
- `redact_config_json()` scrubs sensitive keys from JSON.
|
||||
- `is_sensitive()` detects PEM private key blocks.
|
||||
- `is_auth_token()` detects long alphanumeric strings.
|
||||
- `is_connection_key()` detects strings starting with `rtun1.`.
|
||||
- `is_connection_key()` detects strings starting with `rtun2.`.
|
||||
|
||||
The E2E test `ops_auth_failure_is_actionable_and_redacted` verifies that error messages do not contain raw token values.
|
||||
|
||||
|
||||
Reference in New Issue
Block a user