Understanding OpenVPN’s persist-tun: Privilege Escalation, TUN Device Management, and Connection Resilience


2 views

When OpenVPN runs with user nobody and group nogroup, it drops privileges after initialization. The persist-tun option maintains the TUN/TAP device across connection disruptions. Here's why this matters:


# Without persist-tun (problem scenario)
1. OpenVPN starts as root → creates tun0
2. Drops privileges to nobody/nogroup
3. Network disruption occurs
4. OpenVPN (as nobody) cannot recreate tun0 → connection fails

Observe these behavioral contrasts in server configurations:


# Sample config WITH persist-tun
dev tun
persist-tun
user nobody
group nogroup
keepalive 10 60

# Sample config WITHOUT persist-tun
dev tun
user nobody
group nogroup
keepalive 10 60

The TUN device handling differs significantly:

  • With persist-tun: Device remains open as file descriptor even when inactive
  • Without persist-tun: Device closes completely on connection drop

Key permission requirements for recreation:


$ ls -l /dev/net/tun
crw-rw-rw- 1 root root 10, 200 Feb 15 09:00 /dev/net/tun

# Required capabilities:
CAP_NET_ADMIN - for network device operations
CAP_IPC_LOCK - for key persistence (when using persist-key)

The complete interaction flow with keepalive:


1. Initial connection: [root] creates tun0 → drops privileges
2. Network hiccup occurs
3. Keepalive timeout triggers reconnection
4. With persist-tun: Reuses existing tun0 (nobody can access)
5. Without persist-tun: Fails (nobody cannot create new tun0)

For different deployment scenarios:


# Secure production setup (recommended)
persist-tun
persist-key
user nobody
group nogroup
keepalive 10 60
tls-auth /etc/openvpn/ta.key 0

# Debugging setup (root required)
dev tun
keepalive 10 60
verb 4

Diagnostic commands for persistence problems:


# Check device persistence
ip link show tun0

# Verify running privileges
ps aux | grep openvpn

# Check capability retention
cat /proc/[PID]/status | grep Cap

The persist-tun directive prevents OpenVPN from tearing down and recreating the TUN/TAP interface during connection flaps. When running as non-root (typically user nobody and group nogroup), OpenVPN loses the capability to recreate network interfaces after initial setup.

# Server configuration demonstrating critical options
user nobody
group nogroup
persist-tun
persist-key
keepalive 10 60
dev tun0

Without persist-tun, OpenVPN's standard behavior would be:

  1. Create tun0 during initialization (requires root)
  2. Drop privileges to nobody/nogroup
  3. Destroy tun0 on connection termination
  4. Fail to recreate tun0 during reconnection (missing root privileges)

The visible effects in ifconfig can be misleading. What matters is the interface's operational state:

# Shows interface exists regardless of persist-tun
$ ip link show tun0
8: tun0: <POINTOPOINT,MULTICAST,NOARP> mtu 1500 qdisc noop state DOWN mode DEFAULT group default qlen 100
Option Relationship with persist-tun
persist-key Maintains SSL/TLS key between reconnections
keepalive Triggers reconnection attempts where persist-tun enables success
user/group Creates the privilege boundary requiring persist-tun

When troubleshooting, check these log patterns:

# Successful reconnection with persist-tun:
Thu Jul 20 10:15:23 2023 /sbin/ip link set dev tun0 up mtu 1500

# Failed reconnection without persist-tun:
Thu Jul 20 10:15:25 2023 Cannot allocate TUN/TAP dev dynamically

For production deployments, consider this enhanced configuration:

# Secure production setup
user nobody
group nogroup
persist-tun
persist-key
chroot /var/lib/openvpn
dev tun
topology subnet
keepalive 10 120
remote-cert-tls client
tls-auth /etc/openvpn/ta.key 0