I ended up finding a use case for removing the network from something. It goes like this:
I have a virtual machine (guest) set up with nodejs and npm installed, along with @redocly/cli
for generating some documentation from an OpenAPI specification. This machine has two NICs, one in the default NAT configuration, and one attached to a host-only network with a static IP. The files I want to build are shared via NFS on the host-only network, and I connect over the host-only network to issue the build command.
Meaning, there is no loss of functionality to remove the default NIC (the one configured for NAT), but it does cut npm off from the internet. That’s an immediate UX improvement: npm can no longer complain that it is out of date! Furthermore, if the software I installed happened to be compromised and running a Bitcoin miner, it has been cut off from its c2 server, and can’t make anyone money.
An interesting side benefit is that it also cuts off everyone’s telemetry, impassively.
I can’t update the OS packages, but I’m not sure that is an actual problem. If the code installed doesn’t have an exploit payload already, there’s no way to get one later. The vulnerability remains, but nothing is there to go after it.
Level Up
(Updated 2024-12-19: this section was a P.S. hypothetical on the original post. Later sections are added.)
It is actually possible to deactivate both NICs. The network was used for only two things: logging in to run commands, and to (re)use the NFS share to get the files.
Getting the files is easy: they can be shared using the hypervisor’s shared-folders system. Logging in to run commands can be done on the hypervisor’s graphical console. As a bonus, if the machine has a snapshot when starting, it can be shut down by closing the hypervisor’s window and reverting to snapshot.
Now, we really have a network-less (and stateless) appliance.
Reconfigure
Before I made that first snapshot, I configured the console to boot with the Dvorak layout, because the default of Qwerty is pretty much why I use SSH when available for virtual machines. But then, after a while, I got tired of being told that the list of packages was more than a week old, so I set out to de-configure some other things.
I cleared out things that would just waste energy on a system that would revert to snapshot: services like rsyslog, cron, and logrotate. Then I trawled through systemctl list-units --all
and cleared a number of timers, such as ones associated with “ua”, apt, dpkg, man-db, and update-notifier. Any work these tasks do will simply be thrown away every time.
I took the pam_motd
modules out of /etc/pam.d/login
, too. If Canonical doesn't want me to clear out the dynamic motd entirely, the next best thing is to completely ignore it.
After a reboot, I went through systemd-analyze critical-chain
and its friend, systemd-analyze blame
, and turned off more things, like ufw and apport.
With all that out of the way, I rebooted and checked how much memory my actual task consumed; it was apparently a hundred megabytes, so I pared the machine’s memory allocation down from 2,048 MiB to 512 MiB. The guest runs with neither swap nor earlyoom, so I didn’t want to push it much farther, but 384 MiB is theoretically possible.
NFS
A small, tiny note: besides cutting off the Internet as a whole, sharing files from the hypervisor instead of NFS adds another small bit of security. The NFS export is a few directories up, and the host has no_subtree_check
to improve performance on the other guest that the mount is actually meant for.
Super theoretically, if the guest turned evil, it could possibly look around the entire host filesystem, or at least the entire export. When using the hypervisor’s file sharing, only the intended directory is accessible to the guest kernel.