SSH Tunneling
SSH tunneling validation guide
SSH forwarding is an administrative feature that can cross network trust boundaries. Use it only for endpoints and services named in authorization. Bind to loopback by default, use the narrowest destination, preserve host-key checking, and keep an operator-visible session unless the runbook requires background operation.
Forwarding model
| Mode | Listener | Connection made by | Typical authorized use |
|---|---|---|---|
Local -L | SSH client | SSH server | reach one internal service through a bastion |
Remote -R | SSH server | SSH client | expose one local lab service to the SSH server |
Dynamic -D | SSH client | SSH server | SOCKS access through a managed bastion |
Local forwarding
The SSH client listens on loopback and asks the SSH server to connect to one destination:
ssh -N -o ExitOnForwardFailure=yes \
-L 127.0.0.1:15432:db.internal.example:5432 \
operator@approved-bastion.example
Validate with one benign database health query or TCP connection. The destination name is resolved and reached from the SSH server's network position.
For a second SSH hop, prefer the standard jump-host feature:
ssh -J operator@approved-bastion.example admin@approved-private-host.example
Remote forwarding
Keep the remote listener on the SSH server's loopback interface unless a reviewed requirement says otherwise:
ssh -N -o ExitOnForwardFailure=yes \
-R 127.0.0.1:18080:127.0.0.1:8080 \
operator@approved-gateway.example
A process on the gateway can now reach the approved local lab service at 127.0.0.1:18080. Do not set GatewayPorts yes for a single test. If another approved host must connect, use a dedicated bastion configuration with GatewayPorts clientspecified, host firewall restrictions, and an exact source allowlist. Back up the configuration, validate it with sshd -t, and restore it during cleanup.
Dynamic forwarding
Use a loopback SOCKS listener and direct only approved applications through it:
ssh -N -o ExitOnForwardFailure=yes \
-D 127.0.0.1:1080 operator@approved-bastion.example
Confirm whether the client resolves DNS locally or through the proxy. Validate one approved host and port; do not use a broad subnet scan as a tunnel test.
Server controls
A managed bastion can restrict forwarding in sshd_config or authorized_keys:
AllowTcpForwarding local
PermitOpen db.internal.example:5432
PermitOpen accepts host and port destinations, not CIDR ranges. Pair it with account restrictions, MFA or short-lived certificates, firewall policy, and session logging.
Verification and cleanup
# Client-side listeners
lsof -nP -iTCP -sTCP:LISTEN
# Stop the foreground SSH session with Ctrl-C, then confirm the listener closed.
Record the SSH client and server, source and destination, listener address, ports, start and end time, one benign validation request, and relevant authentication, process, and network events. Remove temporary server configuration and firewall rules and confirm the original state.