--- - name: Validate system requirements ansible.builtin.assert: that: - ansible_os_family == "Debian" - ansible_python_version is version('3.6', '>=') fail_msg: "Unsupported system - requires Debian and Python 3.6+" - name: Update package cache ansible.builtin.apt: update_cache: true cache_valid_time: 3600 changed_when: false - name: Install base packages ansible.builtin.apt: name: "{{ base_packages }}" state: present update_cache: true - name: Check if admin user exists ansible.builtin.getent: database: passwd key: "{{ admin_user }}" register: admin_check failed_when: false changed_when: false - name: Create admin user ansible.builtin.user: name: "{{ admin_user }}" groups: sudo append: true create_home: true shell: /bin/bash when: admin_check.failed - name: Configure timezone community.general.timezone: name: "{{ node_timezone }}" - name: Configure SSH security block: - name: Disable root SSH login ansible.builtin.lineinfile: path: /etc/ssh/sshd_config regexp: '^PermitRootLogin' line: 'PermitRootLogin no' state: present when: ssh_disabled_root_login notify: restart sshd - name: Set SSH port ansible.builtin.lineinfile: path: /etc/ssh/sshd_config regexp: '^Port' line: "Port {{ ssh_port }}" state: present notify: restart sshd - name: Disable password authentication ansible.builtin.lineinfile: path: /etc/ssh/sshd_config regexp: '^PasswordAuthentication' line: 'PasswordAuthentication no' state: present when: ssh_disable_password_auth notify: restart sshd - name: Configure firewall block: - name: Enable UFW firewall community.general.ufw: state: enabled policy: "{{ firewall_default_policy }}" when: firewall_enabled - name: Allow SSH access community.general.ufw: rule: allow port: "{{ ssh_port }}" proto: tcp when: firewall_enabled - name: Allow HTTP/HTTPS community.general.ufw: rule: allow port: "{{ item }}" proto: tcp loop: "{{ firewall_allowed_tcp_ports }}" when: firewall_enabled and item not in [ssh_port] - name: Configure fail2ban ansible.builtin.template: src: jail.local.j2 dest: /etc/fail2ban/jail.local backup: true mode: '0644' notify: restart fail2ban - name: Enable unattended upgrades ansible.builtin.lineinfile: path: /etc/apt/apt.conf.d/20auto-upgrades regexp: '^APT::Periodic::Unattended-Upgrade' line: 'APT::Periodic::Unattended-Upgrade "1";' state: present - name: Create application directories ansible.builtin.file: path: "{{ item.path }}" state: directory owner: "{{ item.owner }}" group: "{{ item.group }}" mode: "{{ item.mode }}" loop: "{{ app_directories }}" - name: Record role-specific service intent ansible.builtin.debug: msg: "Would configure {{ node_type | default('generic') }} service components in a full lab deployment" - name: Verify services are running ansible.builtin.service: name: "{{ item }}" state: started enabled: true loop: "{{ services_to_verify }}" when: services_to_verify | length > 0 failed_when: false - name: Run health checks ansible.builtin.uri: url: http://localhost/health method: GET status_code: 200 register: health_check failed_when: false ignore_errors: true when: "'webservers' in group_names"