--- - name: Install iptables and iptables-persistent ansible.builtin.apt: name: - iptables - iptables-persistent - netfilter-persistent state: present update_cache: true - name: Deploy SSH hardening configuration ansible.builtin.template: src: 99-ssh-hardening.conf.j2 dest: /etc/ssh/sshd_config.d/99-ssh-hardening.conf mode: '0644' owner: root group: root validate: 'sshd -t -f %s' register: ssh_config_changed - name: Restart SSH daemon asynchronously (to maintain connection) ansible.builtin.shell: "nohup systemctl restart sshd &" when: ssh_config_changed.changed changed_when: true - name: Wait for SSH port to become available ansible.builtin.wait_for: host: "{{ ansible_host | default(inventory_hostname) }}" port: 22 delay: 2 timeout: 30 state: started when: ssh_config_changed.changed delegate_to: localhost - name: Reset SSH connection to pick up new configuration ansible.builtin.meta: reset_connection when: ssh_config_changed.changed - name: Verify SSH connection after restart ansible.builtin.ping: when: ssh_config_changed.changed - name: Configure iptables for SSH restrictions (non-Forgejo servers) block: - name: Accept SSH from WireGuard network ansible.builtin.iptables: chain: INPUT protocol: tcp destination_port: '22' source: "{{ wireguard_network }}" jump: ACCEPT comment: Allow SSH from WireGuard VPN - name: Accept SSH from VPC network ansible.builtin.iptables: chain: INPUT protocol: tcp destination_port: '22' source: "{{ vpc_network }}" jump: ACCEPT comment: Allow SSH from internal VPC - name: Accept established SSH connections ansible.builtin.iptables: chain: INPUT protocol: tcp destination_port: '22' ctstate: ESTABLISHED,RELATED jump: ACCEPT comment: Allow established SSH connections - name: Drop all other SSH connections ansible.builtin.iptables: chain: INPUT protocol: tcp destination_port: '22' jump: DROP comment: Drop SSH from untrusted networks when: not ssh_allow_public_git - name: Save iptables rules ansible.builtin.shell: | iptables-save > /etc/iptables/rules.v4 netfilter-persistent save args: executable: /bin/bash changed_when: true when: not ssh_allow_public_git - name: Display SSH access information ansible.builtin.debug: msg: | SSH hardening applied to {{ inventory_hostname }}: - Shell users ({{ ssh_shell_users | join(', ') }}): Only from {{ ssh_allowed_networks | join(', ') }} {% if ssh_allow_public_git %} - Git user ({{ ssh_git_user }}): Public access allowed for Forgejo - No iptables restrictions (sshd AllowUsers controls access) {% else %} - iptables rules: SSH blocked except from trusted networks {% endif %} - Strong cryptography enforced (RSA-SHA2, Ed25519, ChaCha20, AES-GCM) - Authorized keys files: .ssh/authorized_keys (manual), .ssh/authorized_keys.forgejo (git-managed)