--- # Security and firewall configuration tasks - name: Configure SSH security lineinfile: path: /etc/ssh/sshd_config regexp: "{{ item.regexp }}" line: "{{ item.line }}" backup: yes loop: - { regexp: '^#?PermitRootLogin', line: 'PermitRootLogin yes' } - { regexp: '^#?PasswordAuthentication', line: 'PasswordAuthentication {{ "yes" if not ssh_key_based_auth else "no" }}' } - { regexp: '^#?PubkeyAuthentication', line: 'PubkeyAuthentication yes' } - { regexp: '^#?Port', line: 'Port {{ ssh_port }}' } - { regexp: '^#?MaxAuthTries', line: 'MaxAuthTries 3' } - { regexp: '^#?ClientAliveInterval', line: 'ClientAliveInterval 300' } - { regexp: '^#?ClientAliveCountMax', line: 'ClientAliveCountMax 2' } notify: restart sshd tags: ['ssh_security'] - name: Configure fail2ban for SSH template: src: jail.local.j2 dest: /etc/fail2ban/jail.local backup: yes notify: restart fail2ban tags: ['fail2ban'] - name: Configure fail2ban filter for Plex template: src: plex-fail2ban-filter.j2 dest: /etc/fail2ban/filter.d/plex.conf backup: yes when: plex_public_access | default(false) notify: restart fail2ban tags: ['fail2ban', 'plex'] - name: Start and enable fail2ban systemd: name: fail2ban state: started enabled: yes tags: ['fail2ban'] - name: Reset UFW to defaults ufw: state: reset when: ufw_enabled tags: ['firewall'] - name: Configure UFW default policies ufw: direction: "{{ item.direction }}" policy: "{{ item.policy }}" loop: - { direction: 'incoming', policy: "{{ ufw_default_policy_incoming }}" } - { direction: 'outgoing', policy: "{{ ufw_default_policy_outgoing }}" } when: ufw_enabled tags: ['firewall'] - name: Allow SSH through UFW ufw: rule: allow port: "{{ ssh_port }}" proto: tcp when: ufw_enabled tags: ['firewall'] - name: Check if Tailscale is installed command: which tailscale register: tailscale_check failed_when: false changed_when: false when: tailscale_enabled tags: ['tailscale'] - name: Install Tailscale shell: | curl -fsSL https://tailscale.com/install.sh | sh when: tailscale_enabled and tailscale_check.rc != 0 tags: ['tailscale'] - name: Get Tailscale interface information shell: ip addr show {{ tailscale_interface }} | grep 'inet ' | awk '{print $2}' | cut -d'/' -f1 register: tailscale_ip failed_when: false changed_when: false when: tailscale_enabled tags: ['tailscale'] - name: Allow Tailscale interface through UFW ufw: rule: allow interface: "{{ tailscale_interface }}" direction: in when: ufw_enabled and tailscale_enabled tags: ['firewall', 'tailscale'] - name: Allow Arrs services from Tailscale network ufw: rule: allow port: "{{ item.value }}" proto: tcp src: "{{ tailscale_ip.stdout | regex_replace('\\.[0-9]+$', '.0/24') }}" loop: "{{ ports | dict2items }}" when: ufw_enabled and tailscale_enabled and tailscale_ip.stdout != "" tags: ['firewall', 'tailscale'] - name: Allow Docker bridge network communication ufw: rule: allow from_ip: "{{ docker_network_subnet }}" to_ip: "{{ docker_network_subnet }}" when: ufw_enabled tags: ['firewall', 'docker'] - name: Allow Plex Media Server through UFW (public access) ufw: rule: allow port: "{{ item.port }}" proto: "{{ item.proto }}" comment: "{{ item.comment }}" loop: - { port: "32400", proto: "tcp", comment: "Plex Media Server" } - { port: "3005", proto: "tcp", comment: "Plex Home Theater via Plex Companion" } - { port: "8324", proto: "tcp", comment: "Plex for Roku via Plex Companion" } - { port: "32469", proto: "tcp", comment: "Plex DLNA Server" } - { port: "1900", proto: "udp", comment: "Plex DLNA Server" } - { port: "32410", proto: "udp", comment: "Plex GDM network discovery" } - { port: "32412", proto: "udp", comment: "Plex GDM network discovery" } - { port: "32413", proto: "udp", comment: "Plex GDM network discovery" } - { port: "32414", proto: "udp", comment: "Plex GDM network discovery" } when: ufw_enabled and plex_public_access | default(false) tags: ['firewall', 'plex'] - name: Enable UFW ufw: state: enabled when: ufw_enabled tags: ['firewall'] - name: Configure Docker security options template: src: docker-security.json.j2 dest: /etc/docker/seccomp-profile.json mode: '0644' notify: restart docker tags: ['docker_security'] - name: Create AppArmor profile for Docker containers template: src: docker-apparmor.j2 dest: /etc/apparmor.d/docker-arrs mode: '0644' notify: reload apparmor tags: ['apparmor'] - name: Set secure file permissions file: path: "{{ item.path }}" mode: "{{ item.mode }}" owner: "{{ item.owner | default('root') }}" group: "{{ item.group | default('root') }}" loop: - { path: '/etc/ssh/sshd_config', mode: '0600' } - { path: '/etc/fail2ban/jail.local', mode: '0644' } - { path: '/etc/docker', mode: '0755' } tags: ['file_permissions'] - name: Configure log monitoring template: src: rsyslog-docker.conf.j2 dest: /etc/rsyslog.d/30-docker.conf mode: '0644' notify: restart rsyslog tags: ['logging'] - name: Create security audit script template: src: security-audit.sh.j2 dest: "{{ docker_root }}/scripts/security-audit.sh" owner: "{{ docker_user }}" group: "{{ docker_group }}" mode: '0755' tags: ['security_audit']