Introduction and Terminology
Relevant source files
The following files were used as context for generating this wiki page:
sshpiper is a specialized reverse proxy for SSH (Secure Shell) and related protocols such as SCP and port forwarding. It serves as an intermediary that manages SSH connections by accepting them from a client-side and routing them to a specific server-side based on plugin-defined logic. Its architecture is designed to be highly extensible through a gRPC-based plugin system, allowing for complex routing, authentication remapping, and additional security challenges.
The project is structured into several core components: the sshpiperd daemon which manages the connection pipes, a variety of plugins for routing and authentication logic, and an optional sshpiperd-webadmin for centralized management of multiple instances.
Sources: README.md:1-12, CONTRIBUTING.md:52-61
Core Terminology
The following table defines the primary entities and concepts used throughout the sshpiper ecosystem:
| Term | Description |
|---|---|
| Downstream | The client-side of the connection, typically an SSH client initiated by a user. |
| Upstream | The server-side of the connection, typically the destination SSH server. |
| sshpiperd | The main daemon that wraps the crypto/ssh library to manage connection pipes. |
| Plugin | A separate process (usually a gRPC server) that handles routing and authentication mapping. |
| Additional Challenge | An extra security step (e.g., 2FA or a math question) introduced by a plugin before connecting to the upstream. |
| Mapping Key | A private key provided by a plugin to sign the session_id for upstream public key authentication. |
Sources: README.md:14-20, README.md:162-167, CONTRIBUTING.md:56-61
System Architecture
The sshpiper architecture functions as a "man-in-the-middle" by design to facilitate routing. It maintains two distinct SSH connections: one between the Downstream and sshpiper, and another between sshpiper and the Upstream.
Connection Flow
The diagram below illustrates the high-level flow of a connection through the system:
The system manages the mismatch in session_id (which are hashes of shared secrets and differ for each connection) by having the plugin provide credentials to "re-sign" the connection to the upstream.
Sources: README.md:23-38, README.md:151-160, CONTRIBUTING.md:65-68
Component Interaction
sshpiperd interacts with plugins primarily via gRPC. While plugins can be remote gRPC servers, they typically connect via stdin/stdout, wrapped into a net.Conn for gRPC use.
Data Structures and Protocols
Plugin Metadata (ConnMeta)
Plugins receive connection metadata to make routing decisions. This includes the username, origin address, and a unique identifier.
message ConnMeta {
string user_name = 1;
string from_addr = 2;
string uniq_id = 3;
map<string, string> metadata = 4;
}
Sources: libplugin/plugin.proto:7-12
Upstream Configuration
When a plugin successfully authenticates/routes a user, it returns an Upstream object containing the destination details and authentication method to be used against the upstream server.
| Field | Type | Description |
|---|---|---|
uri | string | The connection URI for the upstream server. |
user_name | string | The username to use for the upstream server. |
ignore_host_key | bool | If true, skips upstream host key verification. |
auth | oneof | Authentication details (None, Password, PrivateKey, etc.). |
Sources: libplugin/plugin.proto:14-30
Admin and Management
For large deployments, sshpiper provides an Admin API and a Web UI.
sshpiperd Admin API
sshpiperd can expose a gRPC-based admin API (enabled via --admin-grpc-port) that allows for:
- Listing live SSH sessions.
- Viewing real-time terminal output (streaming).
- Terminating (killing) sessions.
sshpiperd-webadmin
A separate binary that aggregates multiple sshpiperd instances into a single web dashboard. It uses a static discovery or environment-based endpoint list to connect to various daemons.
Conclusion
sshpiper acts as a sophisticated routing layer for SSH traffic. By decoupling the routing and authentication logic into a plugin-based architecture, it allows administrators to implement complex access patterns (such as routing by username or source IP) while supporting standard SSH protocols. The inclusion of an admin API and a centralized web interface ensures that even large-scale clusters of proxy instances remain manageable and observable.