Running as Non-Root User

Introduction

This guide describes how to configure the Netifyd agent to run as a non-root user by creating a dedicated system user and granting the necessary capabilities.

  • Improved Security: Running Netifyd as a restricted user (netify) reduces the risk of a full system compromise if the process is ever exploited.
  • Principle of Least Privilege: Netifyd only gets the minimal permissions it needs (CAP_NET_ADMIN), not full root powers.
  • Safer Maintenance and Upgrades: Fewer services running as root means fewer things to worry about during updates, audits, or system hardening.
  • Better Auditability: It's easier to monitor and control what the netify user is doing, compared to root processes.
  • Compliance Benefits: Many security standards (like CIS Benchmarks, PCI-DSS, SOC 2) recommend or require minimizing the use of root for network services.
  • Damage Limitation: In the event of a bug or crash, the system is better protected because the service has limited access to the OS.
  • Cleaner System Management: Using capabilities (setcap) avoids the need for complex sudoers rules or full privilege escalation.
  • Future-Proofing: Modern Linux environments (especially containers, systemd, and immutable systems) assume minimal privilege models.

Minimizing privileges is a core best practice for securing network services. By running Netifyd as a non-root user with only the specific capabilities it needs, you significantly reduce the attack surface of the system. This approach not only strengthens security and simplifies compliance, but also ensures that any potential issues with the Netifyd agent have minimal impact on the overall stability and integrity of the device.

Common Setup

Step 1 - Create a netify User

First, create a system user specifically for running Netifyd. This creates a non-login, system-level user without a home directory.

sudo useradd --system --no-create-home --shell /usr/sbin/nologin netify

Step 2 - Set File Permissions

sudo chown -R netify:netify /etc/netifyd
sudo chown -R netify:netify /var/run/netifyd

Step 3 - Grant Required Capabilities

Netifyd requires certain network privileges, traditionally only available to the root user. You can grant the necessary capability (CAP_NET_ADMIN) using setcap.

sudo setcap cap_net_admin=eip /usr/sbin/netifyd

Systemd

Step 1 - Update Netifyd Service

Modify the service unit file to run as the netify user. Edit an override for the service:

# Netify systemd.unit(5) Service File
# Copyright (C) 2016-2024 eGloo Incorporated
#
# This is free software, licensed under the GNU General Public License v3.

[Unit]
Description=Netify Agent
After=syslog.target network-online.target
Documentation=man:netifyd(8) man:netifyd.conf(5)
Documentation=https://netify.ai/

[Service]
Type=forking
User=netify
Group=netify
AmbientCapabilities=CAP_NET_ADMIN
NoNewPrivileges=true
EnvironmentFile=/usr/share/netifyd/env.sh
ExecStartPre=/usr/share/netifyd/exec-pre.sh
ExecStart=/usr/sbin/netifyd $NETIFYD_OPTS
ExecReload=/bin/kill -HUP $MAINPID
Restart=on-failure
RestartSec=3

[Install]
WantedBy=multi-user.target

SysVinit

Modify Netify's default init script in /etc/init.d/netifyd.

#!/bin/sh /etc/rc.common
#
# Copyright (C) 2016-2024 eGloo Incorporated
#
# This is free software, licensed under the GNU General Public License v2.

START=99
STOP=1

USE_PROCD=1
PROG=/usr/sbin/netifyd
NETIFYD_USER="netify"


function append_params() {
	procd_append_param command $@
}

check_setcap() {
    if ! getcap "$PROG" | grep -q "cap_net_admin"; then
        echo "Applying cap_net_admin to $PROG..."
        setcap cap_net_admin=eip "$PROG"
        if [ $? -ne 0 ]; then
            echo "Failed to set capabilities. Are you root?"
            exit 1
        fi
    fi
}

function append_ifopts() {
	local filter=0
	local filter_expr=

	for a in $1; do
		case $a in
		-F|--device-filter)
			filter=1
			procd_append_param command $a
			;;
		-*)
			if [ $filter -gt 0 ]; then
				procd_append_param command "${filter_expr#\ }"
				filter=0; filter_expr=
			fi
			procd_append_param command $a
			;;
		*)
			if [ $filter -gt 0 ]; then
				a=${a#\"}; a=${a%\"}; a=${a#\'}; a=${a%\'}
				filter_expr="$filter_expr $a"
			else
				procd_append_param command $a
			fi
		esac
	done

	if [ $filter -gt 0 ]; then
		procd_append_param command "${filter_expr#\ }"
	fi
}

function append_internal_if() {
	append_ifopts "-I $@"
}

function append_external_if() {
	append_ifopts "-E $@"
}

start_netifyd() {
	local autoconfig enabled instance options

	instance="$1"
	config_get_bool enabled "$instance" enabled 0
	[ "$enabled" -eq 0 ] && return 0

	source /usr/share/netifyd/functions.sh
	load_modules

	procd_open_instance
	procd_set_param file /etc/netifyd.conf
	procd_set_param term_timeout 35
	procd_set_param respawn 3600 5 0
	procd_set_param command $PROG -R

	config_list_foreach "$instance" options append_params

	config_get_bool autoconfig "$instance" autoconfig 1

	if [ "$autoconfig" -gt 0 ]; then
		NETIFYD_AUTODETECT=yes
		options="$(auto_detect_options)"
		[ ! -z "$options" ] && procd_append_param command $options
	fi

	config_list_foreach "$instance" internal_if append_internal_if
	config_list_foreach "$instance" external_if append_external_if

	procd_close_instance
}

service_data() {
	$PROG --version
}

start_service() {
    check_setcap

	[ ! -d /var/run/netifyd ] && mkdir -o "$NETIFYD_USER" -g "$NETIFYD_USER" -p /var/run/netifyd

	config_load netifyd
	config_foreach start_netifyd netifyd
}

reload_service() {
	procd_send_signal netifyd
}

Next Steps

Technical Support

Haven't found the answers you're looking for?

Contact Us