1
0
Fork 0
mirror of https://github.com/imjasonh/ssh-proxy synced 2026-07-07 00:23:33 +00:00

update readme

Signed-off-by: Jason Hall <jason@chainguard.dev>
This commit is contained in:
Jason Hall 2025-09-12 12:35:53 -04:00
parent 53bb324f1f
commit 571ea87cd2
2 changed files with 28 additions and 42 deletions

View file

@ -1,59 +1,45 @@
# SSH Proxy
A Go proxy server for proxying incoming SSH connections to backend services over WebSockets, designed for Cloud Run deployments.
A Go library and proxy server for tunneling SSH connections over WebSockets, designed for Cloud Run apps that don't support raw TCP connections.
## Overview
SSH Proxy provides two main components:
SSH Proxy provides two main functions:
1. **SSH Proxy Server** - Forwards SSH connections to a WebSocket backend
2. **Websocket Wrapper Package** - Wraps an existing SSH server implementation in a WebSocket façade, to receive WebSocket requests.
1. **SSH → WebSocket Proxy** - Accepts SSH connections and forwards them to a WebSocket backend on Cloud Run.
2. **WebSocket → SSH Proxy** - Accepts WebSocket connections and forwards them to a local SSH server implementation.
This allows you to deploy SSH services on platforms that don't support raw TCP connections (like Cloud Run) by tunneling SSH over WebSocket/HTTP.
This allows you to deploy SSH services on Cloud Run by tunneling SSH traffic over HTTP/WebSocket connections.
## Usage
### Wrap your SSH server implementation as a WebSocket server.
### SSH → WebSocket Proxy
Use the SSH proxy command to forward local SSH connections to a WebSocket endpoint.
You can run this in [GKE Autopilot](https://cloud.google.com/kubernetes-engine/docs/concepts/autopilot-overview) for a minimal, cost-effective and low-maintenance environment to proxy requests.
### WebSocket → SSH Proxy
Create a WebSocket handler that forwards connections to a local SSH server:
```go
import (
"golang.org/x/crypto/ssh"
"net/http"
"github.com/gorilla/websocket"
sshproxy "github.com/imjasonh/ssh-proxy"
)
// Create WebSocket wrapper
wsServer := sshproxy.NewWebSocketServer(&ssh.ServerConfig{
PublicKeyCallback: yourAuthFunction,
}, func(channel ssh.Channel, requests <-chan *ssh.Request, perms *ssh.Permissions) {
// Handle SSH session
})
upgrader := websocket.Upgrader{
// Accept requests from all origins; consider changing this.
CheckOrigin: func(r *http.Request) bool { return true },
}
// Serve over HTTP
http.Handle("/ssh", wsServer)
// Forward WebSocket connections to local SSH server at :22
http.Handle("/ssh", sshproxy.ProxyWebSocketToSSH(":22", upgrader))
http.ListenAndServe(":8080", nil)
```
### SSH Proxy Server (for external access)
Use the provided `ssh-proxy` command locally, or integrate into your own application:
```bash
# Set environment variables
export WEBSOCKET_URL="wss://your-service.run.app/ssh"
export SSH_ADDR=":2222"
# Run the proxy
ssh-proxy
# Connect via SSH
ssh user@localhost -p 2222
```
You can run this server in GKE Autopilot behind a GCLB load balancer, and expose SSH servers running on Cloud Run.
## Authentication
The SSH proxy supports Google Cloud identity token authentication for secure WebSocket connections to Cloud Run services, so the Cloud Run service can be configured to only accept requests from the proxy.
## Examples
See the `cmd/ssh-proxy` directory for a complete example implementation.
The SSH proxy supports Google Cloud identity token authentication for secure WebSocket connections. When connecting to Cloud Run services, the proxy automatically obtains and includes identity tokens in the Authorization header.

View file

@ -54,7 +54,7 @@ func TestProxyWebSocketToSSH_BidirectionalTraffic(t *testing.T) {
}()
// Create test server with proxy handler
server := httptest.NewServer(http.HandlerFunc(ProxyWebSocketToSSH(actualAddr, upgrader)))
server := httptest.NewServer(ProxyWebSocketToSSH(actualAddr, upgrader))
defer server.Close()
// Connect WebSocket client
@ -139,7 +139,7 @@ func TestProxyWebSocketToSSH_MultipleMessages(t *testing.T) {
}()
// Create test server
server := httptest.NewServer(http.HandlerFunc(ProxyWebSocketToSSH(actualAddr, upgrader)))
server := httptest.NewServer(ProxyWebSocketToSSH(actualAddr, upgrader))
defer server.Close()
// Connect WebSocket client
@ -213,7 +213,7 @@ func TestProxyWebSocketToSSH_LargeData(t *testing.T) {
}()
// Create test server
server := httptest.NewServer(http.HandlerFunc(ProxyWebSocketToSSH(actualAddr, upgrader)))
server := httptest.NewServer(ProxyWebSocketToSSH(actualAddr, upgrader))
defer server.Close()
// Connect WebSocket client
@ -284,7 +284,7 @@ func TestProxyWebSocketToSSH_ConnectionClosed(t *testing.T) {
}()
// Create test server
server := httptest.NewServer(http.HandlerFunc(ProxyWebSocketToSSH(actualAddr, upgrader)))
server := httptest.NewServer(ProxyWebSocketToSSH(actualAddr, upgrader))
defer server.Close()
// Connect WebSocket client
@ -327,7 +327,7 @@ func TestProxyWebSocketToSSH_SSHServerUnavailable(t *testing.T) {
tempListener.Close() // Close so it becomes unavailable
// Create test server
server := httptest.NewServer(http.HandlerFunc(ProxyWebSocketToSSH(unavailableAddr, upgrader)))
server := httptest.NewServer(ProxyWebSocketToSSH(unavailableAddr, upgrader))
defer server.Close()
// Try to connect WebSocket client