Bastillion unter Ubuntu installieren und konfigurieren

Unter einem Bastion Host, manchmal auch Jump Server oder Jump Host, versteht man einen Server, der Dienste für das öffentliche Internet oder nicht vertrauenswürdige Netze (beispielsweise große nicht separierte Intranet Umgebungen) anbietet und daher besonders gegen Angriffe geschützt werden muss. Die Rolle des Bastion Hosts eignet sich für Server im exponierten Bereich und sollte daher nicht mit anderen Serverrollen kombiniert werden (Quelle: Wikipedia).

Im Rahmen eines anstehenden Projekts habe ich mich mit Bastillion beschäftigt. Es handelt sich dabei um ein webbasierter SSH-Terminal-Emulator. Sprich es ist einzig moderner Browser für die Nutzung erforderlich. Diese Software kann kostenlos unter der AGPL-Lizenz verwendet werden.

Nachstehend beschreibe ich die Installation des Tools auf einer virtuellen Maschine, welche als Betriebssystem Ubuntu 20.04 hat. Die VM wird von Hetzner Online GmbH bereitgestellt.

Vorbereitungen

Synchronisieren Sie die Paketindexdateien erneut aus ihren Quellen.

apt-get update && apt-get upgrade -y

Bastillion ist eine Java-basierte Webanwendung und erfordert OpenJDK 9 oder höher. In diesen Fall habe ich mich für 11er entschieden, da es sich um eine LTS Version handelt.

apt-get install openjdk-11-jdk -y

Nach der Installation muss geprüft werden, ob Java auch funktioniert.

java -version
    openjdk version "11.0.8" 2020-07-14
    OpenJDK Runtime Environment (build 11.0.8+10-post-Ubuntu-0ubuntu120.04)
    OpenJDK 64-Bit Server VM (build 11.0.8+10-post-Ubuntu-0ubuntu120.04, mixed mode, sharing)

Installation der Anwendung

Download der aktuellen Version.

wget https://github.com/bastillion-io/Bastillion/releases/download/v3.10.00/bastillion-jetty-v3.10_00.tar.gz

Die Archivdatei entpacken.

tar xvf bastillion-jetty-v3.10_00.tar.gz

Das entpackte Verzeichnis an den Zielort verschieben.

mv Bastillion-jetty/ /usr/lib/
mkdir /usr/lib/Bastillion-jetty/run

Eigenen Benutzer für die Anwendung anlegen.

useradd --user-group --shell /bin/bash --home-dir /usr/lib/Bastillion-jetty/ jetty

Besitzer für das Programmverzeichnis und alle drin enthaltenen Dateien ändern.

chown -R jetty:jetty /usr/lib/Bastillion-jetty/

Nun wird ein Zufallspasswort generiert. Dies ist erforderlich, da beim ersten Start der Anwendung ein Passwort für die Datenbank eingegeben werden muss.

openssl rand -hex 32
    1e10cfae16b73b91d276ddaa56469e833948cb3be8af55277a1d3d7407f1b2c4

Den ausgegebene Zeichensatz (1e10…) kopieren und temporär in einem Notepad/Editor einfügen. Falls die Möglichkeit besteht,  diesen sicher in einem Passwort Manager verwahren.

Zu dem Benutzer  jetty wechseln.

su - jetty

Die Anwendung Bastillion manuell starten.

./startBastillion.sh

Nach wenigen Sekunden erscheint die Aufforderung für die Datenbankverbindung ein Passwort zu vergeben.

Das vorher kopierte Passwort per Copy & Paste einfügen. Anschließend die Eingabe mit der Taste ENTER oder RETURN bestätigen. Danach muss das Passwort nochmals eingegeben (bestätigt) werden. Nicht erschrecken, es werden keinerlei Zeichen (auch keine Sterne) angezeigt. Wenn keine Fehlermeldung auf der Konsole ausgegeben wird, wurde das Passwort akzeptiert.

Die laufenden Anwendung mit dem Drücken von Strg + C beenden und die Sitzung des Benutzers jetty mit dem Befehl exit verlassen.

Anwendung als Dienst einrichten

cat << EOF > /etc/default/bastillion
JETTY_HOME=/usr/lib/Bastillion-jetty/jetty
JETTY_RUN=/usr/lib/Bastillion-jetty/run
JETTY_USER=jetty
EOF
cp /usr/lib/Bastillion-jetty/jetty/bin/jetty.sh /etc/init.d/bastillion
update-rc.d bastillion defaults

Konfiguration des Dienstes ausgeben.

service bastillion check

Folgende Werte werden aus gegeben.

Wenn alle ausgegebene Pfade und Dateinamen stimmen, kann der Dienst gestartet werden.

service bastillion start

Nicht ungeduldig werden… der Start kann mehrere Sekunden dauern.

Überprüfung des Dienstes.

service bastillion status

Konfiguration der Firewall

Standardmäßig ist die Firewall ufw nach der Installation von Ubuntu 20.04 LTS nicht aktiviert. Das holen wir natürlich nach. Bastilltion lauscht nachdem Start standardmäßig auf Port 8443/tcp. Der Zugriff per SSH soll natürlich weiterhin möglich sein.

ufw allow ssh
ufw allow in 8443/tcp
echo y | ufw enable
ufw status

Änderung des Standard Ports

Gerade auf Hinblick von Firewalls oder Proxy Server ist der Port 8443/tcp ein Dorn im Auge. Nachstehend beschreibe ich die notwendigen Änderungen.

cp /usr/lib/Bastillion-jetty/jetty/etc/jetty-ssl.xml /usr/lib/Bastillion-jetty/jetty/etc/jetty-ssl.xml.$(date '+%Y-%m-%d_%H-%M-%S')
sed -i -e 25s"#8443#443#g" /usr/lib/Bastillion-jetty/jetty/etc/jetty-ssl.xml

setcap cap_net_bind_service+ep $(readlink -f $(which java))

Firewall Regeln anpassen.

ufw delete allow in 8443/tcp
ufw allow in https

Dienst neu starten.

service bastillion restart

Let’s Encrypt Zertifikat nuztzen

Standardmäßig wird die Anwendung mit einem Self-Signed-Zertifikat ausgeliefert. Was zur Folge hat, dass beim Auruf von Bastillion in Browser eine Warnung angezeigt wird. Nachstehend beschreibe ich den Weg für die Nutzung von Let’s Encrypt (LE).

Zuerst den DNS Namen, auf den der Server bzw. Applikation hören soll in eine Variable speichern. Das erleichtert alle nachfolgenden Schritte enorm und vermeidet auch Tippfehler.

export FqdnServer=static.248.122.119.168.clients.your-server.de
echo $FqdnServer

Das Tool certbot installieren.

apt-get install certbot -y

Damit der Abruf bzw. Validierung über HTTP Challenge funktioniert, muss natürlich der Port 80 in der Firewall freigegeben werden.

ufw allow in http

Abruf des Zertifikats.

certbot certonly --standalone -d $FqdnServer --agree-tos --non-interactive

Erstellen eines zufälligen Zeichensatzes, der später als Passwort für den notwendigen Zertifikatstyp, dienen soll.

openssl rand -hex 16 > /etc/letsencrypt/live/$FqdnServer/password.txt
CertP12password=$(cat /etc/letsencrypt/live/$FqdnServer/password.txt)
chmod 700 /etc/letsencrypt/live/$FqdnServer/password.txt
chown jetty:jetty /etc/letsencrypt/live/$FqdnServer/password.txt

Erstellen eines Zertfikats vom Typ pfx/pkcs12. Denn ausschließlich dieses Format kann in den Java Keystore von Bastillion importiert werden.

openssl pkcs12 -export -in /etc/letsencrypt/live/$FqdnServer/fullchain.pem -inkey /etc/letsencrypt/live/$FqdnServer/privkey.pem -out /usr/lib/Bastillion-jetty/jetty/etc/bastillion.pkcs12 -name tomcat -passout pass:$CertP12password

Erstellen eines weiteren zufälligen Zeichensatzes, der später als Passwort für den neuen Java Keystore dienen soll.

openssl rand -hex 16 > /usr/lib/Bastillion-jetty/jetty/etc/keystore.password.txt
keystorePassword=$(cat /usr/lib/Bastillion-jetty/jetty/etc/keystore.password.txt)
chmod 700 /usr/lib/Bastillion-jetty/jetty/etc/keystore.password.txt
chown jetty:jetty /usr/lib/Bastillion-jetty/jetty/etc/keystore.password.txt

Dienst beenden.

service bastillion stop

Der Java Keystore des Self-Signed-Zertikats unbenennen bzw. sichern.

mv /usr/lib/Bastillion-jetty/jetty/etc/keystore /usr/lib/Bastillion-jetty/jetty/etc/keystore.orginal

Neuer Java Keystore mit dem vorher erzeugten Passwort erstellen.

keytool -importkeystore -srckeystore /usr/lib/Bastillion-jetty/jetty/etc/bastillion.pkcs12 -srcstorepass $CertP12password -srcstoretype PKCS12 -destkeystore /usr/lib/Bastillion-jetty/jetty/etc/keystore -deststorepass $keystorePassword

Austausch des neuen Passworts bzw. Hashes für den neuen Java Keystore in den Konfigurationsdateien des Webservers Jetty.

keystoreOBF=$( (java -cp /usr/lib/Bastillion-jetty/jetty/lib/jetty-util-9.4.29.v20200521.jar org.eclipse.jetty.util.security.Password $keystorePassword 2>&1 ) | sed -n 's/\(OBF\)/\1/p')

cp /usr/lib/Bastillion-jetty/jetty/etc/jetty-ssl-context.xml /usr/lib/Bastillion-jetty/jetty/etc/jetty-ssl-context.xml.$(date '+%Y-%m-%d_%H-%M-%S')
sed -i -e s"#OBF:1kmu19bz1n0m1i9c1mbb1mfb1i6m1mwo19bz1kjs#$keystoreOBF#g" /usr/lib/Bastillion-jetty/jetty/etc/jetty-ssl-context.xml


cp /usr/lib/Bastillion-jetty/jetty/modules/ssl.mod /usr/lib/Bastillion-jetty/jetty/modules/ssl.mod.$(date '+%Y-%m-%d_%H-%M-%S')
sed -i -e s"#OBF:1kmu19bz1n0m1i9c1mbb1mfb1i6m1mwo19bz1kjs#$keystoreOBF#g" /usr/lib/Bastillion-jetty/jetty/modules/ssl.mod

Sind keine Fehler aufgetreten kann der Dienst wieder gestartet werden.

service bastillion start

Die Erneuerung des LE Zertifikats erfolgt wie gewohnt +- alle 90 Tage automatisch. Die oben aufgeführten Schritte müssen,  wie gerade eben,  jedes Mal ausgeführt werden. Abhilfe schafft nachstehendes Skript. Dieses wird jedes nach dem erfolgreichen Erneuerung des LE Zertifikats (Hook) ausgeführt.

TAB="$(printf '\t')"

cat << EOF > /etc/letsencrypt/renewal-hooks/deploy/78-bastillion-update-keystore.sh
#!/bin/bash

set -e


case $domain in
$FqdnServer) # Update this with your own server

${TAB}# Dienst anhalten
${TAB}service bastillion stop


${TAB}# Passwort für das Zertifikat auslesen
${TAB}CertP12password=\$(cat /etc/letsencrypt/live/$FqdnServer/password.txt)


${TAB}# Aus den LE PEM Dateien ein PFX/pkcs12 erzeugen
${TAB}openssl pkcs12 -export -in /etc/letsencrypt/live/$FqdnServer/fullchain.pem -inkey /etc/letsencrypt/live/$FqdnServer/privkey.pem -out /usr/lib/Bastillion-jetty/jetty/etc/bastillion.pkcs12 -name tomcat -passout pass:$CertP12password


${TAB}# Passwort für den Keystore auslesen
${TAB}keystorePassword=\$(cat /usr/lib/Bastillion-jetty/jetty/etc/keystore.password.txt)


${TAB}# Das Zertifikat in den Keystore importieren und das bestehende Zertifikat überschreiben
${TAB}keytool -importkeystore -srckeystore /usr/lib/Bastillion-jetty/jetty/etc/bastillion.pkcs12 -srcstorepass \$CertP12password -srcstoretype PKCS12 -destkeystore /usr/lib/Bastillion-jetty/jetty/etc/keystore -deststorepass \$keystorePassword


${TAB}# Dienst starten
${TAB}service bastillion start
${TAB};;
esac

EOF

Berechtigungen für die Datei anpassen.

chmod 750 /etc/letsencrypt/renewal-hooks/deploy/78-bastillion-update-keystore.sh

Ein Aufruf der Anwendung in einem Browser zeigt nur keine Warnung mehr an.

Anmerkungen

  1. Anstatt den Port zu wechseln kann selbstverständlich auch ein Reverse Proxy (RP) auf Basis von Apache, Nginx oder HAproxy auf dem Server eingerichtet werden.
  2. Falls Punkt 1) umgesetzt wird, nimmt das Self-Signed Zertifikat der Anwendung keine wichtige Rolle mehr ein. Der Datenvekehr wird bei richtiger Konfiguration des RP über localhost / 127.0.0.1 abgewickelt. Somit werden die Datenpakte zwischen RP und Applikation direkt übermittelt und verlassen den Server nicht mehr.
  3. Die Installation und vorallem die Konfiguration eines RP sprengt meiner Meinung nach den Rahmen des Artikels. Bei entsprechenden Rückmeldungen verfasse ich dazu ein eigenen Beitrag.

Viel Spaß beim Ausprobieren. 🙂