- Added references to existing test files in the UI/UX testing plan. - Updated CI failure remediation plan with improved file paths and clarity. - Expanded CrowdSec full implementation documentation with detailed configuration steps and scripts. - Improved CrowdSec testing plan with clearer objectives and expected results. - Updated current specification documentation with additional context on CVE remediation. - Enhanced docs-to-issues workflow documentation for better issue tracking. - Corrected numbering in UI/UX bugfixes specification for clarity. - Improved WAF testing plan with detailed curl commands and expected results. - Updated QA reports for CrowdSec implementation and UI/UX testing with detailed results and coverage metrics. - Fixed rate limit integration test summary with clear identification of issues and resolutions. - Enhanced rate limit test status report with detailed root causes and next steps for follow-up.
258 lines
10 KiB
Markdown
258 lines
10 KiB
Markdown
# 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.
|
|
|
|
## 9. Packaging & Install Options
|
|
|
|
Orthrus should be distributed in multiple formats so users can choose one that fits their environment and security posture.
|
|
|
|
### 9.1 Supported Distribution Formats
|
|
|
|
* **Docker / Docker Compose**: easiest for container-based hosts.
|
|
* **Standalone static binary (recommended)**: small, copy to `/usr/local/bin`, run via `systemd`.
|
|
* **Deb / RPM packages**: for managed installs via `apt`/`yum`.
|
|
* **Homebrew formula**: for macOS / Linuxbrew users.
|
|
* **Tarball with installer**: for offline or custom installs.
|
|
* **Kubernetes DaemonSet**: for fleet deployment inside clusters.
|
|
|
|
### 9.2 Quick Install Snippets (copyable)
|
|
|
|
1) Docker Compose
|
|
|
|
```yaml
|
|
version: "3.8"
|
|
services:
|
|
orthrus:
|
|
image: wikid82/orthrus:latest
|
|
restart: always
|
|
environment:
|
|
- ORTHRUS_NAME=remote-media-server
|
|
- CHARON_LINK=100.x.y.z:8080
|
|
- AUTH_KEY=REPLACE_WITH_AUTH_KEY
|
|
volumes:
|
|
- /var/run/docker.sock:/var/run/docker.sock:ro
|
|
```
|
|
|
|
1) Standalone binary + `systemd` (Linux)
|
|
|
|
```bash
|
|
# download and install
|
|
curl -L https://example.com/orthrus/latest/orthrus-linux-amd64 -o /usr/local/bin/orthrus
|
|
chmod +x /usr/local/bin/orthrus
|
|
|
|
# systemd unit (/etc/systemd/system/orthrus.service)
|
|
cat > /etc/systemd/system/orthrus.service <<'EOF'
|
|
[Unit]
|
|
Description=Orthrus agent
|
|
After=network.target
|
|
|
|
[Service]
|
|
Environment=ORTHRUS_NAME=remote-media-server
|
|
Environment=CHARON_LINK=100.x.y.z:8080
|
|
Environment=AUTH_KEY=REPLACE_WITH_AUTH_KEY
|
|
ExecStart=/usr/local/bin/orthrus
|
|
Restart=on-failure
|
|
User=root
|
|
|
|
[Install]
|
|
WantedBy=multi-user.target
|
|
EOF
|
|
|
|
systemctl daemon-reload
|
|
systemctl enable --now orthrus
|
|
```
|
|
|
|
1) Tarball + install script
|
|
|
|
```bash
|
|
curl -L -o orthrus.tar.gz https://example.com/orthrus/vX.Y.Z/orthrus-linux-amd64.tar.gz
|
|
sha256sum orthrus.tar.gz # compare with UI-provided hash
|
|
tar -xzf orthrus.tar.gz -C /usr/local/bin
|
|
chmod +x /usr/local/bin/orthrus
|
|
# then use the systemd unit above
|
|
```
|
|
|
|
1) Homebrew (macOS / Linuxbrew)
|
|
|
|
```
|
|
brew tap wikid82/charon
|
|
brew install orthrus
|
|
```
|
|
|
|
1) Kubernetes DaemonSet
|
|
|
|
Provide a DaemonSet YAML referencing the `orthrus` image and the required env vars (`AUTH_KEY`, `CHARON_LINK`), optionally mounting the Docker socket or using hostNetworking.
|
|
|
|
### 9.3 Security & UX Notes
|
|
|
|
* Provide SHA256 checksums and GPG signatures for binary downloads.
|
|
* Avoid recommending `curl | sh`; prefer explicit steps and checksum verification.
|
|
* The Hecate UI should present each snippet as a selectable tab with a copy button and an inline checksum.
|
|
* Offer a one-click `AUTH_KEY` regenerate action in the UI and mark old keys revoked.
|