- Überblick über die Einrichtung
- Einrichten eines Buildservers
- Builds ausführen
- QEMU/KVM/libvirt einrichten
Der F-Droid-Buildserver isoliert die Herstellung eines jeden Pakets in einer sauberen, abgeschirmten und sicheren Wegwerfarbeitsumgebung einer virtuellen Maschine. Das Herstellen tausender Apps, insbesondere mit automatisierten und/oder unbeaufsichtigten Prozessen, muss vom Sicherheitsaspekt her als eine gefahrbringende Beschäftigung angesehen werden. Das ist umso mehr der Fall, wenn die hergestellten Produkte zudem weit verbreitet werden und dies in einer halbautomatischen Weise (“Es stehen Aktualisierungen bereit”) geschieht.
Nehmen wir an, ein Originalcode-Repository ist kompromittiert. Dann finden wir hier eine kleine Auswahl an Maßnahmen, die ein Angreifer in einer solchen Situation ergreifen könnte:
- Benutze eigene Build-Schritt, die alle ausgeführt werden, als würde der Benutzer den Build erstellen.
- Auf den Schlüsselspeicher zugreifen.
- Die erstellten APK-Dateien oder Quell-Tarballs für andere Anwendungen im Repository ändern.
- Verändern von Metadaten (zu denen auch Build-Skripte gehören, die wiederum ebenfalls die Fähigkeit mitbringen, alles auszuführen) für andere Anwendungen im Repository.
Durch die vollständige Isolierung bleiben die Auswirkungen zumindest auf die jeweilige Anwendung beschränkt. Die Build-Umgebung wird nicht nur frisch für jeden Build geschaffen und danach verworfen, sie wird auch komplett von der Signatur-Umgebung abgeschirmt.
Abgesehen von Sicherheitsproblemen gibt es einige Anwendungen, die seltsame Anforderungen haben, wie etwa alte Versionen des NDK. Es wäre nicht praktikabel (oder zumindest extrem chaotisch), damit zu beginnen, das SDK auf einem Mehrzwecksystem zu modifizieren und wiederherzustellen, aber innerhalb der Grenzen einer Virtual Machine zum einmaligen Gebrauch ist alles möglich.
Hinzu kommt der offensichtliche Vorteil, eine standardisierte und vollständig reproduzierbare Umgebung zu besitzen, in der gebaut wird. Darüber hinaus schafft sie die Voraussetzungen für spezialisierte, maßgeschneiderte Build-Umgebungen für besondere Anwendungsfälle.
Überblick über die Einrichtung
Ausgehend von einer komplett sauberen minimalen Debian/Stable-Installation
richtest du so einen funktionierenden Buildserver ein. Diese Anleitung geht
davon aus, dass du bereits den fdroidserver aufgesetzt
hast. Das Ausführen der
fdroidserver-Werkzeuge direkt aus
git heraus
(z. B. ~/fdroidserver/fdroid build org.adaway), wird wahrscheinlich fürs
Erste am einfachsten sein, da die Buildserver-Setup-Skripte noch nicht
wirklich fertig sind, um sie sauber zusammenzupacken. Außerdem wird es
wahrscheinlich nur auf Debian, Ubuntu und anderen Debian-Derivaten
funktionieren, da F-Droid nur Debian in seiner Infrastruktur verwendet (wir
begrüßen Portierungsbeiträge!).
Der Basisserver braucht mindestens Debian/trixie oder es müssen einige schwierige Anpassungen vorgenommen werden. Wenn du Ubuntu oder eine abgeleitete Distribution nutzt, kannst du alle Pakete, die in deiner Version fehlen, wie vagrant-cachier, von diesem PPA beziehen: https://launchpad.net/~fdroid/+archive/ubuntu/buildserver/
Installiere zunächst die notwendigen Pakete und lege einen neuen Benutzer an, der den gesamten Prozess hier ausführen soll, z. B. fdroid. Dies sind nur die Pakete, die von allen Builds benötigt werden. Möglicherweise musst du zusätzliche Pakete installieren, um Apps herzustellen, z. B. mercurial oder subversion. Sobald die Pakete installiert sind und der Benutzer fdroid erstellt wurde, sollte in diesem Prozess nichts mehr mit root oder sudo ausgeführt werden.
root:~# apt-get install vagrant git python3-certifi \
python3-libvirt python3-requestbuilder python3-yaml \
python3-progress python3-vagrant python3-paramiko python3-pyasn1 \
python3-pyasn1-modules python3-requests python3-git
vagrant-mutate vagrant-libvirt ebtables dnsmasq-base \
libvirt-clients libvirt-daemon-system qemu-kvm qemu-utils
root:~# adduser --disabled-password fdroid
root:~# su fdroid
Klone den Quellcode, der als Benutzer fdroid ausgeführt wird:
fdroid:~$ cd ~
fdroid:~$ git clone https://gitlab.com/fdroid/fdroidserver.git
Du musst außerdem sicherstellen, dass die
Einrichtung deiner
ANDROID_HOME-Umgebungsvariable korrekt ist.
Der Einfachheit halber kannst du optional die ausführbare Datei „fdroid“ zu deinem Pfad hinzufügen:
fdroid:~$ echo "PATH=\$PATH:$HOME/fdroidserver" >> ~/.bashrc
Alle Build-Metadaten der App werden aus dem fdroiddata-Repo abgerufen …
fdroid:~/fdroidserver$ cd ~
fdroid:~$ git clone https://gitlab.com/fdroid/fdroiddata.git
fdroid:~$ cp fdroidserver/examples/config.yml fdroiddata/
fdroid:~$ sed -i "s@^[# ]*build_server_always.*@build_server_always: true@" fdroiddata/config.yml
Einrichten eines Buildservers
Zusätzlich zum zuvor beschriebenen Basis-Setup liefern wir eine Vagrant-kompatible Debian/Bullseye-Basebox namens „fdroid/bullseye64“ aus.
Das Bootstrapping der Debian-Vagrant-Boxen für unseren Buildserver erfolgt von Grund auf. Der Bezug und die Überprüfung unserer vorgefertigten Vagrant-Boxen ist voll automatisiert. (Solltest du Interesse an diesem Prozess haben oder das Bootstrapping selbst in die Hand nehmen wollen, solltest du dir das hier ansehen: F-Droid Base Box)
Erstellen der F-Droid-Buildserver-Box
Erstelle eine Konfigurationsdatei für Vagrant als
~/fdroidserver/buildserver/Vagrantfile.yaml, die Folgendes enthält:
vm_provider: libvirt
Dann das Basis-Buildserver-Image … (das Herunterladen der Basebox und aller SDK-Plattformen kann lange dauern).
fdroid:~$ cd fdroidserver
fdroid:~/fdroidserver$ ./makebuildserver --verbose
Dies wird lange dauern, viel Bandbreite und Speicherplatz beanspruchen – der größte Teil davon wird für die Installation der notwendigen Teile des Android-SDKs für die verschiedenen Plattformen aufgewendet. Zum Glück musst du das nur gelegentlich tun. Sobald du ein funktionierendes Buildserver-Image hast, kannst du, wenn sich Rezepte ändern (z. B. wenn Pakete hinzugefügt werden müssen), dieses Skript einfach erneut ausführen, dann wird das vorhandene an Ort und Stelle aktualisiert.
Sobald es fertig ist, hast du eine neue Basis-Box namens „buildserver“, die
für die eigentlichen Builds verwendet wird. Du kannst dann Pakete wie
gewohnt erstellen, aber bei Ausführung von fdroid build --verbose --server
… erfolgt die App-Erstellung nun isoliert innerhalb der virtuellen
Maschine.
Während das erstellte Image eine begrenzte Anzahl von CPU-Kernen und
Speicher zugewiesen hat, kannst du ~/fdroiddata/builder/Vagrantfile
bearbeiten, um diese zur Laufzeit dynamisch zu ändern, z. B. libvirt.cpus =
6 und libvirt.memory = 12288, aber stelle sicher, dass die Grenzen des
Host-Rechners nicht überschritten werden, sonst könnte die VM abstürzen.
Beim ersten Build wird eine neue virtuelle Maschine erstellt, die die
„Buildserver“-Box als Basis verwendet. Ein Snapshot dieses sauberen
Maschinenzustandes wird für zukünftige Builds gespeichert, um die Leistung
zu verbessern. Du kannst das Verwerfen dieses Snapshots und den Neuaufbau
von Grund auf erzwingen, indem du den Schalter fdroid build --resetserver
… verwendest.
Cache-Anpassungen für makebuildserver (optional)
Die wichtigsten SDK/NDK-Downloads werden automatisch zwischengespeichert, um
den nächsten Durchgang zu beschleunigen. Aber es gibt keine einfache
Möglichkeit, dies für längere Abschnitte zu tun, die das android-Tool des
SDK verwendet, um Plattformen, Add-ons und Tools zu installieren. Anstatt
jedoch ein automatisches Caching zu erlauben, kannst du ein vorgefülltes
Cache-Verzeichnis angeben, das nicht nur diese Downloads, sondern auch
.tar.gz-Dateien für alle relevanten Ergänzungen enthält. Wenn die
Provisionierungsskripte diese erkennen, werden sie anstelle der
Android-Tools verwendet. Hast du zum Beispiel
buildserver/addons/cache/platforms/android-19.tar.gz, wird sie für die
Installation der Android-19-Plattform verwendet, anstatt sie mit android
update sdk --no-ui -t android-19 erneut herunterzuladen. Es ist möglich,
aus einer lokalen Installation des SDK die Cache-Dateien dieser Ergänzungen
zu erstellen, diese eingeschlossen:
cd /pfad/zum/android-sdk/platforms
tar czf android-19.tar.gz android-19
mv android-19.tar.gz /path/to/buildserver/addons/cache/platforms/
Wenn du bereits einen Buildserver erstellt hast, ist es auch möglich, diese Dateien direkt vom Buildserver zu beziehen:
vagrant ssh -- -C 'tar -C ~/android-sdk/platforms czf android-19.tar.gz android-19'
vagrant ssh -- -C 'cat ~/android-sdk/platforms/android-19.tar.gz' > /pfad/zum/fdroidserver/buildserver/cache/platforms/android19.tar.gz
Builds ausführen
Bei Verwendung des Buildservers ist es am einfachsten, fdroid direkt von
einem Git-Checkout von fdroidserver aus zu starten. Wenn du die
fdroidserver-Tools noch nicht installiert und eingerichtet hast, musst du
das als nächstes tun: Server und Repo-Werkzeuge
installieren. Das liefert alle
Abhängigkeiten, die benötigt werden, um fdroidserver von git auszuführen.
Jetzt bist du bereit, Builds auszuführen. Teste die neueste Version von fdroid:
fdroid:~/fdroidserver$ cd ~/fdroiddata
fdroid:~/fdroiddata$ ~/fdroidserver/fdroid build org.fdroid.fdroid -l --server
QEMU/KVM/libvirt einrichten
Während VirtualBox in der Vergangenheit verwendet wurde, ist QEMU/KVM-Gast
VMs via libvirt immer noch die empfohlene Einrichtung, da das auch von
f-droid.org eingesetzt wird. Um die libvirt-Abbilddateien direkt mit
vagrant package lesbar zu machen, muss QEMU von libvirt so konfiguriert
werden, dass der Eigentümer immer auf libvirt.libvirt gesetzt wird.
root:~# cat << EOF >> /etc/libvirt/qemu.conf
user = "libvirt"
group = "libvirt"
dynamic_ownership = 1
EOF
root:~# service libvirtd restart
Debian/bullseye und Ubuntu/xenial
root:~# adduser fdroid libvirt
root:~# adduser fdroid libvirt-qemu
älteres Debian und Ubuntu
root:~# adduser fdroid libvirtd
root:~# adduser fdroid kvm
Erweitertes verschachteltes KVM Setup:
Dieser Abschnitt ist nicht relevant für die Verwendung von F-Droid in einem
normalen Setup. Wenn du das Flag fdroid build --server innerhalb einer KVM
ausführen möchtest, hilft dir dieses Kapitel beim Einstieg.
Beachte die folgenden grundlegenden Schachtelungseinstellungen:
bare metal host (l0)
\- F-Droid VM (l1)
\- F-Droid builder VM (l2)
Die obigen Schritte beschreiben, wie man (l1) und makebuildserver einrichtet (l2).
Zuerst musst du prüfen, ob die CPU den Befehlssatz vmx (oder svm auf amd) unterstützt. Mit diesem Befehl kannst du Details über deine CPU auflisten:
root:~# cat /proc/cpuinfo
Bei (l0) musst du prüfen, ob die Verschachtelung aktiviert ist:
root:~# cat /sys/module/kvm_intel/parameters/nested
Wenn es nicht aktiviert ist, kannst du es einschalten durch Ausführen von:
echo "options kvm-intel nested=Y" > /etc/modprobe.d/kvm-intel.conf
Du musst einen Neustart durchführen, damit dies wirksam wird.
Als Nächstes musst du sicherstellen, dass deine (l1) VM-Konfiguration die zum Verschachteln benötigten CPU-Funktionen weiterleitet. Öffne dazu die Konfiguration für die VM /etc/libvirt/qemu/my-vm.xml und füge einen CPU-Block in den Domain-Tag ein. (virt-manager bietet auch eine Bedienoberfläche für diesen Vorgang.)
<cpu mode='custom' match='exact'>
<model fallback='allow'>SandyBridge</model>
<vendor>Intel</vendor>
<feature policy='require' name='vmx'/>
</cpu>
Die tatsächlich benötigte Konfiguration hängt von deiner CPU ab. Details findest du im libvirts Handbuch. Das wichtigste ist vmx (oder svm auf amd) an das Gastsystem weiterzuleiten.
