SSH Crypto & Private Key Remapping
Relevant source files
The following files were used as context for generating this wiki page:
SSHPiper acts as a reverse proxy for SSH, sitting between a downstream client and an upstream server. Because SSH authentication (specifically public key authentication as per RFC 4252) involves signing a unique session_id, a proxy cannot simply pass through signatures between two different SSH connections. SSHPiper solves this by implementing "Private Key Remapping," where it validates the downstream identity and then uses a separate mapping key to authenticate against the upstream server.
Sources: README.md:12-25, README.md:167-175
Architecture and Core Logic
SSHPiper is built upon a seasoned crypto library, which is a modified version of standard golang.org/x/crypto/ssh. It includes a drop-in sshpiper.go that exposes low-level APIs required for the proxy to intercept and manipulate SSH handshake data.
Sources: CONTRIBUTING.md:46-50
The Challenge of Public Key Auth
In standard SSH public key authentication, the client signs the session_id. However, because SSHPiper maintains two distinct connections, the session_id for the downstream (Client <-> SSHPiper) and upstream (SSHPiper <-> Server) will never match, as they are hashes of different shared secrets. To overcome this, SSHPiper's plugins must provide a new private key (the "mapping key") to sign the upstream session_id.
Sources: README.md:175-185
Connection Flow Diagram
The following diagram illustrates the lifecycle of a connection involving key remapping:
Sources: README.md:188-202, CONTRIBUTING.md:52-56
Implementation via Plugins
Plugins are responsible for mapping authentication methods. A downstream client might provide a password or a public key, which the plugin then "remaps" to a different credential for the upstream.
Sources: README.md:16-20
Upstream Authentication Data Structures
The communication between sshpiperd and plugins uses gRPC. The Upstream message defines how the upstream connection should be authenticated, including fields for private keys and certificates.
| Field | Type | Description |
|---|---|---|
user_name | string | The username to use for the upstream server. |
ignore_host_key | bool | If true, skips upstream host key verification. |
private_key | bytes | The mapping private key used to sign the upstream session. |
ca_public_key | bytes | Used when the upstream requires certificate-based auth. |
Sources: libplugin/plugin.proto:20-50
Key Remapping in Specific Plugins
1. YAML Plugin
The YAML plugin allows defining static pipes where a downstream public key is matched, and an upstream private key is provided.
pipes:
- from:
- username: "alice"
authorized_keys: /path/to/downstream_pubkeys
to:
host: internal.srv:22
private_key: /path/to/upstream_mapping_key
Sources: plugin/yaml/README.md:85-103
2. Lua Plugin
The Lua plugin provides dynamic remapping via the sshpiper_on_publickey callback. It returns a table containing private_key_data.
function sshpiper_on_publickey(conn, key)
return {
host = "secure-server:22",
username = "admin",
private_key_data = "-----BEGIN OPENSSH PRIVATE KEY-----\n...",
ignore_hostkey = false
}
end
Sources: plugin/lua/README.md:120-130, plugin/lua/README.md:215-225
3. Kubernetes Plugin
In Kubernetes environments, remapping is managed via a Custom Resource Definition (CRD). The upstream private key is often sourced from a Kubernetes Secret.
Sources: plugin/kubernetes/README.md:144-165
SSH Certificate Support
SSHPiper supports verifying downstream connections using SSH User Certificates via trusted_user_ca_keys.
User/CA/Host Triple
Connections can be routed based on the certificate authority that signed the client's key. This allows the same downstream username to be routed to different upstreams depending on the issuing CA.
Sources: plugin/yaml/README.md:135-157
Security and Verification
Upstream Host Key Verification
Plugins can control whether SSHPiper verifies the upstream server's host key.
ignore_hostkey: true: Skips verification (insecure, recommended for testing only).known_hosts: Plugins likeworkingdirandyamlsupport specifyingknown_hostsfiles or data to ensure the upstream is trusted.
Sources: plugin/yaml/README.md:38-50, plugin/workingdir/workingdir.go:27-35
Permission Checking
For security, many plugins (like workingdir and yaml) enforce strict permissions (typically 0400) on private key files to prevent unauthorized access. This can be disabled via --no-check-perm if necessary (e.g., in certain Docker/volume environments).
Sources: plugin/workingdir/workingdir.go:48-60, plugin/yaml/README.md:29-33
Conclusion
SSH Crypto and Private Key Remapping are the core mechanisms that allow SSHPiper to function as a transparent but secure proxy. By decoupling downstream and upstream authentication, SSHPiper enables complex routing and protocol translations (e.g., downstream password to upstream public key) while maintaining the cryptographic integrity required by the SSH protocol.