tg123/sshpiper

Cannot create upstream when client has multiple key pairs

Closed this issue ยท 15 comments

Hi! I just saw this project today and wanted to try it out to reverse proxy my SSH servers. When using public key authentication, the server errors out if the incorrect private key is used by the client. I believe the normal behaviour seen in openssh server is either a "permission denied (publickey)" or allow the client to retry with a different key. Is there some kind of configuration I can use/enable to allow the normal behaviour?

Here is my YAML file

version: "1.0"
pipes:
  - from:
      - username: "user"
        authorized_keys: /home/user/sshpiper/keys/authorized_c1
    to:
      host: 127.0.0.1:5522
      username: "user"
      password: "pass"
      ignore_hostkey: true
  - from:
      - username: "user2"
        authorized_keys: /home/user/sshpiper/keys/authorized_c2
    to:
      host: 127.0.0.1:5422
      username: "user2"
      password: "pass"
      ignore_hostkey: true

and here is the command I used

./out/sshpiperd -i /tmp/sshpiperkey --server-key-generate-mode notexist --log-level=trace ./out/yaml --config config.yaml --no-check-perm

Thank you so much for this project by the way, it is the only functional SSH reverse proxy I've come across

server here is unclear

I believe you are looking for mapping something to key auth to upstream (real sshd)

to:
  private_key: /path/to/host-publickey/id_rsa

reason TL;DR
https://github.com/tg123/sshpiper?tab=readme-ov-file#public-key-authentication-when-using-sshpiper-private-key-remapping

I am currently attempting to have downstream connect to sshpiper via key auth, and sshpiper to upstream using password auth. Currently, a working configuration (please correct me if I'm missing something important) requires me to enable ignore_hostkey in the yaml and the --no-check-perm flag.

On my local machine, I have multiple SSH keys, and normally when connecting to an OpenSSH server my client can retry with a different key until either all keys have been tried or it succeeds. Under my current configuration, if the initial offered key matches, the connection works, but if the initial key offered does not match, my client hangs and sshpiper's logs are spammed with

ERRO[0136] cannot create upstream for mydownstreamip (username [user]) with public key auth: rpc error: code = Unknown desc = no matching pipe for username [user] found

if I remove the ignore_hostkey option in the yaml file, I get a Permission denied (publickey) response if the key matches, and the same issue as above if the key doesn't match.

if I remove --no-check-perm flag, I get a config.yaml's perm is too open error in sshpiper even though the configuration seems to be correct from the examples.

Thanks!

i assume you are running

ssh user@xxx -i key

could you please confirm if key.pub in /home/user/sshpiper/keys/authorized_c1
sshpiper will treat user as not matched if key.pub not found in authorized_keys

Yes, the public key is in /home/user/sshpiper/keys/authorized_c1. However, I have multiple key pairs on my machine so, for example, if the public key in that file is the second key pair on my device, and my SSH client offers the first one initially, then sshpiper spams the log and my client hangs (as opposed to normal ssh server where my client retries with second key). In this case, I must manually specify which key my client must use with the -i option, as opposed to just ssh user@xxx

Here is the version:

sshpiperd version (devel), 38be0fdd8, 2024-05-18T09:51:39Z, go1.22.3

built directly from master branch

got it, could you please test if last know stable v1.2.8 good for your case

also i am working on a fix to it

I just tried stable v1.2.8, I get Permission denied (publickey) if I don't specify which key client should use (as opposed to hanging + spamming logs from before). I'm still forced to use --no-check-perm and ignore-hostkey: true to make it work.

will support multiple key

--no-check-perm: you need to set yaml to 400 (chmod 400 xxx.yaml)
ignore-hostkey: true: to have secure connection, need to put upstream hostkey.pub to known_hosts_data

ah 600 is good too

see code here

if fi.Mode().Perm()&0077 != 0 {

Thanks, setting 600 worked. As for known_hosts, I tried adding known_hosts and putting the public key in the file, and I also tried base64 encoding the public key and adding it inline as known_hosts_data, but I still get Permission denied (publickey) on downstream client side
(I pulled the SSH host public key from /etc/ssh/ssh_host_ed25519_key.pub, if that's what I'm supposed to use)

the known_hosts_data here is for sshpiper to verify upstream (real sshd)
if ignore-hostkey: true works, then you are putting wrong key

I feel like I'm doing things right, correct me if I did anything wrong:

  • on upstream machine, I updated sshd to use /etc/ssh/ssh_host_rsa_key (the autogenerated one), and copied the corresponding public key (ssh_host_rsa_key.pub) to sshpiper's directory
  • on sshpiper's machine, in config.yaml, I added the path to ssh_host_rsa_key.pub under known_hosts: /home/ubuntu/sshpiper/ssh_host_rsa_key.pub

Nevermind fixed it, I looked at the known hosts parsing and it needs to contain the host IP as well in addition to pubkey

hi @ApocalypseCalculator

i added testcase cover your scenario in #396

seems ssh client worked well (current sshpiper master 6fe67e3, with ssh client OpenSSH_9.2p1 Debian-2+deb12u2, OpenSSL 3.0.11 19 Sep 2023)

could you please review the testcase?

using multiple keyfile, first wrong, second right

ssh -v -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null -p 33803 -l publickey_simple -i /tmp/3823507707/key -i /tmp/4237723506/id_rsa_simple

logs

debug1: Next authentication method: publickey
DEBU[0001] downstream 127.0.0.1:46118 (username [publickey_simple]) is sending public key auth 
debug1: Offering public key: /tmp/3823507707/key RSA SHA256:wrUs0Z/BBZCbkp6ANbU4DlaNkld85eIDbCk2H0wFI9I explicit
ERRO[0001] cannot create upstream for 127.0.0.1:46118 (username [publickey_simple]) with public key auth: rpc error: code = Unknown desc = no matching pipe for username [publickey_simple] found 
DEBU[0001] next auth methods [password publickey] for downstream  127.0.0.1:46118 (username [publickey_simple]) 
debug1: Authentications that can continue: password,publickey
debug1: Offering public key: /tmp/4237723506/id_rsa_simple RSA SHA256:BT5nRpf60kdFVV6fzDEvm0hYhmVx9wAHkT/Qk8MkOlg explicit
DEBU[0001] downstream 127.0.0.1:46118 (username [publickey_simple]) is sending public key auth 
DEBU[0001] connecting to upstream 172.19.0.6:2222 with auth [privatekey] 
debug1: Server accepts key: /tmp/4237723506/id_rsa_simple RSA SHA256:BT5nRpf60kdFVV6fzDEvm0hYhmVx9wAHkT/Qk8MkOlg explicit
Authenticated to 127.0.0.1 ([127.0.0.1]:33803) using "publickey".

Nice! It works ๐Ÿ‘