[Unit] Description=MultiSimAdmin relay agent Documentation=https://gitea.chickliu.fun/Hermes/msa-agent After=network-online.target Wants=network-online.target [Service] Type=simple ExecStart=/opt/msa-agent/msa-agent --config /etc/msa-agent/config.json Restart=always # Backing off on our own is not enough: a relay that is down for an hour should not be hammered by # every node in the fleet the moment it comes back. RestartSec=5 # A freshly installed node has no paired devices, and the daemon refuses to run in that state on # purpose: an agent that could authorise nothing must not sit there looking healthy. But pairing happens # *after* install — the operator runs `--pair` on the node and then pairs the phone — so between those # two moments this unit would restart every five seconds, forever, filling the journal with the same # line. Measured on a real kernel: exit 1, "devices is empty, so no phone could ever be authorised". # # StartLimitIntervalSec/StartLimitBurst make systemd give up instead: ten attempts inside five minutes # and the unit enters `failed`, which is a state an operator can see and act on. The install command # prints the next step precisely so that state is expected rather than surprising. StartLimitIntervalSec=300 StartLimitBurst=10 TimeoutStopSec=20 KillSignal=SIGTERM User=msa-agent Group=msa-agent # The agent needs almost nothing from the host. Everything below is a capability the process never # uses, removed so that a compromise of the agent is not automatically a compromise of the box. NoNewPrivileges=yes PrivateDevices=yes PrivateTmp=yes PrivateUsers=yes ProtectSystem=strict ProtectHome=yes ProtectKernelTunables=yes ProtectKernelModules=yes ProtectClock=yes ProtectControlGroups=yes ProtectHostname=yes ProtectKernelLogs=yes RestrictNamespaces=yes RestrictRealtime=yes RestrictSUIDSGID=yes LockPersonality=yes MemoryDenyWriteExecute=yes RemoveIPC=yes UMask=0077 # Configuration and the audit log are the only writable paths. ReadWritePaths is what keeps # ProtectSystem=strict from making the audit log unwritable. ReadWritePaths=/var/log/msa-agent ConfigurationDirectory=msa-agent LogsDirectory=msa-agent # AF_INET and AF_INET6 only: the agent dials out to the relay and to 127.0.0.1, so it has no reason # to reach a Unix socket, a netlink family or a packet socket. # # No IPAddressDeny / IPAddressAllow pair here, deliberately. It reads like the obvious way to pin the # agent to loopback, and it is wrong: those directives filter both directions, so IPAddressDeny=any # would also cut the outbound connection to the relay the agent exists to maintain. The loopback # invariant is enforced in code by internal/egress, which is testable, rather than by a directive # that silently breaks the only path out. RestrictAddressFamilies=AF_INET AF_INET6 # No capability at all, so the process cannot even ask to bind a privileged port. CapabilityBoundingSet= AmbientCapabilities= SystemCallFilter=@system-service SystemCallErrorNumber=EPERM [Install] WantedBy=multi-user.target