Initial commit — OpenClaw VM infrastructure
- 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>
This commit is contained in:
@@ -0,0 +1,165 @@
|
||||
---
|
||||
# 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
|
||||
Reference in New Issue
Block a user