Files
DECNET/deploy/decnet-swarmctl.service
anti f5a5fec607 feat(deploy): systemd units w/ capability-based hardening; updater restarts agent via systemctl
Add deploy/ unit files for every DECNET daemon (agent, updater, api, web,
swarmctl, listener, forwarder). All run as User=decnet with NoNewPrivileges,
ProtectSystem, PrivateTmp, LockPersonality; AmbientCapabilities=CAP_NET_ADMIN
CAP_NET_RAW only on the agent (MACVLAN/scapy). Existing api/web units migrated
to /opt/decnet layout and the same hardening stanza.

Make the updater's _spawn_agent systemd-aware: under systemd (detected via
INVOCATION_ID + systemctl on PATH), `systemctl restart decnet-agent.service`
replaces the Popen path so the new agent inherits the unit's ambient caps
instead of the updater's empty set. _stop_agent becomes a no-op in that mode
to avoid racing systemctl's own stop phase.

Tests cover the dispatcher branch selection, MainPID parsing, and the
systemd no-op stop.
2026-04-19 00:44:06 -04:00

41 lines
1.1 KiB
Desktop File

[Unit]
Description=DECNET Swarm Controller (master)
Documentation=https://github.com/4nt11/DECNET/wiki/SWARM-Mode
After=network-online.target decnet-api.service
Wants=network-online.target
[Service]
Type=simple
User=decnet
Group=decnet
WorkingDirectory=/opt/decnet
EnvironmentFile=-/opt/decnet/.env.local
# Default bind is loopback — the controller is a master-local orchestrator
# reached by the CLI and the web dashboard, not by workers.
ExecStart=/opt/decnet/venv/bin/decnet swarmctl --host 127.0.0.1 --port 8770
# No special capabilities — the controller issues mTLS certs and talks to
# workers over TCP on unprivileged ports.
CapabilityBoundingSet=
AmbientCapabilities=
# Security Hardening
NoNewPrivileges=yes
ProtectSystem=full
ProtectHome=read-only
PrivateTmp=yes
ProtectKernelTunables=yes
ProtectKernelModules=yes
ProtectControlGroups=yes
RestrictSUIDSGID=yes
LockPersonality=yes
# Reads/writes the CA bundle and the master DB.
ReadWritePaths=/opt/decnet /var/log/decnet
ReadOnlyPaths=/etc/decnet
Restart=on-failure
RestartSec=5
[Install]
WantedBy=multi-user.target