I wanted to present a small (= 340 lines of bash) project I did over the weekend to scratch an itch: sshtunnel.
It's used to manage ssh tunnels via systemd, quite like netctl. This is how a tunnel in the config looks:
[tunnel.lupin] user=sshtunnel host=example.org port=22 tunnel=-D 9999 -L 9001:localhost:9001 ssh_options=
and the tool itself in action:
[florian@ginny ~]$ sshtunnel Usage: /usr/bin/sshtunnel [-c <config>] <command> [<name>] -c: Use an alternate config file Commands: start <name> Starts the tunnel named <name> stop <name> Stops the tunnel named <name> print <name> Validates config and prints command that would be run ssh-keygen Generates ssh-key start-all Starts all configured tunnels stop-all Stops running tunnels list Lists running tunnels test <name> Opens a test-connection to the tunnel <name> (to accept host keys, etc) [florian@ginny ~]$ sudo sshtunnel start lupin [florian@ginny ~]$ sshtunnel list lupin [florian@ginny ~]$ sudo sshtunnel status lupin email@example.com - SSH Tunnel managment Loaded: loaded (/usr/lib/systemd/system/sshtunnel@.service; static) Active: active (running) since Mon 2013-08-12 15:29:44 CEST; 7s ago Main PID: 22782 (autossh) CGroup: name=systemd:/system/sshtunnel@.firstname.lastname@example.org ├─22782 autossh -M 0 -- -o ServerAliveInterval=15 -o ServerAliveCountMax=3 -N -p 22 -D 9999 -L 9001:localhost:9001 email@example.com... └─22811 /usr/bin/ssh -o ServerAliveInterval=15 -o ServerAliveCountMax=3 -N -p 22 -D 9999 -L 9001:localhost:9001 firstname.lastname@example.org Aug 12 15:29:44 ginny systemd: Started SSH Tunnel managment. Aug 12 15:29:44 ginny autossh: port set to 0, monitoring disabled Aug 12 15:29:44 ginny autossh: starting ssh (count 1) Aug 12 15:29:44 ginny autossh: ssh child pid is 22811
It requires to have a key-based login without a passphrase set up, so be sure you create a non-privileged user on the server, as explained in the README. The source is in my git repo and there is sshtunnel-git in the AUR.
With the default config, it uses autossh for a stable connection if it's installed, and falls back to plain ssh otherwise.
Any kind of feedback welcome!
Last edited by The Compiler (2013-08-12 13:34:12)
Thanks for this - this is just what I was looking for. It took me some tinkering to get going but it's working for now.
I kinda lost track of the process but I think some problems with running the test meant that the server wasn't added to the list of known hosts (I noticed that the file was only recently added to /var/lib/sshtunnel/.ssh/ ) Also I had to manually add the public key to the server which wasn't mentioned in the directions.
A few things/suggestions:
The ssh-keygen command is kinda puzzling. You expect to be able to use the full range of ssh-keygen options but it seems to only use a fixed length RSA key. Adding to the confusion is that 'sshtunnel ssh-keygen' fails. You have to provide it with an option - '-' will do - which it will then promptly ignore. Given the current state of cryptography shouldn't ECDSA at least be an option? It's not a big issue since using Putty already requires me to use RSA (doesn't work with ECDSA) but still.
I generally want to move as many things to systemd as possible for the sake of neatness if nothing else but without an 'enable' command I can't really see that this accomplishes anything much. Currently I'm just using it to channel all interaction with transmission's web interface through ssh so I don't have to open up a public port in my firewall for that purpose. This means that I would like to have the tunnel up as soon as the network is up.
I suppose this is really a problem with openssh but I got very little help troubleshooting my issue from the systemd log, which simply stated that the connection had failed due to 'permissions' or something like it.
Anyway, thanks again for your efforts and I hope you'll continue working on this project.
Wheee, I didn't expect anyone besides me actually using this
Thanks for your feedback, I'll take a closer look and implement your suggestions somewhen next week (or this week, depending on your timezone) I think.
I use a NetworkManager dispatcher file to start/stop the tunnels by the way.
$ cat /etc/NetworkManager/dispatcher.d/sshtunnel #!/bin/bash [[ "$2" == up ]] && sshtunnel start-all [[ "$2" == down ]] && sshtunnel stop-all
Wheee, I didn't expect anyone besides me actually using this
And I didn't expect you to be so responsive. Awesome! Thanks :-) And the dispatcher solution works nicely, thanks.
I'm gonna push my luck here and ask for one more thing, then:
I tried the following tunnel to access my web server from my laptop:
and found out that only root could forward 'privileged' ports. I figured then that I could simply change the local port to non-privileged 8080 and it works as far as the tunnel is concerned.
The reason I'd want to do it, is because I would like to restrict access to wordpress' administration section to requests emanating from localhost, figuring that it would be a simple and pretty cast-iron security measure against unwanted attempts to log in.
However, when I then open localhost:8080 I get a sorry looking sign saying 'Multisite Wordpress only works when there are no port numbers in the URL'.
So the request is: Can you find/suggest some way of allowing the program to forward privileged ports?
Last edited by reannual (2013-11-10 20:38:59)
I added commands for enable/disable/restart, these are already pushed.
Regarding ssh-keygen: It was indeed a bug that it required an argument. I fixed that and I'm working on bits/type options now. Anything else one would need?
Adding the public key to the server is described in the readme (Then copy the echoed key by hand to /var/lib/sshtunnel/.ssh/authorized_keys.) but maybe I should clarify this is on the server side.
I really don't feel like implementing something like starting sshtunnel as root, and then dropping privileges when not requiring them, but luckily there are better options:
You could use a dynamic forwarding to any port (say, -D9999), and then tell your browser to use localhost:9999 as SOCKS proxy. Be sure localhost/127.0.0.1 is not in the list of hosts where the proxy shouldn't be used (Whah, double negation. Make sure localhost is proxied.). Then everything is tunneled like you were actually browsing from the server, so you can just surf to localhost.
You could also use capabilities to give the ssh binary the permission to bind to a lowport without root, using
# setcap 'cap_net_bind_service=+ep' /usr/bin/ssh
I haven't tested this, but I think it should work. You just have to do it again after each OpenSSH update.
Last edited by The Compiler (2013-11-15 05:59:12)
Thanks for the update and the response.
I've been testing this a bit over the weekend but I'm stuck at getting the 'enable' part to work.
After having updated saturday the following things will give me a working tunnel:
Manually running the 'ssh' command as my regular user
Sticking with the dispatcher solution
Running the command 'sudo sshtunnel start (name of tunnel in sshtunnel.conf)'
Taking my cue from the sshtunnel@.service file: Running the command 'sudo -u sshtunnel /usr/bin/sshtunnel connect (name of tunnel in sshtunnel.conf)'
What does not work is 'sudo sshtunnel enable (name of tunnel in sshtunnel.conf)'. While it will create a service file in /etc/systemd/system/multi-user.target.wants, it will not start any tunnels. Running 'sshtunnel list' after boot (and after network is up) reveals no tunnels running.
As all the ssh commands seem to be perfectly fine, the problem is probably about systemd at some level, though I'm not enough of a systemd expert to understand what exactly.
Last edited by reannual (2013-11-17 20:20:19)