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.
Recommended base¶
| 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:
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:
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¶
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.
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