Run programs in network namespaces without root privileges
  • Python 94.3%
  • Makefile 5.5%
  • Shell 0.2%
Find a file
2026-10-05 01:17:53 +05:00
packaging chore: update systemd service description 2026-10-05 01:17:53 +05:00
src/unetns_exec chore: update version to 1.1.0 2026-10-05 00:50:42 +05:00
tools build: add tools with resolve_constants.py 2026-10-05 00:58:13 +05:00
.gitignore initial commit 2026-07-31 17:32:03 +05:00
LICENSE initial commit 2026-07-31 17:32:03 +05:00
Makefile build: improve Makefile, add resolve_constants integration and validation checks 2026-10-05 01:00:43 +05:00
README.md chore: improve README.md 2026-10-05 01:04:05 +05:00

unetns-exec

unetns-exec (Unprivileged Network Namespace Execute) - a utility that allows you to run any program in a network namespace without elevating to root, using a privileged helper daemon.


Navigation


Why unetns-exec?

A common approach is:

sudo ip netns exec <netns> sudo -u $(whoami) <command...>

However, this still requires root privileges, unetns-exec provides the same workflow without requiring root privileges for the client.

It also differs from runns in several important ways:

  • Network namespaces are opened by the client rather than by the daemon;
  • The daemon does not store information about child processes;
  • Contemporary Linux privilege dropping.

Capabilities and peculiarities

  • This utility executes arbitary programs inside network namespaces opened by the client. Therefore, the client must have read access to the selected namespace;
  • The unetns-exec client acts as a PTY client. Once the daemon replies, it connects to the provided PTY and functions as an intermediary;
  • The daemon has a lightweight, stateless architecture: it does not store information about spawned processes and does not manage their lifecycle;
  • It is also single-threaded, meaning it processes requests sequentially, one at a time;
  • By default, the daemon builds a minimal environment needed for user programs to run. This includes: PATH, HOME, USER, LOGNAME, SHELL, TERM, LANG, and XDG_RUNTIME_DIR (if present). This behavior can be overridden using either -E or --copy-env option;
  • It performs a privilege-dropping procedure by disabling PR_SET_KEEPCAPS, then using setresuid and setresgid instead of the traditional setuid and setgid.

Execution example

$ sudo ip netns add vpn

$ whoami
librellium

$ groups
librellium unetns-admin

$ grep Cap /proc/self/status
CapInh: 0000000800000000
CapPrm: 0000000000000000
CapEff: 0000000000000000
CapBnd: 000001ffffffffff
CapAmb: 0000000000000000

$ ip netns identify
  # initial namespace

$ unetns-exec -E vpn bash

$ whoami
librellium

$ groups
librellium unetns-admin

$ grep Cap /proc/self/status
CapInh: 0000000000000000
CapPrm: 0000000000000000
CapEff: 0000000000000000
CapBnd: 000001ffffffffff
CapAmb: 0000000000000000

$ ip netns identify
vpn

Attention! Restricting the daemon restricts the processes it launches too. They cannot inherit the capabilities of the requesting process. This behavior can be seen in the Execution example above.


Requirements

  • Python 3.7+ (3.6 is also supported with the dataclasses backport);
  • No external Python dependencies are required, unetns-exec works only on pure stdlib;
  • systemd is recommended for daemon management and system configuration;
  • GNU Make 3.82+ and any version of GCC compiler are required for installation.

Installation

  1. Clone the repository:
git clone https://github.com/librellium/unetns-exec.git
  1. Navigate to the project directory:
cd unetns-exec
  1. Install unetns-exec:
sudo make install

See make help for more info.

  1. Create the unetns-admin system group:

    • With systemd:
      sudo systemd-sysusers /usr/lib/sysusers.d/unetns-exec.conf
      
    • or without:
      sudo groupadd --system unetns-admin
      
  2. Add your user to the unetns-admin group:

sudo usermod -aG unetns-admin $USER
  1. Enable and start the daemon:
sudo systemctl enable --now unetns-daemon.service
  1. Log out and log back in to apply the new group membership.