fix: cleanup freebsd and alpine stuff (#105)
Some checks are pending
Deploy (on merge) / Discover hosts (push) Waiting to run
Deploy (on merge) / Deploy → (push) Blocked by required conditions

This commit is contained in:
Rasmus Wejlgaard 2026-05-12 22:43:12 +01:00 committed by GitHub
parent e502a92451
commit d3b516c594
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
12 changed files with 22 additions and 300 deletions

View file

@ -11,7 +11,7 @@
#
# Prerequisites:
# - Target host has SSH access via Tailscale
# - Target host has a base OS installed (Debian/FreeBSD)
# - Target host has a base OS installed (Debian)
# - ansible-galaxy install -r requirements.yml
# ──────────────────────────────────────────────

View file

@ -1,5 +1,5 @@
---
# Update all hosts (apt for Linux, pkg for FreeBSD, apk for Alpine).
# Update all hosts (apt upgrade).
# Usage: ansible-playbook playbooks/update-all.yml
- name: Update Linux hosts (apt)
@ -28,37 +28,3 @@
ansible.builtin.debug:
msg: "WARNING: REBOOT REQUIRED on {{ inventory_hostname }}"
when: reboot_required.stat.exists
- name: Update Alpine hosts (apk)
hosts: alpine
ignore_unreachable: true
tags: [update, alpine]
tasks:
- name: Apk update + upgrade
community.general.apk:
update_cache: true
upgrade: true
register: apk_result
- name: Show upgrade summary
ansible.builtin.debug:
msg: "{{ apk_result.stdout_lines | default(['No output']) }}"
- name: Update FreeBSD hosts (pkg)
hosts: freebsd
ignore_unreachable: true
tags: [update, freebsd]
tasks:
- name: Pkg update
ansible.builtin.command: pkg update -f
register: pkg_update_result
changed_when: "'Updating' in pkg_update_result.stdout"
- name: Pkg upgrade
ansible.builtin.command: pkg upgrade -y
register: pkg_upgrade_result
changed_when: "'upgraded' in pkg_upgrade_result.stdout or 'installed' in pkg_upgrade_result.stdout"
- name: Show upgrade summary
ansible.builtin.debug:
msg: "{{ pkg_upgrade_result.stdout_lines | default(['No output']) }}"

View file

@ -1,24 +0,0 @@
---
# Update FreeBSD hosts only (pkg).
# Usage: ansible-playbook playbooks/update-freebsd.yml
#
# Equivalent to: ansible-playbook playbooks/update-all.yml --tags freebsd
# This is a convenience wrapper for when you only want FreeBSD hosts.
- name: Update FreeBSD hosts (pkg)
hosts: freebsd
ignore_unreachable: true
tasks:
- name: Pkg update
ansible.builtin.command: pkg update -f
register: pkg_update_result
changed_when: "'Updating' in pkg_update_result.stdout"
- name: Pkg upgrade
ansible.builtin.command: pkg upgrade -y
register: pkg_upgrade_result
changed_when: "'upgraded' in pkg_upgrade_result.stdout or 'installed' in pkg_upgrade_result.stdout"
- name: Show upgrade summary
ansible.builtin.debug:
msg: "{{ pkg_upgrade_result.stdout_lines | default(['No output']) }}"

View file

@ -1,9 +1,6 @@
---
# Update Linux hosts only (apt + Alpine apk).
# Update Linux hosts (apt upgrade). Alias for update-all.yml.
# Usage: ansible-playbook playbooks/update-linux.yml
#
# Equivalent to: ansible-playbook playbooks/update-all.yml --tags linux,alpine
# This is a convenience wrapper for when you only want Linux hosts.
- name: Update Linux hosts (apt)
hosts: linux
@ -30,17 +27,3 @@
ansible.builtin.debug:
msg: "WARNING: REBOOT REQUIRED on {{ inventory_hostname }}"
when: reboot_required.stat.exists
- name: Update Alpine hosts (apk)
hosts: alpine
ignore_unreachable: true
tasks:
- name: Apk update + upgrade
community.general.apk:
update_cache: true
upgrade: true
register: apk_result
- name: Show upgrade summary
ansible.builtin.debug:
msg: "{{ apk_result.stdout_lines | default(['No output']) }}"

View file

@ -6,9 +6,8 @@
ansible.builtin.apt:
update_cache: true
cache_valid_time: 3600
when: ansible_facts["os_family"] == "Debian"
- name: Install baseline packages (Debian)
- name: Install baseline packages
ansible.builtin.apt:
name:
- curl
@ -24,44 +23,6 @@
- fail2ban
- ufw
state: present
when: ansible_facts["os_family"] == "Debian"
- name: Install baseline packages (Alpine)
community.general.apk:
name:
- curl
- wget
- git
- htop
- tmux
- vim
- jq
- fish
- rsync
- shadow
- py3-requests
state: present
when: ansible_facts["os_family"] == "Alpine"
- name: Install baseline packages (FreeBSD)
community.general.pkgng:
name:
- curl
- wget
- git
- htop
- tmux
- vim
- jq
- rsync
state: present
when: ansible_facts["os_family"] == "FreeBSD"
- name: Install fish shell
ansible.builtin.package:
name: fish
state: present
when: inventory_hostname != 'london-a'
- name: Get fish shell path
ansible.builtin.command: which fish
@ -92,33 +53,27 @@
- {regexp: '^#?PasswordAuthentication', line: 'PasswordAuthentication no'}
- {regexp: '^#?X11Forwarding', line: 'X11Forwarding no'}
notify: Restart sshd
when: ansible_facts["os_family"] != "FreeBSD"
- name: Enable fail2ban (Debian)
- name: Enable fail2ban
ansible.builtin.service:
name: fail2ban
state: started
enabled: true
when: ansible_facts["os_family"] == "Debian"
# --- UFW firewall (Debian only) ---
# --- UFW firewall ---
- name: Set UFW default deny incoming
community.general.ufw:
direction: incoming
default: deny
when:
- ansible_facts["os_family"] == "Debian"
- common_ufw_enabled | bool
when: common_ufw_enabled | bool
notify: Reload ufw
- name: Set UFW default allow outgoing
community.general.ufw:
direction: outgoing
default: allow
when:
- ansible_facts["os_family"] == "Debian"
- common_ufw_enabled | bool
when: common_ufw_enabled | bool
notify: Reload ufw
- name: Allow all traffic on Tailscale interface
@ -127,9 +82,7 @@
direction: in
interface: tailscale0
comment: "Tailscale mesh - allow all"
when:
- ansible_facts["os_family"] == "Debian"
- common_ufw_enabled | bool
when: common_ufw_enabled | bool
notify: Reload ufw
- name: Allow SSH (safety net)
@ -138,9 +91,7 @@
port: '22'
proto: tcp
comment: "SSH"
when:
- ansible_facts["os_family"] == "Debian"
- common_ufw_enabled | bool
when: common_ufw_enabled | bool
notify: Reload ufw
- name: Allow host-specific ports
@ -151,7 +102,6 @@
comment: "{{ item.comment | default(omit) }}"
loop: "{{ common_ufw_allowed_ports }}"
when:
- ansible_facts["os_family"] == "Debian"
- common_ufw_enabled | bool
- common_ufw_allowed_ports | length > 0
notify: Reload ufw
@ -159,6 +109,4 @@
- name: Enable UFW
community.general.ufw:
state: enabled
when:
- ansible_facts["os_family"] == "Debian"
- common_ufw_enabled | bool
when: common_ufw_enabled | bool

View file

@ -9,14 +9,12 @@
- gnupg
state: present
update_cache: true
when: ansible_facts["os_family"] == "Debian"
- name: Create keyrings directory
ansible.builtin.file:
path: /etc/apt/keyrings
state: directory
mode: '0755'
when: ansible_facts["os_family"] == "Debian"
- name: Set Docker repo variables
ansible.builtin.set_fact:
@ -26,7 +24,6 @@
{{ ansible_facts['architecture']
| regex_replace('x86_64', 'amd64')
| regex_replace('aarch64', 'arm64') }}
when: ansible_facts["os_family"] == "Debian"
- name: Build Docker repo line
ansible.builtin.set_fact:
@ -35,7 +32,6 @@
signed-by=/etc/apt/keyrings/docker.asc]
https://download.docker.com/linux/{{ docker_distro }}
{{ ansible_facts['distribution_release'] }} stable
when: ansible_facts["os_family"] == "Debian"
- name: Add Docker GPG key
ansible.builtin.get_url:
@ -43,7 +39,6 @@
dest: /etc/apt/keyrings/docker.asc
mode: '0644'
force: false
when: ansible_facts["os_family"] == "Debian"
- name: Add Docker apt repository
ansible.builtin.apt_repository:
@ -51,7 +46,6 @@
filename: docker
state: present
update_cache: true
when: ansible_facts["os_family"] == "Debian"
- name: Remove old docker packages (Debian/Ubuntu)
ansible.builtin.apt:
@ -60,7 +54,6 @@
- docker-compose
- docker-compose-v2
state: absent
when: ansible_facts["os_family"] == "Debian"
- name: Install Docker (Debian/Ubuntu)
ansible.builtin.apt:
@ -70,15 +63,6 @@
- containerd.io
- docker-compose-plugin
state: present
when: ansible_facts["os_family"] == "Debian"
- name: Install Docker (Alpine)
community.general.apk:
name:
- docker
- docker-cli-compose
state: present
when: ansible_facts["os_family"] == "Alpine"
- name: Enable and start Docker
ansible.builtin.service:

View file

@ -1,9 +0,0 @@
---
# firewall_alpine defaults
# Enable iptables persistence via OpenRC
firewall_alpine_persist: true
# fail2ban SSH protection
firewall_alpine_fail2ban_enabled: true
firewall_alpine_fail2ban_maxretry: 10

View file

@ -1,9 +0,0 @@
---
- name: Restore iptables
ansible.builtin.shell: iptables-restore < /etc/iptables/rules-save
changed_when: true
- name: Restart fail2ban
ansible.builtin.service:
name: fail2ban
state: restarted

View file

@ -1,52 +0,0 @@
---
# Firewall management for Alpine hosts.
# Manages iptables persistence and fail2ban for SSH protection.
#
# NOTE: Docker manages port-forwarding rules for published container ports
# (e.g. mail ports on nuremberg-a). This role only handles non-Docker rules.
- name: Install iptables and fail2ban
community.general.apk:
name:
- iptables
- fail2ban
state: present
# --- iptables persistence ---
- name: Ensure /etc/iptables directory exists
ansible.builtin.file:
path: /etc/iptables
state: directory
mode: '0700'
- name: Deploy iptables rules
ansible.builtin.template:
src: rules.v4.j2
dest: /etc/iptables/rules-save
mode: '0600'
notify: Restore iptables
when: firewall_alpine_persist | bool
- name: Ensure iptables starts on boot
ansible.builtin.service:
name: iptables
enabled: true
when: firewall_alpine_persist | bool
# --- fail2ban ---
- name: Deploy fail2ban Alpine SSH jail
ansible.builtin.template:
src: alpine-ssh.conf.j2
dest: /etc/fail2ban/jail.d/alpine-ssh.conf
mode: '0644'
notify: Restart fail2ban
when: firewall_alpine_fail2ban_enabled | bool
- name: Enable fail2ban
ansible.builtin.service:
name: fail2ban
state: started
enabled: true
when: firewall_alpine_fail2ban_enabled | bool

View file

@ -1,16 +0,0 @@
# {{ ansible_managed }}
# fail2ban SSH jails for Alpine Linux
[sshd]
enabled = true
filter = alpine-sshd
port = ssh
logpath = /var/log/messages
maxretry = {{ firewall_alpine_fail2ban_maxretry }}
[sshd-ddos]
enabled = true
filter = alpine-sshd-ddos
port = ssh
logpath = /var/log/messages
maxretry = {{ firewall_alpine_fail2ban_maxretry }}

View file

@ -1,33 +0,0 @@
# {{ ansible_managed }}
# iptables rules for {{ inventory_hostname }}
#
# Docker and Tailscale manage their own chains automatically.
# This file captures non-Docker, non-Tailscale INPUT rules only.
#
# Mail ports (25,80,110,143,443,465,587,993,995) are exposed via
# Docker port mappings — traffic goes through FORWARD, not INPUT.
*filter
:INPUT DROP [0:0]
:FORWARD ACCEPT [0:0]
:OUTPUT ACCEPT [0:0]
# Allow loopback
-A INPUT -i lo -j ACCEPT
# Allow established and related connections
-A INPUT -m conntrack --ctstate ESTABLISHED,RELATED -j ACCEPT
# Allow all traffic on Tailscale interface
-A INPUT -i tailscale0 -j ACCEPT
# Allow SSH (public access — fail2ban provides brute-force protection)
-A INPUT -p tcp --dport 22 -j ACCEPT
# Allow ICMP (ping)
-A INPUT -p icmp -j ACCEPT
{% for rule in firewall_alpine_extra_input_rules | default([]) %}
{{ rule }}
{% endfor %}
COMMIT

View file

@ -1,24 +1,7 @@
---
# ZFS management: scrub scheduling, pool monitoring.
# Supports both Linux (systemd timers / cron) and FreeBSD (crontab).
# ZFS scrub scheduling.
- name: "ZFS scrub scheduling (Linux)"
when: ansible_os_family != "FreeBSD" and zfs_scrub_enabled
block:
- name: Install ZFS scrub cron jobs (Linux)
ansible.builtin.cron:
name: "ZFS scrub {{ item }}"
minute: "{{ zfs_scrub_minute }}"
hour: "{{ zfs_scrub_hour }}"
weekday: "{{ zfs_scrub_weekday }}"
job: "/sbin/zpool scrub {{ item }}"
user: root
loop: "{{ zfs_pools }}"
- name: "ZFS scrub scheduling (FreeBSD)"
when: ansible_os_family == "FreeBSD" and zfs_scrub_enabled
block:
- name: Install ZFS scrub cron jobs (FreeBSD)
- name: Install ZFS scrub cron jobs
ansible.builtin.cron:
name: "ZFS scrub {{ item }}"
minute: "{{ zfs_scrub_minute }}"
@ -27,3 +10,4 @@
job: "/sbin/zpool scrub {{ item }}"
user: root
loop: "{{ zfs_pools }}"
when: zfs_scrub_enabled