Aller au contenu

Sécurité et validation

Hardening de l'image avec fail2ban, firewall et SSH. Recapitulatif des assertions. Couche sécurité.


Rôle security

Ce rôle sécurisé l'image VDI :

  • fail2ban — protection contre le brute-force
  • Firewall — ufw (Ubuntu) ou firewalld (Rocky)
  • SSH hardening — desactivation du login root, authentification par clé

Variables par défaut

Créez roles/security/defaults/main.yml :

security_enabled: true
security_fail2ban: true
security_ufw: true
security_firewalld: true
security_ssh_hardening: true
security_allowed_ports:
  - "22"
  - "3389"

Tâches principales

Créez roles/security/tasks/main.yml :

---
# --- fail2ban ---
- name: Installer fail2ban
  ansible.builtin.package:
    name: fail2ban
    state: present
  when: security_fail2ban

- name: Configurer fail2ban pour xRDP
  ansible.builtin.copy:
    dest: /etc/fail2ban/jail.d/xrdp.conf
    content: |
      [xrdp]
      enabled = true
      port = 3389
      filter = xrdp
      logpath = /var/log/xrdp.log
      maxretry = 5
      bantime = 600
    mode: '0644'
  when: security_fail2ban
  notify: Restart fail2ban

- name: Activer fail2ban
  ansible.builtin.systemd:
    name: fail2ban
    enabled: true
    state: started
  when: security_fail2ban

# --- Firewall (Ubuntu) ---
- name: Installer ufw
  ansible.builtin.apt:
    name: ufw
    state: present
  when: security_ufw and ansible_os_family == "Debian"

- name: Autoriser les ports (ufw)
  ansible.builtin.command:
    cmd: "ufw allow {{ item }}"
  loop: "{{ security_allowed_ports }}"
  when: security_ufw and ansible_os_family == "Debian"
  changed_when: true

- name: Activer ufw
  ansible.builtin.command:
    cmd: "ufw --force enable"
  when: security_ufw and ansible_os_family == "Debian"
  changed_when: true

# --- Firewall (Rocky) ---
- name: Installer firewalld
  ansible.builtin.dnf:
    name: firewalld
    state: present
  when: security_firewalld and ansible_os_family == "RedHat"

- name: Activer firewalld
  ansible.builtin.systemd:
    name: firewalld
    enabled: true
    state: started
  when: security_firewalld and ansible_os_family == "RedHat"

- name: Autoriser les ports (firewalld)
  ansible.builtin.firewalld:
    port: "{{ item }}/tcp"
    permanent: true
    state: enabled
    immediate: true
  loop: "{{ security_allowed_ports }}"
  when: security_firewalld and ansible_os_family == "RedHat"

# --- SSH Hardening ---
- name: Desactiver le login root SSH
  ansible.builtin.lineinfile:
    path: /etc/ssh/sshd_config
    regexp: '^#?PermitRootLogin'
    line: 'PermitRootLogin no'
  when: security_ssh_hardening
  notify: Restart SSH

- name: Desactiver l'authentification par mot de passe SSH
  ansible.builtin.lineinfile:
    path: /etc/ssh/sshd_config
    regexp: '^#?PasswordAuthentication'
    line: 'PasswordAuthentication no'
  when: security_ssh_hardening
  notify: Restart SSH

- name: Validation du role
  ansible.builtin.include_tasks: validate.yml
  tags: [validate]

Handlers

Créez roles/security/handlers/main.yml :

---
- name: Restart fail2ban
  ansible.builtin.systemd:
    name: fail2ban
    state: restarted

- name: Restart SSH
  ansible.builtin.systemd:
    name: sshd
    state: restarted

Assertions

Créez roles/security/tasks/validate.yml :

---
# --- Niveau 1 : technique ---
- name: "Assert : fail2ban actif"
  ansible.builtin.systemd:
    name: fail2ban
  register: f2b_status
  failed_when: f2b_status.status.ActiveState != "active"
  when: security_fail2ban

# --- Niveau 2 : cas d'usage ---
- name: "Assert : SSH n'autorise pas le login root"
  ansible.builtin.command: sshd -T
  register: sshd_config
  changed_when: false
  failed_when: "'permitrootlogin no' not in sshd_config.stdout | lower"
  when: security_ssh_hardening

- name: "Assert : Le firewall est actif (Ubuntu)"
  ansible.builtin.command: ufw status
  register: ufw_result
  changed_when: false
  failed_when: "'active' not in ufw_result.stdout | lower"
  when: security_ufw and ansible_os_family == "Debian"

- name: "Assert : Le firewall est actif (Rocky)"
  ansible.builtin.systemd:
    name: firewalld
  register: fw_status
  failed_when: fw_status.status.ActiveState != "active"
  when: security_firewalld and ansible_os_family == "RedHat"

- name: "Assert : Seuls les ports autorises sont ouverts"
  ansible.builtin.shell: |
    ss -tlnp | grep LISTEN
  register: open_ports
  changed_when: false

- name: "Assert : La jail xRDP est active dans fail2ban"
  ansible.builtin.command: fail2ban-client status xrdp
  changed_when: false
  when: security_fail2ban

Recapitulatif des assertions

Toutes les assertions exécutées lors du build, par rôle :

Rôle Niveau 1 (technique) Niveau 2 (cas d'usage)
desktop XFCE installe, xRDP actif Port RDP ouvert, locale active, utilisateur existe
apps LibreOffice/Firefox/VS Code installees VS Code peut installer une extension, LibreOffice headless
podman Podman installe Conteneur rootless, registries accessibles, build multi-arch
qemu qemu-user-static ou qemu-system installe binfmt_misc enregistre, exécution cross-arch
k3s K3s installe, cluster accessible Pod schedulable, rootless vérifié, kubectl sans sudo
security fail2ban actif Root SSH bloque, firewall actif, jail xRDP active

Exécuter les assertions seules

ansible-playbook playbook.yml --tags validate -e profile=developer

Cela exécuté uniquement les blocs tagges validate de chaque rôle actif.