An obvious choice to isolate processes is to use containers or a VM (docker, lxc, qemu). As an alternative, here a few notes on how to use "unshare" to separate most namespaces and run an application in a "unshared chroot". The process user is still root, running as non-root needs more tinkering and learning.
Motivation: I needed to run a NodeJS application "zigbee2mqtt" and wanted to limit its LAN connectivity and limit its access to the filesystem.
Hardware is a RPI3 + ZigbeeDongle attached via USB.
#install packages
opkg install debootstrap unshare kmod-usb-serial-cp210x ip-full kmod-veth mosquitto-client-ssl screen
#create userland from "outside"
debootstrap --arch arm64 bullseye /root/mychroot
#enter the userland
mkdir /var/run/netns
touch /var/run/netns/myChroot
unshare --mount --uts --ipc --pid --kill-child --net=/var/run/netns/myChroot --fork chroot /root/mychroot/ bash
#this is now "inside" the userland
mount -t proc proc /proc
mount -t sysfs sys /sys
apt install -y curl htop build-essential git vim mosquitto
# /!\ these install tips are from nodejs developers
# /!\ please note that this requires a lot of trust to NPM and NodeJS
# seeing such practices convinced me it is worth isolating the process as much as possible
curl -fsSL https://deb.nodesource.com/setup_18.x | bash -
apt-get install -y nodejs
cd
git clone --depth 1 https://github.com/Koenkk/zigbee2mqtt.git
mv zigbee2mqtt /opt/zigbee2mqtt
cd /opt/zigbee2mqtt
mosquitto -d -p 1883
npm --proxy $http_proxy ci
npm start
To autostart the application put screen -d -S zig -m sh "/root/run.sh"
in /etc/rc.local
and create two files:
/root/run.sh
#!/bin/sh
function cleanup {
echo "Outside: cleaning up 🧹"
ip netns exec myChroot ip link set vethInside down
ip netns exec myChroot ip link set lo down
ip netns exec myChroot ip link delete vethInside
#ip netns exec myChroot ip route add 0.0.0.0/0 via 10.2.2.1 dev vethInside
ip netns del myChroot
ip link set vethOutside down
ip link delete vethOutside
rm /var/run/netns/myChroot
rmdir /var/run/netns
killall mosquitto_pub
killall mosquitto_sub
killall socat
}
trap cleanup EXIT SIGINT
cleanup
function MQTTRCV {
while true; do
sleep 1
mosquitto_sub -t "garden/Gemüsebeet/set" -p 8883 --cafile /etc/config/myCA.crt -h server.lan -u "username" -P "passwort" | mosquitto_pub -t 'zigbee2mqtt/Gemüsebeet/set' -l -h 10.2.2.2 -p 1883
done
}
function MQTTTRX {
while true; do
sleep 1
mosquitto_sub -t 'zigbee2mqtt/Gemüsebeet' -p 1883 -h 10.2.2.2 | mosquitto_pub -l -t "garden/Gemüsebeet" -p 8883 --cafile /etc/config/myCA.crt -h kellerap.lan -u "username" -P "passwort"
done
}
socat TCP-LISTEN:8080,fork,reuseaddr,range=192.168.1.0/24 TCP:10.2.2.2:8080 &
MQTTRCV &
MQTTTRX &
mkdir /var/run/netns
touch /var/run/netns/myChroot
unshare --mount --uts --ipc --pid --kill-child --net=/var/run/netns/myChroot --fork chroot /root/mychroot/ bash /root/run.sh &
#unshare --mount --uts --ipc --pid --kill-child --net=/var/run/netns/myChroot --fork chroot /root/mychroot/ bash
sleep 5
ip link add vethOutside type veth peer name vethInside netns myChroot
ip addr add 10.2.2.1/30 dev vethOutside
ip link set vethOutside up
ip netns exec myChroot ip addr add 10.2.2.2/30 dev vethInside
ip netns exec myChroot ip link set vethInside up
ip netns exec myChroot ip link set lo up
wait
and the second file is inside the userland /root/mychroot/root/
#!/bin/sh
function cleanup {
echo "Inside: cleaning up 🧹"
umount /proc
umount /sys
}
trap cleanup EXIT SIGINT
mount -t proc proc /proc
mount -t sysfs sys /sys
echo "===================="
mount
echo "===================="
df -h
echo "===================="
ps ax
echo "===================="
mknod /dev/ttyUSB0 c 188 0
mosquitto -d -c /etc/mosquitto/conf.d/mosquitto.conf
cd /opt/zigbee2mqtt
npm start