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
}