====== remote ssh tunnel ====== ===== client procedure ===== To establish a tunnel account, run this on the client (this would be the system you want to connect to). wget -O - http://my.doma.in/tunnel?IDSTRING | /bin/bash * IDSTRING has to consist of 1 to 25 characters. * permitted are upper and lower case letters, figures, '.' and '-' This will yield the script file /root/remote-ssh-tunnel. You may start the tunnel: /root/remote-ssh-tunnel The client now will connect to your tunnel hub and initiate a remote port forwarding of the client's local SSH service port (usually port 22/tcp) to a high port of your tunnel hub on IP address 127.0.0.1. ==== adopting the client ==== If you plan for a persistent tunnel connection, you have to make some changes: sed -i ' s:#!/bin/sh:#!/bin/bash:; s/~\//\/root\//; s/-l/-o ServerAliveInterval=15 -o TCPKeepAlive=yes -l/ /^done/i\sleep 10 ' /root/remote-ssh-tunnel sed -i '/^exit 0/inohup /root/remote-ssh-tunnel >/dev/null 2>&1 &' /etc/rc.local If the client's SSH service port differs from the usual port 22/tcp, let's say SSH would run on 10022, you may use something like: sed -i 's/:22/:10022/;' /root/remote-ssh-tunnel ===== server procedure ===== Things needed: * a system account to create the new accounts by * a range of UIDs to create the new accounts with e.g. 10000-11000 * a range of TCP ports to create the new accounts with e.g. 10000-11000 * we'll set UID = port nr. for a cleaner structure * a dedicated /home/tun-adm/adduser.conf file * a ssh key pair prereq: * vo - apt-get install vo * sudo - apt-get install sudo addgroup --gid 10000 tun-adm adduser --uid 10000 --gid 10000 tun-adm sed ' /^FIRST_UID=/c\FIRST_UID=10000 /^LAST_UID=/c\LAST_UID=10999 /^FIRST_GID=/c\FIRST_GID=10000 /^LAST_GID=/c\LAST_GID=10999 ' /etc/adduser.conf > /home/tun-adm/adduser.conf cat << 'EOF' > /etc/sudoers.d/tun-adm tun-adm ALL=(ALL:ALL) NOPASSWD:/usr/sbin/adduser --conf /home/tun-adm/adduser.conf --gecos tunnel-user --disabled-password --firstuid 10000 tun-[-a-zA-Z0-9.]* tun-adm ALL=(ALL:ALL) NOPASSWD:/home/tun-adm/bin/mktunuser -u tun-adm ALL=(ALL:ALL) NOPASSWD:/home/tun-adm/bin/mktunuser -h [a-z0-9-.][a-z0-9-.]* tun-adm ALL=(ALL:ALL) NOPASSWD:/home/tun-adm/bin/mktunuser -s [a-z0-9-.][a-z0-9-.]* EOF # prepare /etc/hosts for tunnel aliases vo -o /etc/hosts cat << EOF >> /etc/hosts # tunnel aliases # tunnel ends EOF vo -i /etc/hosts # prepare /root/.ssh/config for tunnel aliases touch /root/.ssh/config vo -o /root/.ssh/config cat << EOF >> /root/.ssh/config # tunnel aliases # tunnel ends EOF vo -i /root/.ssh/config su - tun-adm ssh-keygen -f /home/tun-adm/.ssh/id_rsa_tun -N '' -b 4096 ( echo -n 'command="/home/tun-adm/bin/mktunuser" ' cat /home/tun-adm/.ssh/id_rsa_tun.pub ) >> /home/tun-adm/.ssh/authorized_keys mkdir -p /home/tun-adm/bin # script content listet blow wget -O /home/tun-adm/bin/mktunuser "http://wiki.fischglas.de/wiki/doku.php?do=export_code&id=project:remote-ssh-tunnel&codeblock=5" chmod 755 /home/tun-adm/bin/mktunuser #!/usr/bin/perl -Tw # aufruf auf dem zielsystem: # hostname | ssh -t -i id_rsa_tun -o AddressFamily=inet tun-adm@my.doma.in | sed '1,/^XXX---XXX/s/^/# /' | sh -v use strict; use User::pwent; $ENV{PATH}=""; my @Cmd = (); my $cmd = "/home/tun-adm/bin/mktunuser"; my $vo = "/bin/vo"; # change this in sudoers, also my $addusercfg = "/home/tun-adm/adduser.conf"; if ( ! defined $ARGV[0] or $ARGV[0] eq "" ) { my $l = ; chomp($l); my ( $user ) = $l =~ /^([-a-z0-9.]{1,25})$/; defined $user or die "username '$l' invalid"; $user = "tun-".$user; @Cmd = ("/usr/bin/sudo","/usr/sbin/adduser","--conf",$addusercfg,"--gecos","tunnel-user","--disabled-password","--firstuid","10000",$user); print join " ","#",@Cmd,"\n"; system @Cmd; @Cmd = ( "/usr/bin/sudo","-u",$user,$cmd,"-u"); print join " ","#",@Cmd,"\n"; system @Cmd; @Cmd = ( "/usr/bin/sudo",$cmd,"-h",$user); print join " ","#",@Cmd,"\n"; system @Cmd; @Cmd = ( "/usr/bin/sudo",$cmd,"-s",$user); print join " ","#",@Cmd,"\n"; system @Cmd; } elsif ( $ARGV[0] eq "-u" ) { my $user = getpwuid($<)->[0]; my $id = $<; print "U: $user $id\n"; chdir("/home/".$user); # exit; @Cmd = ("/bin/mkdir",".ssh"); print join " ","#",@Cmd,"\n"; system @Cmd; chdir(".ssh"); @Cmd = ("/usr/bin/ssh-keygen","-t","rsa","-f","id_rsa_remote_tun"); print join " ","#",@Cmd,"\n"; system @Cmd; my $s = q#/bin/echo -n 'command="echo Tunnel Port XXXXX aktiv; while sleep 10; do echo -n .; done" ' >> authorized_keys#; $s =~ s/XXXXX/$id/; @Cmd = ("/bin/sh","-c",$s); print join " ","#",@Cmd,"\n"; system @Cmd; @Cmd = ("/bin/sh","-c",q#/bin/cat id_rsa_remote_tun.pub >> authorized_keys# ); print join " ","#",@Cmd,"\n"; system @Cmd; @Cmd = ("/bin/chmod","600","authorized_keys" ); print join " ","#",@Cmd,"\n"; system @Cmd; print "XXX---XXX---XXX---XXX\n"; @Cmd = ("/bin/cat","id_rsa_remote_tun"); print join " ","#",@Cmd,"\n"; print "cat << EOF > ~/.ssh/id_rsa_remote_tun\n"; system @Cmd; print "EOF\n"; print "chmod 600 ~/.ssh/id_rsa_remote_tun\n"; @Cmd = ("/bin/cat","id_rsa_remote_tun.pub"); print join " ","#",@Cmd,"\n"; print "cat << EOF > ~/.ssh/id_rsa_remote_tun.pub\n"; system @Cmd; print "EOF\n"; print qq|echo "#!/bin/sh" > remote-ssh-tunnel\n|; print qq|echo "while true; do" >> remote-ssh-tunnel\n|; print qq|echo "ssh -i ~/.ssh/id_rsa_remote_tun -4 -l $user {my.tunhub} -R $id:127.0.0.1:22 " >> remote-ssh-tunnel\n|; print qq|echo "done" >> remote-ssh-tunnel\n|; print "chmod 755 remote-ssh-tunnel\n"; } elsif ( $ARGV[0] eq "-h" ) { $ENV{PATH}="/bin:/usr/bin:/sbin:/usr/sbin"; my $user = $ARGV[1]; @Cmd = ($vo,"-o","/etc/hosts" ); print join " ","#",@Cmd,"\n"; system @Cmd; my $dollarslash = $/; $/ = undef; open H,"/etc/hosts" or die "can't open '/etc/hosts': $!"; my $h = ; close H; $/ = $dollarslash; $h =~ s/(# tunnel ends)/127.0.0.1\t$user\n$1/; open H,">","/etc/hosts" or die "can't open '/etc/hosts': $!"; print H $h; close H; @Cmd = ($vo,"-i","/etc/hosts" ); print join " ","#",@Cmd,"\n"; system @Cmd; } elsif ( $ARGV[0] eq "-s" ) { $ENV{PATH}="/bin:/usr/bin:/sbin:/usr/sbin"; my $user = $ARGV[1]; my $pw = getpwnam($user); my $port = $pw->uid; my $r = "Host $user\n". " Port $port\n". " Cipher blowfish\n". " Compression yes\n"; @Cmd = ("touch","/root/.ssh/config" ); print join " ","#",@Cmd,"\n"; system @Cmd; @Cmd = ($vo,"-o","/root/.ssh/config" ); print join " ","#",@Cmd,"\n"; system @Cmd; my $dollarslash = $/; $/ = undef; open H,"/root/.ssh/config" or die "can't open '/root/.ssh/config': $!"; my $h = ; close H; $/ = $dollarslash; $h =~ s/(# tunnel ends)/$r\n$1/; open H,">","/root/.ssh/config" or die "can't open '/root/.ssh/config': $!"; print H $h; close H; @Cmd = ($vo,"-i","/root/.ssh/config" ); print join " ","#",@Cmd,"\n"; system @Cmd; } === the web server part === * copy /home/tun-adm/.ssh/id_rsa_remote_tun to some web server * copy /home/tun-adm/.ssh/id_rsa_remote_tun.pub to some web server * copy the file "cmd" (see below) to some web server * make "cmd" a cgi program (i.e. configure your web server accordingly) * make "cmd" accessible as my.domain/tunnel (i.e. configure your web server accordingly) * adjust URLs and hostname inside "cmd" #!/usr/bin/perl -T use strict; my $url = "http://{my.websrv}/tunnel"; my $urlkey = "http://{my.websrv}/tun/id_rsa_tun"; my $tunhub = "{my.tunhub}"; # der Username darf 32 Zeichen lang werden # da noch ein Prefix hinzukommt, sind hier 25 Zeichen erlaubt my ( $user ) = $ENV{QUERY_STRING} =~ /^([-a-z0-9.]{1,25})$/; if ( ! $user ) { print << "EOF"; Content-type: text/plain echo "FEHLER!" echo "" echo "Der korrekte Aufruf lautet:" echo " wget -O - $url?KENNUNG | sh " echo "" echo "Dabei muss KENNUNG aus 1 bis 25 Zeichen bestehen." echo "" echo "Zulaessig sind Kleinbuchstaben, Ziffern sowie die Zeichen '.' und '-'." echo "" EOF exit 1; } print << "EOF"; Content-type: text/plain wget $urlkey -O ~/.ssh/id_rsa_tun wget $urlkey.pub -O ~/.ssh/id_rsa_tun.pub chmod 600 ~/.ssh/id_rsa_tun cd ~/.ssh echo $user | ssh -t -i id_rsa_tun -o AddressFamily=inet tun-adm\@$tunhub | sed '1,/^XXX---XXX/s/^/# /' | sh -v mv ./remote-ssh-tunnel ~/remote-ssh-tunnel echo "Der Tunnel wurde eingerichtet." echo "Zum Start des Tunnels bitte '~/remote-ssh-tunnel' eingeben" EOF Example: # /var/www/my.doma.in/htdocs would be the document root DOCROOT=/var/www/my.doma.in/htdocs mkdir $DOCROOT/tun cp /home/tun-adm/.ssh/id_rsa_tun /home/tun-adm/.ssh/id_rsa_tun.pub $DOCROOT/tun/ chmod 444 $DOCROOT/tun/* wget -O $DOCROOT/tun/cmd "http://wiki.fischglas.de/wiki/doku.php?do=export_code&id=project:remote-ssh-tunnel&codeblock=5" chmod 755 $DOCROOT/tun/cmd vi /etc/apache2/sites-available/my.doma.in.conf ScriptAlias /tunnel $DOCROOT/tun/cmd service apache2 reload === testing components === == tests without side effects == run $DOCROOT/tun/cmd should yield: Content-type: text/plain echo "FEHLER!" echo "" echo "Der korrekte Aufruf lautet:" echo " wget -O - http://{my.doma.in}/tunnel?KENNUNG | sh " echo "" echo "Dabei muss KENNUNG aus 1 bis 25 Zeichen bestehen." echo "" echo "Zulaessig sind Kleinbuchstaben, Ziffern sowie die Zeichen '.' und '-'." echo "" run curl my.doma.in/tunnel should yield: wget http://{my.doma.in}/tun/id_rsa_tun -O ~/.ssh/id_rsa_tun wget http://{my.doma.in}/tun/id_rsa_tun.pub -O ~/.ssh/id_rsa_tun.pub chmod 600 ~/.ssh/id_rsa_tun cd ~/.ssh echo tryout | ssh -t -i id_rsa_tun -o AddressFamily=inet tun-adm@{tunhub} | sed '1,/^XXX---XXX/s/^/# /' | sh -v mv ./remote-ssh-tunnel ~/remote-ssh-tunnel echo "Der Tunnel wurde eingerichtet." echo "Zum Start des Tunnels bitte '~/remote-ssh-tunnel' eingeben" run curl http://{my.doma.in}/tun/id_rsa_tun should yield: ----BEGIN RSA PRIVATE KEY----- MIIJKQI... ... -----END RSA PRIVATE KEY----- run curl http://{my.doma.in}/tun/id_rsa_tun.pub should yield: ssh-rsa AAAA....== tun-adm@... == tests creating real accounts == wget -O - http://{my.doma.in}/tunnel?tryout | sh should yield: ... Saving to: `{my.home}/.ssh/id_rsa_tun' ... Saving to: `{my.home}/.ssh/id_rsa_tun.pub' ... Pseudo-terminal will not be allocated because stdin is not a terminal. Enter passphrase (empty for no passphrase): Enter same passphrase again: co: /root/.ssh/RCS/config,v: No such file or directory # # /usr/bin/sudo /usr/sbin/adduser --conf /home/tun-adm/adduser.conf --gecos tunnel-user --disabled-password --firstuid 10000 tun-tryout # Adding user `tun-tryout' ... # Adding new group `tun-tryout' (10001) ... # Adding new user `tun-tryout' (10001) with group `tun-tryout' ... # Creating home directory `/home/tun-tryout' ... # Copying files from `/etc/skel' ... # # /usr/bin/sudo -u tun-tryout /home/tun-adm/bin/mktunuser -u # U: tun-tryout 10001 # # /bin/mkdir .ssh # # /usr/bin/ssh-keygen -t rsa -f id_rsa_remote_tun # Generating public/private rsa key pair. # Your identification has been saved in id_rsa_remote_tun. # Your public key has been saved in id_rsa_remote_tun.pub. # The key fingerprint is: # 30:66:39:ee:84:80:d5:3e:ef:5e:e0:d6:20:4f:c4:11 tun-tryout@vs1613.ams2.alvotech.de # The key's randomart image is: ... # # /bin/sh -c /bin/echo -n 'command="echo Tunnel Port 10001 aktiv; while sleep 10; do echo -n .; done" ' >> authorized_keys # # /bin/sh -c /bin/cat id_rsa_remote_tun.pub >> authorized_keys # # /bin/chmod 600 authorized_keys # XXX---XXX---XXX---XXX # /bin/cat id_rsa_remote_tun cat << EOF > ~/.ssh/id_rsa_remote_tun -----BEGIN RSA PRIVATE KEY----- MIIEpAIBAAKCAQEAtjrV4Us2Nwdz/4tBAV7+OjzqYcmU0hPozRS2R0mIr183pYxc ... -----END RSA PRIVATE KEY----- EOF chmod 600 ~/.ssh/id_rsa_remote_tun # /bin/cat id_rsa_remote_tun.pub cat << EOF > ~/.ssh/id_rsa_remote_tun.pub ssh-rsa AAAAB... tun-tryout@... EOF echo "#!/bin/sh" > remote-ssh-tunnel echo "while true; do" >> remote-ssh-tunnel echo "ssh -i ~/.ssh/id_rsa_remote_tun -4 -l tun-tryout {my.tunhub} -R 10001:127.0.0.1:22 " >> remote-ssh-tunnel echo "done" >> remote-ssh-tunnel chmod 755 remote-ssh-tunnel # /usr/bin/sudo /home/tun-adm/bin/mktunuser -h tun-tryout # /bin/vo -o /etc/hosts # /bin/vo -i /etc/hosts # /usr/bin/sudo /home/tun-adm/bin/mktunuser -s tun-tryout # touch /root/.ssh/config # /bin/vo -o /root/.ssh/config # /bin/vo -i /root/.ssh/config Der Tunnel wurde eingerichtet. Zum Start des Tunnels bitte '~/remote-ssh-tunnel' eingeben run @client ls -l ~/.ssh/id_rsa_tun ~/.ssh/id_rsa_tun.pub should yield: -rw------- 1 {my.login} {my.group} 3243 Feb 12 20:05 {my.home}/.ssh/id_rsa_tun -rw-r--r-- 1 {my.login} {my.group} 757 Feb 12 20:05 {my.home}/.ssh/id_rsa_tun.pub run @tunhub grep ^tun- /etc/passwd should yield: tun-adm:x:10000:10000:,,,:/home/tun-adm:/bin/bash tun-tryout:x:10001:10001:tunnel-user,,,:/home/tun-tryout:/bin/bash run @tunhub tail /etc/hosts should yield: ... # tunnel aliases 127.0.0.1 tun-tryout # tunnel ends run @tunhub tail /root/.ssh/config should yield: ... # tunnel aliases Host tun-tryout Port 10001 Cipher blowfish Compression yes # tunnel ends run @client ./remote-ssh-tunnel should yield: Tunnel Port 10001 aktiv . run @tunhub ssh 127.0.0.1 -p 10001 should yield: root@127.0.0.1's password: You may now provide the root passswort for the client system If you can't log in think of the usual sshd config obstructions on the client concerning root login ("PermitRootLogin" config option). You might consider another login using "-l". run @tunhub ssh tun-tryout should yield: The authenticity of host '[tun-tryout]:10001 ([127.0.0.1]:10001)' can't be established. RSA key fingerprint is 3e:46:b3:fa:54:15:8f:fa:f3:d7:c0:28:4d:bc:00:2d. Are you sure you want to continue connecting (yes/no)? yes Warning: Permanently added '[tun-tryout]:10001' (RSA) to the list of known hosts. You may now provide the root passswort for the client system If you can't log in think of the usual sshd config obstructions on the client concerning root login ("PermitRootLogin" config option). You might consider another login using "-l". rollback: userdel -r tun-tryout