11

This question is similar to No tun device in lxc guest for openvpn . The LXC has evolved and the unprivileged LXC containers were introduced recently that offer another layer of security against breaking the jail.

I need to create an OpenVPN server inside one of the unprivileged container. I don't know how to let the container create a private tun network device.

I did append lxc.cgroup.devices.allow = c 10:200 rwm to the ~/.local/share/lxc/mylxc/config.

After starting the container, mknod /dev/net/tun c 10 200 returns mknod: '/dev/net/tun': Operation not permitted inside the container.

I use a vanilla Ubuntu 14.04 64bit as host and a container created with

lxc-create -t download -n mylxc  -- -d ubuntu -r trusty -a amd64

Did anyone managed to get /dev/tun device running under unprivileged LXC?

Adam Ryczkowski
  • 690
  • 1
  • 9
  • 29
  • For information, to make openvpn work in an unprivileged LXC container, I had to add `lxc.mount.entry = /dev/net/tun dev/net/tun none bind,create=file` to the container config file, like described here: https://superuser.com/a/1205662/130915 Then, I ran openvpn as root with sudo inside of the container. – baptx Jan 28 '19 at 19:38

1 Answers1

3

You need to explicitly add the CAP_MKNOD capability to your container.

  lxc.cap.keep
          Specify the capability to be kept in the container. All other
          capabilities will be dropped. When a special value of "none"
          is encountered, lxc will clear any keep capabilities specified
          up to this point. A value of "none" alone can be used to drop
          all capabilities.

You could also try to automate this (if you happen to use systemd inside the container) using:

  lxc.hook.autodev
          A hook to be run in the container's namespace after mounting
          has been done and after any mount hooks have run, but before
          the pivot_root, if lxc.autodev == 1.  The purpose of this hook
          is to assist in populating the /dev directory of the container
          when using the autodev option for systemd based containers.
          The container's /dev directory is relative to the
          ${LXC_ROOTFS_MOUNT} environment variable available when the
          hook is run.

which can point to a script running mknod.

Using docker this is very easy to accomplish. By default, containers are unprivileged.

In this example, I'm pulling a trusty container from the registry:

sudo -r sysadm_r docker pull corbinu/docker-trusty
Pulling repository corbinu/docker-trusty
...
Status: Downloaded newer image for corbinu/docker-trusty:latest

And I'm starting it in interactive mode informing about the capability I need inside:

sudo -r sysadm_r docker run --cap-drop ALL --cap-add MKNOD \
  -i -t corbinu/docker-trusty bash
root@46bbb43095ec:/# ls /dev/
console  fd/      full     fuse     kcore    mqueue/  null     ptmx     pts/     random   shm/     stderr   stdin    stdout   tty      urandom  zero
root@46bbb43095ec:/# mkdir /dev/net
root@46bbb43095ec:/# mknod /dev/net/tun c 10 200
root@46bbb43095ec:/# ls -lrt /dev/net/tun
crw-r--r--. 1 root root 10, 200 Apr  6 16:52 /dev/net/tun

As opposed to:

sudo -r sysadm_r docker run --cap-drop ALL \
  -i -t corbinu/docker-trusty bash
root@9a4cdc75a5ec:/# mkdir /dev/net
root@9a4cdc75a5ec:/# mknod /dev/net/tun c 10 200
mknod: ‘/dev/net/tun’: Operation not permitted
dawud
  • 14,918
  • 3
  • 41
  • 61
  • 1
    I believe, what docker calls "unprivileged" is quite different from what it means in LXC parlance: https://github.com/docker/docker/issues/7906 . It seems that Docker still don't support the unprivileged containers. It doesn't necessarily invalidate your answer - I'll check `CAP_MKNOD` after work. – Adam Ryczkowski Apr 07 '15 at 14:47
  • 1
    Can you give me please a little pointer on how to change the capability of the unprivileged container? At least a correct phrase to Google? – Adam Ryczkowski Apr 26 '15 at 08:31
  • 3
    Adding the `lxc.cap.keep = CAP_MKNOD` to config makes error `Simultaneously requested dropping and keeping caps`. I checked all recursively added configs (`ubuntu.userns.conf`, `ubuntu.common.conf` and `common.conf`) and found only one line with `lxc.cap.drop`: `lxc.cap.drop = mac_admin mac_override sys_time sys_module`. But that is irrelevant isn't it? – Adam Ryczkowski Apr 26 '15 at 08:44
  • `You need to explicitly add the CAP_MKNOD capability to your container.` How to do that for an existing LXC Container? – Philipp Ludwig Nov 15 '21 at 13:46
  • @PhilippLudwig https://stackoverflow.com/a/1422879/2248946 – dawud Nov 15 '21 at 21:37