First server in service, first audit
The T330 is running, and so is the firewall; an audit of what exists sets the priorities before adding services.
The Dell T330 is in service under Proxmox VE, with its four disks in ZFS RAIDZ2 and OPNsense in a virtual machine. Before installing a single service, I carried out an audit of what exists: comparing what actually runs with what the documentation said.
What the audit changed
- The architecture adapts to the actual hardware. The mini-PC cluster and the dedicated firewall are not for now: a single server carries everything, and the corresponding ADRs are superseded by ADR 0010 rather than edited, to keep a record of the reasoning.
- One domain, and only mine. Internal names had been created under a domain that does not belong to me.
Harmless today, but exploitable by whoever bought it: everything moved under
maximebertrand.net(ADR 0009). - Names rather than IP addresses. The internal DNS now knows every machine, with DNSSEC validation.
- A list of fixes ranked by priority, to be dealt with before opening anything to the Internet.
Decisions for what comes next
- Personal services (photos, files) will be published without going through Cloudflare, behind the firewall and a WAF (ADR 0008).
- A single directory and an SSO portal with two-factor authentication for every published service (ADR 0011).
- Nextcloud for files, chosen for its compatibility with every device (ADR 0012).
The same evening: the platform as code
The audit’s priority fixes were applied, then five virtual machines were created by OpenTofu, each in its own network zone, and configured by Ansible: WAF, identity (directory + SSO), applications, internal tools and documentation. The firewall rules are generated from the code too, from the flow matrix. Everything is replayable: a second run of the playbooks no longer changes anything.
A few lessons along the way:
- a Proxmox token with “privilege separation” only gets the intersection of the token’s rights and its user’s;
- removing a bridge’s IPv4 address is not enough: its link-local IPv6 address was still reachable;
- an Ansible role that enforces the permissions of a database folder can break the database using it: the owner must be the container’s user, not root.
Next step: public certificates and opening up to the first users.