Linux Container aka LXC können „unprivileged“ gestartet werden. Das heißt das der Container als User-Prozess gestartet werden. Sollte also wirklich jemand aus den Container ausbrechen so verfügt der böse Benutzer nur über die eingeschränkten Rechte des Benutzers der den Container gestartet hat.
Ich nutze Ubuntu-Server bei anderen Distributionen kann es ein wenig abweichen wobei die Prinzipien dieselben sind.
Es wird der user-namespace benutzt. Das heißt der Container wird mit der user-id des einfachen Benutzers gestartet und der Kernel mapped die user-id zur id 0 in den Conatiner. Vereinfacht gesagt der Benutzer startet ein Container mit der user.id 1001 und die Programme innerhalb des Containers laufen mit der user-id „root“(ohne dies wirklich zutun).
Auch hier gibt es wieder einige Stolperfallen bzw. vorraussetzungen:
Damit das mapping funktioniert benötigen wir noch ein paar Programme:
apt install systemd-services uidmap
1. Der Benutzer muss über sub-uid und sub-gid verfügen. Diese können mit „usermod“ erstellt werden.
usermod --add-subuids 100000-165536 <lxcuser> usermod --add-subgids 100000-165536 <lxcuser>
In den Dateien „/etc/subuid“ und „/etc/subgid“ sollte solch eine Zeile sein:
lxcuser:100000:65537
2. Wenn die Container mit Limits gestartet weden bzw. wenn diese mit cgroups eingeschränkt werden muss der Benutzer dies auch dürfen. Dies kann mit einen Blick in der Datei „etc/pam.d/common-session“ und „/etc/pam.d/common-session-noninteractive“ überprüft werden. Hier sollte folgende Zeile ähnlich eingetragen sein:
session optional pam_cgfs.so -c freezer,memory,cpu,cpuset,name=systemd
Fehlt diese Zeile und der Container wird mit cgroup-limits gestartet erscheint folgende Fehlermeldung:
lxc-start: cgroups/cgfsng.c: cgfsng_setup_limits: 1971 No such file or directory - Error setting cpuset.cpus to 1 for <containername> lxc-start: start.c: lxc_spawn: 1205 Failed to setup cgroup limits for container "<containername>". lxc-start: start.c: __lxc_start: 1358 Failed to spawn container "<containername>". lxc-start: tools/lxc_start.c: main: 366 The container failed to start. lxc-start: tools/lxc_start.c: main: 370 Additional information can be obtained by setting the --logfile and --logpriority options.
3. Da der Benutzer normalerweise nicht Netzwerkeinstellungen ändern kann, also erstellen von veth-pairs oder das hinzufügen dieser zu Netzwerkbrücken, wird dies über ein seperaten Prozess gemacht „lxc-user-nic“.
Dieser Prozess parst die Konfigurationsdatei erstellt daraufhin das Netzwerkdevice und bindet es an die Netzwerkbrücke. Konfiguriert wird es in der Datei „/etc/lxc/lxc-usernet“ typischerweise sieht sie wie folgt aus:
#User Type Bridge Anzahl <lxcuser> veth lxcbr0 100
Jetzt könnt ihr den Benutzer wechseln und euren Container erstellen:
su - <lxcuser> lxc-create -n <containername> -t download -- -d ubuntu -r bionic -a amd64
Wobei ihr auch eine andere Distribution und ein anderes Release wählen könnt. Wenn alles gut gegangen ist startet ihr den Container einfach mittels:
lxc-start -n <containername> -d
Wechselt nun in den Container mit z.b.:
lxc-attach -n <containername>
Ruft „top“ auf und ihr seht das die Prozesse innerhalb des Container als Benutzer „root“ laufen.
Wie ihr den Container konfiguriert und mit cgroup-limits einschränkt wurde ja schon behandelt.
Bestehende Container können meist mit einer kleinen Anpassung der Datei „config“ so geändert werden das diese auch unprivileged laufen:
# if you use ubuntu in container lxc.include = /usr/share/lxc/config/ubuntu.common.conf lxc.include = /usr/share/lxc/config/ubuntu.userns.conf lxc.include = /etc/lxc/default.conf lxc.id_map = u 0 100000 65537 lxc.id_map = g 0 100000 65537
Für weitere Informationen schaut euch diese Seite an: https://stgraber.org/2014/01/17/lxc-1-0-unprivileged-containers/.