Skip to content

Hardening the collector VM

The collector sits in the customer network and holds the credentials of the devices it checks. If a VM runs only the collector, it can be locked down much further than an ordinary server. A script does that: it first shows every step with its reason and only changes something after you confirm. Every change is logged and can be undone with one command.

Only for collector-only VMs

The script stops if Docker or an Active Collector runs on the machine — that is the Vesana server itself. Other services on the VM (for example a syslog receiver) are fine: whatever is reachable from outside when you harden stays reachable.

Language

The script currently prints its plan and messages in German. Options and module names are the same in both languages.

Recommendation
Operating system Debian 13 or Ubuntu 26.04 LTS (24.04 LTS is supported too)
Installation Minimal: SSH server only, no desktop or server task packages
Size 2 vCPU, 2 GB RAM, 20 GB disk
Network Reaches the devices it checks; outbound HTTPS to the Vesana server
Access An admin account with sudo and an SSH key

SSH login with a password stays allowed by default. Key-only is safer — the script asks, but only turns passwords off if a key is on file for you. It never locks anybody out.

Four steps

1. Set up the VM, create the admin account with an SSH key, install updates.

2. Install the collector as described under Collector. To also protect the VM against a compromised Vesana server, install with Agent Lock (VESANA_LOCK=1) — the strongest protection, and not part of this script because it requires approvals on the host.

3. Harden — download the script from your Vesana server and run it:

curl -fsSLo harden.sh https://your-domain.tld/collector/harden.sh && sudo bash harden.sh

First the script asks at most three questions (in German). Enter keeps the default:

Question Input Default
SSH-Anmeldung mit Passwort erlauben? (allow SSH login with a password?) j or n yes (only asked if a key is on file for you)
SSH nur aus bestimmten Netzen erlauben? (SSH only from certain networks?) e.g. 192.168.1.0/24,10.0.0.5 or alle (all) all
root-Passwort sperren? (lock the root password?) j or n yes (only asked if a sudo account with a key exists)

Everything else has a safe default and can be changed with an option if needed (see Options).

Then it shows the full plan and asks Jetzt anwenden? [j/N] (apply now?). After loading the firewall it asks you to open a second SSH session. If the login works, confirm with ok. Without confirmation the VM removes the firewall again after 180 seconds on its own — even if your session drops.

Just look, change nothing: sudo bash harden.sh --plan. The firewall rules verbatim: sudo bash harden.sh --show-firewall.

4. Check — Vesana keeps showing the collector as online, and on the VM:

sudo vesana-haertung --check

This checks the hardening, whether the collector runs, whether it reaches the server and whether its log shows errors. If something is wrong, the command exits with code 1 — so it also fits into your own monitoring or automation.

What the script does

Module What Deliberately not
updates Updates for the installed release daily and automatically (unattended-upgrades). No release upgrade. No automatic reboot unless --auto-reboot 03:30.
ssh Password login as chosen (default: stays; off only if a key is on file for you), root login off or key-only, 30 s login grace, no X11. Never loosens what is already stricter. Port forwarding stays (collector as jump host, ssh -J). MaxAuthTries stays at the default. Ciphers stay unchanged.
firewall Inbound only: replies to own connections, SSH, ping, DHCP, mDNS/SSDP/LLMNR replies (discovery) and every service listening from outside when you harden. Outbound is not filtered — the collector has to reach every device on every port.
sysctl Tighter kernel parameters: kernel info for root only, no unprivileged BPF/user namespaces/io_uring, no ICMP redirects and no source routing. Only tightened, never loosened. ping_group_range stays (the collector pings through it without extra privileges), ip_forward stays, no strict reverse-path filter (would break VMs with several NICs/VLANs).
kernelmodule cramfs, freevxfs, hfs, hfsplus, jffs2, dccp, sctp, rds, tipc can no longer be loaded. USB storage, udf, squashfs stay (cloud-init media, snaps).
dienste (services) Stops avahi, cups, rpcbind if running (not rpcbind while NFS is mounted). systemd-resolved no longer answers LLMNR on the network. The VM still resolves names without a domain via LLMNR.
konten (accounts) Locks the root password — only if the script runs via sudo from an account with an SSH key; can be declined. No accounts created or removed.
protokoll (logging) Persistent journal; auditd records changes to the Vesana configuration and binary, Agent Lock approvals, SSH configuration, sudo and users. No recording of every command.
coredumps Core dumps off — a dump of the collector would contain decrypted credentials.
zeit (time) Makes sure the clock is synchronised (TLS and measurement times depend on it). Time servers stay.
shm /dev/shm without exec permission. /tmp stays executable — the collector installer test-runs the downloaded binary there; with noexec every reinstall and installer-based update would fail.

The collector service itself is already restricted by the installer (own user without login, read-only system, only the network capabilities it needs, signed updates). The script changes nothing about the collector installation.

Is the VM itself monitored?

This is where hardening most easily breaks something.

How is the VM checked? What to do
Ping nothing — ping stays allowed.
SSH with a key (e.g. by the Active Collector) nothing.
SSH with a password nothing, as long as password login stays allowed (default). If you turn it off, exempt the checking server with --password-from <IP> — otherwise the check fails with "credentials rejected".
SNMP (snmpd on the VM) nothing if snmpd is running when you harden — it stays reachable. Otherwise --allow udp/161.
Vesana agent on the VM nothing — the agent only opens outbound connections.

The same applies to services that receive data on the VM, such as a syslog receiver for switches or a NAS: if it runs when you harden, its port stays open. If it comes later: --allow udp/514.

Green only means green after a new connection

The collector keeps SSH connections open and reuses them. An SSH check that was connected before hardening therefore stays green until the connection is rebuilt. To be sure, restart the checking collector after hardening (sudo systemctl restart vesana-collector) and look at the checks afterwards.

Options

Option Effect
--plan Show only, change nothing.
--yes Apply without questions (automation) — defaults, the last run and options apply. Without a terminal there is no 180 s window — SSH stays reachable according to the --ssh-from rules.
--ssh-from 10.0.0.0/8,192.168.1.0/24 SSH only from these networks. The script stops if your current connection is not inside them. Back to "from anywhere": --ssh-from all.
--no-keep-password-login SSH with a key only (back: --keep-password-login).
--password-from 10.1.2.3/32 With passwords off: still allow them from there. Remove: --password-from none.
--allow udp/514,tcp/6556 Additionally allow inbound. Remove: --allow none.
--no-keep-listening Do NOT keep listening services open automatically (back: --keep-listening).
--keep-root-password Do not lock the root password (back: --lock-root-password).
--auto-reboot 03:30 Reboot at this time after security updates that need it (off: --auto-reboot none).
--skip firewall,konten Skip modules for this run (--modules lists all).
--show-firewall Show the firewall rules that would be loaded.

You can run the script as often as you like, and a new run never loosens anything silently: options of an earlier run stay in effect (the plan says "aus dem letzten Lauf übernommen" — taken over from the last run) until you change them explicitly. Opening a port later is therefore just sudo vesana-haertung --allow udp/514 — all other settings stay.

Undo

sudo vesana-haertung --undo

Restores every backed-up original file, removes the script's own files and the firewall, starts stopped services again, unlocks the root password and resets the kernel parameters to their previous values. Installed packages (unattended-upgrades, nftables, auditd) stay installed, just without the script's settings. kernel.kexec_load_disabled cannot be reverted at runtime and stays in effect until the next reboot.

What the script did is in /var/log/vesana-haertung.log; the originals are in /var/lib/vesana-haertung/backup/.

Troubleshooting

A device can no longer reach the VM (e.g. syslog does not arrive): the firewall logs dropped packets, rate-limited, in the kernel log.

sudo journalctl -k | grep vesana-haertung

If sender and port show up there, sudo vesana-haertung --allow udp/514 opens the port (the run shows the plan first; earlier settings stay). LAN broadcasts (e.g. NetBIOS from Windows machines) are dropped without filling the log.

A check shows an error after hardening: the firewall only filters inbound — checks the collector opens itself are not affected. If the check's target is the VM itself, see Is the VM itself monitored?.

The firewall was skipped: if another firewall already runs (ufw, firewalld or your own nftables rules for inbound traffic), the script does not load a second one — two firewalls side by side drop each other's packets. Allow SSH, ping, DHCP, udp/1900 + 5353 + 5355 and your own services in the existing firewall instead.

What else makes sense

Not part of the script, because it lies outside the VM or needs decisions:

  • Agent Lock — the collector only runs scripts approved on the host; a compromised Vesana server cannot run anything new on the VM.
  • Its own network segment for the VM with a firewall in front that only allows the paths the collector needs.
  • Protect access to the hypervisor console — it bypasses every login on the VM.
  • A backup of the VM before larger changes (snapshot).

See also

  • Collector — installation and operation
  • Agent Lock — scripts only after approval on the host
  • Agent gateway — connect agents and collectors through a dedicated port