## ADDED Requirements ### Requirement: Ansible inventory defines server groups The inventory SHALL define a `servers` host group containing all managed servers. Optional groups `snell` and `trojan` MAY be defined for targeted role deployment. The repository SHALL ship `inventory/hosts.yml.example` as a template; the actual `inventory/hosts.yml` SHALL be gitignored and created by the user. #### Scenario: Inventory is valid - **WHEN** the user copies `hosts.yml.example` to `hosts.yml` and fills in their values - **THEN** a `servers` group is available with at least one host - **THEN** optional `snell` and `trojan` groups can be defined #### Scenario: Non-root user with sudo - **WHEN** `ansible_user` is set to a non-root user (e.g., `ubuntu`) - **THEN** Ansible connects as that user and uses `become` for privilege escalation #### Scenario: Root user - **WHEN** `ansible_user` is set to `root` - **THEN** Ansible connects as root directly and `become` is a no-op ### Requirement: Base packages are installed on all servers The base role SHALL install essential packages: `curl`, `wget`, `vim`, `htop`, `unzip`, `ufw`, `fail2ban`, `unattended-upgrades`. #### Scenario: Fresh server provisioning - **WHEN** the base role runs on a fresh Ubuntu/Debian server - **THEN** all listed packages are installed and available ### Requirement: SSH is hardened The base role SHALL configure SSH to disable password authentication, disable root login, and only allow key-based authentication. The SSH port SHALL be configurable per host via `ssh_port`, defaulting to 22. #### Scenario: SSH hardening applied - **WHEN** the base role completes - **THEN** `/etc/ssh/sshd_config` has `PasswordAuthentication no`, `PermitRootLogin no`, and `PubkeyAuthentication yes` - **THEN** the sshd service is restarted #### Scenario: Custom SSH port per host - **WHEN** a host defines `ssh_port: 2222` in inventory - **THEN** sshd listens on port 2222 - **THEN** UFW allows port 2222 instead of 22 - **THEN** fail2ban monitors port 2222 ### Requirement: UFW firewall is configured with default deny The base role SHALL enable UFW with a default deny incoming policy. The base role SHALL allow the SSH port (configurable via `ssh_port`, default 22). #### Scenario: Firewall base rules - **WHEN** the base role completes - **THEN** UFW is active with default deny incoming - **THEN** the SSH port is allowed ### Requirement: fail2ban protects SSH The base role SHALL configure fail2ban to monitor SSH login attempts and ban IPs after repeated failures. #### Scenario: fail2ban is active - **WHEN** the base role completes - **THEN** fail2ban is running with an SSH jail enabled ### Requirement: Automatic security updates are enabled The base role SHALL enable `unattended-upgrades` for security patches. #### Scenario: Unattended upgrades configured - **WHEN** the base role completes - **THEN** unattended-upgrades is configured to auto-install security updates