Skip to content

mac119/ssh_proxy

Folders and files

NameName
Last commit message
Last commit date

Latest commit

ย 

History

16 Commits
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 

Repository files navigation

    โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
    โ”‚         โ•”โ•โ•โ•โ•—                   โ”‚
    โ”‚         โ•‘ โฌก โ•‘  SSH GUARD        โ”‚
    โ”‚         โ•šโ•โ•โ•โ•                   โ”‚
    โ”‚    โ”Œโ”€โ”€โ”€โ”       โ”Œโ”€โ”€โ”€โ”  โ”Œโ”€โ”€โ”€โ”    โ”‚
    โ”‚    โ”‚ U โ”œโ”€โ”€โ†’ P โ”€โ”ค T โ”‚  โ”‚ T โ”‚    โ”‚
    โ”‚    โ””โ”€โ”€โ”€โ”˜  โ†•    โ””โ”€โ”€โ”€โ”˜  โ””โ”€โ”€โ”€โ”˜    โ”‚
    โ”‚         AUDIT                   โ”‚
    โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜

๐Ÿ›ก๏ธ SSH Guard Proxy

A high-performance SSH proxy gateway built in Rust for security auditing, access control, and session recording.

Rust License: MIT tokio

Every keystroke recorded. Every connection authorized. Every session auditable.


๐ŸŽฏ Why SSH Guard Proxy?

In modern infrastructure, direct SSH access to production servers is a security risk. SSH Guard Proxy solves this by acting as a single point of entry โ€” a bastion host that enforces authentication, authorization, and full audit logging for every SSH session.

The Problem

  • Developers SSH directly into production servers with no oversight
  • No centralized record of who did what and when
  • Shared credentials make accountability impossible
  • Revoking access requires touching every server

The Solution

Developer โ†’ SSH Guard Proxy โ†’ Target Server
                โ†“
          Audit Log (every keystroke)

โœจ Features

Feature Description
๐Ÿ” Unified Authentication Password (Argon2id) and public key auth at the gateway
๐ŸŽ›๏ธ Access Control (ACL) Per-user host access policies โ€” who can access what
๐Ÿ“ Full Audit Logging Every input/output recorded in JSON Lines format
๐ŸŽฌ Session Recording Asciicast v2 format โ€” replay any session with asciinema
๐Ÿšซ Command Filtering Blacklist/whitelist mode โ€” block dangerous commands in real-time
๐Ÿ“‚ SCP/SFTP Auditing Full file transfer logging with filenames, sizes, and direction
๐Ÿ‘๏ธ Session Sharing Multiple admins can watch a live session in real-time (read-only)
โšก High Performance Built on Rust + Tokio async runtime โ€” minimal overhead
๐Ÿ—๏ธ Zero Target Changes No agent or modification needed on target servers
๐Ÿ”‘ Host Key Auto-generation Ed25519 host keys generated on first run
๐Ÿšฆ Connection Limiting Max session control and auth failure lockout

๐Ÿ—๏ธ Architecture

โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
โ”‚                      SSH Guard Proxy                              โ”‚
โ”œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ค
โ”‚                                                                   โ”‚
โ”‚   User โ”€โ”€SSHโ”€โ”€โ†’ [SSH Server] โ”€โ”€โ†’ [Auth & ACL] โ”€โ”€โ†’ [Session Mgr]  โ”‚
โ”‚                                                        โ”‚          โ”‚
โ”‚                                                        โ–ผ          โ”‚
โ”‚                  [Audit Logger] โ—€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ [SSH Client] โ”€โ”€โ†’ Target
โ”‚                       โ”‚                                           โ”‚
โ”‚                       โ–ผ                                           โ”‚
โ”‚                 logs/audit.jsonl                                   โ”‚
โ”‚                                                                   โ”‚
โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜

Data Flow

  1. User connects: ssh admin@proxy -p 2222
  2. Proxy authenticates the user (password or public key)
  3. User selects a target host from the authorized list
  4. Proxy establishes SSH connection to target
  5. All data is bidirectionally forwarded and logged
  6. Session ends โ†’ audit record finalized

๐Ÿš€ Quick Start

Installation

Option 1: Download Pre-built Binary (Recommended)

Download the latest release from the Releases page:

# Download and extract (example for macOS arm64)
curl -L https://github.com/mac119/ssh_proxy/releases/download/v0.1.0/ssh-guard-proxy-v0.1.0-darwin-arm64.tar.gz | tar xz

# Or manually download, extract, and set permissions
chmod +x ssh_proxy hash_password

The release package includes:

  • ssh_proxy โ€” Main proxy binary
  • hash_password โ€” Password hash generator tool
  • config/ โ€” Configuration templates

Option 2: Build from Source

Requires Rust 1.70+ (install via rustup):

git clone https://github.com/mac119/ssh_proxy.git
cd ssh_proxy
cargo build --release
# Binaries at: target/release/ssh_proxy, target/release/hash_password

Configure

1. Proxy Settings (config/proxy.toml)

[server]
listen_address = "0.0.0.0"
listen_port = 2222
host_key_path = "config/host_key"

[session]
idle_timeout_secs = 1800
max_sessions = 100

[audit]
log_dir = "logs"
record_session = true

[security]
max_auth_attempts = 3
lockout_duration_secs = 300

2. Add Users (config/users.toml)

Generate a password hash first:

./hash_password 'YourSecurePassword'
# Output: $argon2id$v=19$m=19456,t=2,p=1$...

Then add to config:

[[users]]
name = "admin"
password_hash = "$argon2id$v=19$m=19456,t=2,p=1$..."
public_keys = []
allowed_hosts = ["*"]  # Access to all hosts

[[users]]
name = "developer"
password_hash = "$argon2id$v=19$m=19456,t=2,p=1$..."
public_keys = ["ssh-ed25519 AAAAC3Nza..."]
allowed_hosts = ["web-01", "web-02"]  # Restricted access

3. Add Target Hosts (config/hosts.toml)

[[hosts]]
name = "web-01"
address = "192.168.1.10"
port = 22
username = "deploy"
auth_method = "key"
private_key_path = "config/keys/web-01"

[[hosts]]
name = "db-01"
address = "10.0.0.50"
port = 22
username = "dbadmin"
auth_method = "password"
password = "encrypted:your_password_here"

Run

# Foreground (for testing)
./ssh_proxy

# Background with nohup
nohup ./ssh_proxy > /var/log/ssh_proxy.log 2>&1 &

# Background with output to file (recommended for debugging)
./ssh_proxy >> logs/proxy.log 2>&1 &
echo $! > ssh_proxy.pid   # Save PID for later stop

# Stop the proxy
kill $(cat ssh_proxy.pid)

Note: In production, use systemd (see Production Deployment below) for auto-restart, log management, and proper signal handling.

Connect

ssh admin@your-proxy-host -p 2222

You'll see:

Welcome, admin! Available hosts:
โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
  [1] web-01 (192.168.1.10:22)
  [2] web-02 (192.168.1.11:22)
  [3] db-01 (10.0.0.50:22)
โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
Select host number: 

Select a host and you're in โ€” fully transparent, fully audited.

File Transfer (SCP/SFTP)

SSH Guard Proxy supports SCP and SFTP file transfers with full audit logging. All file transfers are recorded โ€” including filenames, sizes, direction, and timestamps.

Upload a File

# Upload to the default target host (first allowed host)
scp -P 2222 myfile.txt admin@proxy-host:/tmp/

# Upload to a specific target host (use user%host format)
scp -P 2222 myfile.txt admin%db-server-01@proxy-host:/tmp/

# Recursive directory upload
scp -r -P 2222 ./my-folder admin%web-server-01@proxy-host:/opt/

Download a File

# Download from the default target host
scp -P 2222 admin@proxy-host:/etc/hosts ./

# Download from a specific target host
scp -P 2222 admin%db-server-01@proxy-host:/var/log/app.log ./

Legacy SCP Mode

Modern OpenSSH (9.0+) uses SFTP by default for scp commands. Both modes are fully supported:

# Default (SFTP mode) โ€” works out of the box
scp -P 2222 file.txt admin@proxy-host:/tmp/

# Force legacy SCP protocol (if needed)
scp -O -P 2222 file.txt admin@proxy-host:/tmp/

Target Host Selection

Method Example Description
Default admin@proxy Uses the first allowed host from ACL
Explicit admin%db-server-01@proxy Specifies exact target host by name

SCP Audit Log Events

All file transfers generate audit entries:

{"event":"scp_session_start","session_id":"...","user":"admin","direction":"upload","target_host":"db-server-01","remote_path":"/tmp/"}
{"event":"scp_file_transfer","session_id":"...","user":"admin","direction":"upload","filename":"myfile.txt","size":10240,"mode":"0644"}

Session Sharing (Live Watch)

Admins with watch permission can observe another user's active session in real-time (read-only).

Enable Watch Permission

# config/users.toml
[[users]]
name = "admin"
can_watch_sessions = true
watch_allowed_users = ["*"]  # "*" = all users, or specific names

Usage

  1. Connect to the proxy: ssh admin@proxy-host -p 2222
  2. At the host selection menu, enter w:
    Welcome, admin! Available hosts:
    โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
      [1] web-server-01 (192.168.1.10:22)
    โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
      [w] Watch active session
    โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
    Select host number: w
    
  3. Select a session to watch:
    Active sessions:
    โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
      [1] user=developer target=web-server-01 (5m ago, 0 watchers)
    โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
    Select session number (q to cancel): 1
    
  4. You now see the session output in real-time. Press Ctrl+C to stop watching.

Notes

  • Watchers are read-only โ€” no input is sent to the watched session
  • Multiple admins can watch the same session simultaneously
  • All watch events are audit-logged (session_watch_start, session_watch_end)

Demo

  • log in to the remote server
image
  • then execute ls command
image
  • Duplicate the terminal and log in to the ssh-proxy server. We will notice a ls command is being executed
image

๐Ÿ“Š Audit Logs

All audit data is stored in logs/audit.jsonl in append-only JSON Lines format.

Log Events

Event Description
auth_success Successful authentication
auth_failure Failed authentication attempt
session_start User connected to a target host
session_end Session terminated
data (input) User keystrokes / commands
data (output) Server responses
command_blocked Command rejected by filter
scp_session_start SCP/SFTP transfer session initiated
scp_file_transfer File transferred (name, size, direction)
session_watch_start Admin started watching a session
session_watch_end Admin stopped watching (with duration)

Example Log Entries

{"event":"auth_success","timestamp":"2026-05-05T07:10:00Z","user":"admin","peer_addr":"10.0.1.5:54321","method":"password"}
{"event":"session_start","timestamp":"2026-05-05T07:10:05Z","session_id":"a1b2c3d4","user":"admin","peer_addr":"10.0.1.5:54321","target_host":"web-01","target_addr":"192.168.1.10"}
{"event":"data","timestamp":"2026-05-05T07:10:10Z","session_id":"a1b2c3d4","direction":"input","data_base64":"bHMgLWxhCg==","data_len":7}
{"event":"data","timestamp":"2026-05-05T07:10:10Z","session_id":"a1b2c3d4","direction":"output","data_base64":"dG90YWwgNDgK...","data_len":256}
{"event":"session_end","timestamp":"2026-05-05T07:45:00Z","session_id":"a1b2c3d4"}

Decoding Commands from Logs

# View all input commands from a session
grep '"direction":"input"' logs/audit.jsonl | \
  jq -r '.data_base64' | \
  while read line; do echo "$line" | base64 -d; done

# Find who connected today
grep '"event":"session_start"' logs/audit.jsonl | \
  grep "$(date +%Y-%m-%d)" | \
  jq '{user, target_host, timestamp}'

# Count failed logins
grep '"event":"auth_failure"' logs/audit.jsonl | wc -l

Session Replay

Sessions are recorded in asciicast v2 format:

# Replay a recorded session
asciinema play logs/sessions/<session_id>.cast

๐Ÿข Production Deployment

Systemd Service

Create /etc/systemd/system/ssh-guard-proxy.service:

[Unit]
Description=SSH Guard Proxy
After=network.target

[Service]
Type=simple
User=sshproxy
Group=sshproxy
WorkingDirectory=/opt/ssh_proxy
ExecStart=/opt/ssh_proxy/ssh_proxy
Restart=always
RestartSec=5

# Security hardening
NoNewPrivileges=true
ProtectSystem=strict
ReadWritePaths=/opt/ssh_proxy/logs

[Install]
WantedBy=multi-user.target
sudo systemctl enable ssh-guard-proxy
sudo systemctl start ssh-guard-proxy

File Permissions

chmod 600 config/host_key
chmod 600 config/keys/*
chmod 644 config/*.toml
chmod 700 logs/

Log Rotation

Add to /etc/logrotate.d/ssh-guard-proxy:

/opt/ssh_proxy/logs/audit.jsonl {
    daily
    rotate 90
    compress
    delaycompress
    missingok
    notifempty
    copytruncate
}

Firewall

# Only expose the proxy port
ufw allow 2222/tcp
# Block direct SSH to target hosts from outside
ufw deny from any to 192.168.1.0/24 port 22

๐Ÿ“ Project Structure

ssh_proxy/
โ”œโ”€โ”€ Cargo.toml                 # Dependencies & build config
โ”œโ”€โ”€ config/
โ”‚   โ”œโ”€โ”€ proxy.toml             # Main proxy configuration
โ”‚   โ”œโ”€โ”€ users.toml             # User accounts & ACL
โ”‚   โ”œโ”€โ”€ hosts.toml             # Target host definitions
โ”‚   โ””โ”€โ”€ host_key              # Auto-generated Ed25519 host key
โ”œโ”€โ”€ src/
โ”‚   โ”œโ”€โ”€ main.rs               # Entry point
โ”‚   โ”œโ”€โ”€ config.rs             # Configuration loading
โ”‚   โ”œโ”€โ”€ server/
โ”‚   โ”‚   โ”œโ”€โ”€ mod.rs            # TCP listener & session spawning
โ”‚   โ”‚   โ””โ”€โ”€ handler.rs        # SSH protocol handler (auth, data relay)
โ”‚   โ”œโ”€โ”€ client/
โ”‚   โ”‚   โ””โ”€โ”€ mod.rs            # SSH client (connects to targets)
โ”‚   โ”œโ”€โ”€ auth/
โ”‚   โ”‚   โ”œโ”€โ”€ mod.rs            # Authentication (Argon2id, pubkey)
โ”‚   โ”‚   โ””โ”€โ”€ acl.rs            # Access control logic
โ”‚   โ”œโ”€โ”€ session/
โ”‚   โ”‚   โ””โ”€โ”€ mod.rs            # Session lifecycle management
โ”‚   โ””โ”€โ”€ audit/
โ”‚       โ”œโ”€โ”€ mod.rs            # Audit event logger
โ”‚       โ””โ”€โ”€ recorder.rs       # Asciicast session recorder
โ”œโ”€โ”€ src/bin/
โ”‚   โ””โ”€โ”€ hash_password.rs      # CLI tool to generate password hashes
โ””โ”€โ”€ logs/                      # Audit output directory

๐Ÿ”ง Technology Stack

Component Choice Rationale
Language Rust Memory safety, zero-cost abstractions, fearless concurrency
SSH Protocol russh Native async SSH implementation (server + client)
Async Runtime Tokio Industry-standard, battle-tested async runtime
Password Hashing Argon2id Winner of Password Hashing Competition
Logging tracing Structured, async-aware instrumentation
Config TOML + serde Human-readable, type-safe configuration

๐Ÿ—บ๏ธ Roadmap

  • Web management UI (live sessions, replay, user management)
  • Database backend (PostgreSQL/SQLite for config & logs)
  • Multi-factor authentication (TOTP/WebAuthn)
  • Command blacklist/whitelist filtering
  • SCP/SFTP file transfer auditing
  • Cluster mode with load balancing
  • Real-time alerting (Slack/webhook on suspicious activity)
  • Session sharing (multiple admins watching one session)

๐Ÿค Contributing

Contributions are welcome! Please open an issue first to discuss what you'd like to change.


๐Ÿ“„ License

This project is licensed under the MIT License โ€” see the LICENSE file for details.


Built with ๐Ÿฆ€ Rust for maximum performance and safety.

SSH Guard Proxy โ€” Because security shouldn't be an afterthought.

About

๐Ÿ›ก๏ธ A high-performance SSH proxy gateway built in Rust โ€” unified authentication, per-user access control (ACL), full session audit logging, and terminal replay. Secure your infrastructure without modifying target servers.

Topics

Resources

License

Stars

Watchers

Forks

Packages

 
 
 

Contributors

Languages