How to restrict ssh tunnel authority to a certain port?

Solution 1:

In order to keep this tunnel alive. I write a ssh script to monitor and restart it if anything went wrong.

You should look into using autossh instead.

So, I have to store the password in the script.

You should use public key authentication instead of a password.

So, is it possible to restrict the remotehost user can only used ssh tunnel forwarding to port 9999?

First, make sure the user can't open an interactive shell on the server machine. Just create a specific account that is only used for opening this tunnel if you're not using one already. Set the default shell for this account to /sbin/nologin (or /bin/false if the former does not exist)

useradd tunnel
usermod -s /sbin/nologin tunnel

You should go on the client machine and generate an ssh key pair and copy the public key to the server.

ssh-keygen
ssh-copy-id tunnel@server

Finally, on the server, restrict the ability to tunnel anything but localhost:9999 using the authorized_keys file. Append Prepend the following to the authorized key that was uploaded with ssh-copy-id.

no-pty,permitopen="localhost:9999"

The no-pty is another security setting that disallows opening an interactive shell. The resulting line looks something like this:

no-pty,permitopen="localhost:9999" ssh-rsa AAAAB3NzaC1y...Rdo/R user@clientbox

There might be other useful options you can set in the authorized_keys file. For more information, read man sshd.

In addition, you can also lock down the account in the /etc/ssh/sshd_config via a Match block for the account:

Match User tunnel
   ForceCommand /sbin/nologin # An additional configuration to disable any shell command, superfluous when the user's shell is already set to `/sbin/nologin`
   AllowAgentForwarding no
   AllowTcpForwarding local # Disallow port forwarding of remote ports, superfluous when using the `permitopen` restriction in authorized_keys
   AllowStreamLocalForwarding no # Probably not necessary, as the user needs to have access rights to access the AF_UNIX port
   X11Forwarding no # Because some default configuration files, e.g. from Debian, set it to yes
# Beware: Match does not end with indentation!

These are only tips to improve your current ssh tunnel setup. As Dennis suggested, there are other, more elegant tunnelling solutions you should consider.

Solution 2:

No, that is not possible. You can disable port forwarding, but that disables forwarding of any port, there's no per-port setting.

Yes, this is possible by prepending permitopen="localhost:9999" to the key in ~/.ssh/authorized_keys on the server, see the sshd manpage (thanks Kenny!). You'll also want to force a command that does nothing but sleep, to make sure that any attacker can't get a shell (and thus remove that restriction, and do other bad things).

That said, ssh is the wrong way of doing this. Why not use stunnel to make the service available over ssl? Or set up a VPN connection between the two machines with openvpn?