Linux: I2P im chroot mit AppArmor

Das I2P Netzwerk

I2P („Invisible Internet Project“) besteht aus einer Reihe auf Java basierender Anwendungen und Server, mit der ein anonymisierendes Netzwerk aus verteilten Rechnern errichtet wird. Die Rechner stellen die Benutzer des I2P Netzwerks, die ähnlich wie beim Tor Netzwerk als Teil von Transportketten aus mehreren I2P-Knoten den I2P Datenverkehr durch das Internet in I2P Tunnels transportieren, die durch die I2P Verschlüsselungs- und Anonymisierungsfunktionen gebildet werden.

Gleichzeitig können Benutzer innerhalb des I2P Netzwerks selbst Anbieter von Diensten sein, die von anderen Benutzern und ihnen selbst anonymisiert genutzt werden können. Dazu zählen z. B. eigene Websites, -foren und blogs, Torrent-Tracker oder Mailserver. I2P enthält einen BitTorrent Client („I2Psnark“), mit dem Benutzer über I2P Torrent-Tracker Daten austauschen können, eine Webserverkomponente, um Webpräsenzen (sogenannte „Eepsites“) im I2P Netzwerk aufzubauen, einen Webmail Client („susimail“) für den I2P Mail Dienst, mit dem E-Mails auch von Nicht-I2P-Nutzern empfangen und an sie gesendet werden können.

Bei I2P handelt es sich also in erster Linie um ein geschlossenes Netzwerk, das aber über Proxy Dienste von I2P Nutzern um „Schnittstellen“ zum übrigen Internet erweitert wird. So gibt es z. B. einen I2P HTTP „Outproxy“, über den das WWW anonymisiert genutzt werden kann oder einen I2P IRC Proxy zur Nutzung von IRC Servern.

I2P Router Konsole

Die Bedienung und Einrichtung des eigenen I2P-Knotens wird primär über die „I2P Router Konsole“ in einem beliebigen Webbrowser durchgeführt. Weitere bzw. erweiterte Konfigurationen können in den I2P Konfigurationsdateien (*.config) durchgeführt werden.

Vorbereitungen

Die Maßnahmen wurden unter Ubuntu durchgeführt. Für andere Linux-Distributionen sind einzelne Maßnahmen ggf. zu modifizieren. Weitere Änpassungen können sich bei Änderungen im Dateisystem ergeben, z. B. wenn Bibliotheken mit einem neuen Release woanders gespeichert werden als zuvor.

Zuerst ist zu überlegen, wo die chroot Umgebung für I2P und Java angelegt werden soll. In der Anleitung ist es /mp/chroot/i2p/: mp kann irgendein mountpoint sein, also ein logisches Volume bzw. eine Partition, die nur für chroot Umgebungen genutzt wird, mit dem chroot Verzeichnis und i2p Unterverzeichnis, das für I2P und Java zum Wurzelverzeichnis / wird. Später kann man für andere Anwendungen unterhalb von /mp/chroot/ weitere Umgebungen einrichten, z. B. /mp/chroot/tor für Tor.

Java

Die Anleitung geht vom Einsatz der Oracle Java SE (Standard Edition) aus. Da ab Oracle Java SE 1.7.0 Java Pakete offiziell nicht mehr durch Linux-Distributoren verbreitet werden dürfen, wird die Java SE manuell installiert. Aktuelle Information zu neuen Versionen erhält man über den Oracle Security Alerts Feed oder den Java SE News Feed.

Über die Java Downloadseite wird das JRE Archiv (x64 statt i586 für 64-bit) der Java Standard Edition heruntergeladen und danach installiert:

sudo mkdir /usr/lib/jvm ; cd /usr/lib/jvm
sudo tar -xzf /pfad/jre-N-linux-[i586|x64].tar.gz
sudo update-alternatives --install /usr/bin/java java /usr/lib/jreN.N.N/bin/java 100

Danach muss sich eine ähnliche Ausgabe in der Konsole einstellen:

$ java -version
 
java version "1.7.0"
Java(TM) SE Runtime Environment (build 1.7.0-b147)
Java HotSpot(TM) Client VM (build 21.0-b17, mixed mode)

Wer lieber das Java Runtime Environment (JRE) des OpenJDK Projekt verwendet (openjdk-N-jre Paket), kann auch dabei bleiben, muss aber das Skript zur Erstellung der chroot Umgebung entsprechend anpassen.

Anmerkung: Hier gab es Probleme mit dem OpenJDK JRE bei der Darstellung der I2P Performance Grafiken, die nicht zu lösen waren. Im I2P Forum wurde die Meinung geäußert, dass die CPU- und Speichernutzung mit dem Sun JRE besser sei als mit dem OpenJDK JRE.

Über das Alternativen-System können bei Bedarf neben der java Anwendung weitere Anwendungen des installierten Oracle JRE systemweit aufgenommen und verschiedene JREs parallel installiert werden.

I2P

I2P wird zunächst installiert und die I2P Dateien per Skript in die chroot Umgebung kopiert. Anschließend kann das installierte I2P wieder entfernt werden.

Manuelle Installation

Download des aktuellen Java Installationsarchivs i2pinstall_version.jar und der GnuPG Signaturdatei i2pinstall_version.jar.sig über die I2P oder geti2p.net Website mit anschließendem Abgleich der SHA-256 Prüfsumme und Prüfung der OpenPGP Signatur.

Anschließend:

sudo java -jar i2pinstall_version.exe -console
 
press 1 to continue, 2 to quit, 3 to redisplay
1
Select target path
/var/lib/i2p
press 1 to continue, 2 to quit, 3 to redisplay
1

I2P Benutzer

Anlage des I2P Benutzers:

sudo adduser --system --home /mp/chroot/i2p/var/lib/i2p \
--shell /bin/false --no-create-home \
--group --disabled-password i2p-daemon

chroot einrichten

Umgebung mit Skript erstellen

Das folgende Skript als i2p_makechroot abspeichern:

#!/bin/bash

CHROOTDIR="/mp/chroot/i2p"
USERNAME="i2p-daemon"
I2PINST="/var/lib/i2p"
# JAVAINST="/usr/lib/jvm/java-N-openjdk"
JAVAINST="/usr/lib/jvm/jreN.N.N"

echo "Lege $CHROOTDIR und Verzeichnisse in $CHROOTDIR an"
mkdir -p $CHROOTDIR/bin
mkdir -p $CHROOTDIR/dev
mkdir -p $CHROOTDIR/etc
mkdir -p $CHROOTDIR/lib
mkdir -p $CHROOTDIR/proc
mkdir -p $CHROOTDIR/tmp
mkdir -p $CHROOTDIR/var/lib
mkdir -p $CHROOTDIR$JAVAINST/bin
mkdir -p $CHROOTDIR/lib/tls/i686/cmov

echo "Erzeuge Devicedateien"
touch $CHROOTDIR/dev/random
touch $CHROOTDIR/dev/urandom
mknod -m 0666 $CHROOTDIR/dev/null c 1 3

echo "Kopiere Java und I2P"
cp -RLp $I2PINST $CHROOTDIR/var/lib
cp -p $JAVAINST/bin/java $CHROOTDIR$JAVAINST/bin
cp -Rp $JAVAINST/lib $CHROOTDIR$JAVAINST

echo "Füge $USERNAME in $CHROOTDIR/etc/passwd und $CHROOTDIR/etc/group ein"
grep $USERNAME /etc/passwd > $CHROOTDIR/etc/passwd
grep $USERNAME /etc/group > $CHROOTDIR/etc/group

echo ""
echo "  Nicht vergessen, die Angaben in beiden Dateien vor dem ersten Start abzuändern"
echo ""

echo "Kopiere Systemprogramme"
cp /bin/dash $CHROOTDIR/bin
cp -d /bin/sh $CHROOTDIR/bin
cp /bin/false $CHROOTDIR/bin

echo "Kopiere Systemeinstellungen"
# cp -Rp /etc/java-N-openjdk $CHROOTDIR/etc
cp /etc/nsswitch.conf $CHROOTDIR/etc
cp /etc/host.conf $CHROOTDIR/etc
cp /etc/resolv.conf $CHROOTDIR/etc
cp /etc/hosts $CHROOTDIR/etc
cp /etc/localtime $CHROOTDIR/etc

echo "Kopiere Systembibliotheken"
cp /lib/libnsl* $CHROOTDIR/lib
cp /lib/libnss_* $CHROOTDIR/lib
cp /lib/libresolv* $CHROOTDIR/lib
cp /lib/ld-linux* $CHROOTDIR/lib
cp /lib/libz.so.? $CHROOTDIR/lib
cp /usr/lib/libfreetype.so.? $CHROOTDIR/usr/lib
ln -s $CHROOTDIR$JAVAINST/lib/i386/client/libjvm.so $CHROOTDIR$JAVAINST/lib/i386/
ln -s $CHROOTDIR$JAVAINST/lib/i386/jli/libjli.so $CHROOTDIR$JAVAINST/lib/i386/
cp /lib/tls/i686/cmov/libc.so.? $CHROOTDIR/lib/tls/i686/cmov
cp /lib/tls/i686/cmov/libdl.so.? $CHROOTDIR/lib/tls/i686/cmov
cp /lib/tls/i686/cmov/libnsl.so.? $CHROOTDIR/lib/tls/i686/cmov
cp /lib/tls/i686/cmov/libpthread.so.? $CHROOTDIR/lib/tls/i686/cmov
cp /lib/tls/i686/cmov/libresolv.so.? $CHROOTDIR/lib/tls/i686/cmov
cp /lib/tls/i686/cmov/libm.so.? $CHROOTDIR/lib/tls/i686/cmov

echo "Vergebe Berechtigungen"
chown -R $USERNAME:$USERNAME $CHROOTDIR/var/lib/i2p
chmod 0750 $CHROOTDIR/var/lib/i2p
chmod 1777 $CHROOTDIR/tmp

echo "Fertig"
echo ""
echo "  Nicht vergessen, das I2P init Skript abzuändern oder einzurichten"
echo ""

Anmerkung: Das Skript basiert auf den Skripten zur Einrichtung von chroot Umgebungen für Tor und Privoxy von northernsecurity.

Sofern das OpenJDK JRE verwendet wird, die Zeile mit der Definition der JAVAINST Variable für das Oracle Java JRE löschen und dafür die Zeilen für das OpenJDK JRE auskommentieren.

In der Zeile mit der Definition der CHROOTDIR Variable den Pfad zur chroot Umgebung auf das eigene System anpassen.

Die Skriptdatei ausführbar machen und ausführen:

chmod +x i2p_makechroot
sudo ./i2p_makechroot

init Skript für chroot

Das folgende Skript als i2prouter abspeichern:

#!/bin/sh
#
# Start/Stop the I2P-router

### BEGIN INIT INFO
# Provides: i2prouter
# Required-Start: $network
# Required-Stop: $network
# Default-Start: 2 3 4 5
# Default-Stop: 0 1 6
# Short-Description: the router for the Invisible Internet Project
# Description: The Invisibel Internet Project is a highly anonymous
#              network. This router offers a proxy to access the net.
### END INIT INFO


set -e

DESC="I2P router"
NAME="i2prouter"
USER="i2p-daemon"
GROUP="i2p-daemon"
CHROOTDIR="/mp/chroot/i2p"
I2PDIR="/var/lib/i2p"
DAEMON="i2psvc_start"
I2PPID="/tmp/i2p.pid"
pid=""

getpid() {
    if [ -f $CHROOTDIR$I2PPID ]
    then
        if [ -r $CHROOTDIR$I2PPID ]
        then
            pid=`cat $CHROOTDIR$I2PPID`
            if [ "X$pid" != "X" ]
            then
                # Verify that a process with this pid is still running.
                pid=`ps -p $pid | grep $pid | grep -v grep | awk '{print $1}' | tail -n 1`
                if [ "X$pid" = "X" ]
                then
                    # This is a stale pid file.
                    rm -f $CHROOTDIR$I2PPID
                    echo "Removed stale pid file: $CHROOTDIR$I2PPID"
                fi
            fi
        else
            echo "Cannot read $CHROOTDIR$I2PPID."
            exit 1
        fi
    fi
}

case $1 in
  start)
        mount --bind /dev/random $CHROOTDIR/dev/random && \
        mount --bind /dev/urandom $CHROOTDIR/dev/urandom && \  
        mount -t proc proc $CHROOTDIR/proc
        echo -n "Starting $DESC: $NAME..."
        start-stop-daemon --start --quiet --oknodo --chuid $USER:$GROUP --chroot $CHROOTDIR --pidfile $I2PPID --exec $I2PDIR/$DAEMON
        echo "done."
        ;;

  stop)
        echo -n "Stopping $DESC: "
        start-stop-daemon --stop --oknodo --pidfile $CHROOTDIR$I2PPID --retry 30
        echo "done." && \
        umount $CHROOTDIR/dev/urandom && umount $CHROOTDIR/dev/random && \
        umount $CHROOTDIR/proc
        ;;

  status)
        getpid
        if [ "X$pid" = "X" ]
        then
            echo "$DESC is not running."
            exit 1
        else
            echo "$DESC is running ($pid)."
            exit 0
        fi
        ;;

  restart)
        echo "Restarting $DESC: "
        start-stop-daemon --stop --oknodo --pidfile $CHROOTDIR$I2PPID --retry 30
        echo "$DESC stopped "
        sleep 15
        echo "Starting $DESC: "
        start-stop-daemon --start --quiet --oknodo --chuid $USER:$GROUP --chroot $CHROOTDIR --pidfile $I2PPID --exec $I2PDIR/$DAEMON
        echo "done."
        ;;

  *)
        echo "Usage: $0 (start|stop|restart|status)" >&2
        exit 1
        ;;
esac

exit 0

Auch hier gilt es, in der Zeile mit der Definition der CHROOTDIR Variable den Pfad zur chroot Umgebung auf das eigene System anzupassen.

Das init Skript in das /etc/init.d Verzeichnis kopieren und ausführbar machen:

sudo cp i2prouter /etc/init.d/
sudo chmod +x /etc/init.d/i2prouter

Das i2prouter init Skript aktivieren:

sudo update-rc.d i2prouter defaults

Anpassungen im chroot

i2psvc_start Skript

Da Aufruf und Start von I2P und Java über das init Skript nicht mehr mit dem Start der i2psvc Anwendung über das i2prouter Skript im I2P Verzeichnis durchgeführt wird, sondern mit dem i2psvc_start Shellskript als „daemon“, muss das folgende Shellskript als i2psvc_start Datei in das /mp/chroot/i2p/var/lib/i2p Verzeichnis kopiert werden:

#!/bin/sh

# PATH="/bin:/var/lib/i2p:/usr/lib/jvm/java-N-openjdk/jre/bin"
PATH="/bin:/var/lib/i2p:/usr/lib/jvm/jreN.N.N/bin"
I2PDIR=/var/lib/i2p
DAEMON_CONF="$I2PDIR/wrapper.config"
I2PPID="/tmp/i2p.pid"

$I2PDIR/i2psvc $DAEMON_CONF i2psvc.pidfile=$I2PPID wrapper.daemonize=TRUE

exit 0

Sofern man das OpenJDK JRE verwendet, muss die Zeile mit der Definition der PATH Variable für das Oracle Java JRE entfernt und dafür die Zeile mit der PATH Variable für das OpenJDK JRE auskommentiert werden.

Das i2psvc_start Shellskript kopieren, ausführbar machen und den Eigentümer ändern:

sudo cp i2psvc_start /mp/chroot/i2p/var/lib/i2p/
sudo chmod 0744 /mp/chroot/i2p/var/lib/i2p/i2psvc_start
sudo chown i2p-daemon:i2p-daemon /mp/chroot/i2p/var/lib/i2p/i2psvc_start

I2P Benutzer

Die Daten des I2P Benutzers wurden mit der Erstellung der chroot Umgebung aus der /etc/passwd der Systemumgebung in die /etc/passwd im chroot kopiert, aber die Angaben zum Heimatverzeichnis und zur Shell beziehen sich immer noch auf die Systemumgebung. Deshalb muss die /mp/chroot/i2p/etc/passwd editiert und die Angaben geändert werden:

sudo vi mp/chroot/i2p/etc/passwd
i2p-daemon:x:nnn:nnn::/mp/chroot/i2p/var/lib/i2p:/bin/false

in:

i2p-daemon:x:nnn:nnn::/var/lib/i2p:/bin/false

Erster Start

I2P zum ersten Mal im chroot starten:

sudo service i2prouter start

Danach müsste folgende Ausgabe zu sehen sein:

sudo service i2prouter status
 
I2P router is running (10227).

Und die I2P Router Konsole über die Adresse http://localhost:7657/index.jsp im Webbrowser zugänglich sein. Läuft I2P, kann abschließend das unter /var/lib/i2p installierte I2P entfernt werden:

sudo rm -rf /var/lib/i2p

AppArmor

AppArmor ist ein Sicherheitssystem, mit dem die Nutzung von Internetprotokollen, Zugriffs- und Ausführungsberechtigungen auf Verzeichnisse, Dateien und Programme für Anwendungen und Prozesse festgelegt bzw. eingeschränkt werden. Für AppArmor ist das AppArmor Kernelmodul zuständig, das beim Systemstart geladen wird und die Profildateien der Anwendungen auswertet, in denen die Berechtigungsregeln für die Anwendungen definiert sind.

Die Einrichtung und Anwendung von AppArmor wird in AppArmor mit Ubuntu nutzen erklärt. Dort wird auch der Aufbau und die Erstellung eigener AppArmor Profile beschrieben.

Im Fall von I2P betrifft das die java Anwendung des Oracle oder OpenJDK JRE im /mp/chroot/i2p/usr/lib/jvm/jreN.N.N/bin bzw. /mp/chroot/i2p/usr/lib/jvm/openjdk/jre/bin Verzeichnis.

AppArmor Java Profil

Die AppArmor Profile sind im /etc/apparmor.d Verzeichnis gespeichert und die Dateinamen werden aus dem absoluten Pfad zur Anwendung gebildet, wobei Punkte den / ersetzen.

Hier ein Beispiel für das AppArmor Profil für die Oracle JRE java Anwendung, das als „mp.chroot.i2p.usr.lib.jvm.jreN.N.N.bin.java“ Datei im /etc/apparmor.d Verzeichnis gespeichert ist.

# Last Modified: Sat Jan 16 23:35:32 2010
@{HOMEDIRS} = @{HOME},
@{HOME} = /mp/chroot/i2p/var/lib/i2p/,
@{PROC} = /mp/chroot/i2p/proc/,

/mp/chroot/i2p/usr/lib/jvm/jreN.N.N/bin/java {
  #include <abstractions/base>
  #include <abstractions/nameservice>

  /mp/chroot/i2p/usr/lib/jvm/jreN.N.N/bin/java rix,
  /mp/chroot/i2p/usr/lib/jvm/jreN.N.N/lib/** mr,
  /mp/chroot/i2p/usr/lib/libfreetype.so.? mr,
  /mp/chroot/i2p/dev/* r,
  /mp/chroot/i2p/etc/* mr,
  /mp/chroot/i2p/lib/* mr,
  /mp/chroot/i2p/lib/tls/i686/** mr,
  owner /mp/chroot/i2p/proc/** r,
  /mp/chroot/i2p/proc/meminfo r,
  /mp/chroot/i2p/proc/stat r,
  /mp/chroot/i2p/tmp/ r,
  owner /mp/chroot/i2p/tmp/** mrw,
  owner /mp/chroot/i2p/var/lib/i2p/** r,
  owner /mp/chroot/i2p/var/lib/i2p/.i2p/** r,
  owner /mp/chroot/i2p/var/lib/i2p/*.config rw,
  owner /mp/chroot/i2p/var/lib/i2p/*.so mr,
  owner /mp/chroot/i2p/var/lib/i2p/*.txt rw,
  owner /mp/chroot/i2p/var/lib/i2p/docs/news.xml rw,
  owner /mp/chroot/i2p/var/lib/i2p/lib/*.so mr,
  owner /mp/chroot/i2p/var/lib/i2p/lib/*.jar mr,
  owner /mp/chroot/i2p/var/lib/i2p/webapps/*.war mr,
  owner /mp/chroot/i2p/var/lib/i2p/.i2p/*.config rw,
  owner /mp/chroot/i2p/var/lib/i2p/.i2p/*.txt rw,
  owner /mp/chroot/i2p/var/lib/i2p/.i2p/prngseed.rnd rw,
  owner /mp/chroot/i2p/var/lib/i2p/.i2p/router.info rw,
  owner /mp/chroot/i2p/var/lib/i2p/.i2p/addressbook/* rw,
  owner /mp/chroot/i2p/var/lib/i2p/.i2p/docs/news.xml rw,
  owner /mp/chroot/i2p/var/lib/i2p/.i2p/eepsite/eepPriv.dat rw,
  owner /mp/chroot/i2p/var/lib/i2p/.i2p/eepsite/logs/*.log rw,
  owner /mp/chroot/i2p/var/lib/i2p/.i2p/i2psnark/** rw,
  owner /mp/chroot/i2p/var/lib/i2p/.i2p/keyBackup/*.key rw,
  owner /mp/chroot/i2p/var/lib/i2p/.i2p/logs/*.txt rw,
  owner /mp/chroot/i2p/var/lib/i2p/.i2p/netDb/*.dat rw,
  owner /mp/chroot/i2p/var/lib/i2p/.i2p/peerProfiles/*.dat rw,

}

Das Profil kann man nach Änderung des chroot mountpoint verwenden oder sich ein eigenes I2P / Java AppArmor Profil erstellen und nutzen.

Zur Erzeugung von privaten Schlüsseldateien für eigene I2P Tunnel muss in dem Profil fallweise die mknod capability aktiviert werden.

Eigenes Java Profil

Hier folgt eine kurze Anleitung, um sich ein eigenes AppArmor Profil für Java zu erstellen:

  1. am besten drei root Konsolen mit sudo -i öffnen
  2. 1. Konsole: tail -f -n 20 /var/log/messages
  3. 2. Konsole: service i2prouter stop
  4. 3. Konsole: aa-genprof /mp/chroot/i2p/usr/lib/jvm/jreN.N.N/bin/java
  5. 2. Konsole: service i2prouter start
  6. in der I2P Router Konsole alle Links anklicken, möglichen I2P Einstellungen vornehmen, I2P Dienste nutzen, um Rohdaten zu gewinnen, aus denen aa-genprof nach dem Scan der messages Logdatei das Profil generiert - dabei die Logausgabe in der 1. Konsole beobachten
  7. 2. Konsole: service i2prouter stop
  8. 3. Konsole: den aa-genprof Scan mit „S“ Taste durchführen und beenden
  9. 3. Konsole: die Abfragen zur Berechtigungsvergabe bestätigen, verweigern oder ändern (z. B. auch mit Abgleich der Logdateiausgabe in der 1. Konsole oder Inspektion der chroot Dateisystemstruktur in der 2. Konsole oder per Dateimanager)
  10. 3. Konsole: nach Abarbeitung aller Abfragen das Profil mit „F“ Taste speichern lassen
  11. 3. Konsole: mit aa-status nachprüfen, ob das Profil im „complain“ Modus angezeigt wird bzw. mit aa-complain /etc/apparmor.d/mp.chroot.i2p.usr.lib.jvm.jreN.N.N.bin.java in den „complain“ Modus setzen - der „complain“ Modus bedeutet, die Anwendung und Auswirkung der Regeln werden zwar in der Logdatei ausgegeben, aber sie werden tatsächlich nicht angewendet und erzwungen
  12. 3. Konsole: mit service apparmor reload die AppArmor Profile neuladen und erneut mit aa-status überprüfen
  13. 2. Konsole: service i2prouter start

Danach wie unter Punkt 6 weiterhin I2P nutzen und die Logausgabe in der 1. Konsole beobachten.

Deuten spätere Logausgaben darauf hin, dass weitere Abänderungen des Profils nötig sind, geht man wie folgt vor:

1. Überprüfung und Auswertung der /var/log/messages Ausgabe:

sudo aa-logprof

2. Das Profil wie unter Punkt 9 - 10 justieren.

3. Neuladen des Java Profils nach jeder Änderungen per aa-logprof:

sudo apparmor_parser -r /etc/apparmor.d/mp.chroot.i2p.usr.lib.jvm.jreN.N.N.bin.java

Ist das AppArmor Profil vollständig, kann es in den „enforce“ Modus versetzt werden, d. h. die Regeln werden tatsächlich angewendet und damit die Berechtigungen und ihre Verweigerung gesetzt:

sudo aa-enforce /etc/apparmor.d/mp.chroot.i2p.usr.lib.jvm.jreN.N.N.bin.java
sudo apparmor_parser -r /etc/apparmor.d/mp.chroot.i2p.usr.lib.jvm.jreN.N.N.bin.java

Verweise auf aktuelle Seite