1

I've got a server setup to randomise it's SSH Port after a certain amount of time and publish the port to a .txt file available on it's web server. I have then written a simple script on my client which fetches the new port from the web server .txt file and updates a specific hosts Port number in ~/.ssh/config.

Because ~/.ssh/config cannot parse Bash variables I call the script with ProxyCommand (I am using a JumpHost and the JH Port is the dynamic Port).

My ~/.ssh/config as follows:

Host jumphost
HostName jumphost.example.com
Port 51638
User bob
StrictHostKeyChecking no
UserKnownHostsFile=/dev/null

Host myserver
HostName myserver.com
Port 2222
User bob
ProxyCommand ~/.ssh/get_dynamic_port.sh ssh -W %h:%p jumphost

Bash script as follows (get_dynamic_port.sh):

#!/bin/sh
PORT=$(curl -s http://jumphost.example.com/port.txt)
OLDIP=`grep -w "jumphost.example.com" -A 1 ~/.ssh/config | awk '/Port/ {print $2}'`
LINE_NUMBER=`grep -n "jumphost.example.com" -A 1 ~/.ssh/config | grep -v "jumphost.example.com" | awk '{print $1}' FS="-"`
sed -i'.bak' -e "${LINE_NUMBER}s/$OLDIP/$PORT/" ~/.ssh/config

The script works fine and updates the Port for jumphost.example.com but unfortunately I cannot connect, ssh running in debug output below:

macosx:$ ssh -vvv myserver
OpenSSH_7.9p1, LibreSSL 2.7.3
debug1: Reading configuration data ~/.ssh/config
debug1: ~/.ssh/config line 54: Applying options for myserver
debug1: Reading configuration data /etc/ssh/ssh_config
debug1: /etc/ssh/ssh_config line 48: Applying options for *
debug1: Executing proxy command: exec ~/.ssh/get_dynamic_port.sh ssh -W myserver:2222 jumphost
debug1: identity file ~/.ssh/id_rsa type -1
debug1: identity file ~/.ssh/id_rsa-cert type -1
debug1: identity file ~/.ssh/id_dsa type -1
debug1: identity file ~/.ssh/id_dsa-cert type -1
debug1: identity file ~/.ssh/id_ecdsa type -1
debug1: identity file ~/.ssh/id_ecdsa-cert type -1
debug1: identity file ~/.ssh/id_ed25519 type -1
debug1: identity file ~/.ssh/id_ed25519-cert type -1
debug1: identity file ~/.ssh/id_xmss type -1
debug1: identity file ~/.ssh/id_xmss-cert type -1
debug1: Local version string SSH-2.0-OpenSSH_7.9
ssh_exchange_identification: Connection closed by remote host

It should be noted that tailing the secure log file on the jumphost server doesn't show any connection attempts which might be a sign as to what is wrong.

The jumphost config works fine without the dynamic port script, and as stated above the script is actually changing the port of the jumphost correctly but then ssh just fails after that.

Any ideas on how to achieve this or what I could be doing wrong would be appreciated. I could just use a crontab entry to run the script every so often to update the jumphost port, but I would prefer to only have the jumphost port updated when a connection is being made to it, just seems a bit cleaner that way.

Thanks :)

kingmilo
  • 147
  • 2
  • 11
  • where do you use the parameters you pass to `~/.ssh/get_dynamic_port.sh` ? – jhnc Feb 26 '19 at 00:20
  • I’m not passing any parameters, merely executing a script and then continuing with the connection, this is probably the issue, I don’t quite understand what’s required hence my question to the public for assistance :) – kingmilo Feb 26 '19 at 05:38
  • you pass the arguments `ssh -W %h:%p jumphost` when you invoke `~/.ssh/get_dynamic_port.sh` but you don't use them anywhere – jhnc Feb 26 '19 at 05:50
  • Right. Could you give me an example of how I would use them in my script, I think that's what I am misunderstanding? – kingmilo Feb 26 '19 at 06:03
  • `eval "$@"` was the code I was missing for my Bash script, that's the part I was struggling with, not the SSH side of things, so I don't agree with your comment. The question is much better served here to be looked at by someone with programming experience than someone with linux experience and the answer shows that :) – kingmilo Feb 27 '19 at 05:19

1 Answers1

1

The modern way to use "jumphosts" is with the -J option (ProxyJump).

Using the ProxyCommand option still works and has the flexibility to run arbitrary setup code by calling a script, as here. However, your code must, ultimately, run an appropriate ssh command to perform the "jump".

The typical config option looks like:

Host jump
    Hostname jumphost.fqdn
    User juser

Host final
    Hostname final.fqdn
    User fuser
    ProxyCommand ssh -W %h:%p jump

You run ssh final which opens a connection from localhost to jump, then another from jump to final with the necessary forwarding enabled.

In your configuration, you have replaced ProxyCommand with a shell script that performs some setup. You still need to run something like the normal ssh command afterwards.

Given a config line like your:

ProxyCommand ~/.ssh/get_dynamic_port.sh ssh -W %h:%p jumphost

the simplest way to invoke the normal ssh command (which you are passing as arguments to the shell script), is to invoke it at the end:

#!/bin/sh

# ... custom stuff ...

# new final line:
eval "$@"
jhnc
  • 11,310
  • 1
  • 9
  • 26
  • Thanks that did it. I appreciate the info about the new `-J` option for jumphosts which I will explore in more detail. I understand what I was doing wrong i.e. not passing parameters to the script so it had nothing to do, hence the lack of successful connection, but I am hazy on what `eval` is all about so I will go and read up on that some more. Thanks again @jhnc – kingmilo Feb 26 '19 at 06:53