====== 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