I recently disovered systemd-nspawn utility ("chroot on steroids"), and I wanted to share how I set it up on Archlinux. I plan to use it as a sandbox environment, although it's the the recommended usage.
I mainly want to prevent from script-kidding (and accidental) destruction of my environment: instead of running code from the Internet directly on my user session (or event sometimes as root, I must admit), I'll run it inside the container. Hence, the possibilities of an untargeted attack is, I believe, quite limited.
This tutorial is completely inspired from ArchWiki systemd-nspawn.
Also, keep in mind that this is not a script, don't copy and paste it directly, run it step by step and pay attention to what you validate ;-)
Step one: setup a container filesystem
MACHINE_NAME=sandbox CONTAINER=/usr/lib/machines/$MACHINE_NAME sudo mkdir $CONTAINER -p
On Archlinux, pacstrap can bootstrap a new filesystem architecture. debbootstrap on Debian and dnf on Fedora can certainly do the same.
sudo pacman -S arch-install-scripts BASE_PACKAGES="base firefox gdb vim sudo" PKG_TO_EXCLUDE=linux # see the archwiki sudo pacstrap -i -c -d $CONTAINER $BASE_PACKAGES --ignore $PKG_TO_EXCLUDE
And that's it for a minimal system !
Step two: prepare the container environment
Let's boot it, configure it, then we'll come back on some more host-side configuration.
sudo systemd-nspawn --boot --directory $CONTAINER --network-veth # systemd boots the system ... # login as root ... # get these values on the HOST UID=$(echo $UID from HOST) GID=$(echo $GID from HOST) USER=$(echo $USER from HOST) # add and configure the container user: groupadd --gid $GID $USER useradd --uid $UID --create-home --gid $GID $USER passwd $USER # ... visudo # add something like '$USER ALL=(ALL) ALL' # setup the network DHCP (through the virtal-nic) systemctl enable systemd-networkd systemctl start systemd-networkd networkctl # check that everything is prepared: # host0 ether routable configur[ing|ed] # setup the DNS resolver systemctl enable systemd-resolved.service systemctl start systemd-resolved.service rm -f /etc/resolv.conf ln -sf /run/systemd/resolve/resolv.conf /etc/resolv.conf # and quit (the *right* machine ;-) poweroff
Step three: finish the host configuration
We're back on the host for some more configuration:
# just in case sudo systemctl enable systemd-networkd sudo systemctl start systemd-networkd # or sudo systemctl restart systemd-networkd # then check: networkctl status ve-sandbox # if State: no-carrier (unmanaged) cp /usr/lib/systemd/network/80-container-ve.network /etc/systemd/network/80-container-ve.network # and comment: Driver=veth # elif State: routable (configur[ing|ed]) # we're good ! # enable Linux port forwarding sudo sysctl -w net.ipv4.ip_forward=1 # and make it permanent across reboots echo net.ipv4.ip_forward = 1 | sudo tee /etc/sysctl.d/40-portforwarding.conf
We're almost done for the configuration! Now we need to setup the container start and access:
sudo systemctl enable machines.target sudo systemctl enable systemd-nspawn@$MACHINE.service sudo systemctl status systemd-nspawn@$MACHINE.service # it should be up and running # force nic reconfiguration # (do it every time you boot a container) sudo systemctl restart systemd-networkd
Step four: easy access to the container
And now your container is easy to access:
sudo machinectl sudo machinectl login $MACHINE sudo machinectl shell $USER@$MACHINE sudo machinectl status $MACHINE sudo machinectl poweroff $MACHINE
Bonus step: convenient access to the container
sudo cp /usr/lib/systemd/system/systemd-nspawn@.service /etc/systemd/system/machines.target.wants/systemd-nspawn@$MACHINE.service # then add --bind /tmp/.X11-unix to the container option # then (in the container) echo export DISPLAY=:0 >> ~/.profile
That should be enough to be able to run X application on the sandbox. Keep in mind that sharing Xorg between the two environment flaws the sandboxing, Xorg is old and buggy ...
If you want to share anything else, the option syntax is:
# add to /etc/suders.d/$USER something like $USER ALL= NOPASSWD: /usr/bin/systemctl restart systemd-networkd $USER ALL= NOPASSWD: /usr/bin/machinectl shell $USER@$MACHINE*