This Ansible playbook hardens security settings for Ubuntu Server 24 systems running a k3s cluster.
- Firewall Configuration (UFW): Configures firewall rules for SSH and k3s required ports
- SSH Hardening: Disables root login, password authentication, and configures secure SSH settings
- Fail2ban: Protects against brute-force attacks
- Automatic Security Updates: Configures unattended-upgrades for automatic security patches
- System Hardening: Network security settings, file permissions, and password policies
- k3s Port Configuration: Pre-configured firewall rules for k3s master and worker communication
- Ansible installed on your control machine (Ansible 2.9+)
- SSH access to both servers (master and worker)
- Sudo/root privileges on target servers
- Python 3 installed on target servers
- Sudo access: Either passwordless sudo configured, or you'll need to provide sudo password when prompted
- Install Ansible (if not already installed):
sudo apt update
sudo apt install ansible -y- Install required Ansible collections:
ansible-galaxy collection install -r collections.yml-
Edit the inventory file (
inventory.ini):- Replace
YOUR_MASTER_IPwith your k3s master server's public IP - Replace
YOUR_WORKER_IPwith your k3s worker server's public IP - Update
ansible_userif you're not using root (though root is recommended for initial setup)
- Replace
-
Configure SSH access:
- Ensure you can SSH into both servers without password prompts
- Or set up SSH keys:
ssh-copy-id admin@YOUR_MASTER_IPandssh-copy-id admin@YOUR_WORKER_IP
-
Configure sudo access (recommended for automation):
- Option A (Recommended): Set up passwordless sudo on target servers:
# On each target server, run: echo "admin ALL=(ALL) NOPASSWD: ALL" | sudo tee /etc/sudoers.d/admin
- Option B: Use
--ask-become-passflag when running ansible commands (you'll be prompted for sudo password)
- Option A (Recommended): Set up passwordless sudo on target servers:
-
Review playbook variables (in
security-hardening.yml):- Adjust firewall ports if your k3s setup uses different ports
- Modify SSH port if you're using a non-standard port
- Adjust Fail2ban settings if needed
- Disable password authentication for SSH (only key-based auth will work)
- Disable root login via SSH
- Enable UFW firewall (make sure SSH port is accessible!)
- Restart SSH service (you may be disconnected briefly)
Before running, ensure:
- You have SSH key-based authentication set up
- You have an alternative way to access the servers (console access recommended)
- You've tested SSH key access works
# If passwordless sudo is configured:
ansible all -m ping
# If sudo password is required:
ansible all -m ping --ask-become-pass# If passwordless sudo is configured:
ansible-playbook security-hardening.yml
# If sudo password is required:
ansible-playbook security-hardening.yml --ask-become-pass# Only master
ansible-playbook security-hardening.yml --limit k3s_master
# Only workers
ansible-playbook security-hardening.yml --limit k3s_workersansible-playbook security-hardening.yml --check- Default deny incoming, allow outgoing
- Allows SSH (port 22)
- Allows k3s API server (port 6443)
- Allows k3s Kubelet API (port 10250)
- Allows Flannel VXLAN (port 8472 UDP)
- Allows Flannel Wireguard (port 51820 UDP, if used)
- Root login disabled
- Password authentication disabled
- Key-based authentication only
- Max authentication tries: 3
- Connection timeout settings
- Security banner
- SSH brute-force protection
- 1-hour ban time
- 5 max retries in 10 minutes
- Automatic security updates enabled
- Automatic cleanup of old packages
- IP forwarding enabled (required for k3s)
- ICMP redirects disabled
- TCP SYN cookies enabled
- IPv6 security settings
- Restrictive file permissions
- Password policies
- Unnecessary services disabled
After running the playbook:
- Verify SSH access still works with your SSH key
- Check firewall status:
sudo ufw status verbose - Check Fail2ban status:
sudo fail2ban-client status - Verify k3s cluster connectivity between master and worker
- Review logs: Check
/var/log/auth.logfor any issues
- Use console access to the server
- Check SSH configuration:
sudo sshd -T | grep -E "(PermitRootLogin|PasswordAuthentication)" - Temporarily allow password auth if needed
- Check firewall rules:
sudo ufw status numbered - Verify k3s ports are open:
sudo ufw allow 6443/tcp - Check if IP forwarding is enabled:
sysctl net.ipv4.ip_forward
- Check banned IPs:
sudo fail2ban-client status sshd - Unban an IP:
sudo fail2ban-client set sshd unbanip <IP_ADDRESS>
You can customize the playbook by modifying variables at the top of security-hardening.yml:
ssh_port: Change SSH port (remember to update firewall rules)ufw_allowed_ports: Add/remove firewall rulesfail2ban_max_retry: Adjust brute-force protection sensitivityautomatic_reboot: Enable/disable automatic reboots after updates
After running this playbook, consider:
- Regular security audits: Review logs regularly
- Keep systems updated: The playbook enables automatic updates
- Monitor Fail2ban: Check for attack patterns
- Backup configurations: Keep backups of important configs
- Use VPN: Consider setting up a VPN instead of exposing k3s API publicly
- k3s TLS: Ensure k3s is using proper TLS certificates
- Network policies: Configure Kubernetes network policies for pod-level security
This playbook is provided as-is for security hardening purposes.