Working with TUN/TAP devices in unprivileged LXC containers presents unique challenges due to the security constraints of user namespaces. The traditional approach of simply creating device nodes won't work because unprivileged containers operate with mapped UIDs/GIDs.
First, ensure your host system is properly configured:
# On the host system
echo "root:100000:65536" | sudo tee -a /etc/subuid
echo "root:100000:65536" | sudo tee -a /etc/subgid
Modify your container configuration (~/.local/share/lxc/container-name/config):
# Device permissions
lxc.cgroup.devices.allow = c 10:200 rwm
lxc.mount.entry = /dev/net/tun dev/net/tun none bind,create=file 0 0
# Required capabilities
lxc.cap.keep = net_admin
Inside the container, you'll need to create the device node directory and set appropriate permissions:
mkdir -p /dev/net
mknod /dev/net/tun c 10 200
chmod 0666 /dev/net/tun
To test if the TUN device works properly:
# Inside container
ip tuntap add mode tun dev tun0
ip link set tun0 up
ip link show tun0
For persistent configuration across reboots, add this to your container's startup:
# In /etc/rc.local or similar
[ ! -c /dev/net/tun ] && mkdir -p /dev/net && mknod /dev/net/tun c 10 200 && chmod 0666 /dev/net/tun
If you encounter "Operation not permitted" errors:
- Verify the host's cgroup permissions
- Check that the container has CAP_NET_ADMIN
- Ensure proper UID/GID mappings
For production environments, consider additional security measures:
# Restrict device access to specific users
lxc.cgroup.devices.allow = c 10:200 rwm
lxc.cgroup.devices.deny = c 10:200 rw
Working with unprivileged LXC containers introduces additional security constraints that affect device node creation. Unlike privileged containers where you could simply create device nodes with mknod, unprivileged containers require proper cgroup permissions and host-level configuration.
First, ensure your host system has the necessary kernel modules loaded:
sudo modprobe tun
lsmod | grep tun
Edit the container's configuration file (typically at ~/.local/share/lxc/containername/config) to include:
# Device permissions
lxc.cgroup.devices.allow = c 10:200 rwm
# Required for unprivileged containers
lxc.mount.entry = /dev/net dev/net none bind,create=dir 0 0
After starting the container, you'll need to create the device directory structure and node:
# Inside container:
mkdir -p /dev/net
mknod /dev/net/tun c 10 200
chmod 0666 /dev/net/tun
Test the tun device functionality:
# Create test tunnel
ip tuntap add mode tun testtun
ip link show testtun
ip tuntap del mode tun testtun
For automatic device creation on container start, add to /etc/rc.local inside the container:
#!/bin/sh
[ -e /dev/net/tun ] || {
mkdir -p /dev/net
mknod /dev/net/tun c 10 200
chmod 0666 /dev/net/tun
}
exit 0
If you encounter permission issues, verify:
# On host:
cat /proc/$(lxc-info -n containername -p)/cgroup | grep devices
# Check device major:minor numbers
ls -l /dev/net/tun