--- # VPN-Only Access Configuration Tasks - name: Validate management_allowed_sources is defined ansible.builtin.assert: that: - management_allowed_sources is defined - management_allowed_sources | length > 0 fail_msg: "management_allowed_sources must be defined and non-empty when vpn_only_mode is true" success_msg: "Management access sources configured: {{ management_allowed_sources | join(', ') }}" - name: Restrict management ports to allowed sources only community.general.ufw: rule: allow port: "{{ item.0.port }}" proto: "{{ item.0.proto }}" from_ip: "{{ item.1 }}" comment: "{{ item.0.comment }} (from {{ item.1 }})" loop: "{{ management_ports | product(management_allowed_sources) | list }}" loop_control: label: "{{ item.0.comment }} port {{ item.0.port }} from {{ item.1 }}" - name: Apply SSH rate limiting for each allowed source community.general.ufw: rule: limit port: "22" proto: tcp from_ip: "{{ item }}" loop: "{{ management_allowed_sources }}" when: ssh_rate_limit | bool - name: Deny management ports from all other sources community.general.ufw: rule: deny port: "{{ item.port }}" proto: "{{ item.proto }}" comment: "Block {{ item.comment }} from public" loop: "{{ management_ports }}" - name: Create VPN-only access summary ansible.builtin.copy: dest: /root/firewall-config.txt content: | # Firewall Configuration Summary ## VPN-Only Mode: ENABLED ## Management Access Allowed From: {% for source in management_allowed_sources %} - {{ source }} {% endfor %} ## Management Ports (Restricted Access): {% for port in management_ports %} - {{ port.port }}/{{ port.proto }} - {{ port.comment }} {% endfor %} ## Public Ports (Unrestricted): {% for port in public_ports %} - {{ port.port }}/{{ port.proto }} - {{ port.comment }} {% endfor %} ## Security Notes: - Management access ONLY from: {{ management_allowed_sources | join(', ') }} - SSH is rate-limited to prevent brute force - Default policy: DENY all incoming (except allowed above) - Logging level: {{ firewall_logging }} ## To view firewall rules: sudo ufw status verbose ## To modify rules: Edit inventory variables and re-run playbook mode: '0600' - name: Display VPN-only configuration ansible.builtin.debug: msg: - "VPN-Only Mode: ENABLED" - "Management access allowed from: {{ management_allowed_sources | join(', ') }}" - "Management ports are ONLY accessible from allowed sources" - "Public ports remain accessible from internet" - "Configuration saved to /root/firewall-config.txt"