- Merge Infrastructure + Secure + Systems → SNS Networking (Business #1) - Merge Web + Software + Cloud → SNS Digital (planned) - SNS Support unchanged (planned) - Add infra/ folder with 16 FOSS-first buildable designs - Update all agent knowledge, division briefs, legal structure - Restructure businesses/ from 7 to 3 operating folders
3.7 KiB
3.7 KiB
Host Hardening Baseline — SNS Networking
Entity: SNS Networking · Status: Buildable now (Ansible playbook)
What it is
The minimum security posture applied to every Linux host — on-prem VM, LXC, or cloud VPS — before it does anything else. This is the Ansible "base" role that runs first on every new machine.
Stack
| Component | Software | FOSS | Role |
|---|---|---|---|
| Firewall | UFW (iptables frontend) | Yes | Default-deny inbound, explicit allow |
| Brute-force protection | Fail2ban | Yes | SSH + web login jail |
| SSH hardening | OpenSSH (config only) | Yes | Key-only, no root, no password |
| Auto-updates | unattended-upgrades (Debian) | Yes | Security patches only |
| Audit logging | auditd | Yes | File access, privilege escalation events |
| Rootkit detection | rkhunter | Yes | Weekly scan, email on findings |
The Playbook (what it does)
# roles/base-hardening/tasks/main.yml (conceptual)
- name: SSH hardening
# PermitRootLogin no
# PasswordAuthentication no
# PubkeyAuthentication yes
# MaxAuthTries 3
# AllowUsers sam
- name: UFW default deny
# Default incoming: deny
# Default outgoing: allow
# Allow: SSH (22/tcp) from Tailscale/WireGuard subnet only
- name: Fail2ban SSH jail
# maxretry: 3
# bantime: 3600
# findtime: 600
- name: Unattended upgrades (security only)
# Automatic-Reboot: false (manual kernel reboots)
- name: Auditd rules
# Watch /etc/passwd, /etc/shadow, /etc/sudoers
# Log all sudo usage
# Log failed file access attempts
- name: Disable unused services
# Stop & mask: cups, avahi-daemon, bluetooth (if present)
- name: Sysctl hardening
# net.ipv4.conf.all.rp_filter = 1
# net.ipv4.icmp_echo_ignore_broadcasts = 1
# net.ipv4.conf.all.accept_redirects = 0
# net.ipv4.conf.all.send_redirects = 0
# kernel.randomize_va_space = 2
Per-Host Firewall Rules
| Host type | Inbound allowed | Notes |
|---|---|---|
| All hosts | SSH from 10.10.0.0/24 (WireGuard) | Management only over VPN |
| Web-facing (Caddy) | 80, 443 from 0.0.0.0/0 | Public web traffic |
| Bastion (Linode) | 22, 51820/udp from 0.0.0.0/0 | SSH + WireGuard |
| Internal services | App port from service VLAN only | No direct internet access |
| Proxmox host | 8006 from Tailscale only | Web UI never on public IP |
Build Steps
- Write Ansible role
roles/base-hardening/with the above tasks. - Add to
site.ymlas the first role for all host groups. - Run against all existing hosts:
ansible-playbook site.yml --tags hardening - Verify:
ssh root@hostshould fail.ssh sam@hostwith key should work. - Verify:
nmap -sS hostfrom outside WireGuard should show only allowed ports.
Security Posture
- Default deny. Nothing gets in unless explicitly allowed.
- No passwords anywhere. SSH key-only. Service accounts use tokens or certs.
- Audit trail. Every sudo, every sensitive file access logged.
- Automatic patching. Security updates apply daily without manual intervention. Kernel updates require manual reboot (scheduled maintenance window).
Upgrade Path
- CIS Benchmark compliance: Run
cis-catscanner and close gaps for client environments that require formal compliance. - OSSEC/Wazuh: When you need centralized security event management across 10+ hosts.
- SELinux/AppArmor: Enforce MAC policies on high-value services (currently not enabled — adds complexity without proportional gain at this scale).