Firecracker VM sicher mit Jailer starten

Im vorherigen Artikel Firecracker VM Einstieg habe ich schon erklärt, wie eine VM gestartet wird. Um diese sicher von anderen VMs zu isolieren, müssen einige Bestandteile getrennt angelegt werden. Damit auch bei einer größeren Skalierung die Übersicht gewahrt wird und sicher alle Schritte durchgeführt werden, liefert Amazon AWS neben Firecracker auch einen Jailer mit.

Teil der Serie
  1. Firecracker MicroVM Einstieg
  2. Firecracker VM sicher mit Jailer starten
  3. Firecracker VM aus Docker Image erstellen

Installieren link

Die Jailer Binary hat keine Software-Abhängigkeiten und kann einfach auf einem x86_64 Linux heruntergeladen und gestartet werden.

curl -LOJ https://github.com/firecracker-microvm/firecracker/releases/download/v${latest}/jailer-v${latest}

Im Anschluss kann fürs einfachere Handling die Datei noch umbenannt und die Rechte gesetzt werden:

mv jailer-v${latest} jailer
chmod +x jailer

Wie im ersten Teil (Firecracker VM Einstieg) beschrieben muss ebenfalls Firecracker installiert werden.

Um beides einfacher nutzen zu können, kann die Binary in den /usr/bin Ordner verschoben werden.

mv firecracker /usr/bin/firecracker
mv jailer /usr/bin/jailer

Der Jailer arbeitet Standardmäßig im Ordner /srv/jailer. Dieser muss leider zuerst angelegt werden.

mkdir /srv/jailer

Instanz starten link

Der Jailer isoliert die VM. Dafür legt er automatisch eine Art Namespace im UUID Format als Ordner an. In diesem werden alle Komponenten für die VM Instance angelegt.

Das folgende Beispiel startet eine MicoVM mit

  • der selbst vergebenen ID 551e7604-e35c-42b3-b825-416853441234,
  • dem NUMA node 0,
  • der User ID 123
  • und Gruppen ID 100.
/usr/bin/jailer --id 551e7604-e35c-42b3-b825-416853441234 --node 0 \
--exec-file /usr/bin/firecracker --uid 123 --gid 100

Beim ausführen kopiert Jailer die /usr/bin/firecracker Binary nach /srv/jailer/firecracker/<id>/root/firecracker. Die cgoups cpu, cpuset, pids (/sys/fs/cgroup/cpu, …) werden in die von Jailer erzeugten Ordner gemounted.

/sys/fs/cgroup/cpu/firecracker/<id>
/sys/fs/cgroup/cpuset/firecracker/<id>
/sys/fs/cgroup/pids/firecracker/<id>

Anschließend wird Firecracker gestartet und erzeugt einen API Socket unter /srv/jailer/firecracker/<id>/api.socket. Über curl kann mit diesem interagiert werden.

Genauere Erklärung des genauen Ablaufs ist im GitHub Projekt zu finden.

Kernel und Dateisystem

In den erzeugten Ordner /srv/jailer/firecracker/<id>/root werden im Anschluss Kernel und das Dateisystem kopiert. AWS stellt hier beides zum ausprobieren zur Verfügung.

curl -fsSL -o hello-vmlinux.bin https://s3.amazonaws.com/spec.ccfc.min/img/hello/kernel/hello-vmlinux.bin
curl -fsSL -o hello-rootfs.ext4 https://s3.amazonaws.com/spec.ccfc.min/img/hello/fsfiles/hello-rootfs.ext4
cp hello-vmlinux.bin /srv/jailer/firecracker/<id>/root/hello-vmlinux.bin
cp hello-rootfs.ext4 /srv/jailer/firecracker/<id>/root/hello-rootfs.ext4

Alle folgenden Pfade gehen vom instance root Ordner aus.

Gast Kernel

curl --unix-socket /srv/jailer/firecracker/<id>/api.socket -i \
    -X PUT 'http://localhost/boot-source'   \
    -H 'Accept: application/json'           \
    -H 'Content-Type: application/json'     \
    -d '{
        "kernel_image_path": "./hello-vmlinux.bin",
        "boot_args": "console=ttyS0 reboot=k panic=1 pci=off"
    }'

Gast Rootfs

curl --unix-socket /srv/jailer/firecracker/<id>/api.socket -i \
    -X PUT 'http://localhost/drives/rootfs' \
    -H 'Accept: application/json'           \
    -H 'Content-Type: application/json'     \
    -d '{
        "drive_id": "rootfs",
        "path_on_host": "./hello-rootfs.ext4",
        "is_root_device": true,
        "is_read_only": false
    }'

Gast Maschine starten

curl --unix-socket /srv/jailer/firecracker/<id>/api.socket -i \
    -X PUT 'http://localhost/actions'       \
    -H  'Accept: application/json'          \
    -H  'Content-Type: application/json'    \
    -d '{
        "action_type": "InstanceStart"
     }'