Understanding SSH Tunneling

A comprehensive guide to SSH tunneling and port forwarding

Featured image

Image Reference link



Overview

SSH (Secure Shell) is not just a tool for remote server access; it’s also a powerful solution for secure network tunneling. This guide will explore SSH tunneling, its various types, and practical applications in real-world scenarios.


What is SSH Tunneling?

SSH tunneling is a method of transporting arbitrary networking data over an encrypted SSH connection. It can be used to add encryption to legacy applications, implement VPNs, and access remotely exposed services through firewalls.


Types of SSH Tunneling

1️⃣ Local Port Forwarding

# Basic syntax
ssh -L [local_port]:[remote_server]:[remote_port] user@ssh_host

# Example: Access remote web server
ssh -L 8080:localhost:80 user@example.com

2️⃣ Remote Port Forwarding

# Basic syntax
ssh -R [remote_port]:[local_server]:[local_port] user@ssh_host

# Example: Expose local SSH server
ssh -R 9000:localhost:22 user@example.com

3️⃣ Dynamic Port Forwarding

# Basic syntax
ssh -D [local_port] user@ssh_host

# Example: Create SOCKS proxy
ssh -D 1080 user@example.com



Practical Implementation

1️⃣ Setting Up Persistent Tunnels

# Create tunnel script
cat <<EOF > /usr/local/bin/redis-tunnels.sh
#!/bin/bash
ssh -N -i /home/ec2-user/.ssh/id_rsa \
    -L 0.0.0.0:6395:redis-endpoint:6379 \
    ec2-user@10.33.1.252 &
wait
EOF

chmod +x /usr/local/bin/redis-tunnels.sh

2️⃣ Creating Systemd Service

# /etc/systemd/system/redis-tunnels.service
[Unit]
Description=Redis SSH Tunnels
After=network.target

[Service]
User=ec2-user
ExecStart=/usr/local/bin/redis-tunnels.sh
Restart=always
RestartSec=5

[Install]
WantedBy=multi-user.target

3️⃣ Managing the Service

# Enable and start the service
sudo systemctl daemon-reload
sudo systemctl enable redis-tunnels.service
sudo systemctl start redis-tunnels.service



Useful SSH Options

1️⃣ Common Flags

-N  # No command execution
-f  # Background execution
-C  # Enable compression
-v  # Verbose mode

2️⃣ Security Best Practices



Benefits and Considerations

1️⃣ Advantages

2️⃣ Limitations



Real-World Examples

1️⃣ Database Access Through Bastion Host

# Access RDS through bastion host
ssh -L 3306:my-rds.region.rds.amazonaws.com:3306 user@bastion-host

# Multiple database connections
ssh -L 3306:prod-db:3306 -L 3307:stage-db:3306 user@bastion-host

2️⃣ Accessing Internal Web Services

# Access internal Jenkins
ssh -L 8080:jenkins-internal:8080 user@jump-server

# Access multiple web services
ssh -L 8080:web1:80 -L 8081:web2:80 user@gateway



Advanced Configurations

1️⃣ Automatic Tunnel Recovery

# /etc/systemd/system/tunnel-monitor.service
[Unit]
Description=Monitor and Recover SSH Tunnels
After=network.target

[Service]
Type=simple
ExecStart=/usr/local/bin/monitor-tunnels.sh
Restart=always
RestartSec=30

[Install]
WantedBy=multi-user.target
# /usr/local/bin/monitor-tunnels.sh
#!/bin/bash

while true; do
    if ! netstat -an | grep "LISTEN" | grep -q ":6379"; then
        echo "Redis tunnel down, restarting..."
        systemctl restart redis-tunnels.service
    fi
    sleep 60
done

2️⃣ SSH Config File Setup

# ~/.ssh/config
Host bastion
    HostName bastion.example.com
    User ec2-user
    IdentityFile ~/.ssh/id_rsa
    LocalForward 6379 redis.internal:6379
    LocalForward 3306 mysql.internal:3306
    ServerAliveInterval 30
    ServerAliveCountMax 3



Security Hardening

1️⃣ SSH Tunnel Restrictions

# /etc/ssh/sshd_config
AllowTcpForwarding yes
GatewayPorts no
PermitRootLogin no
AllowUsers tunnel-user

2️⃣ Firewall Configuration

# Allow SSH on bastion host
sudo iptables -A INPUT -p tcp --dport 22 -j ACCEPT

# Restrict tunnel access
sudo iptables -A INPUT -p tcp --dport 6379 -s 10.0.0.0/8 -j ACCEPT
sudo iptables -A INPUT -p tcp --dport 6379 -j DROP



Monitoring and Troubleshooting

1️⃣ Tunnel Status Check

# Check active tunnels
netstat -tulpn | grep ssh

# Monitor SSH connections
watch -n 1 "netstat -an | grep :22"

# Check tunnel logs
journalctl -u redis-tunnels -f

2️⃣ Performance Optimization

# SSH config for better performance
Host *
    Compression yes
    CompressionLevel 6
    TCPKeepAlive yes
    ServerAliveInterval 30
    ServerAliveCountMax 3
    ControlMaster auto
    ControlPath ~/.ssh/control-%h-%p-%r
    ControlPersist 1h



Load Balancing and High Availability

1️⃣ Multiple Tunnel Setup

# Primary tunnel
ssh -L 6379:redis-primary:6379 user@bastion-1 &

# Backup tunnel
ssh -L 6380:redis-secondary:6379 user@bastion-2 &

# HAProxy configuration
frontend redis_frontend
    bind *:6379
    default_backend redis_backends

backend redis_backends
    server primary 127.0.0.1:6379 check
    server backup 127.0.0.1:6380 check backup

2️⃣ Automatic Failover Script

#!/bin/bash
PRIMARY_PORT=6379
BACKUP_PORT=6380

while true; do
    if ! nc -z localhost $PRIMARY_PORT; then
        echo "Primary tunnel down, switching to backup..."
        systemctl start backup-tunnel.service
    fi
    sleep 30
done



Common Issues and Solutions

1️⃣ Connection Issues

# Solution: Update sshd_config
AllowTcpForwarding yes
# Add to ~/.ssh/config
ServerAliveInterval 30
ServerAliveCountMax 3

2️⃣ Performance Issues

# Enable compression
ssh -C -L 6379:redis:6379 user@bastion
# Adjust compression level
ssh -o "CompressionLevel 4" -L 6379:redis:6379 user@bastion

3️⃣ Security Issues

# Restrict access
sudo iptables -A INPUT -p tcp --dport 6379 -j DROP
# Check connection
netstat -tulpn | grep ssh

References