- ansible/: VM provisioning playbooks and roles - provision-vm.yml: create KVM VM from Ubuntu cloud image - install.yml: install OpenClaw on guest (upstream) - customize.yml: swappiness, virtiofs fstab, linger - roles/vm/: libvirt domain XML, cloud-init templates - inventory.yml + host_vars/zap.yml: zap instance config - backup-openclaw-vm.sh: daily rsync + MinIO upload - restore-openclaw-vm.sh: full redeploy from scratch - README.md: full operational documentation Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
166 lines
4.5 KiB
YAML
166 lines
4.5 KiB
YAML
---
|
|
# Linux-specific firewall configuration (UFW) with security hardening
|
|
|
|
# Install and configure fail2ban for SSH brute-force protection
|
|
- name: Install fail2ban
|
|
ansible.builtin.apt:
|
|
name: fail2ban
|
|
state: present
|
|
update_cache: true
|
|
|
|
- name: Configure fail2ban for SSH protection
|
|
ansible.builtin.copy:
|
|
dest: /etc/fail2ban/jail.local
|
|
owner: root
|
|
group: root
|
|
mode: '0644'
|
|
content: |
|
|
# OpenClaw security hardening - SSH protection
|
|
[DEFAULT]
|
|
bantime = 3600
|
|
findtime = 600
|
|
maxretry = 5
|
|
backend = systemd
|
|
|
|
[sshd]
|
|
enabled = true
|
|
port = ssh
|
|
filter = sshd
|
|
# logpath not needed - systemd backend reads from journal
|
|
notify: Restart fail2ban
|
|
|
|
- name: Enable and start fail2ban
|
|
ansible.builtin.systemd:
|
|
name: fail2ban
|
|
state: started
|
|
enabled: true
|
|
|
|
# Install and configure unattended-upgrades for automatic security updates
|
|
- name: Install unattended-upgrades
|
|
ansible.builtin.apt:
|
|
name:
|
|
- unattended-upgrades
|
|
- apt-listchanges
|
|
state: present
|
|
|
|
- name: Configure automatic security updates
|
|
ansible.builtin.copy:
|
|
dest: /etc/apt/apt.conf.d/20auto-upgrades
|
|
owner: root
|
|
group: root
|
|
mode: '0644'
|
|
content: |
|
|
APT::Periodic::Update-Package-Lists "1";
|
|
APT::Periodic::Unattended-Upgrade "1";
|
|
APT::Periodic::AutocleanInterval "7";
|
|
|
|
- name: Configure unattended-upgrades to only install security updates
|
|
ansible.builtin.copy:
|
|
dest: /etc/apt/apt.conf.d/50unattended-upgrades
|
|
owner: root
|
|
group: root
|
|
mode: '0644'
|
|
content: |
|
|
// OpenClaw security hardening - automatic security updates
|
|
Unattended-Upgrade::Allowed-Origins {
|
|
"${distro_id}:${distro_codename}-security";
|
|
"${distro_id}ESMApps:${distro_codename}-apps-security";
|
|
"${distro_id}ESM:${distro_codename}-infra-security";
|
|
};
|
|
Unattended-Upgrade::Package-Blacklist {
|
|
};
|
|
Unattended-Upgrade::AutoFixInterruptedDpkg "true";
|
|
Unattended-Upgrade::MinimalSteps "true";
|
|
Unattended-Upgrade::Remove-Unused-Dependencies "true";
|
|
Unattended-Upgrade::Automatic-Reboot "false";
|
|
|
|
# UFW Firewall configuration
|
|
- name: Install UFW
|
|
ansible.builtin.apt:
|
|
name: ufw
|
|
state: present
|
|
update_cache: true
|
|
|
|
- name: Set UFW default policies
|
|
community.general.ufw:
|
|
direction: "{{ item.direction }}"
|
|
policy: "{{ item.policy }}"
|
|
loop:
|
|
- { direction: 'incoming', policy: 'deny' }
|
|
- { direction: 'outgoing', policy: 'allow' }
|
|
- { direction: 'routed', policy: 'deny' }
|
|
|
|
- name: Allow SSH on port 22
|
|
community.general.ufw:
|
|
rule: allow
|
|
port: '22'
|
|
proto: tcp
|
|
comment: 'SSH'
|
|
|
|
- name: Allow Tailscale UDP port 41641
|
|
community.general.ufw:
|
|
rule: allow
|
|
port: '41641'
|
|
proto: udp
|
|
comment: 'Tailscale'
|
|
when: tailscale_enabled | bool
|
|
|
|
- name: Get default network interface
|
|
ansible.builtin.shell:
|
|
cmd: |
|
|
set -o pipefail
|
|
ip route | grep default | awk '{print $5}' | head -n1
|
|
executable: /bin/bash
|
|
register: default_interface
|
|
changed_when: false
|
|
|
|
- name: Validate default network interface was detected
|
|
ansible.builtin.assert:
|
|
that:
|
|
- default_interface.stdout is defined
|
|
- default_interface.stdout | length > 0
|
|
fail_msg: "Failed to detect default network interface. Cannot configure firewall rules safely."
|
|
success_msg: "Default network interface detected: {{ default_interface.stdout }}"
|
|
|
|
- name: Create UFW after.rules for Docker isolation
|
|
ansible.builtin.blockinfile:
|
|
path: /etc/ufw/after.rules
|
|
marker: "# {mark} ANSIBLE MANAGED BLOCK - Docker isolation"
|
|
insertbefore: "^COMMIT$"
|
|
block: |
|
|
# Docker port isolation - block all forwarded traffic by default
|
|
:DOCKER-USER - [0:0]
|
|
|
|
# Allow established connections
|
|
-A DOCKER-USER -m conntrack --ctstate RELATED,ESTABLISHED -j ACCEPT
|
|
|
|
# Allow localhost
|
|
-A DOCKER-USER -i lo -j ACCEPT
|
|
|
|
# Block all other forwarded traffic to Docker containers from external interface
|
|
-A DOCKER-USER -i {{ default_interface.stdout }} -j DROP
|
|
create: false
|
|
|
|
- name: Create Docker daemon config directory
|
|
ansible.builtin.file:
|
|
path: /etc/docker
|
|
state: directory
|
|
mode: '0755'
|
|
|
|
- name: Configure Docker daemon to work with UFW
|
|
ansible.builtin.template:
|
|
src: daemon.json.j2
|
|
dest: /etc/docker/daemon.json
|
|
owner: root
|
|
group: root
|
|
mode: '0644'
|
|
notify: Restart docker
|
|
|
|
- name: Enable UFW
|
|
community.general.ufw:
|
|
state: enabled
|
|
|
|
- name: Reload UFW
|
|
community.general.ufw:
|
|
state: reloaded
|