remote Zugriff auf MySQL Server per SSH Tunnel

Jeder kennt es wohl. Man möchte den Webserver physisch von seiner Datenbank trennen aber dennoch die einzelnen Daten nicht unverschlüsselt durchs Netz jagen. Für solche Fälle eignet sich ideal ein SSH Tunnel, der die Verbindung automatisch verschlüsselt aufbaut und diese auch nach einem Abbruch wieder aufnimmt. Hier zeige ich euch wie es geht. Ihr müsst somit nie wieder Daten unverschlüsselt durchs Netz jagen und habt ein Quantum mehr Sicherheit in eurere Infrastruktur.

Dieses Beispiel lässt sich natürlich auch für beliebige andere Dienste anwenden.

Hier eine visuelle Darstellung des Vorhabens

ssh-tunnel
ssh-tunnel visuell dargestellt

 

 

 

 

 

 

 

Für dieses Beispiel verwende ich zwei Debian 7.8 Systeme aber es sollte auch mit jeder anderen Distribution auf dem gleichen Wege funktionieren.

MySQL Remote Zugriff per SSH Tunnel

Zuerst installieren wir OpenSSH und autossh, falls nicht eh schon vorhanden.

apt-get install openssh autossh

Bevor wir aber mit einer automatischen Lösung beginnen, müssen wir noch einiges vorbereiten und testen.

Hiermit stellen wir eine Portweiterleitung vom lokalen Client über den SSH Tunnel zu einem remote Server her, auf dem unsere Datenbank auf Port 3306 lauscht.

$ ssh -L 3307:localhost:3306 -p 12345 user@remotehost

Nach akzeptieren des Fingerprints und Eingabe des Passworts, sollte der Tunnel auch schon funktionieren. Solange man diese Verbindung nun offen lässt, kann man über den lokalen Port 3307 eine verschlüsselte MySQL Verbindung zum remote Server aufbauen.

Man kann den Tunnel nun ganz einfach, in einer neuen Konsole, mittels

$ mysql -h 127.0.0.1 -P 3307 -uuser -ppassword
Wichtig!

Ihr müsst auf dem Remote Server einen gültigen MySQL Account besitzen, mit dem Ihr euch einloggen könnt! Desweiteren muss zwingend die IP 127.0.0.1 (oder eure lo IP) genommen werden. Benutzt man localhost so wird die Verbindung über den Unix Socket aufgebaut und dieser kann mit dem Tunnel nix anfangen.

Hat dies soweit funktioniert, sollte man sich noch vergewissern das man auf dem korrekten Server ist, das geht in der geöffneten Konsole der MySQL Verbindung dann mittels show databases; .

Automatisches erstellen und aufrecht erhalten des SSH Tunnels

Zum Testen soll das Beispiel oben erst mal ausreichen.

Kommen wir nun zu dem automatischen Verbindungsaufbau des SSH Tunnels und Wiederaufbau der Verbindung wenn diese abbricht.

Diese setze ich mit autossh um.

Autossh ist ein kleines aber feines Tool welches alle erstellten SSH Tunnel beobachtet, automatisch  aufbaut und bei Fehler die Verbindung durch den SSH Tunnel neu herstellt.

Installiert haben wir dieses feine Tool ja bereits ganz am Anfang.

Um das alles ein wenig zu veranschaulichen, habe ich den beiden Servern Namen gegeben.

Webserver (Fruity)
Fruity ist der Initiator des Tunnels und möchte den MySQL Server auf Romeo benutzen.

MySQL Server (Romeo)
Dieser MySQL Server soll unter dem Port 3307 von Fruity aus dauerhaft erreichbar sein.

MySQL Server auf Romeo

Auf Romeo wird ein neuer User angelegt und der sshd so konfiguriert das dieser User sich per PublicKey Authentication anmelden kann.

$ adduser ssh-tunnel
$ nano /etc/ssh/sshd_config
AllowUsers ssh-tunnel
PubkeyAuthentication yes
$ /etc/init.d/ssh restart

Webserver auf Alice

Als erstes wird autossh installiert, falls an dieser Stelle noch nicht geschehen ist. Dann wird ein neue User angelegt. Da man vielleicht mehrere Tunnel aufbauen möchte, lohnt es sich schon jetzt Gedanken über die Namen der User und Scripte zu machen. Bei mir folgen die Namen diesem Muster “tunnel-zielservername-dienst”. Da ich für jeden Tunnel einen eigenen User anlege, heißt das Script also genauso wie der zum Einsatz kommende User.

$ apt-get update && upgrade
$ apt-get install autossh
$ adduser tunnel-romeo-mysql
 

Jetzt loggt man sich als tunnel User ein und testet die Verbindung.

$ su tunnel-bob-mysql
$ cd ~
$ /usr/bin/autossh -M 20009 -N -L 3307:127.0.0.1:3306 -p SSHPORT ssh-tunnel@romeo
Der autossh Aufruf endet nach dem -M 20009 (setzt den Monitoring Port auf 20009). Alles was folgt ist der ganz normale SSH Tunnel Aufruf. Für das Überwachen der Verbindung bietet autossh 2 Möglichkeiten. Bei der ersten Lösung wird eine zweite Verbindung aufgebaut über den per -M angegebenen Port und bei der zweiten wird ein Echo Service benutzt. Da der Echo Service einen inetd benötigt den ich nicht habe, kommt bei mir die erste Lösung zum Einsatz. Wenn alles funktioniert hat man nun einen SSH Tunnel aufgebaut und kann in einem anderen Konsolen Fenster die MySQL Verbindung testen. Der zu verwendende Port ist in diesem Beispiel 3307!
$ mysql -h 127.0.0.1 -P 3307 -uMYSQL-USER -pMYSQL-PASSWORT
mysql> SHOW DATABASES;

Nun kümmern wir uns um den PublicKey zum anmelden ohne Passwort.

$ mkdir ~/keys
$ ssh-keygen -t dsa -b 1024 -f ~/keys/tunnel-key
(Passphrase leer lassen)
$ cd keys
$ ls -1
tunnel-key (private key)
tunnel-key.pub (public key)
 

MySQL Server auf Romeo

Der Public Key von Fruity muss jetzt in die authorized_keys Datei auf Romeo eingetragen werden. Da bei mir alles per Putty läuft, kopiere ich den Key in die Zwischenablage und füge ihn dann in die Datei auf Romeo ein. Wie man es macht ist aber auch egal. Auf Romeo loggen wir uns als ssh-tunnel User ein.

$ cd ~
$ if [ ! -d .ssh ]; then mkdir .ssh ; chmod 700 .ssh ; fi
$ cd .ssh/
$ if [ ! -f authorized_keys ]; then touch authorized_keys ; fi
$ chmod 600 authorized_keys
$ vi authorized_keys
 

Webserver auf Alice

Jetzt noch einmal die Verbindung per PublicKey testen.

$ /usr/bin/autossh -M 20009 -N -L 3307:127.0.0.1:3306 -p SSHPORT \
-i /home/tunnel-bob-mysql/keys/tunnel-key ssh-tunnel@romeo
$ mysql -h 127.0.0.1 -P 3307 -uMYSQL-USER -pMYSQL-PASSWORT
mysql> SHOW DATABASES;
 

Funktioniert alles, kann man mit dem autossh Parameter -f den SSH Tunnel in den Hintergrund legen. Will man den Tunnel beenden, kann man dies ganz normal über kill + PID machen oder wenn man killall hat mit killall -u tunnel-romeo-mysql (deshalb lege ich für jeden Tunnel einen eigenen User an)

$ /usr/bin/autossh -M 20009 -f -N -L 3307:127.0.0.1:3306 -p SSHPORT \
-i /home/tunnel-romeo-mysql/keys/tunnel-key ssh-tunnel@romeo

 

Bei mir kommt ein Init Script zum Einsatz, damit der SSH Tunnel automatisch gestartet wird. 

#!/bin/sh
#
### BEGIN INIT INFO
# Provides:          autossh
# Required-Start:
# Required-Stop:
# Should-Start:
# Should-Stop:
# Default-Start:     2 3 4 5
# Default-Stop:      0 1 6
# Short-Description: Start and stop a autossh tunnel
# Description:       Creates a SSH Tunnel
### END INIT INFO
#
 
# config
 
AUTOSSH="/usr/bin/autossh -M 20009 -f"
TUNNEL="-N -L 3307:127.0.0.1:3306 -p SSHPORT -i ~/keys/tunnel-key ssh-tunnel@romeo";
USER="tunnel-romeo-mysql"
 
# script
 
# check if autossh is installed
test -x /usr/bin/autossh || exit 0
 
# autossh config
export AUTOSSH_GATETIME=30
export AUTOSSH_POLL=15
 
case "$1" in
    start)
        echo "Starting autossh tunnel"
        su $USER -c "$AUTOSSH $TUNNEL"
        ;;
    stop)
        echo "Stopping autossh tunnel"
        killall -u $USER
        ;;
    restart)
        $0 stop && sleep 2 && $0 start
        ;;
    *)
        echo "Usage: $0 {start}" >&2
        exit 3
        ;;
esac
 
exit 0

Nun noch die Defaults eintragen damit der Tunnel auch bei einem Server Restart wieder startet

$ nano /etc/init.d
$ update-rc.d tunnel-romeo-mysql defaults
$ /etc/init.d/tunnel-romeo-mysql start

 

Wer so wie ich mehrere Tunnel haben will und Wert auf die Stop/Restart Logik im Script legt, muss für jeden Tunnel einen eigenen User anlegen, da zum Stoppen einfach alle Prozesse des angegebenen Users beendet werden. Es gibt sicher eine elegantere Lösung, aber diese geht schnell und einfach. Tipps sind natürlich willkommen.

Entfernen eines SSH Tunnels

Auf Fruity:

$ update-rc.d -f tunnel-romeo-mysql remove
$ rm /etc/init.d/tunnel-romeo-mysql
$ deluser --remove-home tunnel-romeo-mysql

 

Auf Romeo:

$ deluser --remove-home ssh-tunnel

 

Oder man nimmt nur den Key aus den authorized_keys.

Solltet Ihr die Meldung bekommen das privilegierte Ports nur von Root weitergeleitet werden können, dann nehmt als lokalen Port einfach etwas über 10000.

 

Wenn alles funktioniert, könnt Ihr euch auf dem Webserver (Fruity) mit jeder Software auf dem Port 3307 (oder welchen Ihr auch immer gewählt habt) auf den MySQL Dienst von Romeo verbinden.

Man kann das natürlich auch mit einer VPN Lösung erreichen aber wenn in diesem VPN Netzwerk eine LDAP Authentifizierung vorhanden ist, und der LDAP Server auch nur via VPN nutzbar ist, kann man mit genau der gleichen Lösung die Authentifizierung dennoch ermöglichen.

Wie immer, wenn Ihr hängt => Meldet euch.

Share it!Share on FacebookEmail this to someoneShare on Google+Tweet about this on Twitter

Schreibe einen Kommentar