feat: Add Orthrus documentation for Remote Socket Proxy Agent and its configuration
This commit is contained in:
149
docs/issues/orthrus.md
Normal file
149
docs/issues/orthrus.md
Normal file
@@ -0,0 +1,149 @@
|
||||
# Orthrus: Remote Socket Proxy Agent
|
||||
|
||||
## 1. Overview
|
||||
**Orthrus** is a lightweight, standalone agent designed to run on remote servers. Named after the brother of Cerberus, its job is to guard the remote resource and securely transport it back to Charon.
|
||||
|
||||
It eliminates the need for SSH tunneling or complex port forwarding by utilizing the tunneling protocols managed by Hecate.
|
||||
|
||||
## 2. Operational Logic
|
||||
Orthrus operates in **Reverse Mode**. It does not listen on a public port. Instead, it dials *out* to the tunneling network to connect with Charon.
|
||||
|
||||
### 2.1 Core Functions
|
||||
1. **Docker Socket Proxy:** Securely proxies the remote server's `/var/run/docker.sock` so Charon can auto-discover containers on the remote host.
|
||||
2. **Service Proxy:** Proxies specific localhost ports (e.g., a database on port 5432) over the tunnel.
|
||||
|
||||
## 3. Technical Implementation
|
||||
|
||||
### 3.1 Tech Stack
|
||||
* **Language:** Go (Golang)
|
||||
* **Base Image:** `scratch` or `alpine` (Goal: < 20MB image size)
|
||||
|
||||
### 3.2 Configuration (Environment Variables)
|
||||
Orthrus is configured entirely via Environment Variables for easy Docker Compose deployment.
|
||||
|
||||
| Variable | Description |
|
||||
| :--- | :--- |
|
||||
| `ORTHRUS_NAME` | Unique identifier for this agent (e.g., `vps-london-01`) |
|
||||
| `ORTHRUS_MODE` | `socket` (Docker Socket) or `port` (Specific Port) |
|
||||
| `CHARON_LINK` | The IP/DNS of the main Charon server (e.g., `100.x.y.z:8080` or `charon.example.com`) |
|
||||
| `AUTH_KEY` | A shared secret or JWT generated by Charon to authorize this agent |
|
||||
|
||||
### 3.3 External Connectivity
|
||||
**Orthrus does NOT manage VPNs or network tunnels internally.**
|
||||
|
||||
It relies entirely on the host operating system for network connectivity.
|
||||
1. **User Responsibility**: The user must ensure the host running Orthrus can reach the `CHARON_LINK` address.
|
||||
2. **VPNs**: If you are using Tailscale, WireGuard, or ZeroTier, you must install and configure the VPN client on the **Host OS** (or a sidecar container). Orthrus simply dials the IP provided in `CHARON_LINK`.
|
||||
3. **Reverse Mode**: Orthrus initiates the connection. Charon waits for the incoming handshake. This means you do not need to open inbound ports on the Orthrus side, but Charon must be reachable.
|
||||
|
||||
### 3.4 The "Leash" Protocol (Communication)
|
||||
Orthrus communicates with Charon via a custom gRPC stream or WebSocket called "The Leash."
|
||||
|
||||
1. **Handshake**: Orthrus connects to `Charon:InternalIP`.
|
||||
2. **Auth**: Orthrus presents the `AUTH_KEY`.
|
||||
3. **Registration**: Orthrus tells Charon: *"I have access to Docker Network X and Port Y."*
|
||||
4. **Tunneling**: Charon requests a resource; Orthrus pipes the data securely over "The Leash."
|
||||
|
||||
## 4. Deployment Example (Docker Compose)
|
||||
|
||||
```yaml
|
||||
services:
|
||||
orthrus:
|
||||
image: wikid82/orthrus:latest
|
||||
container_name: orthrus-agent
|
||||
restart: always
|
||||
environment:
|
||||
- ORTHRUS_NAME=remote-media-server
|
||||
- CHARON_LINK=100.x.y.z:8080
|
||||
- AUTH_KEY=ch_xxxxx_secret
|
||||
volumes:
|
||||
- /var/run/docker.sock:/var/run/docker.sock:ro
|
||||
# No ports required!
|
||||
```
|
||||
|
||||
## 5. Security Considerations
|
||||
* **Read-Only Socket**: By default, Orthrus mounts the Docker socket as Read-Only to prevent Charon (or a compromised Charon) from destroying the remote server.
|
||||
* **Mutual TLS (mTLS)**: All communication between Charon and Orthrus should be encrypted via mTLS if not running inside an encrypted VPN (like Tailscale).
|
||||
|
||||
## 6. Implementation Details
|
||||
|
||||
### 6.1 Communication Architecture
|
||||
Orthrus uses a **Reverse Tunnel** architecture established via **WebSockets** with **Yamux** multiplexing.
|
||||
|
||||
1. **Transport**: Secure WebSocket (`wss://`) initiates the connection from Orthrus to Charon. This bypasses inbound firewall rules on the remote network.
|
||||
2. **Multiplexing**: [Yamux](https://github.com/hashicorp/yamux) is used over the WebSocket stream to create multiple logical channels.
|
||||
* **Control Channel (Stream ID 0)**: Handles heartbeats, configuration updates, and command signals.
|
||||
* **Data Channels (Stream ID > 0)**: Ephemeral streams created for each proxied request (e.g., a single HTTP request to the Docker socket or a TCP connection to a database).
|
||||
|
||||
### 6.2 Authentication & Security
|
||||
* **Token-Based Handshake**: The `AUTH_KEY` is passed in the `Authorization` header during the WebSocket Upgrade request.
|
||||
* **mTLS (Mutual TLS)**:
|
||||
* **Charon as CA**: Charon maintains an internal Certificate Authority.
|
||||
* **Enrollment**: On first connect with a valid `AUTH_KEY`, Orthrus generates a private key and sends a CSR. Charon signs it and returns the certificate.
|
||||
* **Rotation**: Orthrus monitors certificate expiry and initiates a renewal request over the Control Channel 24 hours before expiration.
|
||||
* **Encryption**: All traffic is TLS 1.3 encrypted.
|
||||
|
||||
### 6.3 Docker Socket Proxying (The "Muzzle")
|
||||
To prevent security risks, Orthrus does not blindly pipe traffic to `/var/run/docker.sock`. It implements an application-level filter (The "Muzzle"):
|
||||
1. **Parser**: Intercepts HTTP requests destined for the socket.
|
||||
2. **Allowlist**: Only permits safe methods/endpoints (e.g., `GET /v1.xx/containers/json`, `GET /v1.xx/info`).
|
||||
3. **Blocking**: Rejects `POST`, `DELETE`, `PUT` requests (unless explicitly configured to allow specific actions like "Restart Container") with a `403 Forbidden`.
|
||||
|
||||
### 6.4 Heartbeat & Health
|
||||
* **Mechanism**: Orthrus sends a custom "Ping" packet over the Control Channel every 5 seconds.
|
||||
* **Timeout**: Charon expects a "Ping" within 10 seconds. If missed, the agent is marked `Offline`.
|
||||
* **Reconnection**: Orthrus implements exponential backoff (1s, 2s, 4s... max 30s) to reconnect if the link is severed.
|
||||
|
||||
## 7. Protocol Specification ("The Leash")
|
||||
|
||||
### 7.1 Handshake
|
||||
```http
|
||||
GET /api/v1/orthrus/connect HTTP/1.1
|
||||
Host: charon.example.com
|
||||
Upgrade: websocket
|
||||
Connection: Upgrade
|
||||
Authorization: Bearer <AUTH_KEY>
|
||||
X-Orthrus-Version: 1.0.0
|
||||
X-Orthrus-ID: <ORTHRUS_NAME>
|
||||
```
|
||||
|
||||
### 7.2 Message Types (Control Channel)
|
||||
Messages are Protobuf-encoded for efficiency.
|
||||
|
||||
* `HEARTBEAT`: `{ timestamp: int64, load_avg: float, memory_usage: int }`
|
||||
* `PROXY_REQUEST`: Sent by Charon to request a new stream. `{ stream_id: int, target_type: "docker"|"tcp", target_addr: "localhost:5432" }`
|
||||
* `CONFIG_UPDATE`: Sent by Charon to update allowlists or rotation policies.
|
||||
|
||||
### 7.3 Data Flow
|
||||
1. **Charon** receives a request for a remote container (e.g., user views logs).
|
||||
2. **Charon** sends `PROXY_REQUEST` on Control Channel.
|
||||
3. **Orthrus** accepts, opens a new Yamux stream.
|
||||
4. **Orthrus** dials the local Docker socket.
|
||||
5. **Orthrus** pipes the stream, applying "The Muzzle" filter in real-time.
|
||||
|
||||
## 8. Repository Structure (Monorepo)
|
||||
|
||||
Orthrus resides in the **same repository** as Charon to ensure protocol synchronization and simplified CI/CD.
|
||||
|
||||
### 8.1 Directory Layout
|
||||
To maintain a lightweight footprint (< 20MB), Orthrus uses a separate Go module within the `agent/` directory. This prevents it from inheriting Charon's heavy backend dependencies (GORM, SQLite, etc.).
|
||||
|
||||
```text
|
||||
/projects/Charon
|
||||
├── go.work # Manages the workspace (includes ./backend and ./agent)
|
||||
├── backend/ # The Main Server (Heavy)
|
||||
│ ├── go.mod
|
||||
│ └── ...
|
||||
├── agent/ # Orthrus (Lightweight)
|
||||
│ ├── go.mod # Separate dependencies (Standard Lib + Yamux)
|
||||
│ ├── main.go
|
||||
│ └── Dockerfile # Separate build process
|
||||
└── protocol/ # Shared Definitions (Protobufs)
|
||||
├── go.mod
|
||||
└── leash.proto
|
||||
```
|
||||
|
||||
### 8.2 Build Strategy
|
||||
* **Charon**: Built from `backend/Dockerfile`.
|
||||
* **Orthrus**: Built from `agent/Dockerfile`.
|
||||
* **CI/CD**: A single GitHub Action workflow builds and pushes both images (`charon:latest` and `orthrus:latest`) synchronously.
|
||||
Reference in New Issue
Block a user