Skip to content

Latest commit

 

History

History
398 lines (334 loc) · 14.7 KB

File metadata and controls

398 lines (334 loc) · 14.7 KB

SSH Connection Monitor - Architecture & Design

System Architecture

SSHadow supports three operating modes, each with different trade-offs:

Mode Overview

┌─────────────────────────────────────────────────────────────────────────┐
│                              SSHadow                                    │
├─────────────────────┬─────────────────────┬─────────────────────────────┤
│     Proxy Mode      │   Log Monitor Mode  │        Hybrid Mode          │
├─────────────────────┼─────────────────────┼─────────────────────────────┤
│ • Intercepts SSH    │ • Reads sshd logs   │ • Both simultaneously       │
│ • Real-time         │ • Full cert details │ • Best visibility           │
│ • Password forward  │ • Passive/safe      │ • Shared tracker            │
│ • No cert details*  │ • Slight delay      │ • Single metrics endpoint   │
└─────────────────────┴─────────────────────┴─────────────────────────────┘
* Unless SSH agent forwarding is implemented (future enhancement)

Proxy Mode Architecture

┌─────────────────┐
│   SSH Client    │
└────────┬────────┘
         │ SSH (port 2222)
         ▼
┌─────────────────────────────────────────┐
│           SSHadow Proxy                 │
│  ┌─────────────────────────────────┐    │
│  │     SSH Server (handshake)      │    │
│  │  • Accept connection            │    │
│  │  • Capture auth metadata        │    │
│  │  • Cache credentials            │    │
│  └──────────────┬──────────────────┘    │
│                 │                       │
│  ┌──────────────▼──────────────────┐    │
│  │     SSH Client (to target)      │    │
│  │  • Connect to sshd              │    │
│  │  • Forward password auth        │    │
│  │  • Proxy channels               │    │
│  └──────────────┬──────────────────┘    │
│                 │                       │
│  ┌──────────────▼──────────────────┐    │
│  │        Connection Tracker       │────┼──► Metrics (:9090)
│  └─────────────────────────────────┘    │
└─────────────────┬───────────────────────┘
                  │ SSH (port 22)
                  ▼
┌─────────────────────────────────────────┐
│              sshd                       │
└─────────────────────────────────────────┘

Log Monitor Mode Architecture

┌─────────────────┐
│   SSH Client    │
└────────┬────────┘
         │ SSH (port 22)
         ▼
┌─────────────────────────────────────────┐
│              sshd                       │
│  • Handles authentication directly      │
│  • Logs to auth.log / journald          │
└────────┬────────────────────────────────┘
         │ Log output
         ▼
┌─────────────────────────────────────────┐
│           SSHadow Log Monitor           │
│  ┌─────────────────────────────────┐    │
│  │         Log Watcher             │    │
│  │  • Tail file or journald        │    │
│  └──────────────┬──────────────────┘    │
│                 │                       │
│  ┌──────────────▼──────────────────┐    │
│  │         Log Parser              │    │
│  │  • Parse sshd log format        │    │
│  │  • Extract cert details         │    │
│  └──────────────┬──────────────────┘    │
│                 │                       │
│  ┌──────────────▼──────────────────┐    │
│  │        Connection Tracker       │────┼──► Metrics (:9090)
│  └─────────────────────────────────┘    │
└─────────────────────────────────────────┘

Hybrid Mode Architecture

┌─────────────────┐
│   SSH Client    │
└────────┬────────┘
         │ SSH (port 2222)
         ▼
┌─────────────────────────────────────────┐
│           SSHadow Proxy                 │
│  • Intercepts connection                │
│  • Captures basic metadata              │
│  • Forwards to sshd                     │
└────────┬────────────────────────────────┘
         │ SSH (port 22)
         ▼
┌─────────────────────────────────────────┐
│              sshd                       │
│  • Handles final authentication         │
│  • Logs with full cert details          │
└────────┬────────────────────────────────┘
         │ Log output
         ▼
┌─────────────────────────────────────────┐
│           SSHadow Log Monitor           │
│  • Enriches with cert details           │
└────────┬────────────────────────────────┘
         │
         ▼
┌─────────────────────────────────────────┐
│     Shared Connection Tracker           │◄── Both sources feed here
│  • Unified connection state             │
│  • Combined statistics                  │
└────────┬────────────────────────────────┘
         │
         ▼
┌─────────────────────────────────────────┐
│        Metrics Server (:9090)           │
└─────────────────────────────────────────┘

Component Details

1. Main Application (main.go)

Responsibilities:

  • Command-line argument parsing
  • Mode selection and validation
  • Component initialization based on mode
  • Graceful shutdown handling

Modes:

switch mode {
case "proxy":   runProxyMode(...)
case "logmon":  runLogMonMode(...)
case "hybrid":  // Run both concurrently
    go runProxyMode(...)
    runLogMonMode(...)
}

2. SSH Proxy Server (proxy/server.go)

Responsibilities:

  • Accept incoming SSH connections
  • Perform SSH handshake with clients
  • Extract authentication metadata
  • Forward password authentication to sshd
  • Proxy SSH channels bidirectionally

Key Structures:

type Server struct {
    listenAddr string
    targetAddr string
    config     *ssh.ServerConfig
    tracker    *monitor.Tracker
    authCache  sync.Map  // Temporary credential storage
}

Authentication Flow:

  1. Client connects to SSHadow
  2. SSH handshake captures auth method
  3. Credentials cached by session ID
  4. Connection accepted (all auth accepted at proxy level)
  5. SSHadow connects to sshd as client
  6. Password forwarded; pubkey auth fails (known limitation)
  7. Channels proxied bidirectionally

Current Limitation: Public key and certificate authentication cannot be forwarded because SSHadow doesn't have access to the client's private key. Future enhancement: SSH agent forwarding support.

3. Log Watcher (monitor/watcher.go)

Responsibilities:

  • Tail log files in real-time
  • Connect to journald for systemd systems
  • Parse and process log events

Supported Sources:

  • File: /var/log/auth.log, /var/log/secure
  • Journald: journalctl -u sshd -f

4. Log Parser (monitor/logparser.go)

Responsibilities:

  • Parse sshd log formats
  • Extract full authentication metadata
  • Handle syslog and journald timestamp formats

Parsed Events:

Event Pattern
Cert Auth Accepted publickey ... TYPE-CERT SHA256:FP ID "KEYID" serial N CA TYPE SHA256:CAFP
Pubkey Auth Accepted publickey ... TYPE SHA256:FP
Password Auth Accepted password for USER from IP port PORT
Disconnect Disconnected from user USER IP port PORT
Failed Auth Failed password/publickey for USER from IP
Invalid User Invalid user USER from IP port PORT

Data Extracted:

type LogEvent struct {
    Timestamp     time.Time
    Username      string
    SourceIP      string
    Port          int
    AuthType      AuthType
    KeyType       string
    Fingerprint   string
    CertID        string      // Only from logs
    CertSerial    uint64      // Only from logs
    CAFingerprint string      // Only from logs
}

5. Connection Tracker (monitor/tracker.go)

Responsibilities:

  • Track active connections from both sources
  • Aggregate statistics per user/key
  • Thread-safe state management

Dual Input Methods:

// From proxy - real-time, basic metadata
func (t *Tracker) AddConnectionFromProxy(connID, sourceIP, username string,
    authType AuthType, pubKey ssh.PublicKey, fingerprint string)

// From log parser - delayed, full cert details
func (t *Tracker) AddConnectionFromLog(connID string, event *LogEvent)

Tracking Keys:

  • Password auth: username:sourceIP
  • Public key: username:fingerprint
  • Certificate: username:certKeyID

6. Metrics Server (monitor/metrics.go)

Endpoints:

Endpoint Format Purpose
/ HTML Dashboard
/metrics Prometheus Time-series
/metrics/json JSON API access

Data Flow Examples

Proxy Mode: Password Auth

1. Client: ssh -p 2222 user@host
2. Proxy: Accept TCP, start SSH handshake
3. Proxy: passwordCallback captures password
4. Proxy: Cache password by session ID
5. Proxy: Accept auth (always succeeds at proxy)
6. Proxy: AddConnectionFromProxy(user, ip, AuthPassword, ...)
7. Proxy: ssh.Dial to sshd with password
8. sshd: Validates password
9. Proxy: Bidirectional channel proxy begins
10. Metrics: Shows active connection

Log Monitor Mode: Cert Auth

1. Client: ssh user@host (with certificate)
2. sshd: Validates certificate against CA
3. sshd: Logs "Accepted publickey ... ED25519-CERT ... ID 'key-id' ..."
4. Watcher: Reads log line
5. Parser: Extracts user, IP, cert ID, CA fingerprint
6. Tracker: AddConnectionFromLog with full cert details
7. Metrics: Shows connection with cert metadata

Hybrid Mode: Full Visibility

1. Client: ssh -p 2222 user@host (password)
2. Proxy: Captures user, IP, auth type
3. Proxy: AddConnectionFromProxy (real-time)
4. Proxy: Forwards to sshd
5. sshd: Logs authentication
6. Watcher: Reads log
7. Parser: Extracts details (enriches if cert)
8. Tracker: Already has connection, updates metadata
9. Metrics: Complete picture - real-time + details

Concurrency Model

Thread Safety

type Tracker struct {
    mu sync.RWMutex
    // Protected by mu:
    connections map[string]*ConnectionInfo
    stats       map[string]*UserStats
}
  • Read operations: RLock (concurrent reads)
  • Write operations: Lock (exclusive access)

Goroutine Structure

main()
├─ metrics server (goroutine)
│   └─ HTTP handlers (per request)
│
├─ [proxy mode] proxy server (goroutine)
│   └─ per connection (goroutine)
│       ├─ channel handler
│       └─ data proxying (goroutines)
│
└─ [logmon mode] log watcher (goroutine)
    └─ processEvent (inline)

Performance

Memory

  • Base: ~10-15 MB
  • Per connection: ~500 bytes
  • Per stat entry: ~500 bytes

CPU

  • Idle: <1%
  • Active (1000 conn/sec): <5%

Latency

  • Proxy mode: +1ms per connection
  • Log mode: 100-500ms delay (log flush)
  • Hybrid: Real-time from proxy

Extension Points

Adding SSH Agent Forwarding (Future)

// In proxy/server.go
func (s *Server) handleConnection(...) {
    // After SSH handshake, check for agent forwarding request
    // Open agent channel back to client
    // Use agent.NewClient() for signing
    // Forward signed auth to sshd
}

Adding New Log Patterns

// In monitor/logparser.go
var customPattern = regexp.MustCompile(`...`)

func ParseLogLine(line string) *LogEvent {
    if matches := customPattern.FindStringSubmatch(message); matches != nil {
        // Handle custom pattern
    }
}

sshd Configuration

For log monitor functionality:

# /etc/ssh/sshd_config
LogLevel VERBOSE

This enables logging of:

  • Certificate key IDs
  • Certificate serial numbers
  • CA fingerprints
  • Full authentication details

This architecture balances flexibility, security, and observability while supporting multiple deployment scenarios.