Add Systemd Setup page
373
Systemd-Setup.md
Normal file
373
Systemd-Setup.md
Normal file
@@ -0,0 +1,373 @@
|
||||
# Systemd Setup
|
||||
|
||||
End-to-end walkthrough: take DECNET from a fresh clone to a set of
|
||||
systemd-managed services running as a non-root user with the minimum
|
||||
Linux capabilities needed to manage MACVLAN interfaces.
|
||||
|
||||
See also: [Environment variables](Environment-Variables),
|
||||
[DB drivers](Database-Drivers), [CLI reference](CLI-Reference).
|
||||
|
||||
## 1. Prerequisites
|
||||
|
||||
- Linux host (bare metal or VM). WSL is not supported for the network
|
||||
path.
|
||||
- Docker Engine and the Docker Compose plugin.
|
||||
- Python 3.11, 3.12 or 3.13.
|
||||
- `sudo` / root access (needed once for `decnet deploy` to create
|
||||
MACVLAN links, and to install unit files).
|
||||
- A NIC placed in promiscuous mode if you plan to run the sniffer on
|
||||
the host interface.
|
||||
- A dedicated UNIX user and group named `decnet` (the unit files run
|
||||
as that user):
|
||||
|
||||
```bash
|
||||
sudo useradd --system --create-home --shell /usr/sbin/nologin decnet
|
||||
sudo usermod -aG docker decnet
|
||||
```
|
||||
|
||||
## 2. Clone and install
|
||||
|
||||
Install into a virtualenv owned by the `decnet` user so the service
|
||||
files can point at `.venv/bin/decnet`.
|
||||
|
||||
```bash
|
||||
sudo -u decnet -H bash <<'EOF'
|
||||
cd /opt
|
||||
git clone https://git.resacachile.cl/anti/DECNET.git
|
||||
cd DECNET
|
||||
python3 -m venv .venv
|
||||
.venv/bin/pip install --upgrade pip
|
||||
.venv/bin/pip install -e .
|
||||
EOF
|
||||
```
|
||||
|
||||
After this, the CLI is available at `/opt/DECNET/.venv/bin/decnet`.
|
||||
|
||||
## 3. Configure the environment
|
||||
|
||||
DECNET loads configuration from a `.env` file in the working
|
||||
directory. Create `.env.local` with real values and symlink (or
|
||||
rename) it to `.env`, or point `EnvironmentFile=` at whichever file
|
||||
you use.
|
||||
|
||||
```bash
|
||||
sudo -u decnet cp /opt/DECNET/env.config.example /opt/DECNET/.env
|
||||
sudo -u decnet editor /opt/DECNET/.env
|
||||
```
|
||||
|
||||
See [Environment variables](Environment-Variables) for the full list.
|
||||
The services expect at least:
|
||||
|
||||
- `DECNET_DB_URL` (or the SQLite default) - see [DB drivers](Database-Drivers)
|
||||
- `DECNET_SYSTEM_LOGS` - path to the rotating system log file
|
||||
- API / Web bind hosts and ports if you are overriding the defaults
|
||||
|
||||
## 4. Deploy honeypots once
|
||||
|
||||
`decnet deploy` provisions the MACVLAN network and the decky
|
||||
containers. Run it once, as root, before enabling the long-lived
|
||||
services:
|
||||
|
||||
```bash
|
||||
sudo /opt/DECNET/.venv/bin/decnet deploy \
|
||||
--mode unihost \
|
||||
--deckies 5 \
|
||||
--interface eth0 \
|
||||
--randomize-services
|
||||
```
|
||||
|
||||
Confirm with:
|
||||
|
||||
```bash
|
||||
/opt/DECNET/.venv/bin/decnet status
|
||||
```
|
||||
|
||||
Deploy only needs root for the MACVLAN setup; the long-running API /
|
||||
web / microservice units run unprivileged with the capabilities
|
||||
listed below.
|
||||
|
||||
## 5. Install the bundled unit files
|
||||
|
||||
Two unit files ship in `deploy/`:
|
||||
|
||||
### `/etc/systemd/system/decnet-api.service`
|
||||
|
||||
```ini
|
||||
[Unit]
|
||||
Description=DECNET API Service
|
||||
After=network.target docker.service
|
||||
Requires=docker.service
|
||||
|
||||
[Service]
|
||||
Type=simple
|
||||
User=decnet
|
||||
Group=decnet
|
||||
WorkingDirectory=/opt/DECNET
|
||||
EnvironmentFile=/opt/DECNET/.env
|
||||
ExecStart=/opt/DECNET/.venv/bin/decnet api
|
||||
|
||||
CapabilityBoundingSet=CAP_NET_ADMIN CAP_NET_RAW
|
||||
AmbientCapabilities=CAP_NET_ADMIN CAP_NET_RAW
|
||||
|
||||
NoNewPrivileges=yes
|
||||
ProtectSystem=full
|
||||
ProtectHome=read-only
|
||||
|
||||
Restart=on-failure
|
||||
RestartSec=5
|
||||
|
||||
[Install]
|
||||
WantedBy=multi-user.target
|
||||
```
|
||||
|
||||
### `/etc/systemd/system/decnet-web.service`
|
||||
|
||||
```ini
|
||||
[Unit]
|
||||
Description=DECNET Web Dashboard Service
|
||||
After=network.target decnet-api.service
|
||||
|
||||
[Service]
|
||||
Type=simple
|
||||
User=decnet
|
||||
Group=decnet
|
||||
WorkingDirectory=/opt/DECNET
|
||||
EnvironmentFile=/opt/DECNET/.env
|
||||
ExecStart=/opt/DECNET/.venv/bin/decnet web
|
||||
|
||||
# Uncomment to bind to a privileged port (80/443) as non-root.
|
||||
# CapabilityBoundingSet=CAP_NET_BIND_SERVICE
|
||||
# AmbientCapabilities=CAP_NET_BIND_SERVICE
|
||||
|
||||
NoNewPrivileges=yes
|
||||
ProtectSystem=full
|
||||
ProtectHome=read-only
|
||||
|
||||
Restart=on-failure
|
||||
RestartSec=5
|
||||
|
||||
[Install]
|
||||
WantedBy=multi-user.target
|
||||
```
|
||||
|
||||
### Directive reference
|
||||
|
||||
- `User`, `Group` - run as the unprivileged `decnet` account.
|
||||
- `WorkingDirectory` - sets `$PWD`; DECNET resolves relative paths
|
||||
(log files, sqlite URLs) from here.
|
||||
- `EnvironmentFile` - loads `.env` the same way the CLI does when run
|
||||
interactively.
|
||||
- `ExecStart` - the venv's `decnet` entrypoint; no daemon flag is
|
||||
needed because systemd already runs the process in the background
|
||||
and handles restarts.
|
||||
- `Restart=on-failure`, `RestartSec=5` - systemd restarts crashes
|
||||
after five seconds; successful exits are not restarted.
|
||||
- `CapabilityBoundingSet` / `AmbientCapabilities` - hand the process
|
||||
`CAP_NET_ADMIN` (netlink, MACVLAN/IPVLAN) and `CAP_NET_RAW` (packet
|
||||
capture, ARP) without making it root. `CAP_NET_BIND_SERVICE` is
|
||||
only needed if a service binds a port below 1024.
|
||||
- `NoNewPrivileges=yes` - blocks setuid escalation inside the
|
||||
process tree.
|
||||
- `ProtectSystem=full` - `/usr`, `/boot`, `/etc` become read-only for
|
||||
the unit.
|
||||
- `ProtectHome=read-only` - `/home` and `/root` become read-only.
|
||||
- `After=` / `Requires=` - API needs Docker; Web starts after API.
|
||||
|
||||
Copy them into place and fix the paths:
|
||||
|
||||
```bash
|
||||
sudo install -m 644 /opt/DECNET/deploy/decnet-api.service /etc/systemd/system/
|
||||
sudo install -m 644 /opt/DECNET/deploy/decnet-web.service /etc/systemd/system/
|
||||
sudo sed -i 's|/path/to/DECNET|/opt/DECNET|g' \
|
||||
/etc/systemd/system/decnet-api.service \
|
||||
/etc/systemd/system/decnet-web.service
|
||||
```
|
||||
|
||||
## 6. Optional per-microservice units
|
||||
|
||||
The CLI already supports detached mode for several subcommands
|
||||
(`decnet profiler --daemon`, `decnet sniffer --daemon`,
|
||||
`decnet collect --daemon`, `decnet mutate --daemon`, `decnet probe
|
||||
--daemon`, `decnet correlate --daemon`). Under systemd you should
|
||||
**omit** `--daemon`: systemd is the supervisor, and double-forking
|
||||
breaks its child tracking. Set `Type=simple` and let the foreground
|
||||
process run.
|
||||
|
||||
All microservice units should order after the API. Use `Wants=`
|
||||
unless the microservice cannot function at all without the API
|
||||
(persistence-heavy units such as `collect` and `correlate`), in which
|
||||
case use `Requires=`.
|
||||
|
||||
### `/etc/systemd/system/decnet-profiler.service`
|
||||
|
||||
Wants the API - it enriches sessions but can start independently.
|
||||
|
||||
```ini
|
||||
[Unit]
|
||||
Description=DECNET Profiler
|
||||
After=network.target decnet-api.service
|
||||
Wants=decnet-api.service
|
||||
|
||||
[Service]
|
||||
Type=simple
|
||||
User=decnet
|
||||
Group=decnet
|
||||
WorkingDirectory=/opt/DECNET
|
||||
EnvironmentFile=/opt/DECNET/.env
|
||||
ExecStart=/opt/DECNET/.venv/bin/decnet profiler
|
||||
|
||||
NoNewPrivileges=yes
|
||||
ProtectSystem=full
|
||||
ProtectHome=read-only
|
||||
|
||||
Restart=on-failure
|
||||
RestartSec=5
|
||||
|
||||
[Install]
|
||||
WantedBy=multi-user.target
|
||||
```
|
||||
|
||||
Required env: `DECNET_DB_URL`, `DECNET_SYSTEM_LOGS`.
|
||||
|
||||
### `/etc/systemd/system/decnet-sniffer.service`
|
||||
|
||||
Needs `CAP_NET_RAW` plus `CAP_NET_ADMIN` to attach to the decoy
|
||||
interface. Wants the API.
|
||||
|
||||
```ini
|
||||
[Unit]
|
||||
Description=DECNET Sniffer
|
||||
After=network.target decnet-api.service
|
||||
Wants=decnet-api.service
|
||||
|
||||
[Service]
|
||||
Type=simple
|
||||
User=decnet
|
||||
Group=decnet
|
||||
WorkingDirectory=/opt/DECNET
|
||||
EnvironmentFile=/opt/DECNET/.env
|
||||
ExecStart=/opt/DECNET/.venv/bin/decnet sniffer
|
||||
|
||||
CapabilityBoundingSet=CAP_NET_ADMIN CAP_NET_RAW
|
||||
AmbientCapabilities=CAP_NET_ADMIN CAP_NET_RAW
|
||||
|
||||
NoNewPrivileges=yes
|
||||
ProtectSystem=full
|
||||
ProtectHome=read-only
|
||||
|
||||
Restart=on-failure
|
||||
RestartSec=5
|
||||
|
||||
[Install]
|
||||
WantedBy=multi-user.target
|
||||
```
|
||||
|
||||
Required env: `DECNET_SNIFFER_IFACE` (or the auto-probed interface),
|
||||
`DECNET_SYSTEM_LOGS`.
|
||||
|
||||
### `/etc/systemd/system/decnet-collect.service`
|
||||
|
||||
Writes into the shared database - `Requires=` the API so schema and
|
||||
migrations are in place first.
|
||||
|
||||
```ini
|
||||
[Unit]
|
||||
Description=DECNET Collector
|
||||
After=network.target decnet-api.service
|
||||
Requires=decnet-api.service
|
||||
|
||||
[Service]
|
||||
Type=simple
|
||||
User=decnet
|
||||
Group=decnet
|
||||
WorkingDirectory=/opt/DECNET
|
||||
EnvironmentFile=/opt/DECNET/.env
|
||||
ExecStart=/opt/DECNET/.venv/bin/decnet collect
|
||||
|
||||
NoNewPrivileges=yes
|
||||
ProtectSystem=full
|
||||
ProtectHome=read-only
|
||||
|
||||
Restart=on-failure
|
||||
RestartSec=5
|
||||
|
||||
[Install]
|
||||
WantedBy=multi-user.target
|
||||
```
|
||||
|
||||
Required env: `DECNET_DB_URL`, `DECNET_SYSTEM_LOGS`, and any input
|
||||
source variables documented in [Environment variables](Environment-Variables).
|
||||
|
||||
### `/etc/systemd/system/decnet-mutate.service`
|
||||
|
||||
Stateless helper that rewrites decky personas; Wants the API.
|
||||
|
||||
```ini
|
||||
[Unit]
|
||||
Description=DECNET Mutator
|
||||
After=network.target decnet-api.service
|
||||
Wants=decnet-api.service
|
||||
|
||||
[Service]
|
||||
Type=simple
|
||||
User=decnet
|
||||
Group=decnet
|
||||
WorkingDirectory=/opt/DECNET
|
||||
EnvironmentFile=/opt/DECNET/.env
|
||||
ExecStart=/opt/DECNET/.venv/bin/decnet mutate --watch
|
||||
|
||||
NoNewPrivileges=yes
|
||||
ProtectSystem=full
|
||||
ProtectHome=read-only
|
||||
|
||||
Restart=on-failure
|
||||
RestartSec=5
|
||||
|
||||
[Install]
|
||||
WantedBy=multi-user.target
|
||||
```
|
||||
|
||||
Required env: `DECNET_SYSTEM_LOGS` plus any per-service override
|
||||
files referenced by the mutator.
|
||||
|
||||
## 7. Enable and start
|
||||
|
||||
```bash
|
||||
sudo systemctl daemon-reload
|
||||
sudo systemctl enable --now \
|
||||
decnet-api.service \
|
||||
decnet-web.service \
|
||||
decnet-profiler.service \
|
||||
decnet-sniffer.service \
|
||||
decnet-collect.service \
|
||||
decnet-mutate.service
|
||||
```
|
||||
|
||||
Check status and tail logs:
|
||||
|
||||
```bash
|
||||
systemctl status decnet-api
|
||||
journalctl -u decnet-api -f
|
||||
journalctl -u decnet-web -f
|
||||
```
|
||||
|
||||
## 8. Log locations
|
||||
|
||||
DECNET writes logs in two places:
|
||||
|
||||
- **journald**, via stdout/stderr from each unit. Query with
|
||||
`journalctl -u decnet-<name>`.
|
||||
- **`$DECNET_SYSTEM_LOGS`**, a rotating file handler
|
||||
(`InodeAwareRotatingFileHandler`) that survives external log
|
||||
rotation. The default is `decnet.system.log` in the unit's
|
||||
`WorkingDirectory` (so `/opt/DECNET/decnet.system.log` with the
|
||||
layout above). Point it at `/var/log/decnet/system.log` for
|
||||
multi-service deployments and make sure the `decnet` user owns the
|
||||
target directory:
|
||||
|
||||
```bash
|
||||
sudo install -d -o decnet -g decnet /var/log/decnet
|
||||
```
|
||||
|
||||
Then set `DECNET_SYSTEM_LOGS=/var/log/decnet/system.log` in `.env`
|
||||
and restart the units.
|
||||
Reference in New Issue
Block a user